Skip to content

Commit 18238c1

Browse files
authored
Merge pull request #564 from dotproto/native-update
Update native-messaging to use python3, clarify instructions
2 parents 1d8a18a + 735dee7 commit 18238c1

5 files changed

Lines changed: 93 additions & 88 deletions

File tree

native-messaging/README.md

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,62 @@ The WebExtension, which can be found under "add-on", connects to the native appl
44

55
The native application, which can be found under "app", listens for messages from the WebExtension. When it receives a message, the native application sends a response message whose payload is just "pong". The native application is written in Python.
66

7-
## Setup ##
7+
## Setup
88

99
To get this working, there's a little setup to do.
1010

11-
### Mac OS/Linux setup ###
11+
### Linux/macOS setup
1212

13-
1. Check that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for "ping_pong.py" include the `execute` permission.
14-
2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong.py" on your computer.
15-
3. copy "ping_pong.json" to the correct location on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS.
13+
0. (macOS) Store this extension in a location other than the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that prevent the Python script from executing as expected.
1614

17-
### Windows setup ###
15+
1. Make sure you have Python 3 installed, and your system's PATH environment variable includes the path to Python. You can check by executing this command:
1816

19-
1. Check you have Python installed, and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/3/using/windows.html). You'll need to restart the web browser after making this change, or the browser won't pick up the new environment variable.
20-
2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong_win.bat" on your computer. Note that you'll need to escape the Windows directory separator, like this: `"path": "C:\\Users\\MDN\\native-messaging\\app\\ping_pong_win.bat"`.
21-
3. Edit "ping_pong_win.bat" to refer to the location of "ping_pong.py" on your computer.
22-
4. Add a registry key containing the path to "ping_pong.json" on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find details of the registry key to add.
17+
```bash
18+
> which python3
19+
/usr/local/bin/python3
20+
```
2321

24-
To assist in troubleshooting on Windows, there is a script called `check_config_win.py`. Running this from the command line should give you an idea of any problems.
22+
If you don't see the path for Python, install Python 3. See [Using Python on Unix platforms](https://docs.python.org/3/using/unix.html) (for Linux) or [Using Python on a Mac](https://docs.python.org/3/using/mac.html). After making this change, restart Firefox so it picks up the new PATH environment variable.
2523
26-
## Testing the example ##
24+
2. Make sure that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for `app/ping_pong.py` include the `execute` permission. See [this article by RedHat](https://www.redhat.com/sysadmin/linux-file-permissions-explained) for more information.
2725
28-
First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's "manifest.json".
26+
3. Update the `"path"` field in `app/ping_pong.json` to be the full path to your `app/ping_pong.py` file.
2927
30-
Now, open the extension's console using the "Inspect" button - this is where you'll see communication between the browser and native app.
28+
For example, if you cloned this repository into `/Users/MDN/webextensions-examples/`, you would update the file like this:
29+
30+
```json
31+
"path": "/Users/MDN/webextensions-examples/native-messaging/app/ping_pong.py"
32+
```
33+
34+
4. Copy `app/ping_pong.json` to the correct location on your computer. There are too many options to list here; see the [Linux](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#linux) and [macOS](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#macos) secitons of [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS and personal preference.
35+
36+
### Windows setup
37+
38+
1. Make sure that you have Python 3 installed and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/3/using/windows.html). After making this change, restart Firefox so it picks up the new PATH environment variable.
39+
40+
2. Update the `"path"` field in `app\ping_pong.json` to use the full path of `app\ping_pong_win.bat` on your computer. Be aware that you must escape the Windows directory separator (`\`).
41+
42+
For example, if you cloned this repository into `C:\Users\MDN\webextensions-examples\`, you update the JSON file like this:
43+
44+
```json
45+
"path": "C:\\Users\\MDN\\webextensions-examples\\native-messaging\\app\\ping_pong_win.bat"
46+
```
47+
48+
3. Update `app\ping_pong_win.bat` to use the full path of `app\ping_pong.py` on your computer.
49+
50+
4. Add a registry key containing the full path of `app\ping_pong.json` on your computer. See [App manifest location](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find details of the registry key to add.
51+
52+
To assist in troubleshooting on Windows, there is a script next to this README file named `check_config_win.py`. Running this in a command shell should help you discover of any problems.
53+
54+
## Testing the example
55+
56+
First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's `manifest.json`.
57+
58+
Now, open the extension's console using the "Inspect" button. This is where you see communication between the browser and native app.
3159
3260
You should see a new browser action icon in the toolbar. Click it. You should see output like this in the console:
3361
3462
Sending: ping
35-
Received: pong3
36-
37-
If you're running Python 2.x, you'll see "pong2" as the response instead.
63+
Received: pong
3864
3965
If you don't see this output, see the [Troubleshooting guide](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#Troubleshooting) for ideas.

native-messaging/add-on/background.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,29 @@ On startup, connect to the "ping_pong" app.
44
let port = browser.runtime.connectNative("ping_pong");
55

66
/*
7-
Listen for messages from the app.
7+
Listen for messages from the app and log them to the console.
88
*/
99
port.onMessage.addListener((response) => {
1010
console.log("Received: " + response);
1111
});
1212

1313
/*
14-
On a click on the browser action, send the app a message.
14+
Listen for the native messaging port closing.
15+
*/
16+
port.onDisconnect.addListener((port) => {
17+
if (port.error) {
18+
console.log(`Disconnected due to an error: ${port.error.message}`);
19+
} else {
20+
// The port closed for an unspecified reason. If this occurred right after
21+
// calling `browser.runtime.connectNative()` there may have been a problem
22+
// starting the the native messaging client in the first place.
23+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#troubleshooting
24+
console.log(`Disconnected`, port);
25+
}
26+
});
27+
28+
/*
29+
When the extension's action icon is clicked, send the app a message.
1530
*/
1631
browser.browserAction.onClicked.addListener(() => {
1732
console.log("Sending: ping");

native-messaging/add-on/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"browser_action": {
2323
"default_icon": "icons/message.svg"
2424
},
25-
25+
2626
"permissions": ["nativeMessaging"]
2727

2828
}

native-messaging/app/ping_pong.py

Lines changed: 31 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,36 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22

33
import sys
44
import json
55
import struct
66

7-
try:
8-
# Python 3.x version
9-
# Read a message from stdin and decode it.
10-
def getMessage():
11-
rawLength = sys.stdin.buffer.read(4)
12-
if len(rawLength) == 0:
13-
sys.exit(0)
14-
messageLength = struct.unpack('@I', rawLength)[0]
15-
message = sys.stdin.buffer.read(messageLength).decode('utf-8')
16-
return json.loads(message)
17-
18-
# Encode a message for transmission,
19-
# given its content.
20-
def encodeMessage(messageContent):
21-
# https://docs.python.org/3/library/json.html#basic-usage
22-
# To get the most compact JSON representation, you should specify
23-
# (',', ':') to eliminate whitespace.
24-
# We want the most compact representation because the browser rejects
25-
# messages that exceed 1 MB.
26-
encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8')
27-
encodedLength = struct.pack('@I', len(encodedContent))
28-
return {'length': encodedLength, 'content': encodedContent}
29-
30-
# Send an encoded message to stdout
31-
def sendMessage(encodedMessage):
32-
sys.stdout.buffer.write(encodedMessage['length'])
33-
sys.stdout.buffer.write(encodedMessage['content'])
34-
sys.stdout.buffer.flush()
35-
36-
while True:
37-
receivedMessage = getMessage()
38-
if receivedMessage == "ping":
39-
sendMessage(encodeMessage("pong3"))
40-
except AttributeError:
41-
# Python 2.x version (if sys.stdin.buffer is not defined)
42-
# Read a message from stdin and decode it.
43-
def getMessage():
44-
rawLength = sys.stdin.read(4)
45-
if len(rawLength) == 0:
46-
sys.exit(0)
47-
messageLength = struct.unpack('@I', rawLength)[0]
48-
message = sys.stdin.read(messageLength)
49-
return json.loads(message)
50-
51-
# Encode a message for transmission,
52-
# given its content.
53-
def encodeMessage(messageContent):
54-
# https://docs.python.org/3/library/json.html#basic-usage
55-
# To get the most compact JSON representation, you should specify
56-
# (',', ':') to eliminate whitespace.
57-
# We want the most compact representation because the browser rejects
58-
# messages that exceed 1 MB.
59-
encodedContent = json.dumps(messageContent, separators=(',', ':'))
60-
encodedLength = struct.pack('@I', len(encodedContent))
61-
return {'length': encodedLength, 'content': encodedContent}
62-
63-
# Send an encoded message to stdout
64-
def sendMessage(encodedMessage):
65-
sys.stdout.write(encodedMessage['length'])
66-
sys.stdout.write(encodedMessage['content'])
67-
sys.stdout.flush()
68-
69-
while True:
70-
receivedMessage = getMessage()
71-
if receivedMessage == "ping":
72-
sendMessage(encodeMessage("pong2"))
7+
# Read a message from stdin and decode it.
8+
def getMessage():
9+
rawLength = sys.stdin.buffer.read(4)
10+
if len(rawLength) == 0:
11+
sys.exit(0)
12+
messageLength = struct.unpack('@I', rawLength)[0]
13+
message = sys.stdin.buffer.read(messageLength).decode('utf-8')
14+
return json.loads(message)
15+
16+
# Encode a message for transmission, given its content.
17+
def encodeMessage(messageContent):
18+
# https://docs.python.org/3/library/json.html#basic-usage
19+
# To get the most compact JSON representation, you should specify
20+
# (',', ':') to eliminate whitespace.
21+
# We want the most compact representation because the browser rejects
22+
# messages that exceed 1 MB.
23+
encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8')
24+
encodedLength = struct.pack('@I', len(encodedContent))
25+
return {'length': encodedLength, 'content': encodedContent}
26+
27+
# Send an encoded message to stdout
28+
def sendMessage(encodedMessage):
29+
sys.stdout.buffer.write(encodedMessage['length'])
30+
sys.stdout.buffer.write(encodedMessage['content'])
31+
sys.stdout.buffer.flush()
32+
33+
while True:
34+
receivedMessage = getMessage()
35+
if receivedMessage == "ping":
36+
sendMessage(encodeMessage("pong"))
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
@echo off
22

3-
call python C:\path\to\ping_pong.py
3+
call python3 C:\path\to\ping_pong.py

0 commit comments

Comments
 (0)