pythongoogle-chromefirefoxflaskchrome-native-messaging

Chrome Native Messaging - Execute the host manually


i'm trying to create a web extension using native messaging that can interact with a Web API. So the idea is when someone sends a message through the API, the extension also receive it.

I follow the steps of the firefox example. So far so good, i was able to communicate between the host and the extension.

Here is my host code, using the flask framework:

import json
import sys
import struct
import threading
import os
from flask import Flask, request, jsonify, Response, abort


# Read a message from stdin and decode it.
def get_message():
    raw_length = sys.stdin.read(4)
    if not raw_length:
        sys.exit(0)
    message_length = struct.unpack('=I', raw_length)[0]
    message = sys.stdin.read(message_length)
    return json.loads(message)


# Encode a message for transmission, given its content.
def encode_message(message_content):
    encoded_content = json.dumps(message_content)
    encoded_length = struct.pack('=I', len(encoded_content))
    return {'length': encoded_length, 'content': encoded_content}


# Send an encoded message to stdout.
def send_message(encoded_message):
    sys.stdout.write(encoded_message['length'])
    sys.stdout.write(encoded_message['content'])
    sys.stdout.flush()


def get_message_background():
    while True:
        message = get_message()
        if message == "ping":
            send_message(encode_message("pong"))


thread = threading.Thread(target=get_message_background)
thread.daemon = True
thread.start()


app = Flask(__name__)


@app.route("/test", methods=['GET'])
def test():
    send_message(encode_message('testing'))
    return 'testing'


app.run('localhost', 5001, debug=True)

With this code i receive a ping and respond a pong.

The problem is when i try to run that code on the terminal. The native messaging communicates over stdio and when i'm run my script on the terminal, the terminal became the standard input and output.

If i just load the extension, the flask not start.

Someone has solved this problem?

PS: Sorry for my english


Solution

  • The problem is that the Flask server responses are written to stdout and break the native messaging pipe. Redirect stdout to a file at the beginning of your script, just after the imports:

    sys.stdout = open("log.txt", "a") # or to "nul" if you don't need a log file
    

    In send_message(), redirect stdout to the original __stdout__ and then back to the file:

    def send_message(encoded_message):
        sys.stdout = sys.__stdout__ # to original stdout
        sys.stdout.write(encoded_message['length'])
        sys.stdout.write(encoded_message['content'])
        sys.stdout.flush()
        sys.stdout = open("log.txt", "a") # back to file or "nul"
    

    This worked for me to switch between Firefox tabs by sending GET requests to the Flask server.