feat(mesh): show federated Archipelago nodes on the Mesh Map
Peers that opt in via a new "Share Location" toggle in Settings (server.set-location RPC) get plotted on other trusted peers' Mesh Map with a distinct Archy-logo marker, separate from raw LoRa radio peers. Location is persisted locally, carried in NodeStateSnapshot, and propagated through federation sync/delta like other node state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e3baaa5de3
commit
177b8a4338
@@ -179,6 +179,19 @@ export interface NodePosition {
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
/// An Archipelago node (federation peer), not a raw LoRa radio peer — shown
|
||||
/// on the Mesh Map with its own marker (the Archy logo) since it's a whole
|
||||
/// server, not a mesh-radio contact. Only ones that opted into
|
||||
/// server.set-location's `share` flag ever carry a lat/lon.
|
||||
export interface FederatedNodePosition {
|
||||
did: string
|
||||
lat: number
|
||||
lng: number
|
||||
name: string | null
|
||||
onion: string
|
||||
trusted: boolean
|
||||
}
|
||||
|
||||
export const useMeshStore = defineStore('mesh', () => {
|
||||
const status = ref<MeshStatus | null>(null)
|
||||
const peers = ref<MeshPeer[]>([])
|
||||
@@ -192,6 +205,10 @@ export const useMeshStore = defineStore('mesh', () => {
|
||||
|
||||
// Node position tracking for map view (contact_id -> position)
|
||||
const nodePositions = ref<Map<number, NodePosition>>(new Map())
|
||||
// Federated Archipelago nodes with a shared location (DID -> position) —
|
||||
// separate from nodePositions since these are whole servers, not radio
|
||||
// peers, and render with a different marker on the Mesh Map.
|
||||
const federatedPositions = ref<Map<string, FederatedNodePosition>>(new Map())
|
||||
|
||||
// Track unread message counts per peer (contact_id -> count)
|
||||
const unreadCounts = ref<Record<number, number>>({})
|
||||
@@ -340,6 +357,33 @@ export const useMeshStore = defineStore('mesh', () => {
|
||||
})
|
||||
}
|
||||
|
||||
// Federation nodes that opted into sharing their location (server.set-location
|
||||
// `share: true`) — fed by Mesh.vue's existing federation.list-nodes poll.
|
||||
function updateFederatedPositions(nodes: Array<{
|
||||
did: string
|
||||
name?: string | null
|
||||
onion: string
|
||||
trust_level: string
|
||||
last_state?: { lat?: number | null; lon?: number | null } | null
|
||||
}>) {
|
||||
const next = new Map<string, FederatedNodePosition>()
|
||||
for (const n of nodes) {
|
||||
const lat = n.last_state?.lat
|
||||
const lon = n.last_state?.lon
|
||||
if (typeof lat === 'number' && typeof lon === 'number') {
|
||||
next.set(n.did, {
|
||||
did: n.did,
|
||||
lat,
|
||||
lng: lon,
|
||||
name: n.name ?? null,
|
||||
onion: n.onion,
|
||||
trusted: n.trust_level === 'trusted',
|
||||
})
|
||||
}
|
||||
}
|
||||
federatedPositions.value = next
|
||||
}
|
||||
|
||||
function markChatRead(contactId: number) {
|
||||
viewingChatId.value = contactId
|
||||
delete unreadCounts.value[contactId]
|
||||
@@ -799,6 +843,8 @@ export const useMeshStore = defineStore('mesh', () => {
|
||||
unreadCounts,
|
||||
totalUnread,
|
||||
nodePositions,
|
||||
federatedPositions,
|
||||
updateFederatedPositions,
|
||||
deadmanStatus,
|
||||
blockHeaders,
|
||||
latestBlockHeight,
|
||||
|
||||
Reference in New Issue
Block a user