3

It seems that the protocol for Nativemessaging entails that the native App communicate with the extension via blocking read-then-write loop.

Firstly, is that correct?

If so, that makes it pretty hard to establish bidirectional asynchronous communications between the two sides.

Before I go doing something stupidly complicated to work around this limitation, is there some simple API to achieve bidirectional async messaging with native apps?


Things I'd like to support:

  • Connection-based Nativemessaging (i.e: long running)
  • Requests from either end with async responses
  • Notifications from either end without responses

My first 'stupidly complicated' thought to achieve this is to:

  1. use Nativemessaging to launch the native app and manage its lifetime
  2. on startup have the native app launch a WebSocket server and respond to the first request with a WebSocket URI to be used by the Webextension from therein
David-SkyMesh
  • 5,041
  • 1
  • 31
  • 38

2 Answers2

2

A little late, but for the extension I was working on, I was able to adapt the example on the mdn page you referenced to get rid of the blocking in the stdin reads (the stdout writes appear to be non-blocking from what I can tell so far, but I think the same idea could apply to them too if that's incorrect)

I'm working on Windows so a lot of the other SO posts suggesting using the select module for this weren't going to work for me. I had already been setting up to use asyncio in my project before discovering this, and so the answer to this SO post directed me to this page recommending to use the loop.run_in_executor method to handle these situations (as I understand it this creates a separate thread from the main event loop that gets blocked instead of it). Wrapping the stdin.buffer read from the example with that method got rid of the blocking for me.

grunet
  • 311
  • 2
  • 9
-1

Yes, you can use connection-based, bidirectional, asynchronous communications with native applications.

This is explained in the "Connection-based messaging" section of the MDN documentation page on Native messaging.

runtime.connectNative() creates/returns a runtime.Port which supports asynchronous communication. From the WebExtension side, messages are then sent using port.postMessage() and listened for using port.onMessage, which "contains the addListener() and removeListener() functions common to all events for extensions built using WebExtension APIs."MDN

You appear to have only read about "Connectionless messaging". The method runtime.sendNativeMessage() provides the ability to send only one message, then receive one message. That's it's purpose, and is roughly equivalent to runtime.sendMessage().

Makyen
  • 31,849
  • 12
  • 86
  • 121
  • I read the whole artcicle, multiple times and many supporting articles elsewhere. postMessage/onMessage on the webextension side seem like they could support bidirectional async communications, however the App-side documentation seems to indicate that's not the case there. As I said in my question the documentation seems to imply an app-side blocking read-then-write loop which precludes bidirectional async messaging. I also checked a whole bunch of implementations I found elsewhere and all had the same construction. Do you understand what I mean about the implications of such a construction? – David-SkyMesh Oct 25 '17 at 23:57
  • If the documentation is merely lacking an example of construction of the app-side that supports bidirectional async messaging, then I'd be happy to write one myself if given details of the protocol / API that allows it. – David-SkyMesh Oct 25 '17 at 23:59
  • @David-SkyMesh It communicates with the native application via reading from standard-in and writing to standard-out, which are normal I/O methods under most operating systems/languages, which aren't inherently blocking. I'm not sure what you're having an issue with. If they're blocking, then it's an OS/language constraint or how you're accessing them. The [Native messaging](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#App_side) example is a simple Python script which does implement it in the way you describe, but that's just because it's a simple example. – Makyen Oct 26 '17 at 00:11
  • `which aren't inherently blocking` / Well that depends on the protocol. Do you have knowledge of/ access to any documentation of the protocol that would establish that this limitation is not present in the API implementations on the browser side? It seems clear that the API-side only allows for a single simultaneous connection to each native-App process it launches.... – David-SkyMesh Oct 26 '17 at 00:37
  • For bidirection async messaging to work under those conditions (short of inefficient polling on the webextension side), the API on the webextension side would need to use some sort of select()/epoll()/etc loop. Does it (on Firefox) or does it actually expect the pattern of messages implied by the simple example? – David-SkyMesh Oct 26 '17 at 00:37
  • @David-SkyMesh, In a WebExtension, you can't poll. You *must* add an asynchronous listener using `port.onMessage`. The listener, `port.onMessage.addListener()`, fires when there's a message (data written to STDOUT in the native application). Yes, only one `runtime.Port` is created per native application instance. The format implemented on the interface is [described here](//developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#App_side). I'd have to check the source code/test to see if it actually waits for valid JSON, or just the message length indicated at the message head. – Makyen Oct 26 '17 at 01:34
  • I think we're talking at different levels. It's certainly possible to poll with an asynchronous listener - you just need to ensure that you only send one request at a time, that you use the reply to initiate the next request and that the rate of requests is controlled. As I alluded to, that's inefficient. – David-SkyMesh Oct 26 '17 at 02:10
  • as I already explained I've read and understood all of that. That still leaves a lot to be explained/discovered about the protocol and the webextension-side implementation. `I'd have to check the source code/test to see if it actually waits for valid JSON, or just the message length indicated at the message head`. Yeah, I can do the same, but I asked the SO question to get an authoritative answer. – David-SkyMesh Oct 26 '17 at 02:13