Lorawan-stack: Prend en charge plusieurs messages résultants d'un même format

Créé le 13 août 2019  ·  12Commentaires  ·  Source: TheThingsNetwork/lorawan-stack

Sommaire

Un ttnpb.ApplicationUp devrait pouvoir générer plusieurs messages frontaux, au lieu d'un seul.

Pourquoi avons nous besoin de ça?

Actuellement, un ttnpb.ApplicationUp est rassemblé en une seule tranche d'octets qui se traduit par un message frontal (un appel HTTP, un message MQTT, etc.). Cependant, si la charge utile de la liaison montante contient plusieurs mesures (pensez à plusieurs capteurs connectés à un seul appareil), il serait utile de permettre à certains formats de créer plusieurs messages pour chaque mesure.

Qu'est-ce qu'il y a déjà ? Que voyez-vous maintenant?

https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f03190055542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
Le format ne renvoie actuellement qu'un seul message à envoyer aux frontaux.

Que manque-t-il? Qu'est-ce que tu veux voir?

Le résultat doit être modifié de []byte à [][]byte .

Environnement

93ea01b4b5af2672da5883b570be825a54b8afc1

Comment proposez-vous de mettre cela en œuvre ?

Modifiez l'interface Format . Après cela, chaque frontal doit être modifié pour envoyer tous les messages au lieu d'un seul :

Pouvez-vous le faire vous-même et soumettre une Pull Request ?

Oui, mais je laisse cela à la communauté.

application server needtriage

Tous les 12 commentaires

@adriansmares Je travaille actuellement sur ce problème. Après être passé de []byte à [][]byte pour la fonction *ttnpb.ApplicationUp dans le fichier formatter.go, je l'ai également modifié dans les fichiers json.go et protobuf.go. Mais maintenant, cela donne l'erreur suivante:
image
Veuillez fournir une suggestion. Merci.

@mihirr93 Puisque vous modifiez maintenant les sites d'appel pour renvoyer une tranche de résultats (chaque résultat étant une tranche d'octets), vous devez envelopper les endroits où un seul résultat est renvoyé avec [][]byte{ slice-containing-result } .

Bonjour M. @adriansmares . Je suis un peu confus quant à notre approche. Nous essayons de découper le message frontal (charge utile brute) en plusieurs messages. Mais dans ce cas, le point auquel le message sera découpé dépend de son encodage (Cayenne ou tout encodage personnalisé) qui nous est inconnu. Donc, pour ce faire, nous devons utiliser la charge utile décodée. Une fois que l'utilisateur a entré le décodeur dans l'onglet format de charge utile du TTN, l'application affiche en fait les valeurs décodées en JSON (comme on le voit sur l'image). Ne devrions-nous pas directement diviser cette charge utile décodée et la pousser plus loin en utilisant http ?
image
Pourriez-vous s'il vous plaît éclairer cette confusion?
Et, modifions-nous simplement les fichiers pkg et les fichiers .proto seront-ils automatiquement mis à jour ?
Merci beaucoup pour votre soutien et votre temps.

_Keep à l' esprit que ce référentiel contient la version V3 de notre pile lorawan, et l'image fournie est de TTN, qui dirige la V2 version._

Veuillez garder à l'esprit que ce problème ne traite que de la prise en charge de la production de plusieurs charges utiles à partir d'un seul message, et le nouveau problème de format qui vous intéresse probablement est https://github.com/TheThingsNetwork/lorawan-stack/issues/1158. Veuillez vérifier si ce problème est bien celui que vous recherchez.

Néanmoins, je suggérerais dans ce cas que vous introduisiez un nouveau format, basé sur celui de JSON , qui produit plusieurs charges utiles basées sur les informations décodées trouvées dans la liaison montante.
Vous voudrez probablement gérer spécifiquement le message de liaison montante ApplicationUp_UplinkMessage , car il contient les champs qui vous intéressent dans le cadre du champ DecodedPayload .

Vous ne devriez pas avoir à modifier les fichiers proto pour ce cas d'utilisation.

J'essaie toujours de comprendre le fonctionnement interne et le code de la pile. Actuellement, je me concentre uniquement sur ce problème, et non sur le #1158. Comme vous avez suggéré de modifier le ApplicationUp_Uplinkmessage , j'essaie de comprendre cela. J'ai les requêtes suivantes en ce moment :
1) La struct ApplicationUplink et la fonction ApplicationUp_UplinkMessage sont définies dans le fichier messages.pb.go du répertoire ttnpb. Cependant l'en-tête du fichier mentionne "NE PAS EDITER". Dois-je l'ignorer ? ou existe-t-il une autre approche pour le modifier?
2) Pouvez-vous s'il vous plaît décrire cela plus en détail " introduce a new format, based on the JSON one " ? J'ai pensé qu'il suffisait de modifier le format existant au lieu d'en créer un nouveau.
3) Vous avez également mentionné l'emballage des résultats où un seul résultat est renvoyé. Qu'est-ce que ça va faire exactement ? Re-combinera-t-il le message multiple en un seul et renverra-t-il un seul résultat ? Et devons-nous le faire uniquement pour le message Uplink ?

[Merci @adriansmares pour vos conseils continus. Bien que j'ai suivi le didacticiel sur le golang, c'est ma première interaction avec le langage GO, excusez-moi de vous déranger avec tant de doutes]

  • Vous n'avez pas besoin de modifier ce fichier, ni aucun fichier *.pb.* . Ceux-ci sont générés automatiquement à partir des fichiers *.proto lorsque vous exécutez mage proto:all . Néanmoins, pour les besoins de ce numéro, aucune modification de ce type n'est nécessaire.
  • Veuillez suivre cela dans l'autre numéro.
  • La suggestion d'emballage vous permet de conserver le code existant intact (en renvoyant toujours une charge utile à publier à partir d'un message de liaison montante).

Laissez-moi essayer de mieux expliquer l'ensemble du pipeline, peut-être que cela nous éclairera sur la façon dont cela fonctionne

  1. Un appareil envoie 1 liaison montante.
  2. La liaison montante 1 est reçue par la passerelle et envoyée au serveur de passerelle qui la transmet au serveur réseau, qui la transmet ensuite au serveur d'applications. Le message qui parvient à l'AS est de type *ttnpb.ApplicationUplink .
  3. L'AS prend cette liaison montante 1 et tente de décoder sa charge utile binaire dans les champs décodés (transformer les octets du champ FRMPayload dans la structure décodée de DecodedPayload ) à l'aide du formateur de charge utile de l'appareil.
  4. Il l'enveloppe ensuite dans un *ttnpb.ApplicationUp et l'envoie aux frontends (MQTT, webhooks, PubSub, packages d'application).
  5. Les frontends reçoivent ce 1 *ttnpb.ApplicationUp et en fonction de leurs paramètres (le format) choisissent le formateur à utiliser (l'interface du formateur est définie dans pkg/applicationserver/io/formatters ).
  6. L'interface appelle formatter.FromUp avec le 1 *ttnph.ApplicationUp et reçoit une tranche d'octet ( []byte ), représentant le corps de 1 message.

Maintenant, concernant ce problème, j'espère qu'il est visible que seule l'étape 6 a besoin de modifications :

  • Changer les types de retour de l'interface et des implémentations de telle sorte que FromUp puisse renvoyer plusieurs charges utiles (une tranche de tranches d'octet).
  • Les formats Protobuf et JSON existants ne devraient pas changer leur comportement et, en tant que tels, devraient continuer à ne renvoyer qu'une seule charge utile (c'est pourquoi le wrapping est requis).
  • Après avoir modifié ces 2 (l'interface et les formateurs) pour renvoyer [][]byte vous commencerez à voir des erreurs (puisque la plupart des endroits qui appellent FromUp s'attendent

Ce n'est qu'après la résolution de ce problème, qui ne modifie en rien le comportement, que vous pouvez implémenter votre propre formateur, qui renverrait une tranche de plusieurs charges utiles, une pour chaque mesure (mais gardez à l'esprit que ce nouveau format est hors de portée pour ce problème !).

Merci beaucoup @adriansmares pour une explication et un guide si détaillés. Je pense avoir réussi à résoudre ce problème maintenant. Je l'ai également testé avec ./mage go:test js:test jsSDK:test et il ne donne aucune erreur. Les principales modifications apportées au code sont mises en évidence ci-dessous :
formateur.aller

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
Comme ci-dessus

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
Comme ci-dessus

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
}

Veuillez fournir vos commentaires et commentaires. Je ferai les corrections (nommage Var, indentation, etc.) selon les directives de style de code une fois la tâche complètement terminée. Et si cela semble correct, pourriez-vous s'il vous plaît me guider davantage pour le problème #1158 . Merci une fois de plus.

@mihirr93 a l' air bien ! Veuillez valider vos modifications et soumettre une demande d'extraction pour ce problème. Après l'avoir fusionné, nous pouvons passer au nouveau formateur mentionné dans #1158.

@adriansmares Bien sûr, je vais le faire. Cette demande d'extraction doit-elle être basée sur l'environnement mentionné ou sur la dernière version de la pile ?

Je vous recommande de rebaser vos modifications sur les derniers master afin d'éviter les conflits plus tard.

Ce problème est inactif depuis un certain temps, alors ramenons-le au triage pour voir s'il y a toujours une demande pour cela, ou si nous devrions simplement le laisser tomber.

Ce n'est plus nécessaire, car il évolue mal.

Cette page vous a été utile?
0 / 5 - 0 notes