mirror of
https://github.com/MeshCore-Beacon/beacon-web.git
synced 2026-10-23 22:42:48 +00:00
Fix issues from the 2.0.0 release review (#137)
This commit is contained in:
1 parent
4b9e48a35a
commit
acf46342a1
100 files changed
+1410
-474
No files matched your search
+13
-7
@@ -183,26 +183,32 @@ export function getScopes(iatas?: string[]): Promise<string[]> {
|
||||
|
||||
// Wrap a bare-array endpoint into a CursorPage so it can drive the cursor-paginated hooks. A page that
|
||||
// fills the limit may have more behind it; the next cursor is the last (boundary) row's sort key.
|
||||
function toCursorPage<T>(items: T[], limit: number, cursorOf: (last: T) => number): CursorPage<T> {
|
||||
function toCursorPage<T, C = number>(items: T[], limit: number, cursorOf: (last: T) => C): CursorPage<T, C> {
|
||||
const hasMore = items.length === limit;
|
||||
return { items, nextCursor: hasMore ? cursorOf(items[items.length - 1]!) : null, hasMore };
|
||||
}
|
||||
|
||||
// Known routes. /routes returns a bare array ordered last_seen DESC; its cursor pages by last_seen (ms),
|
||||
// so the last row carries the page's smallest last_seen — the cursor for the next (older) batch. We wrap
|
||||
// Known routes. /routes returns a bare array ordered last_seen DESC, id DESC; the next (older) batch
|
||||
// starts after the last row's lastSeen (ms), with its id breaking ties inside that millisecond. We wrap
|
||||
// it into a CursorPage here so RouteTable can stream pages via useInfinitePages. `iata` is a single code
|
||||
// ("" = all), unlike the comma-separated `iatas` used elsewhere.
|
||||
export interface RouteCursor {
|
||||
lastSeen: number;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export async function getKnownRoutesPage(
|
||||
params?: { iata?: string; hopCount?: number; cursor?: number; limit?: number },
|
||||
): Promise<CursorPage<KnownRoute>> {
|
||||
params?: { iata?: string; hopCount?: number; cursor?: RouteCursor; limit?: number },
|
||||
): Promise<CursorPage<KnownRoute, RouteCursor>> {
|
||||
const limit = params?.limit ?? DEFAULT_PAGE_SIZE;
|
||||
const items = await request<KnownRoute[]>("/routes", {
|
||||
iata: params?.iata,
|
||||
hopCount: params?.hopCount,
|
||||
cursor: params?.cursor,
|
||||
cursor: params?.cursor?.lastSeen,
|
||||
cursorId: params?.cursor?.id,
|
||||
limit,
|
||||
});
|
||||
return toCursorPage(items, limit, (r) => r.lastSeen);
|
||||
return toCursorPage(items, limit, (r) => ({ lastSeen: r.lastSeen, id: r.id }));
|
||||
}
|
||||
|
||||
export function getRouteEvidence(iata: string, pathKey: string, params: { range?: string; since?: number; until?: number; pageCursor?: string; limit?: number }, signal?: AbortSignal): Promise<RouteEvidence> {
|
||||
|
||||
@@ -39,6 +39,8 @@ export class WsManager {
|
||||
private pingTimer: ReturnType<typeof setInterval> | null = null;
|
||||
private msgCounter = 0;
|
||||
private lastEventTimestamp: number = Date.now();
|
||||
// liveness for the ping check; unlike lastEventTimestamp it restarts with each connection
|
||||
private lastHeardAt: number = Date.now();
|
||||
|
||||
private packetHandlers: PacketHandler[] = [];
|
||||
private laggedHandlers: LaggedHandler[] = [];
|
||||
@@ -190,6 +192,7 @@ export class WsManager {
|
||||
case "hello": {
|
||||
const isReconnect = this.everConnected;
|
||||
this.everConnected = true;
|
||||
this.lastHeardAt = Date.now();
|
||||
this.setStatus("connected");
|
||||
this.startPing();
|
||||
this.sendSubscribe();
|
||||
@@ -219,11 +222,11 @@ export class WsManager {
|
||||
|
||||
case "pong":
|
||||
// a pong proves the link is alive, so it counts as recent activity
|
||||
this.lastEventTimestamp = Date.now();
|
||||
this.lastEventTimestamp = this.lastHeardAt = Date.now();
|
||||
break;
|
||||
|
||||
case "event":
|
||||
this.lastEventTimestamp = Date.now();
|
||||
this.lastEventTimestamp = this.lastHeardAt = Date.now();
|
||||
if (msg.event === "packetObservation") {
|
||||
for (const handler of this.packetHandlers) {
|
||||
handler(msg.data);
|
||||
@@ -245,7 +248,7 @@ export class WsManager {
|
||||
|
||||
case "lagged":
|
||||
// a lag notice is still server traffic, so it counts as recent activity
|
||||
this.lastEventTimestamp = Date.now();
|
||||
this.lastEventTimestamp = this.lastHeardAt = Date.now();
|
||||
for (const handler of this.laggedHandlers) {
|
||||
handler(msg);
|
||||
}
|
||||
@@ -257,6 +260,8 @@ export class WsManager {
|
||||
}
|
||||
|
||||
private sendSubscribe(): void {
|
||||
// any subscribe still awaiting its ack is superseded, even when nothing replaces it
|
||||
this.lastSubscribeId = null;
|
||||
// the server reads an empty IATA list as "all", so a region with no IATAs subscribes to nothing
|
||||
if (!this.filter || this.filter.iatas?.length === 0) return;
|
||||
const id = `sub-${this.nextId()}`;
|
||||
@@ -276,7 +281,7 @@ export class WsManager {
|
||||
private startPing(): void {
|
||||
if (this.pingTimer) clearInterval(this.pingTimer); // a second hello must not double the interval
|
||||
this.pingTimer = setInterval(() => {
|
||||
if (Date.now() - this.lastEventTimestamp > WS_PING_INTERVAL_MS * 2 + 5_000) {
|
||||
if (Date.now() - this.lastHeardAt > WS_PING_INTERVAL_MS * 2 + 5_000) {
|
||||
// pongs stopped coming back — the link is half-open, rebuild it
|
||||
this.forceReconnect();
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user