Um ttnpb.ApplicationUp
deve resultar em várias mensagens front-end, em vez de apenas uma.
Atualmente, um ttnpb.ApplicationUp
é empacotado em apenas uma fatia de byte que resulta em uma mensagem front-end (uma chamada HTTP, uma mensagem MQTT etc.). No entanto, se a carga útil do uplink contiver várias medições (pense em vários sensores conectados a um dispositivo), seria útil permitir que certos formatos criem várias mensagens para cada medição.
https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f03190055542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
O formato atualmente retorna apenas uma mensagem a ser enviada aos front-ends.
O resultado deve ser alterado de []byte
para [][]byte
.
93ea01b4b5af2672da5883b570be825a54b8afc1
Altere a interface Format
. Depois disso, cada front-end deve ser alterado para enviar todas as mensagens em vez de apenas uma:
[]http.Request
vez de http.Request
), e o resultado de format.FromUp
deve ser usado para criar essas solicitações.topic.Send
para cada resultado de i.format.FromUp
.[][]byte
, já que o formato JSON padrão retorna apenas uma mensagem.Sim, mas vou deixar isso para a comunidade.
@adriansmares Atualmente estou trabalhando nesta questão. Depois de mudar de [] byte para [] [] byte para a função * ttnpb.ApplicationUp no arquivo formatter.go, também mudei nos arquivos json.go e protobuf.go. Mas agora, dá o seguinte erro:
Por favor, dê algumas sugestões. Obrigada.
@ mihirr93 Como agora você está modificando os sites de chamada para retornar uma fatia dos resultados (cada resultado sendo uma fatia de bytes), você deve agrupar os locais onde apenas um resultado é retornado com [][]byte{ slice-containing-result }
.
Olá Sr. @adriansmares . Estou um pouco confuso quanto à nossa abordagem. Estamos tentando dividir a mensagem front-end (carga útil bruta) em várias mensagens. Mas, neste caso, o ponto em que a mensagem será dividida depende de sua codificação (Cayenne ou qualquer codificação personalizada), que é desconhecida para nós. Portanto, para fazer isso, precisamos usar a carga decodificada. Depois que o usuário insere o decodificador na guia de formato de carga útil do TTN, o aplicativo realmente mostra os valores decodificados em JSON (como visto na imagem). Não deveríamos dividir diretamente essa carga decodificada e empurrá-la ainda mais usando http?
Você poderia, por favor, lançar alguma luz sobre essa confusão?
E, nós apenas modificamos os arquivos pkg e os arquivos .proto serão atualizados automaticamente?
Muito obrigado pelo seu amável apoio e tempo.
_Keep em mente que este repositório contém a versão V3 da nossa pilha LoRaWAN, ea imagem fornecida é de TTN, que executa o V2 version._
Lembre-se de que esse problema trata apenas do suporte para a produção de vários payloads de uma mensagem, e o novo problema de formato no qual você provavelmente está interessado é https://github.com/TheThingsNetwork/lorawan-stack/issues/1158. Verifique se esse problema é realmente o que você está procurando.
No entanto, sugiro, neste caso, que você introduza um novo formato, baseado no JSON , que produz várias cargas com base nas informações decodificadas encontradas dentro do uplink.
Você provavelmente desejará lidar com a mensagem ApplicationUp_UplinkMessage
uplink especificamente, pois ela contém os campos nos quais você está interessado como parte do campo DecodedPayload
.
Você não deveria ter que modificar os arquivos proto para este caso de uso.
Ainda estou tentando entender o funcionamento interno e o código da pilha. Atualmente, estou me concentrando apenas neste problema, e não no # 1158. Como você sugeriu modificar o ApplicationUp_Uplinkmessage
, estou tentando descobrir isso. Tenho as seguintes perguntas neste momento:
1) A struct ApplicationUplink
e a func ApplicationUp_UplinkMessage
são definidas no arquivo messages.pb.go do diretório ttnpb. No entanto, o cabeçalho do arquivo menciona "NÃO EDITAR". Devo ignorar isso? ou existe alguma abordagem alternativa para modificá-lo?
2) Você pode descrever isso em mais detalhes " introduce a new format, based on the JSON one
"? Achei que devíamos apenas modificar o formato existente em vez de criar um novo.
3) Você também mencionou o agrupamento de resultados em que apenas um resultado é retornado. O que exatamente isso vai fazer? Ele vai recombinar as mensagens múltiplas em uma e retornar apenas um resultado? E precisamos fazer isso apenas para mensagem Uplink?
[Obrigado @adriansmares por sua orientação contínua. Embora eu tenha feito o tutorial de golang, esta é minha primeira interação com a linguagem GO, perdão por incomodar com tantas dúvidas]
*.pb.*
arquivos. Eles são gerados a partir dos arquivos *.proto
automaticamente quando você executa mage proto:all
. No entanto, para o propósito deste problema, nenhuma modificação precisa ser feita.Deixe-me tentar explicar melhor todo o pipeline, talvez isso lance alguma luz sobre como isso funciona
*ttnpb.ApplicationUplink
.FRMPayload
na estrutura decodificada de DecodedPayload
) usando o formatador de carga útil do dispositivo.*ttnpb.ApplicationUp
e o envia para os front-ends (MQTT, webhooks, PubSub, pacotes de aplicativos).*ttnpb.ApplicationUp
e com base em suas configurações (o formato) escolhem qual formatador usar (a interface do formatador é definida em pkg/applicationserver/io/formatters
).formatter.FromUp
com o 1 *ttnph.ApplicationUp
e recebe uma fatia do byte ( []byte
), representando o corpo de 1 mensagem.Agora, com relação a esse problema, espero que seja visível que apenas a etapa 6 precisa de alterações:
FromUp
possa retornar várias cargas úteis (uma fatia de fatias de byte).Protobuf
e JSON
não devem mudar seu comportamento e, como tal, devem continuar a retornar apenas 1 carga útil (é por isso que o envoltório é necessário).[][]byte
você começará a ver erros (já que a maioria dos lugares que chamam FromUp
esperam que apenas uma carga útil seja recebida - você deve atualizar esses sites chamam e fazem com que percorram a lista de cargas úteis e enviem cada um deles.Somente depois que esse problema, que não altera o comportamento em nada, for corrigido, você pode prosseguir com a implementação de seu próprio formatador, que retornaria uma fatia de múltiplas cargas úteis, uma para cada medição (mas tenha em mente que este novo formato está fora do escopo deste problema!).
Muito obrigado @adriansmares por uma explicação e guia tão detalhados. Acho que consegui resolver esse problema agora. Eu também testei com ./mage go:test js:test jsSDK:test
e não deu nenhum erro. As principais alterações feitas no código são destacadas abaixo:
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
O mesmo que acima
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
O mesmo que acima
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
}
Forneça seu feedback e comentários. Farei as correções (nomenclatura Var, recuo, etc) de acordo com as diretrizes de estilo de código, uma vez que a tarefa esteja completamente concluída. E se parecer correto, você poderia me orientar mais sobre o problema nº 1158. Agradeço novamente.
@ mihirr93 parece bom! Por favor, comprometa suas alterações e envie uma solicitação pull para este problema. Após mesclá-lo, podemos avançar para o novo formatador mencionado em # 1158.
@adriansmares Claro, vou fazer isso. Essa solicitação de pull deve ser baseada no ambiente mencionado ou na versão mais recente da pilha?
Eu recomendo que você rebase suas alterações sobre os master
mais recentes para evitar conflitos no futuro.
Esse problema está inativo há um bom tempo, então vamos movê-lo de volta para a triagem para ver se ainda há demanda para isso ou se devemos simplesmente descartá-lo.
Isso não é mais necessário, pois tem uma escala insuficiente.