UptimeFlare/worker/src/store.ts

156 lines
4.6 KiB
TypeScript

import { Env } from '.'
import { IncidentRecord, LatencyRecord, MonitorStateCompacted } from '../../types/config'
export async function getFromStore(env: Env, key: string): Promise<string | null> {
const stmt = env.UPTIMEFLARE_D1.prepare('SELECT value FROM uptimeflare WHERE key = ?')
const result = await stmt.bind(key).first<{ value: string }>()
return result?.value || null
}
export async function setToStore(env: Env, key: string, value: string): Promise<void> {
const stmt = env.UPTIMEFLARE_D1.prepare(
'INSERT INTO uptimeflare (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value;'
)
await stmt.bind(key, value).run()
}
export class CompactedMonitorStateWrapper {
data: MonitorStateCompacted
constructor(compactedStateStr: string | null) {
if (!compactedStateStr) {
// Initialize empty state
this.data = {
lastUpdate: 0,
overallUp: 0,
overallDown: 0,
incident: {},
latency: {},
}
return
}
this.data = JSON.parse(compactedStateStr)
}
getCompactedStateStr(): string {
return JSON.stringify(this.data)
}
incidentLen(monitorId: string): number {
const incidents = this.data.incident[monitorId]
if (!incidents) return 0
return incidents.start.length
}
getIncident(monitorId: string, index: number): IncidentRecord {
const incidents = this.data.incident[monitorId]
if (!incidents || index < 0 || index >= incidents.start.length) {
throw new Error('Index out of bounds or monitor not found')
}
return {
start: incidents.start[index],
end: incidents.end[index],
error: incidents.error[index],
}
}
setIncident(monitorId: string, index: number, incident: IncidentRecord) {
const incidents = this.data.incident[monitorId]
if (!incidents || index < 0 || index >= incidents.start.length) {
throw new Error('Index out of bounds or monitor not found')
}
incidents.start[index] = incident.start
incidents.end[index] = incident.end
incidents.error[index] = incident.error
}
appendIncident(monitorId: string, incident: IncidentRecord) {
let incidents = this.data.incident[monitorId]
if (!incidents) {
// Initialize incident arrays
this.data.incident[monitorId] = {
start: [],
end: [],
error: [],
}
incidents = this.data.incident[monitorId]
}
incidents.start.push(incident.start)
incidents.end.push(incident.end)
incidents.error.push(incident.error)
}
shiftIncident(monitorId: string) {
const incidents = this.data.incident[monitorId]
incidents.start.shift()
incidents.end.shift()
incidents.error.shift()
}
unshiftIncident(monitorId: string, incident: IncidentRecord) {
const incidents = this.data.incident[monitorId]
incidents.start.unshift(incident.start)
incidents.end.unshift(incident.end)
incidents.error.unshift(incident.error)
}
latencyLen(monitorId: string): number {
const latencies = this.data.latency[monitorId]
if (!latencies) return 0
return latencies.ping.length / 4 // Uint16Array, 4 characters per entry in hex
}
appendLatency(monitorId: string, record: LatencyRecord) {
let latencies = this.data.latency[monitorId]
if (!latencies) {
// Initialize latency arrays
this.data.latency[monitorId] = {
time: '',
ping: '',
loc: {
c: [],
v: [],
},
}
latencies = this.data.latency[monitorId]
}
// @ts-expect-error
latencies.time += new Uint8Array(new Uint32Array([record.time]).buffer).toHex()
// @ts-expect-error
latencies.ping += new Uint8Array(new Uint16Array([record.ping]).buffer).toHex()
if (latencies.loc.v[latencies.loc.v.length - 1] !== record.loc) {
latencies.loc.c.push(1)
latencies.loc.v.push(record.loc)
} else {
latencies.loc.c[latencies.loc.c.length - 1] += 1
}
}
getFirstLatency(monitorId: string): LatencyRecord {
let latencies = this.data.latency[monitorId]
return {
// @ts-expect-error
time: new Uint32Array(Uint8Array.fromHex(latencies.time.slice(0, 8)).buffer)[0],
// @ts-expect-error
ping: new Uint16Array(Uint8Array.fromHex(latencies.ping.slice(0, 4)).buffer)[0],
loc: latencies.loc.v[0],
}
}
unshiftLatency(monitorId: string) {
let latencies = this.data.latency[monitorId]
latencies.time = latencies.time.slice(8)
latencies.ping = latencies.ping.slice(4)
latencies.loc.c[0] -= 1
if (latencies.loc.c[0] === 0) {
latencies.loc.c.shift()
latencies.loc.v.shift()
}
}
}