Одно ttnpb.ApplicationUp
должно приводить к нескольким интерфейсным сообщениям вместо одного.
В настоящее время один ttnpb.ApplicationUp
упорядочивается только в один байтовый фрагмент, который приводит к одному внешнему сообщению (один вызов HTTP, одно сообщение MQTT и т. Д.). Однако, если полезная нагрузка восходящего канала содержит несколько измерений (подумайте о нескольких датчиках, подключенных к одному устройству), было бы полезно разрешить определенным форматам создавать несколько сообщений для каждого измерения.
https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f03190055542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
В настоящее время формат возвращает только одно сообщение для отправки во внешние интерфейсы.
Результат должен быть изменен с []byte
на [][]byte
.
93ea01b4b5af2672da5883b570be825a54b8afc1
Измените интерфейс Format
. После этого нужно изменить каждый интерфейс, чтобы отправлять все сообщения, а не только одно:
[]http.Request
вместо http.Request
), а результат format.FromUp
следует использовать для создания этих запросов.topic.Send
для каждого результата i.format.FromUp
.[][]byte
, поскольку формат JSON по умолчанию возвращает только одно сообщение.Да, но я оставлю это сообществу.
@adriansmares Я сейчас работаю над этой проблемой. После изменения байта [] на байт [] [] для функции * ttnpb.ApplicationUp в файле formatter.go я также изменил его в файлах json.go и protobuf.go. Но теперь выдает следующую ошибку:
Пожалуйста, дайте несколько предложений. Спасибо.
@ mihirr93 Поскольку вы сейчас модифицируете сайты вызовов, чтобы они возвращали часть результатов (каждый результат представляет собой часть байтов), вам следует обернуть места, где возвращается только один результат, с помощью [][]byte{ slice-containing-result }
.
Привет, мистер @adriansmares . Я немного смущен нашим подходом. Мы привязываем, чтобы разделить внешнее сообщение (необработанную полезную нагрузку) на несколько сообщений. Но в этом случае точка, в которой сообщение будет разрезано, зависит от его кодировки (Cayenne или любая другая кодировка), которая нам неизвестна. Итак, для этого нам нужно использовать декодированную полезную нагрузку. Как только пользователь вводит декодер на вкладке формата полезной нагрузки TTN, приложение фактически показывает декодированные значения в JSON (как показано на рисунке). Разве мы не должны напрямую разделить эту декодированную полезную нагрузку и продвинуть ее дальше, используя http?
Не могли бы вы пролить свет на эту путаницу?
И мы просто изменяем файлы pkg, и файлы .proto будут автоматически обновляться?
Большое спасибо за вашу поддержку и время.
_ Имейте в виду, что этот репозиторий содержит версию V3 нашего стека LoRaWAN, а предоставленное изображение взято из TTN, который запускает версию V2. _
Имейте в виду, что эта проблема касается только поддержки создания нескольких полезных нагрузок из одного сообщения, а проблема нового формата, которая вас, вероятно, интересует, - это https://github.com/TheThingsNetwork/lorawan-stack/issues/1158. Пожалуйста, проверьте, действительно ли эта проблема является той, которую вы ищете.
Тем не менее, в этом случае я бы посоветовал вам ввести новый формат, основанный на формате JSON , который создает несколько полезных нагрузок на основе декодированной информации, находящейся внутри восходящего канала.
Вероятно, вы захотите обработать сообщение восходящей ссылки ApplicationUp_UplinkMessage
специально, поскольку оно содержит интересующие вас поля как часть поля DecodedPayload
.
Вам не нужно изменять прото-файлы для этого варианта использования.
Я все еще пытаюсь понять внутреннюю работу и код стека. В настоящее время я занимаюсь только этим вопросом, а не №1158. Поскольку вы предлагали изменить ApplicationUp_Uplinkmessage
, я пытаюсь понять это. На данный момент у меня есть следующие вопросы:
1) Структура ApplicationUplink
и функция ApplicationUp_UplinkMessage
определены в файле messages.pb.go в каталоге ttnpb. Однако в заголовке файла упоминается «НЕ РЕДАКТИРОВАТЬ». Должен ли я игнорировать это? или есть альтернативный подход к его изменению?
2) Не могли бы вы описать это поподробнее " introduce a new format, based on the JSON one
"? Я подумал, что нам просто нужно изменить существующий формат, а не создавать новый.
3) Вы также упомянули об упаковке результатов, при которой возвращается только один результат. Что именно это будет делать? Будет ли он повторно объединять несколько сообщений в одно и возвращать только один результат? И нужно ли это делать только для сообщения Uplink?
[Спасибо @adriansmares за постоянное руководство. Хотя я взял учебник по голангу, это мое первое знакомство с языком GO, простите за то, что беспокою вас столькими сомнениями]
*.pb.*
. Они генерируются из файлов *.proto
автоматически при запуске mage proto:all
. Тем не менее, для целей данного выпуска такие модификации вносить не нужно.Позвольте мне попытаться лучше объяснить весь конвейер, возможно, это прольет свет на то, как это работает
*ttnpb.ApplicationUplink
.FRMPayload
в декодированную структуру DecodedPayload
), используя форматтер полезной нагрузки устройства.*ttnpb.ApplicationUp
и отправляет во внешние интерфейсы (MQTT, webhooks, PubSub, пакеты приложений).*ttnpb.ApplicationUp
и в зависимости от своих настроек (формата) выбирают, какое средство форматирования использовать (интерфейс средства форматирования определяется в pkg/applicationserver/io/formatters
).formatter.FromUp
с 1 *ttnph.ApplicationUp
и получает фрагмент байта ( []byte
), представляющий тело 1 сообщения.Теперь, что касается этой проблемы, я надеюсь, что видно, что только шаг 6 нуждается в изменениях:
FromUp
может возвращать несколько полезных данных (срез срезов байта).Protobuf
и JSON
не должны изменять своего поведения и, как таковые, должны продолжать возвращать только 1 полезную нагрузку (поэтому требуется перенос).[][]byte
вы начнете видеть ошибки (поскольку большинство мест, вызывающих FromUp
ожидают получения только одной полезной нагрузки, вам необходимо обновить эти сайты вызывают и заставляют их перебирать список полезных данных и отправлять каждый из них.Только после того, как эта проблема, которая вообще не меняет поведение, будет исправлена, вы можете перейти к реализации собственного средства форматирования, которое будет возвращать часть нескольких полезных нагрузок, по одной для каждого измерения (но имейте в виду, что этот новый формат выходит за рамки данной проблемы!).
Большое спасибо @adriansmares за такое подробное объяснение и руководство. Думаю, сейчас мне удалось решить эту проблему. Я также тестировал его с помощью ./mage go:test js:test jsSDK:test
и он не выдает ошибок. Основные изменения, внесенные в код, выделены ниже:
formatter.go
type Formatter interface {
FromUp(*ttnpb.ApplicationUp) ([][]byte, error)
ToDownlinks([]byte) (*ttnpb.ApplicationDownlinks, error)
ToDownlinkQueueRequest([]byte) (*ttnpb.DownlinkQueueRequest, error)
}
json.go
func (json) FromUp(msg *ttnpb.ApplicationUp) ([][]byte, error) {
m, e := jsonpb.TTN().Marshal(msg)
return [][]byte{m}, e
}
protobuf.go
То же, что и выше
mqtt.go
buf, err := c.format.FromUp(up.ApplicationUp)
if err != nil {
logger.WithError(err).Warn("Failed to marshal upstream message")
continue
}
logger.Debug("Publish upstream message")
for _, v := range buf {
c.session.Publish(&packet.PublishPacket{
TopicName: topic.Join(topicParts),
TopicParts: topicParts,
QoS: qosUpstream,
Message: v,
})
}
pubsub.go
То же, что и выше
webhooks.go
unc (w *webhooks) newRequest(ctx context.Context, msg *ttnpb.ApplicationUp, hook *ttnpb.ApplicationWebhook) ([]*http.Request, error) {
var cfg *ttnpb.ApplicationWebhook_Message
switch msg.Up.(type) {
case *ttnpb.ApplicationUp_UplinkMessage:
cfg = hook.UplinkMessage
case *ttnpb.ApplicationUp_JoinAccept:
cfg = hook.JoinAccept
case *ttnpb.ApplicationUp_DownlinkAck:
cfg = hook.DownlinkAck
case *ttnpb.ApplicationUp_DownlinkNack:
cfg = hook.DownlinkNack
case *ttnpb.ApplicationUp_DownlinkSent:
cfg = hook.DownlinkSent
case *ttnpb.ApplicationUp_DownlinkFailed:
cfg = hook.DownlinkFailed
case *ttnpb.ApplicationUp_DownlinkQueued:
cfg = hook.DownlinkQueued
case *ttnpb.ApplicationUp_LocationSolved:
cfg = hook.LocationSolved
}
if cfg == nil {
return nil, nil
}
url, err := url.Parse(hook.BaseURL)
if err != nil {
return nil, err
}
url.Path = path.Join(url.Path, cfg.Path)
expandVariables(url, msg)
if err != nil {
return nil, err
}
format, ok := formats[hook.Format]
if !ok {
return nil, errFormatNotFound.WithAttributes("format", hook.Format)
}
buf, err := format.FromUp(msg)
if err != nil {
return nil, err
}
var requests []*http.Request
for i, v := range buf {
req, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(v))
requests[i] = req
if err != nil {
return nil, err
}
for key, value := range hook.Headers {
req.Header.Set(key, value)
}
if hook.DownlinkAPIKey != "" {
req.Header.Set(downlinkKeyHeader, hook.DownlinkAPIKey)
req.Header.Set(downlinkPushHeader, w.createDownlinkURL(ctx, hook.ApplicationWebhookIdentifiers, msg.EndDeviceIdentifiers, "push"))
req.Header.Set(downlinkReplaceHeader, w.createDownlinkURL(ctx, hook.ApplicationWebhookIdentifiers, msg.EndDeviceIdentifiers, "replace"))
}
req.Header.Set("Content-Type", format.ContentType)
req.Header.Set("User-Agent", userAgent)
}
return requests, nil
}
Пожалуйста, поделитесь своими отзывами и комментариями. Я внесу исправления (имя Var, отступ и т. Д.) В соответствии с рекомендациями по стилю кода, как только задача будет полностью завершена. И если все в порядке, не могли бы вы помочь мне подробнее в вопросе № 1158. Еще раз, спасибо.
@ mihirr93 выглядит хорошо! Подтвердите свои изменения и отправьте запрос на перенос для решения этой проблемы. После слияния мы можем перейти к новому форматеру, упомянутому в # 1158.
@adriansmares Конечно, я сделаю это. Должен ли этот запрос на перенос быть основан на указанной среде или на последней версии стека?
Я бы рекомендовал вам переустановить свои изменения поверх последней версии master
, чтобы избежать конфликтов в дальнейшем.
Эта проблема долгое время не использовалась, поэтому давайте вернем ее к сортировке, чтобы увидеть, есть ли еще спрос на нее, или мы должны просто отказаться от нее.
В этом больше нет необходимости, так как он плохо масштабируется.