mirror of
https://github.com/ajvpot/meshexplorer.git
synced 2026-06-12 18:24:55 +02:00
02623e5559
- Point the seattle region at the letsmesh broker (wss://mqtt-us-v1.letsmesh.net:443, topic meshcore/SEA) where Seattle traffic now lives. - Fix a pre-existing bug in the path-edge extraction: `path` is a hex string of 1-byte hop prefixes, so use substring(path, 2*i-1, 2) instead of hex(substring(path, i, 1)) (which re-hexed a single hex char and never matched the 2-char repeater prefixes -> path edges were always empty). Seattle now yields path edges again. Verified on a full prod snapshot: the MV-backed "show all neighbors" query drops from ~1.6s / 145M rows / 11.8 GiB to ~1ms / 108 rows / 3.8 KiB. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
export interface RegionConfig {
|
|
name: string;
|
|
friendlyName: string;
|
|
broker: string;
|
|
topics: string[];
|
|
}
|
|
|
|
export const REGIONS: RegionConfig[] = [
|
|
{
|
|
name: "seattle",
|
|
friendlyName: "Seattle (PugetMesh, SalishMesh)",
|
|
broker: "wss://mqtt-us-v1.letsmesh.net:443",
|
|
topics: ["meshcore/SEA"]
|
|
},
|
|
{
|
|
name: "portland",
|
|
friendlyName: "Portland",
|
|
broker: "tcp://mqtt.davekeogh.com:1883",
|
|
topics: ["meshcore/pdx"]
|
|
},
|
|
{
|
|
name: "boston",
|
|
friendlyName: "Boston",
|
|
broker: "tcp://mqtt.davekeogh.com:1883",
|
|
topics: ["meshcore/bos"]
|
|
}
|
|
];
|
|
|
|
export function getRegionConfig(regionName: string): RegionConfig | undefined {
|
|
return REGIONS.find(region => region.name === regionName);
|
|
}
|
|
|
|
export function getRegionNames(): string[] {
|
|
return REGIONS.map(region => region.name);
|
|
}
|
|
|
|
export function getRegionFriendlyNames(): { name: string; friendlyName: string }[] {
|
|
return REGIONS.map(region => ({ name: region.name, friendlyName: region.friendlyName }));
|
|
}
|
|
|
|
/**
|
|
* Detects a region from broker and topic combination
|
|
* @param broker The MQTT broker URL
|
|
* @param topic The MQTT topic
|
|
* @returns The region name or null if no match found
|
|
*/
|
|
export function detectRegionFromBrokerTopic(broker: string | null, topic: string | null): string | null {
|
|
if (!broker || !topic) return null;
|
|
|
|
// Check each region configuration
|
|
for (const region of REGIONS) {
|
|
// Check if this topic/broker combination matches the region
|
|
if (broker === region.broker && region.topics.includes(topic)) {
|
|
return region.name;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Combined region detection that tries MQTT topics first, then advert data
|
|
* @param mqttTopics Array of MQTT topic information
|
|
* @param advertBroker Broker from advert data
|
|
* @param advertTopic Topic from advert data
|
|
* @returns The detected region name or null if no region matches
|
|
*/
|
|
export function detectRegion(mqttTopics: Array<{ topic: string; broker: string }>, advertBroker: string | null, advertTopic: string | null): string | null {
|
|
// First try MQTT topics (more reliable for uplinked nodes)
|
|
for (const mqttTopic of mqttTopics) {
|
|
const region = detectRegionFromBrokerTopic(mqttTopic.broker, mqttTopic.topic);
|
|
if (region) return region;
|
|
}
|
|
|
|
// Fallback to advert data (works for non-uplinked nodes)
|
|
return detectRegionFromBrokerTopic(advertBroker, advertTopic);
|
|
}
|
|
|
|
/**
|
|
* Generates a broker/topic condition string for a region
|
|
* @param regionName The region name
|
|
* @param alias Optional table alias for the query
|
|
* @returns The condition string or empty string if region not found
|
|
*/
|
|
export function generateRegionCondition(regionName: string, alias: string = ''): string {
|
|
const regionConfig = getRegionConfig(regionName);
|
|
if (!regionConfig) return '';
|
|
|
|
const prefix = alias ? `${alias}.` : '';
|
|
const topicConditions = regionConfig.topics.map(topic => `${prefix}topic = '${topic}'`);
|
|
const topicClause = topicConditions.length > 1 ? `(${topicConditions.join(' OR ')})` : topicConditions[0];
|
|
|
|
return `${prefix}broker = '${regionConfig.broker}' AND ${topicClause}`;
|
|
}
|
|
|
|
/**
|
|
* Generates an array condition string for a region (for origin_path_info fields)
|
|
* @param regionName The region name
|
|
* @returns The array condition string or empty string if region not found
|
|
*/
|
|
export function generateRegionArrayCondition(regionName: string): string {
|
|
const regionConfig = getRegionConfig(regionName);
|
|
if (!regionConfig) return '';
|
|
|
|
const topicConditions = regionConfig.topics.map(topic => `x.5 = '${topic}'`);
|
|
const topicClause = topicConditions.length > 1 ? `(${topicConditions.join(' OR ')})` : topicConditions[0];
|
|
|
|
return `arrayExists(x -> x.4 = '${regionConfig.broker}' AND ${topicClause}, origin_path_info)`;
|
|
}
|
|
|