'Native Messaging Host (Chrome) failing on receiving messages properly when ported form Python 2 to Python 3
so it happens that I was writing an application alongside a Chrome Extension. Therefore I set up Native Messaging to allow one to talk to one another, I got it to a state where following the documentation and even some tutorials I can get both the Extension side working and the host to work while using Python 2.7, though when I tried porting the same host script to Python 3 which is the actual language the rest of my program is written with, again following documentation, examples and even unzip pypi Package's code snippets to do so, now I can't get it to work properly, it sends messages accordingly but fails to receive them. Please note the Extension side of things didn't and AFAIK shouldn't change.
For reference one of the best resources I used was https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging, which indeed has a Python 3 compatibility section and https://developer.chrome.com/docs/apps/nativeMessaging/, Chrome Documentation for Apps but with the same API for Extensions.
Python 2 Code
import struct
import sys
import os
# On Windows, the default I/O mode is O_TEXT. Set this to O_BINARY
# to avoid unwanted modifications of the input/output streams.
if sys.platform == "win32":
import msvcrt
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
# Thread that reads messages from the webapp.
def read_thread_func():
while True:
# Read the message length (first 4 bytes).
text_length_bytes = sys.stdin.read(4)
if not text_length_bytes:
sys.exit(0)
# Unpack message length as 4 byte integer.
text_length = struct.unpack('=I', text_length_bytes)[0]
# Read the text (JSON object) of the message.
text = sys.stdin.read(text_length).encode("utf-8")
if (os.path.exists('./data')):
with open('./data', 'wb') as f:
f.write(text)
f.close()
else:
with open('./data', 'xb') as f:
f.write(text)
f.close()
# Helper function that sends a message to the webapp.
def send_message(message):
# Write message size.
sys.stdout.write(struct.pack('=I', len(message.encode("utf-8"))))
# Write the message itself.
sys.stdout.write(struct.pack(str(len(message.encode("utf-8")))+"s", message.encode("utf-8")))
sys.stdout.flush()
def index():
send_message('{"msg": "Hello World!"}')
read_thread_func()
if __name__ == '__main__':
index()
The above code works perfectly
Python 3
...
def send_message(message):
# Write message size.
sys.stdout.buffer.write(struct.pack('=I', len(message.encode("utf-8"))))
# Write the message itself.
sys.stdout.buffer.write(struct.pack(str(len(message.encode("utf-8")))+"s", message.encode("utf-8")))
sys.stdout.flush()
...
Above I have only put the code that is actually modified, the rest stays the same, but in theory this should work although it does not, and to be clear this modified part is just for the function responsible for sending messages which even in Python 3 it can do, the problem is reading, I have tried a lot of stuff including just copying out the Mozilla snippet but nothing seems to solve the problem and because the Extension side is probably correct as it is the configuration on the registry and respective manifest because of the fact that in the Python 2 version it does work I can't seem to find the issue, if someone could please help me out I would really appreciate it, thanks for your time.
Error Log (not really an error log but its the only thing that appears when I interrupt the program):
Traceback (most recent call last):
File "C:\path\to\handler", line 69, in <module>
index()
File "C:\path\to\handler", line 65, in index
read_thread_func()
File "C:\path\to\handler", line 17, in read_thread_func
text_length_bytes = sys.stdin.read(4)
KeyboardInterrupt
Otherwise it just shows a symbol (the utf-8 decoded length of the message to be able to get displayed on the console, and the actual message that is sent right away, this applies to both cases and is expected because of the use of the stdin to send the messages AFAIK)
For Python 3: ".\python3.9\python.exe" "handler" For Python 2:
".\python27\python.exe" "handler"
This is the command line which starts the program, note that the file name of the file afore mentioned is handler, also tried launching it with the -u option as I am in Windows 10. Also Python module 2to3.py does not spot anything to port over.
Solution 1:[1]
Solved, it was an issue with both endianness and data types introduced because of Python 3
The full working code is this one if someone is interested:
# Thread that reads messages from the webapp.
def read_thread_func():
while True:
# Read the message length (first 4 bytes).
text_length_bytes = sys.stdin.buffer.read(4)
if not text_length_bytes:
sys.exit(0)
# Unpack message length as 4 byte integer.
if (sys.byteorder == 'big'):
text_length = int.from_bytes(text_length_bytes, byteorder='big')
else:
text_length = int.from_bytes(text_length_bytes, byteorder='little')
# Read the text (JSON object) of the message.
text = sys.stdin.read(text_length)
if (os.path.exists('./data')):
with open('./data', 'w') as f:
f.write(text)
f.close()
else:
with open('./data', 'x') as f:
f.write(text)
f.close()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Arch |
