Merge remote-tracking branch 'origin/dev' into codex/post20-base-20261002

This commit is contained in:
n30nex
2026-10-02 16:34:31 -04:00
26 changed files with 485 additions and 44 deletions
+1 -1
View File
@@ -457,7 +457,7 @@ func getStatsRadioPresets(reader api.Reader) http.HandlerFunc {
// getStatsScopes godoc
//
// @Summary Scope statistics
// @Description Packets are those heard since the window start, each counted once per hour however many of the requested IATAs heard it. Observers and nodes are current memberships: observers filter by the IATA they last reported from, nodes by their IATA memberships. With filters, lists only manual scopes configured for a matching region and imported scopes whose current MeshMapper catalogue includes a matching IATA; those remain listed with zero counts. An empty region returns an empty array.
// @Description Packets are those heard since the window start, each counted once per hour however many of the requested IATAs heard it. Observers and nodes are current memberships: observers filter by the IATA they last reported from, nodes by their IATA memberships. hourly splits packetCount by UTC hour and adds the distinct observers and advertising nodes active in the scope each hour (empty hours omitted; outage gaps come from /stats/series hour status). With filters, lists only manual scopes configured for a matching region and imported scopes whose current MeshMapper catalogue includes a matching IATA; those remain listed with zero counts. An empty region returns an empty array.
// @Tags Stats
// @Produce json
// @Param iatas query string false "Comma-separated IATA codes"
+1
View File
@@ -43,4 +43,5 @@ type PathHour struct {
Empty int64 `json:"empty"`
Trace int64 `json:"trace"`
Unclassified int64 `json:"unclassified"`
MaxEntries int32 `json:"maxEntries"` // longest path received that hour across the requested IATAs; 0 if only empty paths
}
+13 -4
View File
@@ -92,10 +92,19 @@ type PayloadBreakdownItem struct {
// ScopeStats represents aggregate statistics for a single transport scope.
type ScopeStats struct {
Name string `json:"name"` // normalized scope name e.g. "#bc"
PacketCount int64 `json:"packetCount"` // distinct packets matched to this scope
ObserverCount int64 `json:"observerCount"` // distinct observers that forwarded packets in this scope
NodeCount int64 `json:"nodeCount"` // distinct nodes with this as their default scope
Name string `json:"name"` // normalized scope name e.g. "#bc"
PacketCount int64 `json:"packetCount"` // distinct packets matched to this scope
ObserverCount int64 `json:"observerCount"` // distinct observers that forwarded packets in this scope
NodeCount int64 `json:"nodeCount"` // distinct nodes with this as their default scope
Hourly []ScopeHour `json:"hourly"` // packetCount by hour, oldest first; hours with none omitted
}
// ScopeHour is one UTC hour of a scope's activity; a scope's hours' packets sum to its packetCount.
type ScopeHour struct {
Hour int64 `json:"hour"` // epoch ms, start of the UTC hour
Packets int64 `json:"packets"`
Observers int64 `json:"observers"` // distinct observers that heard the scope's packets that hour
Nodes int64 `json:"nodes"` // distinct nodes whose adverts were heard in the scope that hour
}
// TopNode is a node ranked by how often its adverts were heard in the window.