mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-26 00:33:38 +00:00
feat: show "Scope: unknown" for transport-scoped messages with no match
GetChannelMessages already returned an empty scope string for transport-eligible packets whose region couldn't be determined (no configured region matched, or matchScope now reports an HMAC collision as unknown), but the UI treated empty scope the same as "not applicable" and rendered nothing — indistinguishable from a plain FLOOD/DIRECT message that never carries a scope at all. Adds route_type to the channel-message payload (both SQLite and in-memory paths, plus the decrypt-candidate and live WS paths) so the frontend can tell "not transport-scoped" (routeType 1/2, no tag) apart from "transport-scoped but unresolved" (routeType 0/3 with empty scope, now shown as "Scope: unknown").
This commit is contained in:
+5
-3
@@ -1863,7 +1863,7 @@ func (db *DB) GetChannelMessages(channelHash string, limit, offset int, region .
|
||||
var obsSQL string
|
||||
if db.isV3 {
|
||||
obsSQL = `SELECT o.id, t.id, t.hash, t.decoded_json, t.first_seen,
|
||||
obs.id, obs.name, o.snr, o.path_json, o.timestamp` + scopeCol + `
|
||||
obs.id, obs.name, o.snr, o.path_json, o.timestamp, t.route_type` + scopeCol + `
|
||||
FROM observations o
|
||||
JOIN transmissions t ON t.id = o.transmission_id
|
||||
LEFT JOIN observers obs ON obs.rowid = o.observer_idx
|
||||
@@ -1871,7 +1871,7 @@ func (db *DB) GetChannelMessages(channelHash string, limit, offset int, region .
|
||||
ORDER BY o.id ASC`
|
||||
} else {
|
||||
obsSQL = `SELECT o.id, t.id, t.hash, t.decoded_json, t.first_seen,
|
||||
o.observer_id, o.observer_name, o.snr, o.path_json, o.timestamp` + scopeCol + `
|
||||
o.observer_id, o.observer_name, o.snr, o.path_json, o.timestamp, t.route_type` + scopeCol + `
|
||||
FROM observations o
|
||||
JOIN transmissions t ON t.id = o.transmission_id
|
||||
WHERE t.id IN (` + strings.Join(idPlaceholders, ",") + `)
|
||||
@@ -1896,8 +1896,9 @@ func (db *DB) GetChannelMessages(channelHash string, limit, offset int, region .
|
||||
var pktHash, dj, fs, obsID, obsName, pathJSON sql.NullString
|
||||
var snr sql.NullFloat64
|
||||
var obsTs sql.NullInt64
|
||||
var routeType sql.NullInt64
|
||||
var scopeName sql.NullString
|
||||
scanArgs := []interface{}{&pktID, &txID, &pktHash, &dj, &fs, &obsID, &obsName, &snr, &pathJSON, &obsTs}
|
||||
scanArgs := []interface{}{&pktID, &txID, &pktHash, &dj, &fs, &obsID, &obsName, &snr, &pathJSON, &obsTs, &routeType}
|
||||
if db.hasScopeName {
|
||||
scanArgs = append(scanArgs, &scopeName)
|
||||
}
|
||||
@@ -1953,6 +1954,7 @@ func (db *DB) GetChannelMessages(channelHash string, limit, offset int, region .
|
||||
"hops": hops,
|
||||
"snr": nullFloat(snr),
|
||||
"scope": nullStr(scopeName),
|
||||
"routeType": nullInt(routeType),
|
||||
},
|
||||
Repeats: 1,
|
||||
}
|
||||
|
||||
@@ -5519,6 +5519,7 @@ func (s *PacketStore) GetChannelMessages(channelHash string, limit, offset int,
|
||||
"hops": hops,
|
||||
"snr": snrVal,
|
||||
"scope": strOrNil(tx.ScopeName),
|
||||
"routeType": intPtrOrNil(tx.RouteType),
|
||||
},
|
||||
Repeats: 1,
|
||||
Observers: observers,
|
||||
|
||||
@@ -906,6 +906,7 @@ type ChannelMessageResp struct {
|
||||
Hops int `json:"hops"`
|
||||
SNR interface{} `json:"snr"`
|
||||
Scope interface{} `json:"scope"`
|
||||
RouteType interface{} `json:"routeType"`
|
||||
}
|
||||
|
||||
type ChannelMessagesResponse struct {
|
||||
|
||||
@@ -664,6 +664,7 @@
|
||||
hops: d.path_len || 0, snr: c.packet.snr || null,
|
||||
observers: c.packet.observer_name ? [c.packet.observer_name] : [],
|
||||
scope: c.packet.scope_name || null,
|
||||
routeType: c.packet.route_type ?? null,
|
||||
repeats: 1
|
||||
});
|
||||
continue;
|
||||
@@ -681,6 +682,7 @@
|
||||
hops: 0, snr: c.packet.snr || null,
|
||||
observers: c.packet.observer_name ? [c.packet.observer_name] : [],
|
||||
scope: c.packet.scope_name || null,
|
||||
routeType: c.packet.route_type ?? null,
|
||||
repeats: 1
|
||||
});
|
||||
} else {
|
||||
@@ -1420,6 +1422,7 @@
|
||||
var snr = m.data?.snr ?? m.data?.packet?.snr ?? payload.SNR ?? null;
|
||||
var observer = m.data?.packet?.observer_name || m.data?.observer || null;
|
||||
var scope = m.data?.scope_name || m.data?.packet?.scope_name || null;
|
||||
var routeType = m.data?.route_type ?? m.data?.packet?.route_type ?? null;
|
||||
|
||||
// Update channel list entry — only once per unique packet hash
|
||||
var isFirstObservation = pktHash && !seenHashes.has(pktHash + ':' + channelKey);
|
||||
@@ -1472,6 +1475,7 @@
|
||||
hops: payload.path_len || 0,
|
||||
snr: snr,
|
||||
scope: scope,
|
||||
routeType: routeType,
|
||||
// #1498: mark as WS-pushed so a later REST replacement
|
||||
// (selectChannel / refreshMessages) can merge instead of
|
||||
// stomp. Without this flag the REST response wipes any
|
||||
@@ -2262,7 +2266,15 @@
|
||||
if (msg.observers?.length > 1) meta.push(`${msg.observers.length} observers`);
|
||||
if (msg.hops > 0) meta.push(`${msg.hops} hops`);
|
||||
if (msg.snr !== null && msg.snr !== undefined) meta.push(`SNR ${msg.snr}`);
|
||||
// Scope only applies to TRANSPORT_FLOOD(0)/TRANSPORT_DIRECT(3) routes.
|
||||
// Plain FLOOD(1)/DIRECT(2) never carry a scope — show nothing for those.
|
||||
// A transport-eligible message with an empty scope means the region
|
||||
// couldn't be determined (no configured region matched, or an
|
||||
// HMAC collision made the match ambiguous) — show it as unknown
|
||||
// rather than silently omitting the tag.
|
||||
const isTransportRoute = msg.routeType === 0 || msg.routeType === 3;
|
||||
if (msg.scope) meta.push(`Scope: ${escapeHtml(msg.scope)}`);
|
||||
else if (isTransportRoute) meta.push('Scope: unknown');
|
||||
|
||||
const safeId = btoa(encodeURIComponent(sender));
|
||||
// #1367: emit BOTH the new chat-app class names (.ch-message /
|
||||
|
||||
Reference in New Issue
Block a user