Как отправить сообщение дочернему процессу в Firefox add-on, как Chrome native messaging


Я пытаюсь эмулировать родную функцию обмена сообщениями Chrome с помощью дополнения Firefox SDK. В частности, я использую модуль child_process вместе с методом emit для связи с дочерним процессом python.

Я могу успешно отправлять сообщения в дочерний процесс, но у меня возникли проблемы с отправкой сообщений обратно в надстройку. Собственная функция обмена сообщениями Chrome использует stdin/stdout. Первые 4 байта каждого сообщения в обоих направлениях представляет размер в байтах следующего сообщения, чтобы получатель знал, сколько читать. Вот что у меня есть до сих пор:

Дополнение к дочернему процессу

var utf8 = new TextEncoder("utf-8").encode(message);
var latin = new TextDecoder("latin1").decode(utf8);

emit(childProcess.stdin, "data", new TextDecoder("latin1").decode(new Uint32Array([utf8.length])));
emit(childProcess.stdin, "data", latin);
emit(childProcess.stdin, "end");

Дочерний процесс (Python) из дополнения

text_length_bytes = sys.stdin.read(4)
text_length = struct.unpack('i', text_length_bytes)[0]
text = sys.stdin.read(text_length).decode('utf-8')

Дочерний процесс для дополнения

sys.stdout.write(struct.pack('I', len(message)))
sys.stdout.write(message)
sys.stdout.flush()

Дополнение из дочернего процесса

Вот где я борюсь. У меня он работает, когда длина меньше 255. Например, если длина равна 55, это работает:

childProcess.stdout.on('data', (data) => { // data is '7' (55 UTF-8 encoded)
    var utf8Encoded = new TextEncoder("utf-8).encode(data);
    console.log(utf8Encoded[0]); // 55
}
Но, как я уже сказал, это не работает. для всех чисел. Я уверен, что должен что-то сделать с TypedArrays, но я изо всех сил пытаюсь собрать все вместе.
2 7

2 ответа:

Проблема здесь в том, что Firefox по умолчанию пытается читать stdout как поток UTF-8. Поскольку UTF-8 не использует полный первый байт, вы получаете поврежденные символы, например, для 255. Решение состоит в том, чтобы сказать Firefox читать в двоичном кодировании, что означает, что вам придется вручную анализировать фактическое содержание сообщения позже.

var childProcess = spawn("mybin", [ '-a' ], { encoding: null });

Тогда ваш слушатель будет работать как

var decoder = new TextDecoder("utf-8");
var readIncoming = (data) => {
    // read the first four bytes, which indicate the size of the following message
    var size = (new Uint32Array(data.subarray(0, 4).buffer))[0];
    //TODO: handle size > data.byteLength - 4
    // read the message
    var message = decoder.decode(data.subarray(4, size));
    //TODO: do stuff with message
    // Read the next message if there are more bytes.
    if(data.byteLength > 4 + size)
        readIncoming(data.subarray(4 + size));
};
childProcess.stdout.on('data', (data) => {
    // convert the data string to a byte array
    // The bytes got converted by char code, see https://dxr.mozilla.org/mozilla-central/source/addon-sdk/source/lib/sdk/system/child_process/subprocess.js#357
    var bytes = Uint8Array.from(data, (c) => c.charCodeAt(0));
    readIncoming(bytes);
});

Может быть, это похоже на эту проблему: Chrome native messaging не принимает сообщения определенного размера (Windows)

Только для Windows: убедитесь, что режим ввода-вывода программы установлен в O_BINARY. По умолчанию режим ввода-вывода-O_TEXT, который искажает формат сообщения, поскольку разрывы строк (\n = 0A) заменяются окончаниями строк в стиле Windows (\r\n = 0D 0A). Режим ввода-вывода можно задать с помощью __setmode.