mirror of
https://github.com/ajvpot/meshexplorer.git
synced 2026-07-06 17:50:58 +02:00
7528eac3a2
* Derive more neighbor edges: hash-size-aware paths, anchors, confidence tiers Rework the meshcore_all_neighbor_edges materialized view (migration 008) so the map's "show all neighbors" layer surfaces many more, and higher-quality, edges: - Parse routing paths at the packet's real hash_size (1/2/3 bytes per hop) instead of assuming 1-byte hops, so extended-hash packets are no longer mis-sliced, and wide (2-/3-byte) prefixes resolve uniquely. - Add anchored edges: resolve a hop against a fully-known endpoint (the advert originator or the uploading gateway) when exactly one in-region repeater of the right prefix sits within a plausible LoRa-hop distance. - Tag every edge with a derivation `method` and a `confidence` score, and aggregate undirected edges across observations. Frontend: expose method/confidence on the all-neighbors API and color edges by method / fade by confidence. The old "only MQTT neighbors" checkbox becomes the top notch of a single confidence selector (MQTT-direct only -> high -> standard -> all). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Tighten neighbor edges: 100km anchor cap + region-unique anchor binds Two precision fixes after reviewing cross-metro over-linking: - Cap anchored edges at 100 km (was 206 km). Anchors bind a hop to the single nearby repeater of a prefix, so a wrong bind is indistinguishable from a real hop -> a loose cap admitted ~200 km false links. path-uniq and direct edges (observed consecutive hops / zero-hop adverts) keep the 206 km backstop. - Require a region-unique prefix for anchor binds. Without it, a 1-byte hop whose true (unlocated) forwarder is out of set mis-binds to a coincidental same-prefix repeater that merely happens to be the lone nearby candidate (~22% of 1-byte anchors). Region-uniqueness removes the proximity guess; the 100 km check becomes a sanity confirm. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Demote anchored edges to substandard confidence Anchored edges are geographically inferred (resolve a hop to the region-unique repeater near a known endpoint), not observed consecutive hops, so they are less trustworthy than any path-uniq edge. Re-rank confidence to: direct 1.0 > path-uniq-3b 0.8 > path-uniq-2b 0.6 > anchor 0.45 > path-uniq-1b 0.4. Anchors now fall below the 0.5 "Standard" default (hidden by default, just above the noisy 1-byte tier). Add an "Include anchored (lower confidence)" UI tier at 0.45 so they can be opted into without the 1-byte noise. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Unify neighbor inference: global confidence setting, hover + node page - Move the neighbor-confidence preference from per-map-layer settings to global Settings (ConfigContext); the map all-neighbors layer, map hover, and node page all read it. Default "Standard" (0.5). - Map hover and the node detail page now derive neighbors from the unified graph (meshcore_all_neighbor_edges) via a new getMeshcoreNodeAllEdges + a mode=all option on the node neighbors route/hook, so they match "show all neighbors". - Node page shows direct and inferred neighbors in one list; inferred cards carry an "Inferred · <method>" + confidence indicator instead of direction arrows. - Color map hover lines by derivation method (purple/blue/teal), fade by confidence. - Remove the "Manage Channel Keys" button from the Settings popover (still reachable via the + on the messages page). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Keep neighbor lines when either endpoint is in view Both the server bbox filter (getAllNodeNeighbors) and the client filter (AllNeighborLines) required BOTH endpoints inside the viewport, so any line with one end off-screen vanished when zooming in. Switch both to "either endpoint in view": the server returns an edge if source OR target falls in the bbox, and the client keeps it if either endpoint is a visible node. Each edge carries both endpoints' coordinates, so the off-screen end still draws. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Alex Vanderpot <alex@Alexs-MacBook-Pro-2.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
345 lines
18 KiB
SQL
345 lines
18 KiB
SQL
-- +goose Up
|
|
-- Rework meshcore_all_neighbor_edges to derive far more (and higher-quality) neighbor edges.
|
|
--
|
|
-- The migration-004 path-edge logic had three defects:
|
|
-- 1. It hard-coded 1-byte hops (substring(path, 2*i-1, 2)), so every extended-hash packet
|
|
-- (hash_size 2/3, added in migration 007) was mis-sliced into garbage prefixes.
|
|
-- 2. It kept a 1-byte prefix only if exactly one repeater in the region owned it
|
|
-- (HAVING node_count = 1). With only 256 one-byte buckets and often more repeaters than
|
|
-- that per region, birthday collisions discard most prefixes, and a 1-byte "unique" match
|
|
-- is itself unreliable (it frequently stitches together non-adjacent nodes).
|
|
-- 3. It could not exploit extended hashes, whose 2-/3-byte prefixes (65 536+ buckets) are
|
|
-- almost always unique and resolve to genuinely adjacent nodes.
|
|
--
|
|
-- The new MV derives edges in confidence tiers and tags each with `method`/`confidence` so the
|
|
-- map can filter. All path/anchor tiers read FLOOD packets (route_type 0/1, where the path is
|
|
-- accumulated toward the gateway) over a 7-day window, parse hops at the packet's real hash_size,
|
|
-- and aggregate prefix pairs BEFORE joining (keeps the refresh ~20s, not minutes):
|
|
-- * direct - path_len=0 adverts: gateway heard advertiser at zero hops. (unchanged)
|
|
-- * anchor-origin - advert originator (full key + location) was heard by the first path hop;
|
|
-- resolve that hop to the region-unique repeater of that prefix, confirmed within
|
|
-- 100 km of the originator.
|
|
-- * anchor-gateway- the uploading gateway (full key + location) heard the last path hop;
|
|
-- resolve to the region-unique repeater of that prefix, confirmed within 100 km
|
|
-- of the gateway.
|
|
-- Anchors REQUIRE a region-unique prefix (same basis as path-uniq): without it, a 1-byte hop whose
|
|
-- true (unlocated) forwarder is out of set would mis-bind to a coincidental same-prefix repeater that
|
|
-- merely happens to be the lone nearby candidate. The 100 km check is a sanity confirm, not the
|
|
-- disambiguator.
|
|
-- Geographic caps: anchored edges bind a hop to the single nearby repeater of a prefix, so a wrong
|
|
-- bind is indistinguishable from a real one -> strict 100 km gate. path-uniq and direct edges come
|
|
-- from observed consecutive flood hops / zero-hop adverts, so they keep a looser 206 km backstop.
|
|
-- * path-uniq-3b / -2b / -1b - consecutive path hops resolved by region-wide prefix uniqueness
|
|
-- at the pair's own hash width (3-/2-byte are high quality; 1-byte is the noisy
|
|
-- low-confidence fallback).
|
|
-- Edges are canonicalized undirected and aggregated across all observations (observation_count).
|
|
|
|
DROP VIEW IF EXISTS meshcore_all_neighbor_edges;
|
|
-- +goose StatementBegin
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS meshcore_all_neighbor_edges
|
|
REFRESH EVERY 1 HOUR
|
|
ENGINE = MergeTree
|
|
ORDER BY (region, source_node, target_node)
|
|
AS
|
|
WITH
|
|
node_details AS (
|
|
SELECT
|
|
public_key,
|
|
node_name,
|
|
last_seen,
|
|
ifNull(latitude, 0.) AS lat,
|
|
ifNull(longitude, 0.) AS lon,
|
|
-- (0,0) / missing coords are treated as "no usable location" (avoids edges drawn to null island)
|
|
(has_location AND abs(ifNull(latitude, 0.)) > 0.01 AND abs(ifNull(longitude, 0.)) > 0.01) AS loc_ok
|
|
FROM meshcore_adverts_latest
|
|
),
|
|
-- Repeaters seen in the last 2 days, region derived from their latest topic.
|
|
repeaters AS (
|
|
SELECT
|
|
public_key,
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
ifNull(latitude, 0.) AS lat,
|
|
ifNull(longitude, 0.) AS lon,
|
|
(has_location AND abs(ifNull(latitude, 0.)) > 0.01 AND abs(ifNull(longitude, 0.)) > 0.01) AS loc_ok
|
|
FROM meshcore_adverts_latest
|
|
WHERE is_repeater = 1 AND last_seen >= now() - INTERVAL 2 DAY
|
|
),
|
|
repeaters_loc AS (SELECT * FROM repeaters WHERE loc_ok AND region != ''),
|
|
-- (region, width, prefix) -> representative key, with the count used to assert uniqueness (n = 1)
|
|
-- at each possible hash width (1/2/3 bytes = 2/4/6 hex chars).
|
|
prefix_uniq AS (
|
|
SELECT region, 1 AS w, substring(public_key, 1, 2) AS prefix, any(public_key) AS key, count() AS n
|
|
FROM repeaters WHERE region != '' GROUP BY region, substring(public_key, 1, 2)
|
|
UNION ALL
|
|
SELECT region, 2 AS w, substring(public_key, 1, 4) AS prefix, any(public_key) AS key, count() AS n
|
|
FROM repeaters WHERE region != '' GROUP BY region, substring(public_key, 1, 4)
|
|
UNION ALL
|
|
SELECT region, 3 AS w, substring(public_key, 1, 6) AS prefix, any(public_key) AS key, count() AS n
|
|
FROM repeaters WHERE region != '' GROUP BY region, substring(public_key, 1, 6)
|
|
),
|
|
-- Consecutive hop-prefix pairs across all flood packets, aggregated BEFORE the join. Each hop is
|
|
-- 2*hash_size hex chars; pair i is (hop i, hop i+1). Distinct pairs are few, so this collapses the
|
|
-- ~50M exploded pairs to a small set and keeps the downstream joins cheap.
|
|
path_pair_counts AS (
|
|
SELECT region, hash_size, tupleElement(pair, 1) AS src_prefix, tupleElement(pair, 2) AS dst_prefix, count() AS obs
|
|
FROM (
|
|
SELECT
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
hash_size,
|
|
arrayMap(i -> (substring(path, 2*hash_size*(i-1)+1, 2*hash_size), substring(path, 2*hash_size*i+1, 2*hash_size)), range(1, hop_count)) AS pairs
|
|
FROM meshcore_packets
|
|
WHERE ingest_timestamp >= now() - INTERVAL 7 DAY
|
|
AND hash_size_code != 3 AND hash_size != 0 AND route_type IN (0, 1) AND hop_count >= 2
|
|
) ARRAY JOIN pairs AS pair
|
|
WHERE region != '' AND tupleElement(pair, 1) != tupleElement(pair, 2)
|
|
GROUP BY region, hash_size, src_prefix, dst_prefix
|
|
),
|
|
edges_path_uniq AS (
|
|
SELECT ppc.region AS region, su.key AS source_node, du.key AS target_node,
|
|
multiIf(ppc.hash_size >= 3, 'path-uniq-3b', ppc.hash_size = 2, 'path-uniq-2b', 'path-uniq-1b') AS method,
|
|
ppc.obs AS obs
|
|
FROM path_pair_counts ppc
|
|
INNER JOIN prefix_uniq su ON su.region = ppc.region AND su.w = ppc.hash_size AND su.prefix = ppc.src_prefix AND su.n = 1
|
|
INNER JOIN prefix_uniq du ON du.region = ppc.region AND du.w = ppc.hash_size AND du.prefix = ppc.dst_prefix AND du.n = 1
|
|
),
|
|
-- anchor-gateway: the uploading gateway (full key) heard the last hop. Aggregate (gateway, last_prefix)
|
|
-- first, then accept iff exactly one in-region repeater with that prefix is within 150 km of the gateway.
|
|
last_hop_counts AS (
|
|
SELECT region, hash_size, gateway_key, last_prefix, count() AS obs
|
|
FROM (
|
|
SELECT
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
hash_size, hex(origin_pubkey) AS gateway_key,
|
|
substring(path, 2*hash_size*(hop_count-1)+1, 2*hash_size) AS last_prefix
|
|
FROM meshcore_packets
|
|
WHERE ingest_timestamp >= now() - INTERVAL 7 DAY
|
|
AND hash_size_code != 3 AND hash_size != 0 AND route_type IN (0, 1) AND hop_count >= 1
|
|
)
|
|
WHERE region != ''
|
|
GROUP BY region, hash_size, gateway_key, last_prefix
|
|
),
|
|
edges_anchor_gw AS (
|
|
SELECT lhc.region AS region, lhc.gateway_key AS source_node, any(R.public_key) AS target_node,
|
|
'anchor-gateway' AS method, any(lhc.obs) AS obs
|
|
FROM last_hop_counts lhc
|
|
INNER JOIN prefix_uniq pu ON pu.region = lhc.region AND pu.w = lhc.hash_size AND pu.prefix = lhc.last_prefix AND pu.n = 1
|
|
INNER JOIN node_details g ON g.public_key = lhc.gateway_key AND g.loc_ok
|
|
INNER JOIN repeaters_loc R ON R.region = lhc.region AND substring(R.public_key, 1, 2*lhc.hash_size) = lhc.last_prefix
|
|
AND R.public_key != lhc.gateway_key AND greatCircleDistance(R.lon, R.lat, g.lon, g.lat) <= 100000
|
|
GROUP BY lhc.region, lhc.gateway_key, lhc.hash_size, lhc.last_prefix
|
|
HAVING count() = 1
|
|
),
|
|
-- anchor-origin: an advert's originator (full key from the payload) was heard by the first hop.
|
|
advert_first_counts AS (
|
|
SELECT region, hash_size, origin_key, first_prefix, count() AS obs
|
|
FROM (
|
|
SELECT
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
hash_size, hex(substring(payload, 1, 32)) AS origin_key, substring(path, 1, 2*hash_size) AS first_prefix
|
|
FROM meshcore_packets
|
|
WHERE payload_type = 4 AND ingest_timestamp >= now() - INTERVAL 7 DAY
|
|
AND hash_size_code != 3 AND hash_size != 0 AND route_type IN (0, 1) AND hop_count >= 1
|
|
)
|
|
WHERE region != ''
|
|
GROUP BY region, hash_size, origin_key, first_prefix
|
|
),
|
|
edges_anchor_origin AS (
|
|
SELECT afc.region AS region, afc.origin_key AS source_node, any(R.public_key) AS target_node,
|
|
'anchor-origin' AS method, any(afc.obs) AS obs
|
|
FROM advert_first_counts afc
|
|
INNER JOIN prefix_uniq pu ON pu.region = afc.region AND pu.w = afc.hash_size AND pu.prefix = afc.first_prefix AND pu.n = 1
|
|
INNER JOIN node_details o ON o.public_key = afc.origin_key AND o.loc_ok
|
|
INNER JOIN repeaters_loc R ON R.region = afc.region AND substring(R.public_key, 1, 2*afc.hash_size) = afc.first_prefix
|
|
AND R.public_key != afc.origin_key AND greatCircleDistance(R.lon, R.lat, o.lon, o.lat) <= 100000
|
|
GROUP BY afc.region, afc.origin_key, afc.hash_size, afc.first_prefix
|
|
HAVING count() = 1
|
|
),
|
|
-- Direct connections (path_len = 0 adverts): gateway heard the advertiser with no intermediate hops.
|
|
direct_connections AS (
|
|
SELECT
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
hex(origin_pubkey) AS source_node, public_key AS target_node, count() AS obs
|
|
FROM meshcore_adverts
|
|
WHERE path_len = 0 AND hex(origin_pubkey) != public_key AND ingest_timestamp >= now() - INTERVAL 7 DAY
|
|
GROUP BY region, source_node, target_node
|
|
),
|
|
all_edges AS (
|
|
SELECT region, source_node, target_node, method, obs,
|
|
-- rank orders confidence (lower=better). Anchors are demoted BELOW the path-uniq tiers
|
|
-- (substandard, just above the noisy 1-byte tier): an anchor bind is inferred geographically,
|
|
-- not an observed consecutive hop, so it's less trustworthy than any path-uniq edge.
|
|
multiIf(method = 'direct', 0, method = 'path-uniq-3b', 1, method = 'path-uniq-2b', 2, method LIKE 'anchor-%', 3, 4) AS rank
|
|
FROM (
|
|
SELECT region, source_node, target_node, method, obs FROM edges_path_uniq
|
|
UNION ALL SELECT region, source_node, target_node, method, obs FROM edges_anchor_gw
|
|
UNION ALL SELECT region, source_node, target_node, method, obs FROM edges_anchor_origin
|
|
UNION ALL SELECT region, source_node, target_node, 'direct' AS method, obs FROM direct_connections
|
|
)
|
|
),
|
|
-- Canonicalize undirected and merge across methods/observations: best (lowest-rank) method wins.
|
|
edge_consensus AS (
|
|
SELECT region, a AS source_node, b AS target_node,
|
|
argMin(method, rank) AS method, min(rank) AS best_rank, sum(obs) AS observation_count
|
|
FROM (
|
|
SELECT region, method, obs, rank,
|
|
least(source_node, target_node) AS a, greatest(source_node, target_node) AS b
|
|
FROM all_edges
|
|
WHERE source_node != target_node AND source_node != '' AND target_node != '' AND region != ''
|
|
)
|
|
GROUP BY region, a, b
|
|
)
|
|
SELECT
|
|
ec.region AS region,
|
|
ec.source_node AS source_node,
|
|
ec.target_node AS target_node,
|
|
-- back-compat connection_type: only a path_len=0 advert is a literal MQTT-direct edge; anchors
|
|
-- are single-hop but inferred, so they group with 'path'. Fine-grained tier is in `method`.
|
|
if(ec.method = 'direct', 'direct', 'path') AS connection_type,
|
|
ec.method AS method,
|
|
-- tier base: direct 1.0, path-uniq-3b 0.8, path-uniq-2b 0.6, anchor 0.45 (substandard), 1b 0.4,
|
|
-- plus a small capped consensus bonus (<0.05 so anchors stay below the 0.5 default and above 1b).
|
|
least(1.0, greatest(0.0,
|
|
multiIf(ec.best_rank = 0, 1.0, ec.best_rank = 1, 0.8, ec.best_rank = 2, 0.6, ec.best_rank = 3, 0.45, 0.4)
|
|
+ least(0.04, 0.02 * log10(ec.observation_count + 1)))) AS confidence,
|
|
ec.observation_count AS observation_count,
|
|
ec.observation_count AS packet_count,
|
|
sd.node_name AS source_name,
|
|
if(sd.loc_ok, sd.lat, NULL) AS source_latitude,
|
|
if(sd.loc_ok, sd.lon, NULL) AS source_longitude,
|
|
toUInt8(sd.loc_ok) AS source_has_location,
|
|
sd.last_seen AS source_last_seen,
|
|
td.node_name AS target_name,
|
|
if(td.loc_ok, td.lat, NULL) AS target_latitude,
|
|
if(td.loc_ok, td.lon, NULL) AS target_longitude,
|
|
toUInt8(td.loc_ok) AS target_has_location,
|
|
td.last_seen AS target_last_seen
|
|
FROM edge_consensus AS ec
|
|
INNER JOIN node_details AS sd ON ec.source_node = sd.public_key
|
|
INNER JOIN node_details AS td ON ec.target_node = td.public_key
|
|
-- Backstop for path-uniq/direct edges: drop adjacencies between two located nodes beyond 206 km
|
|
-- (not a plausible single hop). Anchored edges are already constrained to 100 km in their joins.
|
|
WHERE NOT (sd.loc_ok AND td.loc_ok AND greatCircleDistance(sd.lon, sd.lat, td.lon, td.lat) > 206000);
|
|
-- +goose StatementEnd
|
|
|
|
SYSTEM REFRESH VIEW meshcore_all_neighbor_edges;
|
|
|
|
|
|
-- +goose Down
|
|
-- Restore the migration-004 neighbor edge graph (1-byte hops, prefix-uniqueness only, no
|
|
-- method/confidence columns).
|
|
DROP VIEW IF EXISTS meshcore_all_neighbor_edges;
|
|
-- +goose StatementBegin
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS meshcore_all_neighbor_edges
|
|
REFRESH EVERY 1 HOUR
|
|
ENGINE = MergeTree
|
|
ORDER BY (region, source_node, target_node)
|
|
AS
|
|
WITH
|
|
node_details AS (
|
|
SELECT
|
|
public_key,
|
|
node_name,
|
|
last_seen,
|
|
ifNull(latitude, 0.) AS lat,
|
|
ifNull(longitude, 0.) AS lon,
|
|
(has_location AND abs(ifNull(latitude, 0.)) > 0.01 AND abs(ifNull(longitude, 0.)) > 0.01) AS loc_ok
|
|
FROM meshcore_adverts_latest
|
|
),
|
|
adverts_latest_r AS (
|
|
SELECT
|
|
public_key,
|
|
is_repeater,
|
|
last_seen,
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region
|
|
FROM meshcore_adverts_latest
|
|
),
|
|
repeater_prefixes AS (
|
|
SELECT
|
|
region,
|
|
substring(public_key, 1, 2) AS prefix,
|
|
count() AS node_count,
|
|
any(public_key) AS representative_key
|
|
FROM adverts_latest_r
|
|
WHERE is_repeater = 1 AND last_seen >= now() - INTERVAL 2 DAY AND region != ''
|
|
GROUP BY region, prefix
|
|
HAVING node_count = 1
|
|
),
|
|
path_src AS (
|
|
SELECT DISTINCT
|
|
payload,
|
|
path,
|
|
path_len,
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region
|
|
FROM meshcore_packets
|
|
WHERE path_len >= 2 AND ingest_timestamp >= now() - INTERVAL 1 DAY
|
|
),
|
|
path_pairs AS (
|
|
SELECT DISTINCT
|
|
region,
|
|
payload,
|
|
upper(substring(path, 2 * i - 1, 2)) AS source_prefix,
|
|
upper(substring(path, 2 * i + 1, 2)) AS target_prefix
|
|
FROM path_src
|
|
ARRAY JOIN range(1, path_len) AS i
|
|
WHERE i < path_len AND region != ''
|
|
),
|
|
path_neighbors AS (
|
|
SELECT region, source_prefix, target_prefix, count() AS packet_count
|
|
FROM path_pairs
|
|
WHERE source_prefix != target_prefix
|
|
GROUP BY region, source_prefix, target_prefix
|
|
),
|
|
path_connections AS (
|
|
SELECT
|
|
pn.region AS region,
|
|
sm.representative_key AS source_node,
|
|
tm.representative_key AS target_node,
|
|
pn.packet_count AS packet_count
|
|
FROM path_neighbors AS pn
|
|
INNER JOIN repeater_prefixes AS sm ON sm.region = pn.region AND sm.prefix = pn.source_prefix
|
|
INNER JOIN repeater_prefixes AS tm ON tm.region = pn.region AND tm.prefix = pn.target_prefix
|
|
),
|
|
direct_connections AS (
|
|
SELECT DISTINCT
|
|
multiIf(lower(topic) IN ('meshcore','meshcore/salish'), 'SEA', match(splitByChar('/', lower(topic))[2], '^[a-z]{3}$'), upper(splitByChar('/', lower(topic))[2]), '') AS region,
|
|
hex(origin_pubkey) AS source_node,
|
|
public_key AS target_node
|
|
FROM meshcore_adverts
|
|
WHERE path_len = 0
|
|
AND hex(origin_pubkey) != public_key
|
|
AND ingest_timestamp >= now() - INTERVAL 7 DAY
|
|
),
|
|
edges AS (
|
|
SELECT region, source_node, target_node, 'path' AS connection_type, packet_count
|
|
FROM path_connections
|
|
UNION ALL
|
|
SELECT d.region, d.source_node, d.target_node, 'direct' AS connection_type, CAST(1 AS UInt64) AS packet_count
|
|
FROM direct_connections AS d
|
|
WHERE d.region != ''
|
|
AND (d.region, d.source_node, d.target_node) NOT IN (SELECT region, source_node, target_node FROM path_connections)
|
|
AND (d.region, d.target_node, d.source_node) NOT IN (SELECT region, source_node, target_node FROM path_connections)
|
|
)
|
|
SELECT
|
|
e.region AS region,
|
|
e.source_node AS source_node,
|
|
e.target_node AS target_node,
|
|
e.connection_type AS connection_type,
|
|
e.packet_count AS packet_count,
|
|
sd.node_name AS source_name,
|
|
if(sd.loc_ok, sd.lat, NULL) AS source_latitude,
|
|
if(sd.loc_ok, sd.lon, NULL) AS source_longitude,
|
|
toUInt8(sd.loc_ok) AS source_has_location,
|
|
sd.last_seen AS source_last_seen,
|
|
td.node_name AS target_name,
|
|
if(td.loc_ok, td.lat, NULL) AS target_latitude,
|
|
if(td.loc_ok, td.lon, NULL) AS target_longitude,
|
|
toUInt8(td.loc_ok) AS target_has_location,
|
|
td.last_seen AS target_last_seen
|
|
FROM edges AS e
|
|
INNER JOIN node_details AS sd ON e.source_node = sd.public_key
|
|
INNER JOIN node_details AS td ON e.target_node = td.public_key
|
|
WHERE NOT (sd.loc_ok AND td.loc_ok AND greatCircleDistance(sd.lon, sd.lat, td.lon, td.lat) > 150000);
|
|
-- +goose StatementEnd
|
|
|
|
SYSTEM REFRESH VIEW meshcore_all_neighbor_edges;
|