Собственный узел обмена сообщениями Chrome в golang дает сбой, когда размер JSON превышает 65500 символов

Я пытаюсь написать собственный хост для обмена сообщениями для chrome в golang. Для этой цели я попытался использовать chrome-go, а также chrome-native-messaging. Оба представили ту же проблему, как описано ниже.

Вот код. Я добавил соответствующие части из пакета chrome-go в основной файл вместо его импорта. для легкого понимания.

Следующий код действительно работает, когда я отправляю ему json-сообщение, например {content:Apple Mango}. Однако он перестает работать, когда длина json превышает примерно 65500 символов, плюс-минус 100 символов. Ошибки тоже не выводятся.

package main

import (
  "encoding/binary"
  "encoding/json"
  "fmt"
  "io"
  "os"
)

var byteOrder binary.ByteOrder = binary.LittleEndian

func Receive(reader io.Reader) ([]byte, error) {
   // Read message length in native byte order
   var length uint32
   if err := binary.Read(reader, byteOrder, &length); err != nil {
       return nil, err
   }

// Return if no message
if length == 0 {
    return nil, nil
}

// Read message body
received := make([]byte, length)
if n, err := reader.Read(received); err != nil || n != len(received) {
    return nil, err
}
return received, nil
}

type response struct {
    Content string `json:"content"`
}

func main() {

  msg, err := Receive(os.Stdin)
  if err != nil {
    panic(err)
  }
  var res response
  err = json.Unmarshal([]byte(msg), &res)
  if err != nil {
     panic(err)
  }
  fmt.Println(res.Content)
 }

Для тех, кто заинтересован в тестировании, я создал репозиторий с инструкциями. Запустите следующее

  git clone --depth=1  https://[email protected]/tesseract-index/chrome-native-messaging-test-riz.git && cd chrome-native-messaging-test-riz
 ./json2msg.js < test-working.json | go run main.go
 ./json2msg.js < test-not-working.json | go run main.go

Вы увидите, что test-not-working.json не дает никакого вывода, хотя его отличие от test-working.json составляет всего несколько сотен символов.

В чем проблема?


person Rizwan Ishak    schedule 30.11.2018    source источник
comment
Основываясь на ответе Алекса, возможно, вы можете сжать поток json.   -  person Nicholas    schedule 30.11.2018


Ответы (2)


Существует ограничение конвейерного буфера, которое зависит от системы. Mac OS X, например, по умолчанию использует емкость 16384 байта.

Вы можете использовать этот bash-скрипт для проверки емкости буфера:

M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999

Так что это не связано с переходом, потому что я пытался изменить ваш код для чтения из файла и Unmarshal, и это сработало:

func main() {
    reader, err := os.Open("test-not-working.json")
    if err != nil {
        panic(err)
    }

    var res response
    decoder := json.NewDecoder(reader)
    err = decoder.Decode(&res)
    if err != nil {
        panic(err)
    }

    fmt.Println(res.Content)
}
person Alex Pliutau    schedule 30.11.2018
comment
Это звучит правильно. Ограничение буфера канала в моей системе составляет 65536. Я пометил ваш ответ как принятый. Однако, если бы вы могли изменить его с помощью информации о том, как это преодолеть, это было бы здорово. PS: Также стоит упомянуть, что нативный хост, написанный на python, каким-то образом не имеет такого же ограничения. - person Rizwan Ishak; 30.11.2018

Это связано с тем, что буфер канала вашей ОС ограничен 65536 байтами. Таким образом, функция os.Stdin.Read(...) может прочитать 65536 байт за раз.

Вы можете исправить свой код с помощью этой простой замены:

n, err := io.ReadFull(reader, received)

И вот ваша ошибка:

msg, err := Receive(os.Stdin)
if err != nil {
    panic(err)
}

Вы сравнили err с nil, но не сравнили msg с nil. Но так как вы прочитали 65532 (65536 - 4) байт, func Receive(...) вернуло nil, nil.

Чтобы исправить это, ваша функция Receive(...) не должна возвращать nil, nil.

person Denis Novikov    schedule 12.02.2020