diff --git a/api/api.md b/api/api.md
index bf053559c3..abceff6646 100644
--- a/api/api.md
+++ b/api/api.md
@@ -35,6 +35,7 @@
- [lorawan-stack/api/applicationserver.proto](#lorawan-stack/api/applicationserver.proto)
- [ApplicationLink](#ttn.lorawan.v3.ApplicationLink)
+ - [ApplicationLinkStats](#ttn.lorawan.v3.ApplicationLinkStats)
- [GetApplicationLinkRequest](#ttn.lorawan.v3.GetApplicationLinkRequest)
- [SetApplicationLinkRequest](#ttn.lorawan.v3.SetApplicationLinkRequest)
@@ -797,6 +798,26 @@ where the user or organization is collaborator on.
+
+
+### ApplicationLinkStats
+Link stats as monitored by the Application Server.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| linked_at | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
+| network_server_address | [string](#string) | | |
+| last_up_received_at | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | Timestamp when the last upstream message has been received from a Network Server. This can be a join-accept, uplink message or downlink message event. |
+| up_count | [uint64](#uint64) | | Number of upstream messages received. |
+| last_downlink_forwarded_at | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | Timestamp when the last downlink message has been forwarded to a Network Server. |
+| downlink_count | [uint64](#uint64) | | Number of downlink messages forwarded. |
+
+
+
+
+
+
### GetApplicationLinkRequest
@@ -859,6 +880,7 @@ The As service manages the Application Server.
| GetLink | [GetApplicationLinkRequest](#ttn.lorawan.v3.GetApplicationLinkRequest) | [ApplicationLink](#ttn.lorawan.v3.GetApplicationLinkRequest) | |
| SetLink | [SetApplicationLinkRequest](#ttn.lorawan.v3.SetApplicationLinkRequest) | [ApplicationLink](#ttn.lorawan.v3.SetApplicationLinkRequest) | |
| DeleteLink | [ApplicationIdentifiers](#ttn.lorawan.v3.ApplicationIdentifiers) | [.google.protobuf.Empty](#ttn.lorawan.v3.ApplicationIdentifiers) | |
+| GetLinkStats | [ApplicationIdentifiers](#ttn.lorawan.v3.ApplicationIdentifiers) | [ApplicationLinkStats](#ttn.lorawan.v3.ApplicationIdentifiers) | |
diff --git a/api/api.swagger.json b/api/api.swagger.json
index 562df5ee1a..8d38843719 100644
--- a/api/api.swagger.json
+++ b/api/api.swagger.json
@@ -864,6 +864,30 @@
]
}
},
+ "/as/applications/{application_id}/link/stats": {
+ "get": {
+ "operationId": "GetLinkStats",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/v3ApplicationLinkStats"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "application_id",
+ "in": "path",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "tags": [
+ "As"
+ ]
+ }
+ },
"/as/applications/{device.ids.application_ids.application_id}/devices": {
"post": {
"operationId": "Set2",
@@ -1859,6 +1883,38 @@
]
}
},
+ "/gs/gateways/{gateway_id}/connection/stats": {
+ "get": {
+ "operationId": "GetGatewayConnectionStats",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/v3GatewayConnectionStats"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "gateway_id",
+ "in": "path",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "eui",
+ "description": "Secondary identifier, which can only be used in specific requests.",
+ "in": "query",
+ "required": false,
+ "type": "string",
+ "format": "byte"
+ }
+ ],
+ "tags": [
+ "Gs"
+ ]
+ }
+ },
"/invitations": {
"get": {
"operationId": "List",
@@ -5346,6 +5402,39 @@
}
}
},
+ "v3ApplicationLinkStats": {
+ "type": "object",
+ "properties": {
+ "linked_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "network_server_address": {
+ "type": "string"
+ },
+ "last_up_received_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Timestamp when the last upstream message has been received from a Network Server.\nThis can be a join-accept, uplink message or downlink message event."
+ },
+ "up_count": {
+ "type": "string",
+ "format": "uint64",
+ "description": "Number of upstream messages received."
+ },
+ "last_downlink_forwarded_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Timestamp when the last downlink message has been forwarded to a Network Server."
+ },
+ "downlink_count": {
+ "type": "string",
+ "format": "uint64",
+ "description": "Number of downlink messages forwarded."
+ }
+ },
+ "description": "Link stats as monitored by the Application Server."
+ },
"v3ApplicationLocation": {
"type": "object",
"properties": {
diff --git a/api/applicationserver.proto b/api/applicationserver.proto
index 03a8e59e00..82ce2d750d 100644
--- a/api/applicationserver.proto
+++ b/api/applicationserver.proto
@@ -19,6 +19,7 @@ import "github.com/mwitkow/go-proto-validators/validator.proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
+import "google/protobuf/timestamp.proto";
import "lorawan-stack/api/end_device.proto";
import "lorawan-stack/api/identifiers.proto";
import "lorawan-stack/api/messages.proto";
@@ -48,6 +49,21 @@ message SetApplicationLinkRequest {
google.protobuf.FieldMask field_mask = 3 [(gogoproto.nullable) = false];
}
+// Link stats as monitored by the Application Server.
+message ApplicationLinkStats {
+ google.protobuf.Timestamp linked_at = 1 [(gogoproto.stdtime) = true];
+ string network_server_address = 2;
+ // Timestamp when the last upstream message has been received from a Network Server.
+ // This can be a join-accept, uplink message or downlink message event.
+ google.protobuf.Timestamp last_up_received_at = 3 [(gogoproto.stdtime) = true];
+ // Number of upstream messages received.
+ uint64 up_count = 4;
+ // Timestamp when the last downlink message has been forwarded to a Network Server.
+ google.protobuf.Timestamp last_downlink_forwarded_at = 5 [(gogoproto.stdtime) = true];
+ // Number of downlink messages forwarded.
+ uint64 downlink_count = 6;
+}
+
// The As service manages the Application Server.
service As {
rpc GetLink(GetApplicationLinkRequest) returns (ApplicationLink) {
@@ -68,6 +84,12 @@ service As {
delete: "/as/applications/{application_id}/link",
};
};
+
+ rpc GetLinkStats(ApplicationIdentifiers) returns (ApplicationLinkStats) {
+ option (google.api.http) = {
+ get: "/as/applications/{application_id}/link/stats"
+ };
+ };
}
// The AppAs service connects an application or integration to an Application Server.
diff --git a/api/gatewayserver.proto b/api/gatewayserver.proto
index ccfdd008a9..8d214c8973 100644
--- a/api/gatewayserver.proto
+++ b/api/gatewayserver.proto
@@ -15,6 +15,7 @@
syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
+import "google/api/annotations.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "lorawan-stack/api/gateway.proto";
@@ -63,5 +64,9 @@ service NsGs {
service Gs {
// Get statistics about the current gateway connection to the Gateway Server.
// This is not persisted between reconnects.
- rpc GetGatewayConnectionStats(GatewayIdentifiers) returns (GatewayConnectionStats);
+ rpc GetGatewayConnectionStats(GatewayIdentifiers) returns (GatewayConnectionStats) {
+ option (google.api.http) = {
+ get: "/gs/gateways/{gateway_id}/connection/stats"
+ };
+ };
}
diff --git a/config/messages.json b/config/messages.json
index 1f82b38fd6..cd3d2f3cf0 100644
--- a/config/messages.json
+++ b/config/messages.json
@@ -4760,6 +4760,24 @@
"file": "observability.go"
}
},
+ "event:as.link.start": {
+ "translations": {
+ "en": "link start"
+ },
+ "description": {
+ "package": "pkg/applicationserver",
+ "file": "observability.go"
+ }
+ },
+ "event:as.link.stop": {
+ "translations": {
+ "en": "link stop"
+ },
+ "description": {
+ "package": "pkg/applicationserver",
+ "file": "observability.go"
+ }
+ },
"event:as.up.data.decode.fail": {
"translations": {
"en": "decode uplink data message fail"
diff --git a/pkg/applicationserver/applicationserver.go b/pkg/applicationserver/applicationserver.go
index caef4032cd..86fbc234eb 100644
--- a/pkg/applicationserver/applicationserver.go
+++ b/pkg/applicationserver/applicationserver.go
@@ -20,6 +20,7 @@ import (
"fmt"
"net"
"sync"
+ "sync/atomic"
"time"
pbtypes "github.com/gogo/protobuf/types"
@@ -229,6 +230,7 @@ func (as *ApplicationServer) downlinkQueueOp(ctx context.Context, ids ttnpb.EndD
return err
}
<-link.connReady
+ var encryptedItems []*ttnpb.ApplicationDownlink
_, err = as.deviceRegistry.Set(ctx, ids,
[]string{
"session",
@@ -254,29 +256,29 @@ func (as *ApplicationServer) downlinkQueueOp(ctx context.Context, ids ttnpb.EndD
item.DecodedPayload = nil
item.CorrelationIDs = events.CorrelationIDsFromContext(ctx)
dev.Session.LastAFCntDown = item.FCnt
+ encryptedItems = append(encryptedItems, item)
}
client := ttnpb.NewAsNsClient(link.conn)
req := &ttnpb.DownlinkQueueRequest{
EndDeviceIdentifiers: ids,
- Downlinks: items,
+ Downlinks: encryptedItems,
}
_, err = op(client, ctx, req, link.callOpts...)
if err != nil {
- for _, item := range items {
- registerDropDownlink(ctx, ids, item, err)
- }
return nil, nil, err
}
- for _, item := range items {
- registerForwardDownlink(ctx, ids, item, link.connName)
- }
return dev, []string{"session.last_a_f_cnt_down"}, nil
},
)
if err != nil {
+ for _, item := range encryptedItems {
+ registerDropDownlink(ctx, ids, item, err)
+ }
return err
}
- for _, item := range items {
+ atomic.AddUint64(&link.downlinks, uint64(len(encryptedItems)))
+ atomic.StoreInt64(&link.lastDownlinkTime, time.Now().UnixNano())
+ for _, item := range encryptedItems {
registerForwardDownlink(ctx, ids, item, link.connName)
}
return nil
diff --git a/pkg/applicationserver/grpc_as.go b/pkg/applicationserver/grpc_as.go
index 3fbc9fe256..497e1cb692 100644
--- a/pkg/applicationserver/grpc_as.go
+++ b/pkg/applicationserver/grpc_as.go
@@ -75,3 +75,30 @@ func (as *ApplicationServer) DeleteLink(ctx context.Context, ids *ttnpb.Applicat
}
return ttnpb.Empty, nil
}
+
+// GetLinkStats implements ttnpb.AsServer.
+func (as *ApplicationServer) GetLinkStats(ctx context.Context, ids *ttnpb.ApplicationIdentifiers) (*ttnpb.ApplicationLinkStats, error) {
+ if err := rights.RequireApplication(ctx, *ids, ttnpb.RIGHT_APPLICATION_LINK); err != nil {
+ return nil, err
+ }
+
+ link, err := as.getLink(ctx, *ids)
+ if err != nil {
+ return nil, err
+ }
+ <-link.connReady
+
+ stats := &ttnpb.ApplicationLinkStats{}
+ lt := link.GetLinkTime()
+ stats.LinkedAt = <
+ stats.NetworkServerAddress = link.NetworkServerAddress
+ if n, t, ok := link.GetUpStats(); ok {
+ stats.UpCount = n
+ stats.LastUpReceivedAt = &t
+ }
+ if n, t, ok := link.GetDownlinkStats(); ok {
+ stats.DownlinkCount = n
+ stats.LastDownlinkForwardedAt = &t
+ }
+ return stats, nil
+}
diff --git a/pkg/applicationserver/linking.go b/pkg/applicationserver/linking.go
index c3478f2542..0de2a22b18 100644
--- a/pkg/applicationserver/linking.go
+++ b/pkg/applicationserver/linking.go
@@ -17,6 +17,7 @@ package applicationserver
import (
"context"
"fmt"
+ "sync/atomic"
"time"
"go.thethings.network/lorawan-stack/pkg/applicationserver/io"
@@ -68,6 +69,14 @@ func (as *ApplicationServer) startLinkTask(ctx context.Context, ids ttnpb.Applic
}
type link struct {
+ // Align for sync/atomic.
+ ups,
+ downlinks uint64
+ linkTime,
+ lastUpTime,
+ lastDownlinkTime int64
+
+ ttnpb.ApplicationIdentifiers
ttnpb.ApplicationLink
ctx context.Context
cancel context.CancelFunc
@@ -89,7 +98,7 @@ var (
errNSNotFound = errors.DefineNotFound("network_server_not_found", "Network Server not found for `{application_uid}`")
)
-func (as *ApplicationServer) connectLink(ctx context.Context, ids ttnpb.ApplicationIdentifiers, link *link) error {
+func (as *ApplicationServer) connectLink(ctx context.Context, link *link) error {
var allowInsecure bool
if link.NetworkServerAddress != "" {
options := rpcclient.DefaultDialOptions(ctx)
@@ -108,21 +117,22 @@ func (as *ApplicationServer) connectLink(ctx context.Context, ids ttnpb.Applicat
}()
} else {
allowInsecure = !as.ClusterTLS()
- ns := as.GetPeer(ctx, ttnpb.PeerInfo_NETWORK_SERVER, ids)
+ ns := as.GetPeer(ctx, ttnpb.PeerInfo_NETWORK_SERVER, link.ApplicationIdentifiers)
if ns == nil {
- return errNSNotFound.WithAttributes("application_uid", unique.ID(ctx, ids))
+ return errNSNotFound.WithAttributes("application_uid", unique.ID(ctx, link.ApplicationIdentifiers))
}
link.conn = ns.Conn()
link.connName = ns.Name()
}
link.callOpts = []grpc.CallOption{
grpc.PerRPCCredentials(rpcmetadata.MD{
- ID: ids.ApplicationID,
+ ID: link.ApplicationID,
AuthType: "Bearer",
AuthValue: link.APIKey,
AllowInsecure: allowInsecure,
}),
}
+ link.linkTime = time.Now().UnixNano()
close(link.connReady)
return nil
}
@@ -132,13 +142,14 @@ func (as *ApplicationServer) link(ctx context.Context, ids ttnpb.ApplicationIden
ctx = log.NewContextWithField(ctx, "application_uid", uid)
ctx, cancel := context.WithCancel(ctx)
l := &link{
- ApplicationLink: *target,
- ctx: ctx,
- cancel: cancel,
- connReady: make(chan struct{}),
- subscribeCh: make(chan *io.Subscription, 1),
- unsubscribeCh: make(chan *io.Subscription, 1),
- upCh: make(chan *ttnpb.ApplicationUp, linkBufferSize),
+ ApplicationIdentifiers: ids,
+ ApplicationLink: *target,
+ ctx: ctx,
+ cancel: cancel,
+ connReady: make(chan struct{}),
+ subscribeCh: make(chan *io.Subscription, 1),
+ unsubscribeCh: make(chan *io.Subscription, 1),
+ upCh: make(chan *ttnpb.ApplicationUp, linkBufferSize),
}
if _, loaded := as.links.LoadOrStore(uid, l); loaded {
cancel()
@@ -148,7 +159,7 @@ func (as *ApplicationServer) link(ctx context.Context, ids ttnpb.ApplicationIden
cancel()
as.links.Delete(uid)
}()
- if err := as.connectLink(ctx, ids, l); err != nil {
+ if err := as.connectLink(ctx, l); err != nil {
return err
}
client := ttnpb.NewAsNsClient(l.conn)
@@ -160,6 +171,7 @@ func (as *ApplicationServer) link(ctx context.Context, ids ttnpb.ApplicationIden
return err
}
logger.Info("Linked")
+ registerLink(ctx, l)
go l.run()
for _, sub := range as.defaultSubscribers {
@@ -178,8 +190,12 @@ func (as *ApplicationServer) link(ctx context.Context, ids ttnpb.ApplicationIden
} else {
logger.WithError(err).Warn("Link failed")
}
+ registerUnlink(ctx, l, err)
return err
}
+ atomic.AddUint64(&l.ups, 1)
+ atomic.StoreInt64(&l.lastUpTime, time.Now().UnixNano())
+
ctx := events.ContextWithCorrelationID(ctx, fmt.Sprintf("as:up:%s", events.NewCorrelationID()))
up.CorrelationIDs = append(up.CorrelationIDs, events.CorrelationIDsFromContext(ctx)...)
registerReceiveUp(ctx, up, l.connName)
@@ -242,7 +258,7 @@ func (l *link) run() {
case <-l.ctx.Done():
return
case sub := <-l.subscribeCh:
- correlationID := fmt.Sprintf("subscriber:%s", events.NewCorrelationID())
+ correlationID := fmt.Sprintf("as:subscriber:%s", events.NewCorrelationID())
subscribers[sub] = correlationID
registerSubscribe(events.ContextWithCorrelationID(l.ctx, correlationID), sub)
log.FromContext(sub.Context()).Debug("Subscribed")
@@ -261,3 +277,24 @@ func (l *link) run() {
}
}
}
+
+// GetLinkTime returns the timestamp when the link got established.
+func (l *link) GetLinkTime() time.Time { return time.Unix(0, l.linkTime) }
+
+// GetUpStats returns the upstream statistics.
+func (l *link) GetUpStats() (total uint64, t time.Time, ok bool) {
+ total = atomic.LoadUint64(&l.ups)
+ if ok = total > 0; ok {
+ t = time.Unix(0, atomic.LoadInt64(&l.lastUpTime))
+ }
+ return
+}
+
+// GetDownlinkStats returns the downlink statistics.
+func (l *link) GetDownlinkStats() (total uint64, t time.Time, ok bool) {
+ total = atomic.LoadUint64(&l.downlinks)
+ if ok = total > 0; ok {
+ t = time.Unix(0, atomic.LoadInt64(&l.lastDownlinkTime))
+ }
+ return
+}
diff --git a/pkg/applicationserver/linking_test.go b/pkg/applicationserver/linking_test.go
index 91296dc929..13bfab7330 100644
--- a/pkg/applicationserver/linking_test.go
+++ b/pkg/applicationserver/linking_test.go
@@ -118,6 +118,8 @@ func TestLink(t *testing.T) {
},
})
a.So(errors.IsNotFound(err), should.BeTrue)
+ _, err = as.GetLinkStats(ctx, &app2)
+ a.So(errors.IsNotFound(err), should.BeTrue)
// Set link, expect link to establish.
_, err = as.SetLink(ctx, &ttnpb.SetApplicationLinkRequest{
@@ -142,6 +144,9 @@ func TestLink(t *testing.T) {
})
a.So(err, should.BeNil)
a.So(*actual, should.Resemble, link)
+ stats, err := as.GetLinkStats(ctx, &app2)
+ a.So(err, should.BeNil)
+ a.So(stats.NetworkServerAddress, should.Equal, link.NetworkServerAddress)
// Wait for link to subscribe internally.
time.Sleep(timeout)
@@ -162,6 +167,8 @@ func TestLink(t *testing.T) {
},
})
a.So(errors.IsNotFound(err), should.BeTrue)
+ _, err = as.GetLinkStats(ctx, &app2)
+ a.So(errors.IsNotFound(err), should.BeTrue)
})
}
}
diff --git a/pkg/applicationserver/observability.go b/pkg/applicationserver/observability.go
index 348bf590f0..b521dbe974 100644
--- a/pkg/applicationserver/observability.go
+++ b/pkg/applicationserver/observability.go
@@ -26,6 +26,9 @@ import (
)
var (
+ evtLinkStart = events.Define("as.link.start", "link start")
+ evtLinkStop = events.Define("as.link.stop", "link stop")
+
evtApplicationSubscribe = events.Define("as.application.subscribe", "application subscribe")
evtApplicationUnsubscribe = events.Define("as.application.unsubscribe", "application unsubscribe")
@@ -54,6 +57,22 @@ const (
)
var asMetrics = &messageMetrics{
+ linksStarted: metrics.NewContextualCounterVec(
+ prometheus.CounterOpts{
+ Subsystem: subsystem,
+ Name: "links_started",
+ Help: "Number of links started",
+ },
+ []string{networkServer},
+ ),
+ linksStopped: metrics.NewContextualCounterVec(
+ prometheus.CounterOpts{
+ Subsystem: subsystem,
+ Name: "links_stopped",
+ Help: "Number of links stopped",
+ },
+ []string{networkServer},
+ ),
subscriptionsStarted: metrics.NewContextualCounterVec(
prometheus.CounterOpts{
Subsystem: subsystem,
@@ -62,11 +81,11 @@ var asMetrics = &messageMetrics{
},
[]string{protocol},
),
- subscriptionsEnded: metrics.NewContextualCounterVec(
+ subscriptionsStopped: metrics.NewContextualCounterVec(
prometheus.CounterOpts{
Subsystem: subsystem,
- Name: "subscriptions_ended",
- Help: "Number of subscriptions ended",
+ Name: "subscriptions_stopped",
+ Help: "Number of subscriptions stopped",
},
[]string{protocol},
),
@@ -125,8 +144,10 @@ func init() {
}
type messageMetrics struct {
+ linksStarted *metrics.ContextualCounterVec
+ linksStopped *metrics.ContextualCounterVec
subscriptionsStarted *metrics.ContextualCounterVec
- subscriptionsEnded *metrics.ContextualCounterVec
+ subscriptionsStopped *metrics.ContextualCounterVec
uplinkReceived *metrics.ContextualCounterVec
uplinkForwarded *metrics.ContextualCounterVec
uplinkDropped *metrics.ContextualCounterVec
@@ -136,8 +157,10 @@ type messageMetrics struct {
}
func (m messageMetrics) Describe(ch chan<- *prometheus.Desc) {
+ m.linksStarted.Describe(ch)
+ m.linksStopped.Describe(ch)
m.subscriptionsStarted.Describe(ch)
- m.subscriptionsEnded.Describe(ch)
+ m.subscriptionsStopped.Describe(ch)
m.uplinkReceived.Describe(ch)
m.uplinkForwarded.Describe(ch)
m.uplinkDropped.Describe(ch)
@@ -147,8 +170,10 @@ func (m messageMetrics) Describe(ch chan<- *prometheus.Desc) {
}
func (m messageMetrics) Collect(ch chan<- prometheus.Metric) {
+ m.linksStarted.Collect(ch)
+ m.linksStopped.Collect(ch)
m.subscriptionsStarted.Collect(ch)
- m.subscriptionsEnded.Collect(ch)
+ m.subscriptionsStopped.Collect(ch)
m.uplinkReceived.Collect(ch)
m.uplinkForwarded.Collect(ch)
m.uplinkDropped.Collect(ch)
@@ -157,6 +182,16 @@ func (m messageMetrics) Collect(ch chan<- prometheus.Metric) {
m.downlinkDropped.Collect(ch)
}
+func registerLink(ctx context.Context, link *link) {
+ events.Publish(evtLinkStart(ctx, link.ApplicationIdentifiers, nil))
+ asMetrics.linksStarted.WithLabelValues(ctx, link.NetworkServerAddress).Inc()
+}
+
+func registerUnlink(ctx context.Context, link *link, err error) {
+ events.Publish(evtLinkStop(ctx, link.ApplicationIdentifiers, err))
+ asMetrics.linksStopped.WithLabelValues(ctx, link.NetworkServerAddress).Inc()
+}
+
func registerSubscribe(ctx context.Context, sub *io.Subscription) {
var ids ttnpb.Identifiers
if appIDs := sub.ApplicationIDs(); appIDs != nil {
@@ -172,7 +207,7 @@ func registerUnsubscribe(ctx context.Context, sub *io.Subscription) {
ids = appIDs
}
events.Publish(evtApplicationUnsubscribe(ctx, ids, nil))
- asMetrics.subscriptionsEnded.WithLabelValues(ctx, sub.Protocol()).Inc()
+ asMetrics.subscriptionsStopped.WithLabelValues(ctx, sub.Protocol()).Inc()
}
func registerReceiveUp(ctx context.Context, msg *ttnpb.ApplicationUp, ns string) {
diff --git a/pkg/ttnpb/applicationserver.pb.fm.go b/pkg/ttnpb/applicationserver.pb.fm.go
index e8d822a85b..559072dbc6 100644
--- a/pkg/ttnpb/applicationserver.pb.fm.go
+++ b/pkg/ttnpb/applicationserver.pb.fm.go
@@ -202,3 +202,89 @@ func (dst *SetApplicationLinkRequest) SetFields(src *SetApplicationLinkRequest,
}
return nil
}
+
+var ApplicationLinkStatsFieldPathsNested = []string{
+ "downlink_count",
+ "last_downlink_forwarded_at",
+ "last_up_received_at",
+ "linked_at",
+ "network_server_address",
+ "up_count",
+}
+
+var ApplicationLinkStatsFieldPathsTopLevel = []string{
+ "downlink_count",
+ "last_downlink_forwarded_at",
+ "last_up_received_at",
+ "linked_at",
+ "network_server_address",
+ "up_count",
+}
+
+func (dst *ApplicationLinkStats) SetFields(src *ApplicationLinkStats, paths ...string) error {
+ for name, subs := range _processPaths(append(paths[:0:0], paths...)) {
+ switch name {
+ case "linked_at":
+ if len(subs) > 0 {
+ return fmt.Errorf("'linked_at' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.LinkedAt = src.LinkedAt
+ } else {
+ dst.LinkedAt = nil
+ }
+ case "network_server_address":
+ if len(subs) > 0 {
+ return fmt.Errorf("'network_server_address' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.NetworkServerAddress = src.NetworkServerAddress
+ } else {
+ var zero string
+ dst.NetworkServerAddress = zero
+ }
+ case "last_up_received_at":
+ if len(subs) > 0 {
+ return fmt.Errorf("'last_up_received_at' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.LastUpReceivedAt = src.LastUpReceivedAt
+ } else {
+ dst.LastUpReceivedAt = nil
+ }
+ case "up_count":
+ if len(subs) > 0 {
+ return fmt.Errorf("'up_count' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.UpCount = src.UpCount
+ } else {
+ var zero uint64
+ dst.UpCount = zero
+ }
+ case "last_downlink_forwarded_at":
+ if len(subs) > 0 {
+ return fmt.Errorf("'last_downlink_forwarded_at' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.LastDownlinkForwardedAt = src.LastDownlinkForwardedAt
+ } else {
+ dst.LastDownlinkForwardedAt = nil
+ }
+ case "downlink_count":
+ if len(subs) > 0 {
+ return fmt.Errorf("'downlink_count' has no subfields, but %s were specified", subs)
+ }
+ if src != nil {
+ dst.DownlinkCount = src.DownlinkCount
+ } else {
+ var zero uint64
+ dst.DownlinkCount = zero
+ }
+
+ default:
+ return fmt.Errorf("invalid field: '%s'", name)
+ }
+ }
+ return nil
+}
diff --git a/pkg/ttnpb/applicationserver.pb.go b/pkg/ttnpb/applicationserver.pb.go
index cba632eb86..029547a0f7 100644
--- a/pkg/ttnpb/applicationserver.pb.go
+++ b/pkg/ttnpb/applicationserver.pb.go
@@ -12,12 +12,16 @@ import types "github.com/gogo/protobuf/types"
import _ "github.com/mwitkow/go-proto-validators"
import _ "google.golang.org/genproto/googleapis/api/annotations"
+import time "time"
+
import (
context "context"
grpc "google.golang.org/grpc"
)
+import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
+
import strings "strings"
import reflect "reflect"
@@ -28,6 +32,7 @@ var _ = proto.Marshal
var _ = golang_proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
+var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
@@ -50,7 +55,7 @@ type ApplicationLink struct {
func (m *ApplicationLink) Reset() { *m = ApplicationLink{} }
func (*ApplicationLink) ProtoMessage() {}
func (*ApplicationLink) Descriptor() ([]byte, []int) {
- return fileDescriptor_applicationserver_bb4b6097f23b5b16, []int{0}
+ return fileDescriptor_applicationserver_2b21ee51f35bd800, []int{0}
}
func (m *ApplicationLink) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -110,7 +115,7 @@ type GetApplicationLinkRequest struct {
func (m *GetApplicationLinkRequest) Reset() { *m = GetApplicationLinkRequest{} }
func (*GetApplicationLinkRequest) ProtoMessage() {}
func (*GetApplicationLinkRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_applicationserver_bb4b6097f23b5b16, []int{1}
+ return fileDescriptor_applicationserver_2b21ee51f35bd800, []int{1}
}
func (m *GetApplicationLinkRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -157,7 +162,7 @@ type SetApplicationLinkRequest struct {
func (m *SetApplicationLinkRequest) Reset() { *m = SetApplicationLinkRequest{} }
func (*SetApplicationLinkRequest) ProtoMessage() {}
func (*SetApplicationLinkRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_applicationserver_bb4b6097f23b5b16, []int{2}
+ return fileDescriptor_applicationserver_2b21ee51f35bd800, []int{2}
}
func (m *SetApplicationLinkRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -193,6 +198,97 @@ func (m *SetApplicationLinkRequest) GetFieldMask() types.FieldMask {
return types.FieldMask{}
}
+// Link stats as monitored by the Application Server.
+type ApplicationLinkStats struct {
+ LinkedAt *time.Time `protobuf:"bytes,1,opt,name=linked_at,json=linkedAt,proto3,stdtime" json:"linked_at,omitempty"`
+ NetworkServerAddress string `protobuf:"bytes,2,opt,name=network_server_address,json=networkServerAddress,proto3" json:"network_server_address,omitempty"`
+ // Timestamp when the last upstream message has been received from a Network Server.
+ // This can be a join-accept, uplink message or downlink message event.
+ LastUpReceivedAt *time.Time `protobuf:"bytes,3,opt,name=last_up_received_at,json=lastUpReceivedAt,proto3,stdtime" json:"last_up_received_at,omitempty"`
+ // Number of upstream messages received.
+ UpCount uint64 `protobuf:"varint,4,opt,name=up_count,json=upCount,proto3" json:"up_count,omitempty"`
+ // Timestamp when the last downlink message has been forwarded to a Network Server.
+ LastDownlinkForwardedAt *time.Time `protobuf:"bytes,5,opt,name=last_downlink_forwarded_at,json=lastDownlinkForwardedAt,proto3,stdtime" json:"last_downlink_forwarded_at,omitempty"`
+ // Number of downlink messages forwarded.
+ DownlinkCount uint64 `protobuf:"varint,6,opt,name=downlink_count,json=downlinkCount,proto3" json:"downlink_count,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ApplicationLinkStats) Reset() { *m = ApplicationLinkStats{} }
+func (*ApplicationLinkStats) ProtoMessage() {}
+func (*ApplicationLinkStats) Descriptor() ([]byte, []int) {
+ return fileDescriptor_applicationserver_2b21ee51f35bd800, []int{3}
+}
+func (m *ApplicationLinkStats) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *ApplicationLinkStats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_ApplicationLinkStats.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (dst *ApplicationLinkStats) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ApplicationLinkStats.Merge(dst, src)
+}
+func (m *ApplicationLinkStats) XXX_Size() int {
+ return m.Size()
+}
+func (m *ApplicationLinkStats) XXX_DiscardUnknown() {
+ xxx_messageInfo_ApplicationLinkStats.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ApplicationLinkStats proto.InternalMessageInfo
+
+func (m *ApplicationLinkStats) GetLinkedAt() *time.Time {
+ if m != nil {
+ return m.LinkedAt
+ }
+ return nil
+}
+
+func (m *ApplicationLinkStats) GetNetworkServerAddress() string {
+ if m != nil {
+ return m.NetworkServerAddress
+ }
+ return ""
+}
+
+func (m *ApplicationLinkStats) GetLastUpReceivedAt() *time.Time {
+ if m != nil {
+ return m.LastUpReceivedAt
+ }
+ return nil
+}
+
+func (m *ApplicationLinkStats) GetUpCount() uint64 {
+ if m != nil {
+ return m.UpCount
+ }
+ return 0
+}
+
+func (m *ApplicationLinkStats) GetLastDownlinkForwardedAt() *time.Time {
+ if m != nil {
+ return m.LastDownlinkForwardedAt
+ }
+ return nil
+}
+
+func (m *ApplicationLinkStats) GetDownlinkCount() uint64 {
+ if m != nil {
+ return m.DownlinkCount
+ }
+ return 0
+}
+
func init() {
proto.RegisterType((*ApplicationLink)(nil), "ttn.lorawan.v3.ApplicationLink")
golang_proto.RegisterType((*ApplicationLink)(nil), "ttn.lorawan.v3.ApplicationLink")
@@ -200,6 +296,8 @@ func init() {
golang_proto.RegisterType((*GetApplicationLinkRequest)(nil), "ttn.lorawan.v3.GetApplicationLinkRequest")
proto.RegisterType((*SetApplicationLinkRequest)(nil), "ttn.lorawan.v3.SetApplicationLinkRequest")
golang_proto.RegisterType((*SetApplicationLinkRequest)(nil), "ttn.lorawan.v3.SetApplicationLinkRequest")
+ proto.RegisterType((*ApplicationLinkStats)(nil), "ttn.lorawan.v3.ApplicationLinkStats")
+ golang_proto.RegisterType((*ApplicationLinkStats)(nil), "ttn.lorawan.v3.ApplicationLinkStats")
}
func (this *ApplicationLink) Equal(that interface{}) bool {
if that == nil {
@@ -288,6 +386,57 @@ func (this *SetApplicationLinkRequest) Equal(that interface{}) bool {
}
return true
}
+func (this *ApplicationLinkStats) Equal(that interface{}) bool {
+ if that == nil {
+ return this == nil
+ }
+
+ that1, ok := that.(*ApplicationLinkStats)
+ if !ok {
+ that2, ok := that.(ApplicationLinkStats)
+ if ok {
+ that1 = &that2
+ } else {
+ return false
+ }
+ }
+ if that1 == nil {
+ return this == nil
+ } else if this == nil {
+ return false
+ }
+ if that1.LinkedAt == nil {
+ if this.LinkedAt != nil {
+ return false
+ }
+ } else if !this.LinkedAt.Equal(*that1.LinkedAt) {
+ return false
+ }
+ if this.NetworkServerAddress != that1.NetworkServerAddress {
+ return false
+ }
+ if that1.LastUpReceivedAt == nil {
+ if this.LastUpReceivedAt != nil {
+ return false
+ }
+ } else if !this.LastUpReceivedAt.Equal(*that1.LastUpReceivedAt) {
+ return false
+ }
+ if this.UpCount != that1.UpCount {
+ return false
+ }
+ if that1.LastDownlinkForwardedAt == nil {
+ if this.LastDownlinkForwardedAt != nil {
+ return false
+ }
+ } else if !this.LastDownlinkForwardedAt.Equal(*that1.LastDownlinkForwardedAt) {
+ return false
+ }
+ if this.DownlinkCount != that1.DownlinkCount {
+ return false
+ }
+ return true
+}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
@@ -304,6 +453,7 @@ type AsClient interface {
GetLink(ctx context.Context, in *GetApplicationLinkRequest, opts ...grpc.CallOption) (*ApplicationLink, error)
SetLink(ctx context.Context, in *SetApplicationLinkRequest, opts ...grpc.CallOption) (*ApplicationLink, error)
DeleteLink(ctx context.Context, in *ApplicationIdentifiers, opts ...grpc.CallOption) (*types.Empty, error)
+ GetLinkStats(ctx context.Context, in *ApplicationIdentifiers, opts ...grpc.CallOption) (*ApplicationLinkStats, error)
}
type asClient struct {
@@ -341,11 +491,21 @@ func (c *asClient) DeleteLink(ctx context.Context, in *ApplicationIdentifiers, o
return out, nil
}
+func (c *asClient) GetLinkStats(ctx context.Context, in *ApplicationIdentifiers, opts ...grpc.CallOption) (*ApplicationLinkStats, error) {
+ out := new(ApplicationLinkStats)
+ err := c.cc.Invoke(ctx, "/ttn.lorawan.v3.As/GetLinkStats", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
// AsServer is the server API for As service.
type AsServer interface {
GetLink(context.Context, *GetApplicationLinkRequest) (*ApplicationLink, error)
SetLink(context.Context, *SetApplicationLinkRequest) (*ApplicationLink, error)
DeleteLink(context.Context, *ApplicationIdentifiers) (*types.Empty, error)
+ GetLinkStats(context.Context, *ApplicationIdentifiers) (*ApplicationLinkStats, error)
}
func RegisterAsServer(s *grpc.Server, srv AsServer) {
@@ -406,6 +566,24 @@ func _As_DeleteLink_Handler(srv interface{}, ctx context.Context, dec func(inter
return interceptor(ctx, in, info, handler)
}
+func _As_GetLinkStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ApplicationIdentifiers)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AsServer).GetLinkStats(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/ttn.lorawan.v3.As/GetLinkStats",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AsServer).GetLinkStats(ctx, req.(*ApplicationIdentifiers))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
var _As_serviceDesc = grpc.ServiceDesc{
ServiceName: "ttn.lorawan.v3.As",
HandlerType: (*AsServer)(nil),
@@ -422,6 +600,10 @@ var _As_serviceDesc = grpc.ServiceDesc{
MethodName: "DeleteLink",
Handler: _As_DeleteLink_Handler,
},
+ {
+ MethodName: "GetLinkStats",
+ Handler: _As_GetLinkStats_Handler,
+ },
},
Streams: []grpc.StreamDesc{},
Metadata: "lorawan-stack/api/applicationserver.proto",
@@ -874,6 +1056,70 @@ func (m *SetApplicationLinkRequest) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
+func (m *ApplicationLinkStats) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *ApplicationLinkStats) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if m.LinkedAt != nil {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(*m.LinkedAt)))
+ n7, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LinkedAt, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n7
+ }
+ if len(m.NetworkServerAddress) > 0 {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, uint64(len(m.NetworkServerAddress)))
+ i += copy(dAtA[i:], m.NetworkServerAddress)
+ }
+ if m.LastUpReceivedAt != nil {
+ dAtA[i] = 0x1a
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastUpReceivedAt)))
+ n8, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastUpReceivedAt, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n8
+ }
+ if m.UpCount != 0 {
+ dAtA[i] = 0x20
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, m.UpCount)
+ }
+ if m.LastDownlinkForwardedAt != nil {
+ dAtA[i] = 0x2a
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastDownlinkForwardedAt)))
+ n9, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastDownlinkForwardedAt, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n9
+ }
+ if m.DownlinkCount != 0 {
+ dAtA[i] = 0x30
+ i++
+ i = encodeVarintApplicationserver(dAtA, i, m.DownlinkCount)
+ }
+ return i, nil
+}
+
func encodeVarintApplicationserver(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
@@ -919,6 +1165,25 @@ func NewPopulatedSetApplicationLinkRequest(r randyApplicationserver, easy bool)
return this
}
+func NewPopulatedApplicationLinkStats(r randyApplicationserver, easy bool) *ApplicationLinkStats {
+ this := &ApplicationLinkStats{}
+ if r.Intn(10) != 0 {
+ this.LinkedAt = github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+ }
+ this.NetworkServerAddress = randStringApplicationserver(r)
+ if r.Intn(10) != 0 {
+ this.LastUpReceivedAt = github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+ }
+ this.UpCount = uint64(r.Uint32())
+ if r.Intn(10) != 0 {
+ this.LastDownlinkForwardedAt = github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+ }
+ this.DownlinkCount = uint64(r.Uint32())
+ if !easy && r.Intn(10) != 0 {
+ }
+ return this
+}
+
type randyApplicationserver interface {
Float32() float32
Float64() float64
@@ -1040,6 +1305,37 @@ func (m *SetApplicationLinkRequest) Size() (n int) {
return n
}
+func (m *ApplicationLinkStats) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if m.LinkedAt != nil {
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.LinkedAt)
+ n += 1 + l + sovApplicationserver(uint64(l))
+ }
+ l = len(m.NetworkServerAddress)
+ if l > 0 {
+ n += 1 + l + sovApplicationserver(uint64(l))
+ }
+ if m.LastUpReceivedAt != nil {
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastUpReceivedAt)
+ n += 1 + l + sovApplicationserver(uint64(l))
+ }
+ if m.UpCount != 0 {
+ n += 1 + sovApplicationserver(m.UpCount)
+ }
+ if m.LastDownlinkForwardedAt != nil {
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastDownlinkForwardedAt)
+ n += 1 + l + sovApplicationserver(uint64(l))
+ }
+ if m.DownlinkCount != 0 {
+ n += 1 + sovApplicationserver(m.DownlinkCount)
+ }
+ return n
+}
+
func sovApplicationserver(x uint64) (n int) {
for {
n++
@@ -1088,6 +1384,21 @@ func (this *SetApplicationLinkRequest) String() string {
}, "")
return s
}
+func (this *ApplicationLinkStats) String() string {
+ if this == nil {
+ return "nil"
+ }
+ s := strings.Join([]string{`&ApplicationLinkStats{`,
+ `LinkedAt:` + strings.Replace(fmt.Sprintf("%v", this.LinkedAt), "Timestamp", "types.Timestamp", 1) + `,`,
+ `NetworkServerAddress:` + fmt.Sprintf("%v", this.NetworkServerAddress) + `,`,
+ `LastUpReceivedAt:` + strings.Replace(fmt.Sprintf("%v", this.LastUpReceivedAt), "Timestamp", "types.Timestamp", 1) + `,`,
+ `UpCount:` + fmt.Sprintf("%v", this.UpCount) + `,`,
+ `LastDownlinkForwardedAt:` + strings.Replace(fmt.Sprintf("%v", this.LastDownlinkForwardedAt), "Timestamp", "types.Timestamp", 1) + `,`,
+ `DownlinkCount:` + fmt.Sprintf("%v", this.DownlinkCount) + `,`,
+ `}`,
+ }, "")
+ return s
+}
func valueToStringApplicationserver(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.IsNil() {
@@ -1487,6 +1798,222 @@ func (m *SetApplicationLinkRequest) Unmarshal(dAtA []byte) error {
}
return nil
}
+func (m *ApplicationLinkStats) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: ApplicationLinkStats: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: ApplicationLinkStats: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field LinkedAt", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthApplicationserver
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.LinkedAt == nil {
+ m.LinkedAt = new(time.Time)
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(m.LinkedAt, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field NetworkServerAddress", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthApplicationserver
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.NetworkServerAddress = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field LastUpReceivedAt", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthApplicationserver
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.LastUpReceivedAt == nil {
+ m.LastUpReceivedAt = new(time.Time)
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(m.LastUpReceivedAt, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 4:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field UpCount", wireType)
+ }
+ m.UpCount = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.UpCount |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 5:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field LastDownlinkForwardedAt", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthApplicationserver
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.LastDownlinkForwardedAt == nil {
+ m.LastDownlinkForwardedAt = new(time.Time)
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(m.LastDownlinkForwardedAt, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 6:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field DownlinkCount", wireType)
+ }
+ m.DownlinkCount = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowApplicationserver
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.DownlinkCount |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ default:
+ iNdEx = preIndex
+ skippy, err := skipApplicationserver(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthApplicationserver
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
func skipApplicationserver(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
@@ -1593,75 +2120,86 @@ var (
)
func init() {
- proto.RegisterFile("lorawan-stack/api/applicationserver.proto", fileDescriptor_applicationserver_bb4b6097f23b5b16)
+ proto.RegisterFile("lorawan-stack/api/applicationserver.proto", fileDescriptor_applicationserver_2b21ee51f35bd800)
}
func init() {
- golang_proto.RegisterFile("lorawan-stack/api/applicationserver.proto", fileDescriptor_applicationserver_bb4b6097f23b5b16)
-}
-
-var fileDescriptor_applicationserver_bb4b6097f23b5b16 = []byte{
- // 997 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x96, 0x4f, 0x68, 0x1b, 0x47,
- 0x1b, 0xc6, 0x77, 0x2c, 0xc7, 0xfe, 0x3c, 0x86, 0xe4, 0xcb, 0x36, 0x04, 0x5b, 0x6d, 0x47, 0x66,
- 0x13, 0x82, 0x6d, 0xea, 0xdd, 0xa2, 0x94, 0x50, 0x52, 0xda, 0x22, 0x63, 0xc7, 0xb8, 0xb1, 0xc1,
- 0x95, 0x5a, 0xda, 0xa6, 0x07, 0x31, 0xd2, 0x8e, 0x56, 0x83, 0x56, 0x3b, 0xdb, 0x9d, 0x59, 0xab,
- 0x22, 0x0d, 0x84, 0x9e, 0x72, 0x2c, 0x94, 0x40, 0x8e, 0xa5, 0xa7, 0x40, 0x2f, 0x21, 0x25, 0x34,
- 0xc7, 0x1c, 0x0d, 0xb9, 0xb8, 0xf4, 0x92, 0x93, 0x13, 0xad, 0x7a, 0xc8, 0x31, 0xa7, 0x12, 0x7a,
- 0x2a, 0x9a, 0x5d, 0xfd, 0xdb, 0xb5, 0x1c, 0x3b, 0x0d, 0xe9, 0x6d, 0x57, 0xef, 0x33, 0xef, 0xfc,
- 0x9e, 0xf7, 0x19, 0x0d, 0x0b, 0x17, 0x6c, 0xe6, 0xe1, 0x06, 0x76, 0x96, 0xb8, 0xc0, 0xe5, 0x9a,
- 0x81, 0x5d, 0x6a, 0x60, 0xd7, 0xb5, 0x69, 0x19, 0x0b, 0xca, 0x1c, 0x4e, 0xbc, 0x6d, 0xe2, 0xe9,
- 0xae, 0xc7, 0x04, 0x53, 0x8f, 0x0b, 0xe1, 0xe8, 0x91, 0x5c, 0xdf, 0x3e, 0x9f, 0x5e, 0xb2, 0xa8,
- 0xa8, 0xfa, 0x25, 0xbd, 0xcc, 0xea, 0x86, 0xc5, 0x2c, 0x66, 0x48, 0x59, 0xc9, 0xaf, 0xc8, 0x37,
- 0xf9, 0x22, 0x9f, 0xc2, 0xe5, 0xe9, 0x0b, 0x03, 0xf2, 0x7a, 0x83, 0x8a, 0x1a, 0x6b, 0x18, 0x16,
- 0x5b, 0x92, 0xc5, 0xa5, 0x6d, 0x6c, 0x53, 0x13, 0x0b, 0xe6, 0x71, 0xa3, 0xf7, 0x18, 0xad, 0x7b,
- 0xcb, 0x62, 0xcc, 0xb2, 0x49, 0x88, 0xe6, 0x38, 0x4c, 0x84, 0x64, 0x51, 0xf5, 0xcd, 0xa8, 0xda,
- 0xdb, 0x9b, 0xd4, 0x5d, 0xd1, 0x8c, 0x8a, 0x73, 0xf1, 0x62, 0x85, 0x12, 0xdb, 0x2c, 0xd6, 0x31,
- 0xaf, 0x45, 0x0a, 0x2d, 0x69, 0x9f, 0x38, 0x66, 0xd1, 0x24, 0xdb, 0xb4, 0x4c, 0x22, 0xcd, 0x99,
- 0xa4, 0x86, 0x9a, 0xc4, 0x11, 0xb4, 0x42, 0x89, 0xd7, 0xe5, 0x98, 0x4b, 0x8a, 0xea, 0x84, 0x73,
- 0x6c, 0x91, 0x48, 0xa1, 0x3d, 0x04, 0xf0, 0x44, 0xae, 0x3f, 0xda, 0x0d, 0xea, 0xd4, 0xd4, 0xf7,
- 0xe0, 0x69, 0x87, 0x88, 0x06, 0xf3, 0x6a, 0xc5, 0x70, 0xd4, 0x45, 0x6c, 0x9a, 0x1e, 0xe1, 0x7c,
- 0x06, 0xcc, 0x81, 0xf9, 0xa9, 0xfc, 0xa9, 0xa8, 0x5a, 0x90, 0xc5, 0x5c, 0x58, 0x53, 0x17, 0xe0,
- 0x24, 0x76, 0x69, 0xb1, 0x46, 0x9a, 0x33, 0x63, 0x1d, 0xd9, 0xf2, 0xff, 0x83, 0xbd, 0xcc, 0x44,
- 0x6e, 0x6b, 0xfd, 0x32, 0x69, 0x06, 0x8f, 0x33, 0x63, 0x5f, 0x82, 0xfc, 0x04, 0x76, 0xe9, 0x65,
- 0xd2, 0x54, 0xbf, 0x80, 0xaa, 0x49, 0x2a, 0xd8, 0xb7, 0x45, 0xb1, 0xc2, 0xbc, 0x3a, 0x16, 0x82,
- 0x78, 0x7c, 0x26, 0x35, 0x07, 0xe6, 0xa7, 0xb3, 0xf3, 0xfa, 0x70, 0xa0, 0xfa, 0x66, 0x08, 0xbc,
- 0x85, 0x9b, 0x36, 0xc3, 0xe6, 0xa5, 0x9e, 0x3e, 0x7f, 0x32, 0xea, 0xd1, 0xff, 0x49, 0xfb, 0x0d,
- 0xc0, 0xd9, 0x35, 0x22, 0x62, 0x86, 0xf2, 0xe4, 0x1b, 0x9f, 0x70, 0xa1, 0x7e, 0x05, 0x4f, 0x0c,
- 0x9c, 0xa2, 0x22, 0x35, 0x43, 0x43, 0xd3, 0xd9, 0x73, 0xf1, 0x3d, 0x07, 0x1a, 0xac, 0xf7, 0x87,
- 0xba, 0xfc, 0xbf, 0x9d, 0xbd, 0x8c, 0xb2, 0xbb, 0x97, 0x01, 0xf9, 0xe3, 0x78, 0x50, 0xc1, 0xd5,
- 0x8f, 0x21, 0xec, 0xa7, 0x28, 0xfd, 0x4f, 0x67, 0xd3, 0x7a, 0x18, 0xb4, 0xde, 0x0d, 0x5a, 0xbf,
- 0xd4, 0x91, 0x6c, 0x62, 0x5e, 0x5b, 0x1e, 0xef, 0x74, 0xca, 0x4f, 0x55, 0xba, 0x3f, 0x68, 0x7f,
- 0x01, 0x38, 0x5b, 0xf8, 0x2f, 0xc8, 0x3f, 0x84, 0xe3, 0x36, 0x75, 0xba, 0xcc, 0x99, 0x03, 0xfa,
- 0x75, 0x80, 0x06, 0x1a, 0xc9, 0x65, 0x31, 0xe3, 0xa9, 0x23, 0x1b, 0xcf, 0xde, 0x4b, 0xc1, 0xb1,
- 0x1c, 0x57, 0x6f, 0x02, 0x38, 0xb9, 0x46, 0x84, 0x3c, 0x7f, 0x0b, 0x71, 0x88, 0x91, 0x91, 0xa6,
- 0x5f, 0xc4, 0xab, 0x7d, 0xf4, 0xfd, 0x1f, 0x7f, 0xfe, 0x38, 0xf6, 0xbe, 0x7a, 0xc1, 0xc0, 0x7c,
- 0xe8, 0x0e, 0x31, 0xae, 0xc6, 0x26, 0xaa, 0x0f, 0xbf, 0x5f, 0x33, 0xa4, 0xbf, 0x5b, 0x00, 0x4e,
- 0x16, 0x46, 0x71, 0x15, 0x5e, 0x9e, 0x2b, 0x27, 0xb9, 0x3e, 0x48, 0xbf, 0x24, 0xd7, 0x45, 0xb0,
- 0xa8, 0x7e, 0x07, 0xe1, 0x0a, 0xb1, 0x89, 0x20, 0x12, 0xee, 0x90, 0x27, 0x21, 0x7d, 0x3a, 0x11,
- 0xce, 0x6a, 0xe7, 0x6e, 0xd2, 0x74, 0x09, 0x34, 0xbf, 0x78, 0xee, 0x45, 0x40, 0x21, 0x40, 0xf6,
- 0xde, 0x31, 0x78, 0x2c, 0xe7, 0xba, 0x39, 0xae, 0x7e, 0x06, 0xa7, 0x0a, 0x7e, 0x89, 0x97, 0x3d,
- 0x5a, 0x22, 0x87, 0xc6, 0x78, 0xfb, 0x00, 0xdd, 0xe7, 0xee, 0xbb, 0x40, 0x7d, 0x08, 0xe0, 0xc9,
- 0x15, 0xd6, 0x70, 0x3a, 0x9b, 0x7d, 0xea, 0x13, 0x9f, 0x6c, 0xf9, 0xbc, 0xaa, 0x9e, 0x8d, 0x2f,
- 0x1b, 0x92, 0x74, 0xa7, 0x3f, 0xca, 0xe3, 0xb7, 0xd2, 0xa3, 0xa7, 0xd5, 0x93, 0x1e, 0xfb, 0xf7,
- 0xeb, 0x3e, 0x33, 0x4f, 0x66, 0x10, 0x4a, 0x93, 0xeb, 0x7a, 0x8f, 0xd7, 0x0c, 0x93, 0x35, 0x1c,
- 0xc3, 0xf5, 0x79, 0xb5, 0x93, 0xd5, 0xef, 0x00, 0x9e, 0x8a, 0xa1, 0xba, 0x36, 0x2e, 0x93, 0x7f,
- 0x69, 0xe8, 0xaa, 0x34, 0xe4, 0x6b, 0xee, 0x6b, 0x33, 0xe4, 0x85, 0xdc, 0x1d, 0x4f, 0xbf, 0xc6,
- 0x13, 0xda, 0xa0, 0x5c, 0x24, 0x0d, 0xad, 0x3a, 0xe6, 0x8a, 0x6c, 0x32, 0x18, 0xff, 0xd9, 0x03,
- 0xe2, 0xef, 0xf6, 0xe4, 0x5a, 0x5e, 0xda, 0xdb, 0x50, 0x3f, 0x39, 0xfa, 0x9f, 0xa4, 0xe7, 0x27,
- 0x66, 0x20, 0xfb, 0x78, 0x1c, 0xbe, 0x91, 0xe3, 0x3d, 0xa8, 0x3c, 0xb1, 0x28, 0x17, 0x5e, 0x53,
- 0xbd, 0x0b, 0x60, 0x6a, 0x8d, 0x08, 0xf5, 0xcc, 0x3e, 0x97, 0xcf, 0x80, 0x3a, 0xcc, 0x63, 0x76,
- 0xa4, 0x49, 0xad, 0x26, 0x99, 0x89, 0x5a, 0x7e, 0x0d, 0x91, 0xa8, 0x7f, 0x03, 0x98, 0x2a, 0xec,
- 0x07, 0x5d, 0x38, 0x1a, 0xf4, 0x5d, 0x20, 0xa9, 0x7f, 0x01, 0xe9, 0xaf, 0x93, 0xd8, 0xd1, 0x67,
- 0xc7, 0x91, 0x90, 0x07, 0xd6, 0xf4, 0x71, 0x2f, 0x82, 0xc5, 0x2b, 0xeb, 0xda, 0xca, 0xab, 0xd8,
- 0xa1, 0x73, 0xfe, 0x6e, 0x02, 0x38, 0x11, 0x5e, 0x80, 0x87, 0x3c, 0x74, 0xa3, 0xfe, 0x45, 0x9b,
- 0xd2, 0xfc, 0xda, 0xe2, 0xea, 0x2b, 0x39, 0x66, 0xcb, 0x3f, 0x83, 0x9d, 0x16, 0x02, 0xbb, 0x2d,
- 0x04, 0x1e, 0xb5, 0x90, 0xf2, 0xa4, 0x85, 0x94, 0xa7, 0x2d, 0xa4, 0x3c, 0x6b, 0x21, 0xe5, 0x79,
- 0x0b, 0x81, 0xeb, 0x01, 0x02, 0x37, 0x02, 0xa4, 0xdc, 0x0e, 0x10, 0xb8, 0x13, 0x20, 0xe5, 0x7e,
- 0x80, 0x94, 0x07, 0x01, 0x52, 0x76, 0x02, 0x04, 0x76, 0x03, 0x04, 0x1e, 0x05, 0x48, 0x79, 0x12,
- 0x20, 0xf0, 0x34, 0x40, 0xca, 0xb3, 0x00, 0x81, 0xe7, 0x01, 0x52, 0xae, 0xb7, 0x91, 0x72, 0xa3,
- 0x8d, 0xc0, 0x0f, 0x6d, 0xa4, 0xdc, 0x6a, 0x23, 0xf0, 0x53, 0x1b, 0x29, 0xb7, 0xdb, 0x48, 0xb9,
- 0xd3, 0x46, 0xe0, 0x7e, 0x1b, 0x81, 0x07, 0x6d, 0x04, 0xae, 0xbc, 0x63, 0x31, 0x5d, 0x54, 0x89,
- 0xa8, 0x52, 0xc7, 0xe2, 0x7a, 0xf4, 0x89, 0x66, 0x0c, 0x7f, 0x00, 0xba, 0x35, 0xcb, 0x10, 0xc2,
- 0x71, 0x4b, 0xa5, 0x09, 0x39, 0x83, 0xf3, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x46, 0x93, 0x3e,
- 0x61, 0x6a, 0x0b, 0x00, 0x00,
+ golang_proto.RegisterFile("lorawan-stack/api/applicationserver.proto", fileDescriptor_applicationserver_2b21ee51f35bd800)
+}
+
+var fileDescriptor_applicationserver_2b21ee51f35bd800 = []byte{
+ // 1173 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0x4d, 0x6c, 0x1b, 0xc5,
+ 0x17, 0xdf, 0x71, 0xdc, 0x7c, 0x4c, 0xfe, 0xff, 0xb4, 0x9d, 0x46, 0x25, 0x31, 0x30, 0x8e, 0xb6,
+ 0x50, 0x25, 0x51, 0xb3, 0x8b, 0xdc, 0xaa, 0x42, 0x45, 0x80, 0x1c, 0xf2, 0xa1, 0xd0, 0x44, 0x04,
+ 0xbb, 0x15, 0x50, 0x84, 0xac, 0xb1, 0x77, 0xec, 0x8c, 0x6c, 0xef, 0x2e, 0x3b, 0xb3, 0x31, 0x56,
+ 0xa9, 0x54, 0x71, 0xea, 0xb1, 0x02, 0x55, 0xea, 0x11, 0x71, 0xaa, 0xc4, 0xa5, 0x2a, 0x42, 0xf4,
+ 0xd8, 0x63, 0x44, 0x2f, 0x41, 0x5c, 0x7a, 0x4a, 0xea, 0x35, 0x87, 0x1e, 0x7b, 0x42, 0x15, 0x12,
+ 0x12, 0xda, 0xd9, 0xf5, 0x47, 0xec, 0x7c, 0x38, 0xa5, 0x2a, 0xb7, 0xdd, 0x7d, 0xbf, 0xf7, 0xde,
+ 0xef, 0x37, 0xef, 0xf7, 0xd6, 0x6b, 0x38, 0x55, 0xb2, 0x1c, 0x52, 0x21, 0xe6, 0x0c, 0x17, 0x24,
+ 0x57, 0xd4, 0x89, 0xcd, 0x74, 0x62, 0xdb, 0x25, 0x96, 0x23, 0x82, 0x59, 0x26, 0xa7, 0xce, 0x3a,
+ 0x75, 0x34, 0xdb, 0xb1, 0x84, 0x85, 0x46, 0x84, 0x30, 0xb5, 0x10, 0xae, 0xad, 0x9f, 0x8d, 0xcd,
+ 0x14, 0x98, 0x58, 0x73, 0xb3, 0x5a, 0xce, 0x2a, 0xeb, 0x05, 0xab, 0x60, 0xe9, 0x12, 0x96, 0x75,
+ 0xf3, 0xf2, 0x4e, 0xde, 0xc8, 0xab, 0x20, 0x3d, 0x76, 0xbe, 0x0d, 0x5e, 0xae, 0x30, 0x51, 0xb4,
+ 0x2a, 0x7a, 0xc1, 0x9a, 0x91, 0xc1, 0x99, 0x75, 0x52, 0x62, 0x06, 0x11, 0x96, 0xc3, 0xf5, 0xe6,
+ 0x65, 0x98, 0xf7, 0x5a, 0xc1, 0xb2, 0x0a, 0x25, 0x1a, 0x50, 0x33, 0x4d, 0x4b, 0x04, 0xcc, 0xc2,
+ 0xe8, 0xab, 0x61, 0xb4, 0xd9, 0x9b, 0x96, 0x6d, 0x51, 0x0d, 0x83, 0x13, 0x9d, 0xc1, 0x3c, 0xa3,
+ 0x25, 0x23, 0x53, 0x26, 0xbc, 0x18, 0x22, 0xe2, 0x9d, 0x08, 0xc1, 0xca, 0x94, 0x0b, 0x52, 0xb6,
+ 0x43, 0x80, 0xda, 0x7d, 0x3e, 0xd4, 0x34, 0x32, 0x06, 0x5d, 0x67, 0x39, 0x1a, 0x62, 0x4e, 0x75,
+ 0x63, 0x98, 0x41, 0x4d, 0xc1, 0xf2, 0x8c, 0x3a, 0x0d, 0xa2, 0x13, 0xdd, 0xa0, 0x32, 0xe5, 0x9c,
+ 0x14, 0x68, 0x88, 0x50, 0x1f, 0x02, 0x78, 0x34, 0xd9, 0x3a, 0xfb, 0x65, 0x66, 0x16, 0xd1, 0x39,
+ 0x78, 0xd2, 0xa4, 0xa2, 0x62, 0x39, 0xc5, 0x4c, 0x30, 0x8b, 0x0c, 0x31, 0x0c, 0x87, 0x72, 0x3e,
+ 0x06, 0x26, 0xc0, 0xe4, 0x50, 0x6a, 0x34, 0x8c, 0xa6, 0x65, 0x30, 0x19, 0xc4, 0xd0, 0x14, 0x1c,
+ 0x20, 0x36, 0xcb, 0x14, 0x69, 0x75, 0x2c, 0xe2, 0xc3, 0x66, 0x8f, 0x79, 0x5b, 0xf1, 0xfe, 0xe4,
+ 0xea, 0xd2, 0x45, 0x5a, 0xf5, 0xb6, 0xe3, 0x91, 0x4f, 0x41, 0xaa, 0x9f, 0xd8, 0xec, 0x22, 0xad,
+ 0xa2, 0x4f, 0x20, 0x32, 0x68, 0x9e, 0xb8, 0x25, 0x91, 0xc9, 0x5b, 0x4e, 0x99, 0x08, 0x41, 0x1d,
+ 0x3e, 0xd6, 0x37, 0x01, 0x26, 0x87, 0x13, 0x93, 0xda, 0xce, 0x89, 0x6b, 0x2b, 0x01, 0xe1, 0x55,
+ 0x52, 0x2d, 0x59, 0xc4, 0x58, 0x68, 0xe2, 0x53, 0xc7, 0xc3, 0x1a, 0xad, 0x47, 0xea, 0x2f, 0x00,
+ 0x8e, 0x2f, 0x52, 0xd1, 0x21, 0x28, 0x45, 0xbf, 0x74, 0x29, 0x17, 0xe8, 0x33, 0x78, 0xb4, 0xcd,
+ 0x66, 0x19, 0x66, 0x04, 0x82, 0x86, 0x13, 0xa7, 0x3b, 0x7b, 0xb6, 0x15, 0x58, 0x6a, 0x1d, 0xea,
+ 0xec, 0xe0, 0xc6, 0x56, 0x5c, 0xd9, 0xdc, 0x8a, 0x83, 0xd4, 0x08, 0x69, 0x47, 0x70, 0xf4, 0x3e,
+ 0x84, 0xad, 0x31, 0x4b, 0xfd, 0xc3, 0x89, 0x98, 0x16, 0xcc, 0x59, 0x6b, 0xcc, 0x59, 0x5b, 0xf0,
+ 0x21, 0x2b, 0x84, 0x17, 0x67, 0xa3, 0x7e, 0xa5, 0xd4, 0x50, 0xbe, 0xf1, 0x40, 0xfd, 0x13, 0xc0,
+ 0xf1, 0xf4, 0x7f, 0xc1, 0xfc, 0x5d, 0x18, 0x2d, 0x31, 0xb3, 0xc1, 0x39, 0xbe, 0x4f, 0x3d, 0x9f,
+ 0x50, 0x5b, 0x21, 0x99, 0xd6, 0x21, 0xbc, 0xef, 0xf0, 0xc2, 0xff, 0x8e, 0xc0, 0xd1, 0x8e, 0x26,
+ 0x69, 0x41, 0x84, 0x4f, 0x6c, 0xc8, 0xef, 0x40, 0x8d, 0x0c, 0x11, 0xa1, 0xda, 0xee, 0xc2, 0x97,
+ 0x1a, 0x9b, 0x33, 0x1b, 0xbd, 0xb9, 0x1d, 0x07, 0xa9, 0xc1, 0x20, 0x25, 0x29, 0xf6, 0x31, 0x71,
+ 0x64, 0x1f, 0x13, 0x7f, 0x04, 0x4f, 0x94, 0x08, 0x17, 0x19, 0xd7, 0xce, 0x38, 0x34, 0x47, 0xd9,
+ 0x7a, 0xd0, 0xbe, 0xaf, 0xc7, 0xf6, 0xc7, 0xfc, 0xe4, 0xcb, 0x76, 0x2a, 0x4c, 0x4d, 0x0a, 0x34,
+ 0x0e, 0x07, 0x5d, 0x3b, 0x93, 0xb3, 0x5c, 0x53, 0x8c, 0x45, 0x27, 0xc0, 0x64, 0x34, 0x35, 0xe0,
+ 0xda, 0x1f, 0xf8, 0xb7, 0xe8, 0x0b, 0x18, 0x93, 0xbd, 0x0c, 0xab, 0x62, 0xfa, 0xb4, 0xfd, 0x5d,
+ 0xa8, 0x10, 0xc7, 0x08, 0x5a, 0x1e, 0xe9, 0xb1, 0xe5, 0x2b, 0x7e, 0x8d, 0xb9, 0xb0, 0xc4, 0x42,
+ 0xa3, 0x42, 0x52, 0xa0, 0x37, 0xe1, 0x48, 0xb3, 0x72, 0xd0, 0xbf, 0x5f, 0xf6, 0xff, 0x7f, 0xe3,
+ 0xa9, 0x64, 0x91, 0xf8, 0x35, 0x0a, 0x23, 0x49, 0x8e, 0x6e, 0x01, 0x38, 0xb0, 0x48, 0x85, 0xdc,
+ 0xff, 0xa9, 0x4e, 0x13, 0xec, 0xb9, 0x52, 0xb1, 0x83, 0xfc, 0xa2, 0xbe, 0xf7, 0xcd, 0xef, 0x7f,
+ 0x7c, 0x17, 0x79, 0x1b, 0x9d, 0xd7, 0x09, 0xdf, 0xf1, 0x92, 0xd7, 0xaf, 0x76, 0x38, 0x5a, 0xdb,
+ 0x79, 0x7f, 0x4d, 0x97, 0xfe, 0xba, 0x0d, 0xe0, 0x40, 0x7a, 0x2f, 0x5e, 0xe9, 0xe7, 0xe7, 0x95,
+ 0x94, 0xbc, 0xde, 0x89, 0x3d, 0x27, 0xaf, 0x0b, 0x60, 0x1a, 0x7d, 0x0d, 0xe1, 0x1c, 0x2d, 0x51,
+ 0x41, 0x25, 0xb9, 0x1e, 0x37, 0x31, 0x76, 0xb2, 0x6b, 0xa2, 0xf3, 0xfe, 0x8f, 0x87, 0xaa, 0x49,
+ 0x42, 0x93, 0xd3, 0xa7, 0x0f, 0x22, 0x14, 0x1e, 0xcc, 0xb7, 0x00, 0xfe, 0x2f, 0x1c, 0x58, 0xb0,
+ 0x2f, 0xbd, 0x12, 0x78, 0xe3, 0x80, 0xa3, 0x91, 0xd5, 0xd4, 0x73, 0x92, 0x8e, 0x86, 0xce, 0xf4,
+ 0x46, 0x47, 0xe7, 0x7e, 0x56, 0xe2, 0xe7, 0x23, 0xf0, 0x48, 0xd2, 0xb6, 0x93, 0x1c, 0x5d, 0x82,
+ 0x43, 0x69, 0x37, 0xcb, 0x73, 0x0e, 0xcb, 0xd2, 0x9e, 0xa9, 0xbd, 0xbe, 0x0f, 0xee, 0xb2, 0xfd,
+ 0x16, 0x40, 0x0f, 0x01, 0x3c, 0xde, 0xf0, 0xfa, 0xc7, 0x2e, 0x75, 0xe9, 0xaa, 0xcb, 0xd7, 0x50,
+ 0x97, 0xa2, 0x1d, 0x90, 0x86, 0x25, 0xf6, 0x3a, 0xf8, 0xaf, 0xa4, 0x52, 0x47, 0x2d, 0x77, 0x2b,
+ 0x6d, 0xfd, 0xe8, 0xee, 0x62, 0x84, 0x6e, 0x63, 0x04, 0xd0, 0xee, 0xbc, 0xe6, 0xe5, 0x35, 0xdd,
+ 0xdf, 0x3d, 0xdd, 0x76, 0xf9, 0x9a, 0x6f, 0xa0, 0xdf, 0x00, 0x1c, 0xed, 0xa0, 0x6a, 0x97, 0x48,
+ 0x8e, 0xfe, 0x4b, 0x41, 0x57, 0xa5, 0x20, 0x57, 0xb5, 0x5f, 0x9a, 0x20, 0x27, 0xe0, 0xed, 0x6b,
+ 0xfa, 0xa9, 0x73, 0x42, 0xcb, 0x8c, 0x8b, 0x6e, 0x41, 0xf3, 0xa6, 0x31, 0x27, 0x8b, 0xf4, 0xea,
+ 0xcc, 0x46, 0x4d, 0xae, 0xa6, 0xa4, 0xbc, 0x65, 0xf4, 0xe1, 0xe1, 0x37, 0xb7, 0xa9, 0xa7, 0x43,
+ 0x40, 0x62, 0x3b, 0x0a, 0x4f, 0x24, 0x79, 0x93, 0x54, 0x8a, 0x16, 0x18, 0x17, 0x4e, 0x15, 0xdd,
+ 0x03, 0xb0, 0x6f, 0x91, 0x0a, 0x74, 0x6a, 0x97, 0x37, 0x62, 0x1b, 0x3a, 0x98, 0xc7, 0xf8, 0x9e,
+ 0x22, 0xd5, 0xa2, 0xe4, 0x4c, 0x51, 0xee, 0x25, 0x8c, 0x04, 0xfd, 0x05, 0x60, 0x5f, 0x7a, 0x37,
+ 0xd2, 0xe9, 0xc3, 0x91, 0xbe, 0x07, 0x24, 0xeb, 0x1f, 0x41, 0xec, 0xf3, 0x6e, 0xda, 0xe1, 0xb7,
+ 0xe8, 0xa1, 0x28, 0xb7, 0xe5, 0xb4, 0xe8, 0x5e, 0x00, 0xd3, 0x57, 0x96, 0xd4, 0xb9, 0x17, 0xd1,
+ 0xc1, 0xf7, 0xdf, 0x2d, 0x00, 0xfb, 0x83, 0xb7, 0x72, 0x8f, 0xa6, 0xdb, 0x6b, 0x8b, 0x56, 0xa4,
+ 0xf8, 0xc5, 0xe9, 0xf9, 0x17, 0x62, 0xb3, 0xd9, 0x1f, 0xc0, 0x46, 0x0d, 0x83, 0xcd, 0x1a, 0x06,
+ 0x8f, 0x6a, 0x58, 0x79, 0x5c, 0xc3, 0xca, 0x93, 0x1a, 0x56, 0x9e, 0xd6, 0xb0, 0xf2, 0xac, 0x86,
+ 0xc1, 0x75, 0x0f, 0x83, 0x1b, 0x1e, 0x56, 0xee, 0x78, 0x18, 0xdc, 0xf5, 0xb0, 0x72, 0xdf, 0xc3,
+ 0xca, 0x03, 0x0f, 0x2b, 0x1b, 0x1e, 0x06, 0x9b, 0x1e, 0x06, 0x8f, 0x3c, 0xac, 0x3c, 0xf6, 0x30,
+ 0x78, 0xe2, 0x61, 0xe5, 0xa9, 0x87, 0xc1, 0x33, 0x0f, 0x2b, 0xd7, 0xeb, 0x58, 0xb9, 0x51, 0xc7,
+ 0xe0, 0x66, 0x1d, 0x2b, 0xb7, 0xeb, 0x18, 0x7c, 0x5f, 0xc7, 0xca, 0x9d, 0x3a, 0x56, 0xee, 0xd6,
+ 0x31, 0xb8, 0x5f, 0xc7, 0xe0, 0x41, 0x1d, 0x83, 0x2b, 0x67, 0x0a, 0x96, 0x26, 0xd6, 0xa8, 0x58,
+ 0x63, 0x66, 0x81, 0x6b, 0xe1, 0x27, 0x8f, 0xbe, 0xf3, 0x5f, 0x81, 0x5d, 0x2c, 0xe8, 0x42, 0x98,
+ 0x76, 0x36, 0xdb, 0x2f, 0xcf, 0xe0, 0xec, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x0b, 0x70,
+ 0xf2, 0xa0, 0x0d, 0x00, 0x00,
}
diff --git a/pkg/ttnpb/applicationserver.pb.gw.go b/pkg/ttnpb/applicationserver.pb.gw.go
index e9fe7d5cdf..e1f2529fd2 100644
--- a/pkg/ttnpb/applicationserver.pb.gw.go
+++ b/pkg/ttnpb/applicationserver.pb.gw.go
@@ -126,6 +126,33 @@ func request_As_DeleteLink_0(ctx context.Context, marshaler runtime.Marshaler, c
}
+func request_As_GetLinkStats_0(ctx context.Context, marshaler runtime.Marshaler, client AsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq ApplicationIdentifiers
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["application_id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "application_id")
+ }
+
+ protoReq.ApplicationID, err = runtime.String(val)
+
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "application_id", err)
+ }
+
+ msg, err := client.GetLinkStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
func request_AppAs_DownlinkQueuePush_0(ctx context.Context, marshaler runtime.Marshaler, client AppAsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DownlinkQueueRequest
var metadata runtime.ServerMetadata
@@ -535,6 +562,26 @@ func RegisterAsHandlerClient(ctx context.Context, mux *runtime.ServeMux, client
})
+ mux.Handle("GET", pattern_As_GetLinkStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_As_GetLinkStats_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_As_GetLinkStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
return nil
}
@@ -544,6 +591,8 @@ var (
pattern_As_SetLink_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"as", "applications", "application_ids.application_id", "link"}, ""))
pattern_As_DeleteLink_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"as", "applications", "application_id", "link"}, ""))
+
+ pattern_As_GetLinkStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"as", "applications", "application_id", "link", "stats"}, ""))
)
var (
@@ -552,6 +601,8 @@ var (
forward_As_SetLink_0 = runtime.ForwardResponseMessage
forward_As_DeleteLink_0 = runtime.ForwardResponseMessage
+
+ forward_As_GetLinkStats_0 = runtime.ForwardResponseMessage
)
// RegisterAppAsHandlerFromEndpoint is same as RegisterAppAsHandler but
diff --git a/pkg/ttnpb/applicationserver.validator.pb.go b/pkg/ttnpb/applicationserver.validator.pb.go
index 218951a64e..abfdca3dbe 100644
--- a/pkg/ttnpb/applicationserver.validator.pb.go
+++ b/pkg/ttnpb/applicationserver.validator.pb.go
@@ -9,6 +9,7 @@ import proto "github.com/gogo/protobuf/proto"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "github.com/golang/protobuf/ptypes/empty"
+import _ "github.com/golang/protobuf/ptypes/timestamp"
import _ "github.com/mwitkow/go-proto-validators"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "google.golang.org/genproto/protobuf/field_mask"
@@ -53,3 +54,21 @@ func (this *SetApplicationLinkRequest) Validate() error {
}
return nil
}
+func (this *ApplicationLinkStats) Validate() error {
+ if this.LinkedAt != nil {
+ if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.LinkedAt); err != nil {
+ return github_com_mwitkow_go_proto_validators.FieldError("LinkedAt", err)
+ }
+ }
+ if this.LastUpReceivedAt != nil {
+ if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.LastUpReceivedAt); err != nil {
+ return github_com_mwitkow_go_proto_validators.FieldError("LastUpReceivedAt", err)
+ }
+ }
+ if this.LastDownlinkForwardedAt != nil {
+ if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.LastDownlinkForwardedAt); err != nil {
+ return github_com_mwitkow_go_proto_validators.FieldError("LastDownlinkForwardedAt", err)
+ }
+ }
+ return nil
+}
diff --git a/pkg/ttnpb/gatewayserver.pb.go b/pkg/ttnpb/gatewayserver.pb.go
index 57770cda74..97500b5cd6 100644
--- a/pkg/ttnpb/gatewayserver.pb.go
+++ b/pkg/ttnpb/gatewayserver.pb.go
@@ -9,6 +9,7 @@ import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import types "github.com/gogo/protobuf/types"
+import _ "google.golang.org/genproto/googleapis/api/annotations"
import time "time"
@@ -51,7 +52,7 @@ type GatewayUp struct {
func (m *GatewayUp) Reset() { *m = GatewayUp{} }
func (*GatewayUp) ProtoMessage() {}
func (*GatewayUp) Descriptor() ([]byte, []int) {
- return fileDescriptor_gatewayserver_9e6408bf5e13ce4c, []int{0}
+ return fileDescriptor_gatewayserver_e68d277882a06166, []int{0}
}
func (m *GatewayUp) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -112,7 +113,7 @@ type GatewayDown struct {
func (m *GatewayDown) Reset() { *m = GatewayDown{} }
func (*GatewayDown) ProtoMessage() {}
func (*GatewayDown) Descriptor() ([]byte, []int) {
- return fileDescriptor_gatewayserver_9e6408bf5e13ce4c, []int{1}
+ return fileDescriptor_gatewayserver_e68d277882a06166, []int{1}
}
func (m *GatewayDown) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -157,7 +158,7 @@ type ScheduleDownlinkResponse struct {
func (m *ScheduleDownlinkResponse) Reset() { *m = ScheduleDownlinkResponse{} }
func (*ScheduleDownlinkResponse) ProtoMessage() {}
func (*ScheduleDownlinkResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_gatewayserver_9e6408bf5e13ce4c, []int{2}
+ return fileDescriptor_gatewayserver_e68d277882a06166, []int{2}
}
func (m *ScheduleDownlinkResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1305,53 +1306,56 @@ var (
)
func init() {
- proto.RegisterFile("lorawan-stack/api/gatewayserver.proto", fileDescriptor_gatewayserver_9e6408bf5e13ce4c)
+ proto.RegisterFile("lorawan-stack/api/gatewayserver.proto", fileDescriptor_gatewayserver_e68d277882a06166)
}
func init() {
- golang_proto.RegisterFile("lorawan-stack/api/gatewayserver.proto", fileDescriptor_gatewayserver_9e6408bf5e13ce4c)
-}
-
-var fileDescriptor_gatewayserver_9e6408bf5e13ce4c = []byte{
- // 643 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x31, 0x4c, 0xdb, 0x4c,
- 0x14, 0xc7, 0xef, 0xe0, 0xe3, 0xd3, 0xf7, 0x1d, 0xfa, 0x80, 0xef, 0xa4, 0x56, 0x21, 0xa8, 0x2f,
- 0x51, 0xaa, 0x56, 0x0c, 0xc5, 0xa9, 0xc2, 0xd4, 0xb1, 0x90, 0xd6, 0xa2, 0x2a, 0x1d, 0x42, 0x33,
- 0xb4, 0x52, 0x85, 0x9c, 0xf8, 0xb8, 0x58, 0x71, 0xee, 0x2c, 0xdf, 0x19, 0xc3, 0xc6, 0xc8, 0xd8,
- 0x91, 0xb1, 0xea, 0x52, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0xa6, 0x16, 0xdb, 0x0b, 0x23, 0x23,
- 0x63, 0x15, 0xc7, 0x11, 0xc4, 0x69, 0xda, 0xcd, 0xef, 0xde, 0xef, 0xfe, 0xef, 0xbd, 0xbf, 0xdf,
- 0x91, 0x27, 0xae, 0xf4, 0xad, 0xd0, 0x12, 0x2b, 0x4a, 0x5b, 0xed, 0x6e, 0xd5, 0xf2, 0x9c, 0x2a,
- 0xb7, 0x34, 0x0b, 0xad, 0x7d, 0xc5, 0xfc, 0x5d, 0xe6, 0x1b, 0x9e, 0x2f, 0xb5, 0xa4, 0x73, 0x5a,
- 0x0b, 0x23, 0x43, 0x8d, 0xdd, 0xd5, 0xe2, 0x0a, 0x77, 0x74, 0x27, 0x68, 0x19, 0x6d, 0xd9, 0xab,
- 0x72, 0xc9, 0x65, 0x35, 0xc5, 0x5a, 0xc1, 0x4e, 0x1a, 0xa5, 0x41, 0xfa, 0x35, 0xb8, 0x5e, 0x04,
- 0x2e, 0x25, 0x77, 0xd9, 0x1d, 0x65, 0x07, 0xbe, 0xa5, 0x1d, 0x29, 0xb2, 0xfc, 0x52, 0x3e, 0xcf,
- 0x7a, 0x9e, 0xde, 0xcf, 0x92, 0xa5, 0x89, 0x2d, 0x66, 0xc0, 0xe3, 0x71, 0xc0, 0xb1, 0x99, 0xd0,
- 0xce, 0x8e, 0xc3, 0x7c, 0x95, 0x41, 0xe5, 0x71, 0xa8, 0xc7, 0x94, 0xb2, 0x38, 0xfb, 0x0d, 0xe1,
- 0x33, 0xee, 0x48, 0x61, 0xb9, 0x03, 0xa2, 0x72, 0x8d, 0xc9, 0xbf, 0xe6, 0xa0, 0x74, 0xd3, 0xa3,
- 0xaf, 0xc9, 0x7c, 0xe0, 0xb9, 0x8e, 0xe8, 0x6e, 0x0f, 0x85, 0x0a, 0xb8, 0x3c, 0xbd, 0x3c, 0x5b,
- 0x7b, 0x64, 0x8c, 0xba, 0x65, 0x34, 0x53, 0x6c, 0x73, 0x40, 0x35, 0xe6, 0x82, 0xfb, 0xa1, 0xa2,
- 0x75, 0x32, 0x97, 0xcd, 0xb3, 0xad, 0xb4, 0xa5, 0x03, 0x55, 0x98, 0x2a, 0xe3, 0x5f, 0xc9, 0x64,
- 0xa5, 0xb7, 0x52, 0xa8, 0xf1, 0x1f, 0xbf, 0x1f, 0xd2, 0x4d, 0xf2, 0xbf, 0xde, 0xdb, 0xb6, 0xda,
- 0x5d, 0x21, 0x43, 0x97, 0xd9, 0xbc, 0xc7, 0x84, 0x2e, 0x4c, 0xa7, 0x42, 0xe5, 0xbc, 0xd0, 0xfb,
- 0xbd, 0x97, 0x23, 0x5c, 0x63, 0x41, 0xe7, 0x4e, 0x2a, 0x1f, 0xc8, 0x6c, 0x56, 0xae, 0x2e, 0x43,
- 0x41, 0xdf, 0x90, 0x05, 0x5b, 0x86, 0xe2, 0xfe, 0xb4, 0x05, 0x9c, 0x8a, 0x97, 0xf2, 0xe2, 0xf5,
- 0x8c, 0x1b, 0x8e, 0x3b, 0x6f, 0x8f, 0x1e, 0x54, 0x9a, 0xa4, 0xb0, 0xd5, 0xee, 0x30, 0x3b, 0x70,
- 0xd9, 0x90, 0x6d, 0x30, 0xe5, 0x49, 0xa1, 0x18, 0x7d, 0x41, 0x66, 0x6c, 0xe6, 0x5a, 0xfb, 0x99,
- 0xf8, 0xa2, 0x31, 0x58, 0x0c, 0x63, 0xb8, 0x18, 0x46, 0x3d, 0x5b, 0x9c, 0xb5, 0x7f, 0xce, 0xbf,
- 0x97, 0xd0, 0xd1, 0x8f, 0x12, 0x6e, 0x0c, 0x6e, 0xd4, 0xbe, 0x61, 0x32, 0x63, 0xea, 0xd0, 0x54,
- 0x74, 0x83, 0xcc, 0xbe, 0x75, 0x44, 0x37, 0xeb, 0x9f, 0x2e, 0x4e, 0xf0, 0xb1, 0xe9, 0x15, 0x97,
- 0x26, 0xa4, 0xfa, 0x7d, 0x2d, 0xe3, 0xe7, 0x98, 0x6e, 0x91, 0x07, 0x26, 0xd3, 0xeb, 0x52, 0xb4,
- 0x99, 0xd0, 0xbe, 0xa5, 0xa5, 0xbf, 0x2e, 0xc5, 0x8e, 0xc3, 0xe9, 0xc3, 0xb1, 0xce, 0x5e, 0xf5,
- 0x57, 0xb6, 0x58, 0xc9, 0x2b, 0x8e, 0xdf, 0xad, 0x31, 0xf2, 0xd7, 0x3b, 0x65, 0x2a, 0xfa, 0x89,
- 0x2c, 0xe4, 0x8d, 0xa0, 0x7f, 0xb2, 0xb3, 0xb8, 0x9c, 0x07, 0x26, 0x79, 0x59, 0xeb, 0x91, 0x29,
- 0x53, 0x51, 0x4e, 0x16, 0x4d, 0xa6, 0xb3, 0xb9, 0xd6, 0xa5, 0x10, 0xac, 0xdd, 0xf7, 0xaf, 0xbf,
- 0x35, 0x8a, 0x56, 0x26, 0xcc, 0xbf, 0x71, 0xf7, 0x7c, 0x8a, 0x4f, 0x27, 0x30, 0x39, 0xad, 0xb5,
- 0xaf, 0xf8, 0x3c, 0x02, 0x7c, 0x11, 0x01, 0xbe, 0x8c, 0x00, 0x5d, 0x45, 0x80, 0xae, 0x23, 0x40,
- 0x37, 0x11, 0xa0, 0xdb, 0x08, 0xf0, 0x41, 0x0c, 0xf8, 0x30, 0x06, 0x74, 0x1c, 0x03, 0x3e, 0x89,
- 0x01, 0x9d, 0xc6, 0x80, 0xce, 0x62, 0x40, 0xe7, 0x31, 0xe0, 0x8b, 0x18, 0xf0, 0x65, 0x0c, 0xe8,
- 0x2a, 0x06, 0x7c, 0x1d, 0x03, 0xba, 0x89, 0x01, 0xdf, 0xc6, 0x80, 0x0e, 0x12, 0x40, 0x87, 0x09,
- 0xe0, 0xcf, 0x09, 0xa0, 0xa3, 0x04, 0xf0, 0x97, 0x04, 0xd0, 0x71, 0x02, 0xe8, 0x24, 0x01, 0x7c,
- 0x9a, 0x00, 0x3e, 0x4b, 0x00, 0x7f, 0x7c, 0xc6, 0xa5, 0xa1, 0x3b, 0x4c, 0x77, 0x1c, 0xc1, 0x95,
- 0x21, 0x98, 0x0e, 0xa5, 0xdf, 0xad, 0x8e, 0x3e, 0x65, 0xaf, 0xcb, 0xab, 0x5a, 0x0b, 0xaf, 0xd5,
- 0xfa, 0x3b, 0xfd, 0x5d, 0xab, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xed, 0xf4, 0x48, 0xbd, 0xf7,
- 0x04, 0x00, 0x00,
+ golang_proto.RegisterFile("lorawan-stack/api/gatewayserver.proto", fileDescriptor_gatewayserver_e68d277882a06166)
+}
+
+var fileDescriptor_gatewayserver_e68d277882a06166 = []byte{
+ // 695 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0x41, 0x4c, 0x13, 0x4d,
+ 0x14, 0xc7, 0x67, 0xe0, 0xe3, 0xcb, 0xf7, 0x0d, 0xf9, 0x80, 0x6f, 0x12, 0x4d, 0x29, 0xfa, 0xda,
+ 0xd4, 0x68, 0x88, 0x81, 0x5d, 0x53, 0x4e, 0x1e, 0x85, 0x6a, 0x83, 0x11, 0x0f, 0xc5, 0x1e, 0x34,
+ 0x31, 0x64, 0xdb, 0x1d, 0xa6, 0x9b, 0xb6, 0x33, 0x9b, 0x9d, 0x29, 0x85, 0x18, 0x13, 0xe2, 0x89,
+ 0xa3, 0x89, 0x17, 0x12, 0x2f, 0x86, 0x8b, 0x1c, 0x39, 0x72, 0xe4, 0xc8, 0x91, 0xc4, 0x0b, 0x27,
+ 0x65, 0x77, 0x3d, 0x70, 0xe4, 0xc8, 0xd1, 0x74, 0xbb, 0x45, 0xba, 0xb5, 0x7a, 0xeb, 0x9b, 0xf7,
+ 0x7b, 0xff, 0x79, 0xef, 0xf5, 0xbf, 0x43, 0xee, 0x36, 0xa4, 0x67, 0xb5, 0x2d, 0x31, 0xaf, 0xb4,
+ 0x55, 0xad, 0x9b, 0x96, 0xeb, 0x98, 0xdc, 0xd2, 0xac, 0x6d, 0x6d, 0x29, 0xe6, 0x6d, 0x30, 0xcf,
+ 0x70, 0x3d, 0xa9, 0x25, 0x9d, 0xd0, 0x5a, 0x18, 0x31, 0x6a, 0x6c, 0x2c, 0xa4, 0xe7, 0xb9, 0xa3,
+ 0x6b, 0xad, 0x8a, 0x51, 0x95, 0x4d, 0x93, 0x4b, 0x2e, 0xcd, 0x08, 0xab, 0xb4, 0xd6, 0xa3, 0x28,
+ 0x0a, 0xa2, 0x5f, 0xdd, 0xf2, 0xf4, 0x2d, 0x2e, 0x25, 0x6f, 0xb0, 0x48, 0xde, 0x12, 0x42, 0x6a,
+ 0x4b, 0x3b, 0x52, 0xa8, 0x38, 0x0b, 0x71, 0xf6, 0x4a, 0xc3, 0x6e, 0x79, 0x11, 0x10, 0xe7, 0x67,
+ 0x92, 0x79, 0xd6, 0x74, 0xf5, 0x56, 0x9c, 0xcc, 0x0c, 0x1d, 0x20, 0x06, 0xee, 0x0c, 0x02, 0x8e,
+ 0xcd, 0x84, 0x76, 0xd6, 0x1d, 0xe6, 0xf5, 0x5a, 0xc8, 0x0e, 0x42, 0x4d, 0xa6, 0x94, 0xc5, 0xd9,
+ 0x6f, 0x08, 0x8f, 0x71, 0x47, 0x0a, 0xab, 0xd1, 0x25, 0x72, 0xe7, 0x98, 0xfc, 0x5b, 0xec, 0x5e,
+ 0x5d, 0x76, 0xe9, 0x13, 0x32, 0xd9, 0x72, 0x1b, 0x8e, 0xa8, 0xaf, 0xf5, 0x84, 0x52, 0x38, 0x3b,
+ 0x3a, 0x3b, 0x9e, 0xbf, 0x6d, 0xf4, 0xef, 0xd2, 0x28, 0x47, 0xd8, 0x4a, 0x97, 0x2a, 0x4d, 0xb4,
+ 0xae, 0x87, 0x8a, 0x16, 0xc8, 0x44, 0x3c, 0xcf, 0x9a, 0xd2, 0x96, 0x6e, 0xa9, 0xd4, 0x48, 0x16,
+ 0xff, 0x4a, 0x26, 0xbe, 0x7a, 0x35, 0x82, 0x4a, 0xff, 0xf1, 0xeb, 0x21, 0x5d, 0x21, 0xff, 0xeb,
+ 0xcd, 0x35, 0xab, 0x5a, 0x17, 0xb2, 0xdd, 0x60, 0x36, 0x6f, 0x32, 0xa1, 0x53, 0xa3, 0x91, 0x50,
+ 0x36, 0x29, 0xf4, 0x62, 0xf3, 0x51, 0x1f, 0x57, 0x9a, 0xd2, 0x89, 0x93, 0xdc, 0x4b, 0x32, 0x1e,
+ 0x5f, 0x57, 0x90, 0x6d, 0x41, 0x9f, 0x92, 0x29, 0x5b, 0xb6, 0xc5, 0xf5, 0x69, 0x53, 0x38, 0x12,
+ 0xcf, 0x24, 0xc5, 0x0b, 0x31, 0xd7, 0x1b, 0x77, 0xd2, 0xee, 0x3f, 0xc8, 0x95, 0x49, 0x6a, 0xb5,
+ 0x5a, 0x63, 0x76, 0xab, 0xc1, 0x7a, 0x6c, 0x89, 0x29, 0x57, 0x0a, 0xc5, 0xe8, 0x43, 0x32, 0x66,
+ 0xb3, 0x86, 0xb5, 0x15, 0x8b, 0x4f, 0x1b, 0x5d, 0x63, 0x18, 0x3d, 0x63, 0x18, 0x85, 0xd8, 0x38,
+ 0x8b, 0xff, 0x1c, 0x7f, 0xcd, 0xa0, 0xdd, 0x6f, 0x19, 0x5c, 0xea, 0x56, 0xe4, 0x3f, 0x63, 0x32,
+ 0x56, 0xd4, 0xed, 0xa2, 0xa2, 0xcb, 0x64, 0xfc, 0x99, 0x23, 0xea, 0x71, 0xff, 0x74, 0x7a, 0xc8,
+ 0x1e, 0xcb, 0x6e, 0x7a, 0x66, 0x48, 0xaa, 0xd3, 0xd7, 0x2c, 0x7e, 0x80, 0xe9, 0x2a, 0xb9, 0x51,
+ 0x64, 0x7a, 0x49, 0x8a, 0x2a, 0x13, 0xda, 0xb3, 0xb4, 0xf4, 0x96, 0xa4, 0x58, 0x77, 0x38, 0xbd,
+ 0x39, 0xd0, 0xd9, 0xe3, 0x8e, 0x65, 0xd3, 0xb9, 0xa4, 0xe2, 0x60, 0x6d, 0x9e, 0x91, 0xbf, 0x9e,
+ 0xab, 0xa2, 0xa2, 0xaf, 0xc9, 0x54, 0x72, 0x11, 0xf4, 0x4f, 0xeb, 0x4c, 0xcf, 0x26, 0x81, 0x61,
+ 0xbb, 0xcc, 0xef, 0x61, 0x32, 0x52, 0x54, 0xf4, 0x23, 0x26, 0xd3, 0x45, 0xa6, 0xe3, 0xc9, 0x96,
+ 0xa4, 0x10, 0xac, 0xda, 0xd9, 0x60, 0xc7, 0x37, 0x8a, 0xe6, 0x86, 0x6c, 0x60, 0xf9, 0xe7, 0x07,
+ 0x94, 0xbe, 0x37, 0x84, 0x49, 0x68, 0xe5, 0xf2, 0xef, 0xbe, 0x7c, 0xff, 0x30, 0x32, 0x47, 0xef,
+ 0x9b, 0x5c, 0x5d, 0xbd, 0x31, 0xe6, 0x9b, 0x9e, 0xb9, 0x1d, 0xfb, 0xad, 0x59, 0xbd, 0x2a, 0x31,
+ 0x3b, 0x5e, 0x57, 0x8b, 0x7b, 0xf8, 0xd8, 0x07, 0x7c, 0xe2, 0x03, 0x3e, 0xf5, 0x01, 0x9d, 0xf9,
+ 0x80, 0xce, 0x7d, 0x40, 0x17, 0x3e, 0xa0, 0x4b, 0x1f, 0xf0, 0x76, 0x00, 0x78, 0x27, 0x00, 0xb4,
+ 0x1f, 0x00, 0x3e, 0x08, 0x00, 0x1d, 0x06, 0x80, 0x8e, 0x02, 0x40, 0xc7, 0x01, 0xe0, 0x93, 0x00,
+ 0xf0, 0x69, 0x00, 0xe8, 0x2c, 0x00, 0x7c, 0x1e, 0x00, 0xba, 0x08, 0x00, 0x5f, 0x06, 0x80, 0xb6,
+ 0x43, 0x40, 0x3b, 0x21, 0xe0, 0xf7, 0x21, 0xa0, 0xdd, 0x10, 0xf0, 0xa7, 0x10, 0xd0, 0x7e, 0x08,
+ 0xe8, 0x20, 0x04, 0x7c, 0x18, 0x02, 0x3e, 0x0a, 0x01, 0xbf, 0x9a, 0xe3, 0xd2, 0xd0, 0x35, 0xa6,
+ 0x6b, 0x8e, 0xe0, 0xca, 0x10, 0x4c, 0xb7, 0xa5, 0x57, 0x37, 0xfb, 0x1f, 0x00, 0xb7, 0xce, 0x4d,
+ 0xad, 0x85, 0x5b, 0xa9, 0xfc, 0x1d, 0xfd, 0xc9, 0x0b, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xb7,
+ 0x17, 0x07, 0xbb, 0x4b, 0x05, 0x00, 0x00,
}
diff --git a/pkg/ttnpb/gatewayserver.pb.gw.go b/pkg/ttnpb/gatewayserver.pb.gw.go
new file mode 100644
index 0000000000..bb4f995e8c
--- /dev/null
+++ b/pkg/ttnpb/gatewayserver.pb.gw.go
@@ -0,0 +1,134 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: lorawan-stack/api/gatewayserver.proto
+
+/*
+Package ttnpb is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package ttnpb
+
+import (
+ "io"
+ "net/http"
+
+ "context"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+var (
+ filter_Gs_GetGatewayConnectionStats_0 = &utilities.DoubleArray{Encoding: map[string]int{"gateway_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
+)
+
+func request_Gs_GetGatewayConnectionStats_0(ctx context.Context, marshaler runtime.Marshaler, client GsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq GatewayIdentifiers
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["gateway_id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "gateway_id")
+ }
+
+ protoReq.GatewayID, err = runtime.String(val)
+
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "gateway_id", err)
+ }
+
+ if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Gs_GetGatewayConnectionStats_0); err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.GetGatewayConnectionStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+// RegisterGsHandlerFromEndpoint is same as RegisterGsHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterGsHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+ conn, err := grpc.Dial(endpoint, opts...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ return
+ }
+ go func() {
+ <-ctx.Done()
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ }()
+ }()
+
+ return RegisterGsHandler(ctx, mux, conn)
+}
+
+// RegisterGsHandler registers the http handlers for service Gs to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterGsHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+ return RegisterGsHandlerClient(ctx, mux, NewGsClient(conn))
+}
+
+// RegisterGsHandlerClient registers the http handlers for service Gs
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "GsClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "GsClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "GsClient" to call the correct interceptors.
+func RegisterGsHandlerClient(ctx context.Context, mux *runtime.ServeMux, client GsClient) error {
+
+ mux.Handle("GET", pattern_Gs_GetGatewayConnectionStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_Gs_GetGatewayConnectionStats_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_Gs_GetGatewayConnectionStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+var (
+ pattern_Gs_GetGatewayConnectionStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"gs", "gateways", "gateway_id", "connection", "stats"}, ""))
+)
+
+var (
+ forward_Gs_GetGatewayConnectionStats_0 = runtime.ForwardResponseMessage
+)
diff --git a/pkg/ttnpb/gatewayserver.validator.pb.go b/pkg/ttnpb/gatewayserver.validator.pb.go
index 3cc6aec361..4cec92742a 100644
--- a/pkg/ttnpb/gatewayserver.validator.pb.go
+++ b/pkg/ttnpb/gatewayserver.validator.pb.go
@@ -10,6 +10,7 @@ import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "github.com/golang/protobuf/ptypes/duration"
import _ "github.com/golang/protobuf/ptypes/empty"
+import _ "google.golang.org/genproto/googleapis/api/annotations"
import time "time"