fix(api): нормализовать дату сохранённого снимка Internet path

This commit is contained in:
Denozordec committed 2026-10-07 21:26:23 +07:00
1 parent 4d88b97d49
commit 673e5ba444
7 files changed
+276 -8

No files matched your search

+2 -7
View File
@@ -1,5 +1,5 @@
import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
import { readStoredInternetPathPayload } from "../services/internet-path-snapshot.js"
import { mapStoredInternetPathResponse } from "../services/internet-path-snapshot.js"
import { refreshScheduler } from "../services/scheduler.js"
import {
getInternetPathSettings,
@@ -48,16 +48,11 @@ const internetPathRoutes: FastifyPluginAsyncZod = async (app) => {
app.get("/internet-path/latest", async (_req, reply) => {
const row = await getLatestInternetPathSnapshot()
if (!row) return reply.send({ snapshot: null })
let payload: object
try {
payload = readStoredInternetPathPayload(row.payloadJson)
return reply.send(mapStoredInternetPathResponse(row))
} catch {
return reply.code(502).send({error: "Сохранённый снимок Internet path повреждён"})
}
return reply.send({
snapshot: payload,
sampledAt: row.sampledAt,
})
})
}
@@ -1,5 +1,5 @@
import assert from "node:assert/strict"
import {collectConfirmedInternetPath, readInternetPathRows, readStoredInternetPathPayload} from "./internet-path-snapshot.js"
import {collectConfirmedInternetPath, readInternetPathRows, readStoredInternetPathPayload, mapStoredInternetPathResponse} from "./internet-path-snapshot.js"
const servers=[{id:1,type:"home-router",enabled:true},{id:2,type:"home-router",enabled:false},{id:3,type:"exit-node",enabled:true}]
const sampledAt="2026-10-04T00:00:00Z"
const defaults={servers:async()=>servers,gre:async()=>[],filters:async()=>[],speed:async()=>[],route:async(id:number)=>{assert.equal(id,1);return {gateway:null,routingMark:null}},wan:async(id:number)=>{assert.equal(id,1);return {defaultGateway:null,defaultInterface:null,uplinks:[]}}}
@@ -26,3 +26,12 @@ for(const [fields,row] of [[ ["dst-address"],{"message":"denied"} ],[["interface
assert.deepEqual(readInternetPathRows([],"routes",["dst-address"]),[])
assert.equal(readInternetPathRows([{ "dst-address":"0.0.0.0/0",active:"true" }],"routes",["dst-address"]).length,1)
assert.equal(readInternetPathRows([{ ".id":"*1",name:"gre", "local-address":"0.0.0.0","remote-address":"192.0.2.2" }],"gre",[".id","name","local-address","remote-address"]).length,1)
for (const stored of ["2026-10-04 07:00:00+07", "2026-10-04T00:00:00Z"]) {
const response=mapStoredInternetPathResponse({payloadJson:good,sampledAt:stored})
assert.equal(response.sampledAt,"2026-10-04T00:00:00.000Z")
assert.deepEqual(response.snapshot,good)
}
for (const invalid of ["", "bad", null]) assert.throws(()=>mapStoredInternetPathResponse({payloadJson:good,sampledAt:invalid as string}))
assert.throws(()=>mapStoredInternetPathResponse({payloadJson:"bad",sampledAt}))
console.log("internet path HTTP timestamp: PostgreSQL/ISO instant preserved; invalid metadata rejected")
@@ -30,3 +30,9 @@ export function readStoredInternetPathPayload(raw: unknown): object {
if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new Error("Сохранённый снимок Internet path повреждён")
return payload
}
/** PostgreSQL string-mode timestamps must be normalized at the HTTP boundary. */
export function mapStoredInternetPathResponse(row: { payloadJson: unknown; sampledAt: string }) {
if (typeof row.sampledAt !== "string" || !row.sampledAt.trim()) throw new Error("Сохранённая дата Internet path повреждена")
return { snapshot: readStoredInternetPathPayload(row.payloadJson), sampledAt: new Date(row.sampledAt).toISOString() }
}