Lorawan-stack: Admite múltiples mensajes resultantes de un formato

Creado en 13 ago. 2019  ·  12Comentarios  ·  Fuente: TheThingsNetwork/lorawan-stack

Resumen

Un ttnpb.ApplicationUp debería poder dar como resultado varios mensajes de front-end, en lugar de solo uno.

¿Porqué necesitamos esto?

Actualmente, un ttnpb.ApplicationUp se agrupa en un solo segmento de bytes que da como resultado un mensaje de interfaz (una llamada HTTP, un mensaje MQTT, etc.). Sin embargo, si la carga útil del enlace ascendente contiene múltiples mediciones (piense en múltiples sensores conectados a un dispositivo), sería útil permitir que ciertos formatos creen múltiples mensajes para cada medición.

¿Qué hay ya ahí? ¿Qué ves ahora?

https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f03190055542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
Actualmente, el formato devuelve solo un mensaje para enviar a las interfaces.

¿Lo que falta? ¿Qué quieres ver?

El resultado debe cambiarse de []byte a [][]byte .

Medio ambiente

93ea01b4b5af2672da5883b570be825a54b8afc1

¿Cómo se propone implementar esto?

Cambie la interfaz Format . Después de eso, cada interfaz debe cambiarse para enviar todos los mensajes en lugar de solo uno:

¿Puede hacer esto usted mismo y enviar una solicitud de extracción?

Sí, pero dejaré esto a la comunidad.

application server needtriage

Todos 12 comentarios

@adriansmares Actualmente estoy trabajando en este tema. Después de cambiar de [] byte a [] [] byte para la función * ttnpb.ApplicationUp en el archivo formatter.go, también lo cambié en los archivos json.go y protobuf.go. Pero ahora, da el siguiente error:
image
Amablemente proporcione alguna sugerencia. Gracias.

@ mihirr93 Dado que ahora está modificando los sitios de llamada para devolver una porción de resultados (cada resultado es una porción de bytes), debe ajustar los lugares donde solo se devuelve un resultado con [][]byte{ slice-containing-result } .

Hola Sr. @adriansmares . Estoy un poco confundido con respecto a nuestro enfoque. Estamos tratando de dividir el mensaje de front-end (carga útil sin procesar) en varios mensajes. Pero en este caso, el punto en el que se dividirá el mensaje depende de su codificación (Cayenne o cualquier codificación personalizada) que desconocemos. Entonces, para hacer esto, necesitamos usar la carga útil decodificada. Una vez que el usuario ingresa al decodificador en la pestaña de formato de carga útil del TTN, la aplicación realmente muestra los valores decodificados en JSON (como se ve en la imagen). ¿No deberíamos dividir directamente esta carga útil decodificada y llevarla más lejos usando http?
image
¿Podría arrojar algo de luz sobre esta confusión?
Y, ¿simplemente modificamos los archivos pkg y los archivos .proto se actualizarán automáticamente?
Muchas gracias por su amable apoyo y su tiempo.

_Tenga en cuenta que este repositorio contiene la versión V3 de nuestra pila LoRaWAN, y la imagen proporcionada es de TTN, que ejecuta la versión V2 .

Tenga en cuenta que este problema solo se ocupa del soporte para producir múltiples cargas útiles a partir de un mensaje, y el nuevo problema de formato que probablemente le interese es https://github.com/TheThingsNetwork/lorawan-stack/issues/1158. Compruebe si este problema es realmente el que está buscando.

No obstante, le sugiero que en este caso introduzca un nuevo formato, basado en el JSON , que produce múltiples cargas útiles basadas en la información decodificada que se encuentra dentro del enlace ascendente.
Probablemente desee manejar el mensaje de enlace ascendente ApplicationUp_UplinkMessage específicamente, ya que contiene los campos que le interesan como parte del campo DecodedPayload .

No debería tener que modificar los archivos proto para este caso de uso.

Todavía estoy tratando de comprender el funcionamiento interno y el código de la pila. Actualmente, me estoy enfocando solo en este tema, y ​​no en el n. ° 1158. Como sugirió modificar el ApplicationUp_Uplinkmessage , estoy tratando de averiguarlo. Tengo las siguientes consultas en este momento:
1) La estructura ApplicationUplink y la función ApplicationUp_UplinkMessage se definen en el archivo messages.pb.go en el directorio ttnpb. Sin embargo, el encabezado del archivo menciona "NO EDITAR". ¿Debería ignorarlo? ¿O hay algún enfoque alternativo para modificarlo?
2) ¿Puede describir esto con más detalle " introduce a new format, based on the JSON one "? Pensé que solo teníamos que modificar el formato existente en lugar de crear uno nuevo.
3) También mencionó el ajuste de resultados donde solo se devuelve un resultado. ¿Qué hará eso exactamente? ¿Volverá a combinar el mensaje múltiple en uno y devolverá solo un resultado? ¿Y necesitamos hacer eso solo para el mensaje de enlace ascendente?

[Gracias @adriansmares por su orientación continua. Aunque tomé el tutorial de golang, esta es mi primera interacción con el lenguaje GO, perdón por molestarte con tantas dudas]

  • No es necesario editar ese archivo, ni ningún archivo *.pb.* . Estos se generan a partir de los archivos *.proto automáticamente cuando ejecuta mage proto:all . No obstante, a los efectos de este número, no es necesario realizar dichas modificaciones.
  • Continúe con eso en el otro número.
  • La sugerencia de empaquetado le permite mantener intacto el código existente (aún devolviendo una carga útil para publicar desde un mensaje de enlace ascendente).

Permítanme tratar de explicar mejor todo el proceso, tal vez esto arroje algo de luz sobre cómo funciona esto.

  1. Un dispositivo envía 1 enlace ascendente.
  2. La puerta de enlace recibe el enlace ascendente 1 y lo envía al servidor de puerta de enlace, que lo reenvía al servidor de red, que luego lo reenvía al servidor de aplicaciones. El mensaje que llega al AS es de tipo *ttnpb.ApplicationUplink .
  3. El AS toma este enlace ascendente 1 e intenta decodificar su carga útil binaria en los campos decodificados (convierte los bytes en el campo FRMPayload en la estructura decodificada de DecodedPayload ) utilizando el formateador de carga útil del dispositivo.
  4. Luego lo envuelve en *ttnpb.ApplicationUp y lo envía a las interfaces (MQTT, webhooks, PubSub, paquetes de aplicaciones).
  5. Los frontends reciben este 1 *ttnpb.ApplicationUp y según su configuración (el formato) eligen qué formateador usar (la interfaz del formateador se define en pkg/applicationserver/io/formatters ).
  6. La interfaz llama a formatter.FromUp con 1 *ttnph.ApplicationUp y recibe una porción de byte ( []byte ), que representa el cuerpo de 1 mensaje.

Ahora, con respecto a este problema, espero que sea visible que solo el paso 6 necesita cambios:

  • Cambiar los tipos de retorno tanto de la interfaz como de las implementaciones de modo que FromUp pueda devolver múltiples cargas útiles (una porción de porciones de byte).
  • Los formatos existentes Protobuf y JSON no deben cambiar su comportamiento y, como tales, deben continuar devolviendo solo 1 carga útil (por eso se requiere el ajuste).
  • Después de cambiar estos 2 (la interfaz y los formateadores) para devolver [][]byte , comenzará a ver errores (ya que la mayoría de los lugares que llaman a FromUp esperan que se reciba solo una carga útil; debe actualizar estos llaman a los sitios y los hacen recorrer la lista de cargas útiles y enviar cada uno de ellos.

Solo después de que se haya solucionado este problema, que no cambia el comportamiento en absoluto, puede seguir adelante con la implementación de su propio formateador, que devolvería una porción de múltiples cargas útiles, una para cada medición (pero tenga en cuenta que este nuevo formato está fuera del alcance de este problema!).

Muchas gracias @adriansmares por una explicación y una guía tan detalladas. Creo que he logrado resolver este problema ahora. También lo probé con ./mage go:test js:test jsSDK:test y no da ningún error. Los principales cambios realizados en el código se destacan a continuación:
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
Lo mismo que arriba

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
Lo mismo que arriba

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
}

Por favor proporcione sus comentarios y sugerencias. Haré las correcciones (nombre de Var, sangría, etc.) según las pautas de estilo del código una vez que la tarea esté completamente terminada. Y si esto parece correcto, ¿podría orientarme más sobre el número 1158? Gracias otra vez.

¡@ mihirr93 se ve bien! Confirme sus cambios y envíe una solicitud de extracción para este problema. Después de fusionarlo, podemos avanzar al nuevo formateador mencionado en # 1158.

@adriansmares Claro, lo haré. ¿Esa solicitud de extracción debería basarse en el entorno mencionado o en la última versión de la pila?

Te recomiendo que vuelvas a basar tus cambios sobre los últimos master para evitar conflictos más adelante.

Este problema ha estado inactivo durante bastante tiempo, así que regresemos al triaje para ver si todavía hay demanda para esto, o si simplemente deberíamos eliminarlo.

Esto ya no es necesario, ya que escala mal.

¿Fue útil esta página
0 / 5 - 0 calificaciones