1つのttnpb.ApplicationUp
は、1つだけではなく、複数のフロントエンドメッセージを生成できるはずです。
現在、1つのttnpb.ApplicationUp
は1つのバイトスライスにマーシャリングされ、1つのフロントエンドメッセージ(1つのHTTP呼び出し、1つのMQTTメッセージなど)になります。 ただし、アップリンクのペイロードに複数の測定値が含まれている場合(1つのデバイスに複数のセンサーが接続されていると考えてください)、特定の形式で測定値ごとに複数のメッセージを作成できるようにすると便利です。
https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f03190055542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
この形式は現在、フロントエンドに送信されるメッセージを1つだけ返します。
結果を[]byte
から[][]byte
に変更する必要があります。
93ea01b4b5af2672da5883b570be825a54b8afc1
Format
インターフェースを変更します。 その後、各フロントエンドを変更して、1つだけではなくすべてのメッセージを送信する必要があります。
[]http.Request
ではなくhttp.Request
)、 format.FromUp
の結果を使用してこれらのリクエストを作成する必要があります。topic.Send
の各結果のためにi.format.FromUp
。[][]byte
にラップします。はい、でもこれはコミュニティにお任せします。
@adriansmares私は現在この問題に取り組んでいます。 formatter.goファイルの* ttnpb.ApplicationUp関数の[] byteから[] [] byteに変更した後、json.goファイルとprotobuf.goファイルでも変更しました。 しかし今、それは次のエラーを出します:
親切にいくつかの提案を提供します。 ありがとうございました。
@ mihirr93現在、結果のスライス(各結果はバイトのスライス)を返すように呼び出しサイトを変更しているため、1つの結果のみが返される場所を[][]byte{ slice-containing-result }
ラップする必要があります。
こんにちは@adriansmaresさん。 私たちのアプローチに関して少し混乱しています。 フロントエンドメッセージ(生のペイロード)を複数のメッセージにスライスすることにしています。 ただし、この場合、メッセージがスライスされるポイントは、そのエンコーディング(Cayenneまたはカスタムエンコーディング)によって異なりますが、これは不明です。 したがって、これを行うには、デコードされたペイロードを使用する必要があります。 ユーザーがTTNのペイロード形式タブにデコーダーを入力すると、アプリケーションは実際にデコードされた値をJSONで表示します(図を参照)。 このデコードされたペイロードを直接分割し、httpを使用してさらにプッシュするべきではありませんか?
この混乱に光を当てていただけませんか。
また、pkgファイルを変更するだけで、.protoファイルが自動的に更新されますか?
何卒よろしくお願い申し上げます。
_このリポジトリにはLoRaWANスタックのV3バージョンが含まれており、提供されている画像はV2バージョンを実行するTTNからのものであることに注意してください。_
この問題は、1つのメッセージから複数のペイロードを生成するためのサポートのみを扱っていることに注意してください。おそらく関心のある新しい形式の問題は、
それでも、この場合は、 JSON形式に基づく新しい形式を導入することをお勧めします。この形式では、アップリンク内で見つかったデコードされた情報に基づいて複数のペイロードが生成されます。
DecodedPayload
フィールドの一部として関心のあるフィールドが含まれているため、 ApplicationUp_UplinkMessage
アップリンクメッセージを具体的に処理することをお勧めします。
このユースケースでは、protoファイルを変更する必要はありません。
私はまだスタックの内部動作とコードを理解しようとしています。 現在、私はこの問題のみに焦点を当てており、#1158には焦点を当てていません。 ApplicationUp_Uplinkmessage
を変更することを提案したように、私はそれを理解しようとしています。 現在、次のクエリがあります。
1)構造体ApplicationUplink
と関数ApplicationUp_UplinkMessage
は、ttnpbディレクトリのmessages.pb.goファイルで定義されています。 ただし、ファイルのヘッダーには「編集しないでください」と記載されています。 私はそれを無視すべきですか? またはそれを変更するための代替アプローチはありますか?
2)「 introduce a new format, based on the JSON one
」について詳しく教えてください。 新しいフォーマットを作成するのではなく、既存のフォーマットを変更するだけでよいと思いました。
3)1つの結果のみが返される結果のラッピングについても言及されました。 それは正確に何をしますか? 複数のメッセージを1つに再結合して、1つの結果だけを返しますか? そして、アップリンクメッセージに対してのみそれを行う必要がありますか?
[継続的な指導をありがとう@adriansmares 。 私はgolangチュートリアルを受講しましたが、これはGO言語との最初の対話であり、多くの疑問を抱えてご迷惑をおかけしましたことをお許しください]
*.pb.*
ファイルを編集する必要はありません。 これらは、 mage proto:all
を実行すると、 *.proto
ファイルから自動的に生成されます。 それにもかかわらず、この問題の目的のために、そのような変更を行う必要はありません。パイプライン全体をよりよく説明しようとしましょう。これにより、これがどのように機能するかが明らかになるかもしれません。
*ttnpb.ApplicationUplink
です。FRMPayload
フィールドのバイトをDecodedPayload
のデコードされた構造に変換します)。*ttnpb.ApplicationUp
ラップし、フロントエンド(MQTT、webhook、PubSub、アプリケーションパッケージ)に送信します。*ttnpb.ApplicationUp
を受け取り、設定(フォーマット)に基づいて、使用するフォーマッターを選択します(フォーマッターインターフェイスはpkg/applicationserver/io/formatters
定義されています)。*ttnph.ApplicationUp
でformatter.FromUp
を呼び出し、1つのメッセージの本文を表すバイトのスライス( []byte
)を受け取ります。さて、この問題に関しては、ステップ6だけを変更する必要があることがわかるといいのですが。
FromUp
が複数のペイロード(バイトのスライスのスライス)を返すことができるように、インターフェイスと実装の両方の戻りタイプを変更します。Protobuf
およびJSON
形式は動作を変更しないため、引き続き1つのペイロードのみを返す必要があります(そのため、ラップが必要です)。[][]byte
を返すと、エラーが発生し始めます( FromUp
を呼び出す場所のほとんどは、受信されるペイロードが1つだけであると想定しているため、更新する必要があります)これらの呼び出しサイトは、ペイロードのリストをループして、それぞれを送信します。動作をまったく変更しないこの問題が修正された後でのみ、測定ごとに1つずつ、複数のペイロードのスライスを返す独自のフォーマッターの実装に進むことができます(ただし、この新しいフォーマットに注意してください)この問題の範囲外です!)。
あなたのような詳細、について説明し、ガイドのためにそんなに@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
に基づいて変更をリベースすることをお勧めします。
この問題はかなり長い間非アクティブになっているので、トリアージに戻して、これに対する需要がまだあるかどうか、または単に削除する必要があるかどうかを確認しましょう。
スケーリングが不十分なため、これは不要になりました。