signalk-wakelogger 0.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/LICENSE +201 -0
- package/README.md +49 -0
- package/SECURITY.md +7 -0
- package/assets/screenshots/plugin-config.png +0 -0
- package/assets/screenshots/plugin-status.png +0 -0
- package/assets/wakelogger.svg +6 -0
- package/dist/config/defaults.d.ts +18 -0
- package/dist/config/defaults.js +30 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/schema.d.ts +43 -0
- package/dist/config/schema.js +47 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +338 -0
- package/dist/index.js.map +1 -0
- package/dist/outbox/database-outbox.d.ts +25 -0
- package/dist/outbox/database-outbox.js +186 -0
- package/dist/outbox/database-outbox.js.map +1 -0
- package/dist/outbox/database-types.d.ts +19 -0
- package/dist/outbox/database-types.js +3 -0
- package/dist/outbox/database-types.js.map +1 -0
- package/dist/outbox/factory.d.ts +12 -0
- package/dist/outbox/factory.js +98 -0
- package/dist/outbox/factory.js.map +1 -0
- package/dist/outbox/file-outbox.d.ts +27 -0
- package/dist/outbox/file-outbox.js +280 -0
- package/dist/outbox/file-outbox.js.map +1 -0
- package/dist/outbox/interface.d.ts +33 -0
- package/dist/outbox/interface.js +3 -0
- package/dist/outbox/interface.js.map +1 -0
- package/dist/pairing/association-client.d.ts +3 -0
- package/dist/pairing/association-client.js +31 -0
- package/dist/pairing/association-client.js.map +1 -0
- package/dist/pairing/credentials.d.ts +46 -0
- package/dist/pairing/credentials.js +168 -0
- package/dist/pairing/credentials.js.map +1 -0
- package/dist/pairing/pairing-client.d.ts +19 -0
- package/dist/pairing/pairing-client.js +102 -0
- package/dist/pairing/pairing-client.js.map +1 -0
- package/dist/signalk/normaliser.d.ts +11 -0
- package/dist/signalk/normaliser.js +119 -0
- package/dist/signalk/normaliser.js.map +1 -0
- package/dist/signalk/paths.d.ts +2 -0
- package/dist/signalk/paths.js +14 -0
- package/dist/signalk/paths.js.map +1 -0
- package/dist/signalk/subscriber.d.ts +2 -0
- package/dist/signalk/subscriber.js +20 -0
- package/dist/signalk/subscriber.js.map +1 -0
- package/dist/telemetry/profile-store.d.ts +7 -0
- package/dist/telemetry/profile-store.js +39 -0
- package/dist/telemetry/profile-store.js.map +1 -0
- package/dist/telemetry/profile.d.ts +32 -0
- package/dist/telemetry/profile.js +94 -0
- package/dist/telemetry/profile.js.map +1 -0
- package/dist/telemetry/sampler.d.ts +14 -0
- package/dist/telemetry/sampler.js +44 -0
- package/dist/telemetry/sampler.js.map +1 -0
- package/dist/telemetry/types.d.ts +73 -0
- package/dist/telemetry/types.js +3 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/transport/adaptive-mode.d.ts +23 -0
- package/dist/transport/adaptive-mode.js +63 -0
- package/dist/transport/adaptive-mode.js.map +1 -0
- package/dist/transport/mqtt-client.d.ts +69 -0
- package/dist/transport/mqtt-client.js +365 -0
- package/dist/transport/mqtt-client.js.map +1 -0
- package/dist/transport/topics.d.ts +10 -0
- package/dist/transport/topics.js +13 -0
- package/dist/transport/topics.js.map +1 -0
- package/dist/trips/state-machine.d.ts +38 -0
- package/dist/trips/state-machine.js +118 -0
- package/dist/trips/state-machine.js.map +1 -0
- package/docs/architecture.md +17 -0
- package/docs/development.md +49 -0
- package/docs/implementation-plan.md +1943 -0
- package/docs/original-plan-gap-audit.md +47 -0
- package/docs/pairing.md +17 -0
- package/docs/release.md +52 -0
- package/docs/telemetry-protocol.md +50 -0
- package/docs/trip-detection.md +7 -0
- package/docs/validation.md +35 -0
- package/package.json +80 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createOutbox = createOutbox;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const database_outbox_1 = require("./database-outbox");
|
|
10
|
+
const file_outbox_1 = require("./file-outbox");
|
|
11
|
+
async function createOutbox(app, dataDirectory, deviceId, options, expectedBackend) {
|
|
12
|
+
const root = node_path_1.default.join(dataDirectory, 'outbox');
|
|
13
|
+
const fileDirectory = node_path_1.default.join(root, deviceId);
|
|
14
|
+
const markerTarget = node_path_1.default.join(root, `${deviceId}.backend.json`);
|
|
15
|
+
const marker = await readMarker(markerTarget);
|
|
16
|
+
if (expectedBackend && marker?.backend !== expectedBackend) {
|
|
17
|
+
throw new Error('The bound outbox backend marker is missing or inconsistent; refusing an unsafe sequence reset');
|
|
18
|
+
}
|
|
19
|
+
let databaseApi;
|
|
20
|
+
try {
|
|
21
|
+
databaseApi = app.getDatabaseApi?.();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (marker?.backend === 'database')
|
|
25
|
+
throw error;
|
|
26
|
+
databaseApi = undefined;
|
|
27
|
+
}
|
|
28
|
+
if (marker?.backend === 'database') {
|
|
29
|
+
if (!databaseApi)
|
|
30
|
+
throw new Error('The selected Signal K Database API outbox is unavailable; refusing an unsafe sequence fallback');
|
|
31
|
+
const store = new database_outbox_1.DatabaseOutbox(await databaseApi.getPluginDb('signalk-wakelogger'), deviceId, options);
|
|
32
|
+
await store.open();
|
|
33
|
+
return { store, backend: 'database' };
|
|
34
|
+
}
|
|
35
|
+
const file = new file_outbox_1.FileOutbox(fileDirectory, options);
|
|
36
|
+
await file.open();
|
|
37
|
+
const fileStats = await file.stats();
|
|
38
|
+
if (!databaseApi || fileStats.messageCount > 0) {
|
|
39
|
+
await writeMarker(markerTarget, { version: 1, backend: 'file' });
|
|
40
|
+
return { store: file, backend: 'file' };
|
|
41
|
+
}
|
|
42
|
+
const seed = {
|
|
43
|
+
currentSequence: fileStats.currentSequence,
|
|
44
|
+
acknowledgedSequence: fileStats.acknowledgedSequence,
|
|
45
|
+
droppedCount: fileStats.droppedCount,
|
|
46
|
+
droppedThrough: fileStats.droppedThrough
|
|
47
|
+
};
|
|
48
|
+
let store;
|
|
49
|
+
try {
|
|
50
|
+
store = new database_outbox_1.DatabaseOutbox(await databaseApi.getPluginDb('signalk-wakelogger'), deviceId, options, seed);
|
|
51
|
+
await store.open();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
await writeMarker(markerTarget, { version: 1, backend: 'file' });
|
|
55
|
+
return { store: file, backend: 'file' };
|
|
56
|
+
}
|
|
57
|
+
await file.close();
|
|
58
|
+
await writeMarker(markerTarget, { version: 1, backend: 'database' });
|
|
59
|
+
return { store, backend: 'database' };
|
|
60
|
+
}
|
|
61
|
+
async function readMarker(target) {
|
|
62
|
+
try {
|
|
63
|
+
const value = JSON.parse(await node_fs_1.promises.readFile(target, 'utf8'));
|
|
64
|
+
return value.version === 1 && (value.backend === 'file' || value.backend === 'database')
|
|
65
|
+
? value
|
|
66
|
+
: undefined;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error.code === 'ENOENT' || error instanceof SyntaxError)
|
|
70
|
+
return undefined;
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function writeMarker(target, marker) {
|
|
75
|
+
await node_fs_1.promises.mkdir(node_path_1.default.dirname(target), { recursive: true, mode: 0o700 });
|
|
76
|
+
const temporary = `${target}.tmp`;
|
|
77
|
+
await node_fs_1.promises.writeFile(temporary, `${JSON.stringify(marker)}\n`, { mode: 0o600 });
|
|
78
|
+
const handle = await node_fs_1.promises.open(temporary, 'r+');
|
|
79
|
+
try {
|
|
80
|
+
await handle.sync();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await handle.close();
|
|
84
|
+
}
|
|
85
|
+
await node_fs_1.promises.rename(temporary, target);
|
|
86
|
+
// Windows does not support opening directories for fsync. The file flush and
|
|
87
|
+
// atomic rename above still provide the strongest portable guarantee there.
|
|
88
|
+
if (process.platform === 'win32')
|
|
89
|
+
return;
|
|
90
|
+
const directory = await node_fs_1.promises.open(node_path_1.default.dirname(target), 'r');
|
|
91
|
+
try {
|
|
92
|
+
await directory.sync();
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await directory.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/outbox/factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TelemetryDraft, TelemetrySample } from '../telemetry/types';
|
|
2
|
+
import type { OutboxOptions, OutboxStats, OutboxStore } from './interface';
|
|
3
|
+
export declare class FileOutbox implements OutboxStore {
|
|
4
|
+
private readonly directory;
|
|
5
|
+
private readonly options;
|
|
6
|
+
private metadata;
|
|
7
|
+
private opened;
|
|
8
|
+
private operation;
|
|
9
|
+
constructor(directory: string, options: OutboxOptions);
|
|
10
|
+
open(): Promise<void>;
|
|
11
|
+
append(deviceId: string, draft: TelemetryDraft): Promise<TelemetrySample>;
|
|
12
|
+
pending(limit: number, maxBytes: number): Promise<TelemetrySample[]>;
|
|
13
|
+
pendingAfter(sequence: number, limit: number, maxBytes: number): Promise<TelemetrySample[]>;
|
|
14
|
+
acknowledge(sequence: number): Promise<void>;
|
|
15
|
+
latest(): Promise<TelemetrySample | undefined>;
|
|
16
|
+
stats(): Promise<OutboxStats>;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
private enforceLimits;
|
|
19
|
+
private enforceLimitsUnlocked;
|
|
20
|
+
private reclaimAcknowledgedSegments;
|
|
21
|
+
private readMetadata;
|
|
22
|
+
private persistMetadata;
|
|
23
|
+
private readSegments;
|
|
24
|
+
private segmentNames;
|
|
25
|
+
private assertOpen;
|
|
26
|
+
private exclusive;
|
|
27
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FileOutbox = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const HEADER_BYTES = 4;
|
|
11
|
+
const CHECKSUM_BYTES = 32;
|
|
12
|
+
const META_FILE = 'metadata.json';
|
|
13
|
+
const SEGMENT_PATTERN = /^segment-(\d{12})\.log$/;
|
|
14
|
+
class FileOutbox {
|
|
15
|
+
directory;
|
|
16
|
+
options;
|
|
17
|
+
metadata = { version: 1, nextSequence: 1, acknowledgedSequence: 0, droppedCount: 0, droppedThrough: 0 };
|
|
18
|
+
opened = false;
|
|
19
|
+
operation = Promise.resolve();
|
|
20
|
+
constructor(directory, options) {
|
|
21
|
+
this.directory = directory;
|
|
22
|
+
this.options = options;
|
|
23
|
+
}
|
|
24
|
+
async open() {
|
|
25
|
+
await node_fs_1.promises.mkdir(this.directory, { recursive: true, mode: 0o700 });
|
|
26
|
+
this.metadata = await this.readMetadata();
|
|
27
|
+
const segments = await this.readSegments(true);
|
|
28
|
+
const maximum = segments.flatMap((s) => s.records).reduce((value, r) => Math.max(value, r.sample.sequence), 0);
|
|
29
|
+
const accountedThrough = Math.max(maximum, this.metadata.acknowledgedSequence, this.metadata.droppedThrough);
|
|
30
|
+
if (this.metadata.nextSequence > accountedThrough + 1) {
|
|
31
|
+
this.metadata.droppedCount += this.metadata.nextSequence - accountedThrough - 1;
|
|
32
|
+
this.metadata.droppedThrough = this.metadata.nextSequence - 1;
|
|
33
|
+
}
|
|
34
|
+
this.metadata.nextSequence = Math.max(this.metadata.nextSequence, maximum + 1);
|
|
35
|
+
await this.persistMetadata();
|
|
36
|
+
this.opened = true;
|
|
37
|
+
await this.enforceLimits();
|
|
38
|
+
}
|
|
39
|
+
async append(deviceId, draft) {
|
|
40
|
+
return this.exclusive(async () => {
|
|
41
|
+
this.assertOpen();
|
|
42
|
+
const sample = { v: 1, deviceId, sequence: this.metadata.nextSequence, ...draft };
|
|
43
|
+
const record = encodeRecord(sample);
|
|
44
|
+
const segments = await this.segmentNames();
|
|
45
|
+
let segment = segments.at(-1);
|
|
46
|
+
let rotated = false;
|
|
47
|
+
if (!segment || (await fileSize(node_path_1.default.join(this.directory, segment))) + record.length > this.options.segmentBytes) {
|
|
48
|
+
segment = segmentName(sample.sequence);
|
|
49
|
+
rotated = true;
|
|
50
|
+
}
|
|
51
|
+
const handle = await node_fs_1.promises.open(node_path_1.default.join(this.directory, segment), 'a', 0o600);
|
|
52
|
+
try {
|
|
53
|
+
await handle.write(record);
|
|
54
|
+
await handle.sync();
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await handle.close();
|
|
58
|
+
}
|
|
59
|
+
this.metadata.nextSequence = sample.sequence + 1;
|
|
60
|
+
// Normal recovery derives nextSequence from the last checksummed record. Persist it
|
|
61
|
+
// only at segment boundaries to avoid a second fsync for every one-second sample.
|
|
62
|
+
if (rotated)
|
|
63
|
+
await this.persistMetadata();
|
|
64
|
+
await this.enforceLimitsUnlocked();
|
|
65
|
+
return sample;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async pending(limit, maxBytes) {
|
|
69
|
+
return this.pendingAfter(0, limit, maxBytes);
|
|
70
|
+
}
|
|
71
|
+
async pendingAfter(sequence, limit, maxBytes) {
|
|
72
|
+
return this.exclusive(async () => {
|
|
73
|
+
this.assertOpen();
|
|
74
|
+
const result = [];
|
|
75
|
+
let bytes = 0;
|
|
76
|
+
for (const segment of await this.readSegments(false)) {
|
|
77
|
+
for (const { sample } of segment.records) {
|
|
78
|
+
if (sample.sequence <= Math.max(this.metadata.acknowledgedSequence, sequence))
|
|
79
|
+
continue;
|
|
80
|
+
const size = Buffer.byteLength(JSON.stringify(sample));
|
|
81
|
+
if (result.length > 0 && (result.length >= limit || bytes + size > maxBytes))
|
|
82
|
+
return result;
|
|
83
|
+
result.push(sample);
|
|
84
|
+
bytes += size;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async acknowledge(sequence) {
|
|
91
|
+
await this.exclusive(async () => {
|
|
92
|
+
this.assertOpen();
|
|
93
|
+
const maximum = this.metadata.nextSequence - 1;
|
|
94
|
+
if (!Number.isSafeInteger(sequence) || sequence <= this.metadata.acknowledgedSequence || sequence > maximum)
|
|
95
|
+
return;
|
|
96
|
+
this.metadata.acknowledgedSequence = sequence;
|
|
97
|
+
await this.persistMetadata();
|
|
98
|
+
await this.reclaimAcknowledgedSegments();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async latest() {
|
|
102
|
+
return this.exclusive(async () => {
|
|
103
|
+
const segments = await this.readSegments(false);
|
|
104
|
+
for (let index = segments.length - 1; index >= 0; index -= 1) {
|
|
105
|
+
const sample = segments[index]?.records.at(-1)?.sample;
|
|
106
|
+
if (sample)
|
|
107
|
+
return sample;
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async stats() {
|
|
113
|
+
return this.exclusive(async () => {
|
|
114
|
+
const segments = await this.readSegments(false);
|
|
115
|
+
const pending = segments.flatMap((segment) => segment.records)
|
|
116
|
+
.filter((record) => record.sample.sequence > this.metadata.acknowledgedSequence);
|
|
117
|
+
return {
|
|
118
|
+
storageBackend: 'file',
|
|
119
|
+
messageCount: pending.length,
|
|
120
|
+
diskBytes: segments.reduce((total, segment) => total + segment.bytes, 0),
|
|
121
|
+
oldestCapturedAt: pending[0]?.sample.capturedAt,
|
|
122
|
+
acknowledgedSequence: this.metadata.acknowledgedSequence,
|
|
123
|
+
currentSequence: this.metadata.nextSequence - 1,
|
|
124
|
+
droppedCount: this.metadata.droppedCount,
|
|
125
|
+
droppedThrough: this.metadata.droppedThrough
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async close() {
|
|
130
|
+
await this.operation;
|
|
131
|
+
if (this.opened)
|
|
132
|
+
await this.persistMetadata();
|
|
133
|
+
this.opened = false;
|
|
134
|
+
}
|
|
135
|
+
async enforceLimits() {
|
|
136
|
+
await this.exclusive(() => this.enforceLimitsUnlocked());
|
|
137
|
+
}
|
|
138
|
+
async enforceLimitsUnlocked() {
|
|
139
|
+
const segments = await this.readSegments(false);
|
|
140
|
+
let total = segments.reduce((sum, segment) => sum + segment.bytes, 0);
|
|
141
|
+
const now = this.options.now?.() ?? Date.now();
|
|
142
|
+
const cutoff = now - this.options.maxAgeMs;
|
|
143
|
+
let metadataChanged = false;
|
|
144
|
+
for (let index = 0; index < segments.length - 1; index += 1) {
|
|
145
|
+
const segment = segments[index];
|
|
146
|
+
if (!segment)
|
|
147
|
+
continue;
|
|
148
|
+
const newest = segment.records.at(-1)?.sample;
|
|
149
|
+
const tooOld = newest !== undefined && newest.capturedAt < cutoff;
|
|
150
|
+
if (!tooOld && total <= this.options.maxBytes)
|
|
151
|
+
break;
|
|
152
|
+
const unacknowledged = segment.records.filter((record) => record.sample.sequence > this.metadata.acknowledgedSequence);
|
|
153
|
+
if (unacknowledged.length) {
|
|
154
|
+
this.metadata.droppedCount += unacknowledged.length;
|
|
155
|
+
this.metadata.droppedThrough = unacknowledged.at(-1)?.sample.sequence ?? this.metadata.droppedThrough;
|
|
156
|
+
metadataChanged = true;
|
|
157
|
+
}
|
|
158
|
+
await node_fs_1.promises.unlink(node_path_1.default.join(this.directory, segment.name)).catch(ignoreMissing);
|
|
159
|
+
total -= segment.bytes;
|
|
160
|
+
}
|
|
161
|
+
if (metadataChanged)
|
|
162
|
+
await this.persistMetadata();
|
|
163
|
+
}
|
|
164
|
+
async reclaimAcknowledgedSegments() {
|
|
165
|
+
const segments = await this.readSegments(false);
|
|
166
|
+
for (const segment of segments.slice(0, -1)) {
|
|
167
|
+
const lastSequence = segment.records.at(-1)?.sample.sequence ?? 0;
|
|
168
|
+
if (lastSequence > this.metadata.acknowledgedSequence)
|
|
169
|
+
break;
|
|
170
|
+
await node_fs_1.promises.unlink(node_path_1.default.join(this.directory, segment.name)).catch(ignoreMissing);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async readMetadata() {
|
|
174
|
+
try {
|
|
175
|
+
const value = JSON.parse(await node_fs_1.promises.readFile(node_path_1.default.join(this.directory, META_FILE), 'utf8'));
|
|
176
|
+
if (value.version === 1 && positiveInteger(value.nextSequence) && nonNegativeInteger(value.acknowledgedSequence)) {
|
|
177
|
+
return {
|
|
178
|
+
version: 1,
|
|
179
|
+
nextSequence: value.nextSequence,
|
|
180
|
+
acknowledgedSequence: value.acknowledgedSequence,
|
|
181
|
+
droppedCount: nonNegativeInteger(value.droppedCount) ? value.droppedCount : 0,
|
|
182
|
+
droppedThrough: nonNegativeInteger(value.droppedThrough) ? value.droppedThrough : 0
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
if (!isMissing(error))
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
return { version: 1, nextSequence: 1, acknowledgedSequence: 0, droppedCount: 0, droppedThrough: 0 };
|
|
191
|
+
}
|
|
192
|
+
async persistMetadata() {
|
|
193
|
+
const target = node_path_1.default.join(this.directory, META_FILE);
|
|
194
|
+
const temporary = `${target}.tmp`;
|
|
195
|
+
await node_fs_1.promises.writeFile(temporary, `${JSON.stringify(this.metadata)}\n`, { mode: 0o600 });
|
|
196
|
+
const handle = await node_fs_1.promises.open(temporary, 'r+');
|
|
197
|
+
try {
|
|
198
|
+
await handle.sync();
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
await handle.close();
|
|
202
|
+
}
|
|
203
|
+
await node_fs_1.promises.rename(temporary, target);
|
|
204
|
+
}
|
|
205
|
+
async readSegments(repair) {
|
|
206
|
+
const result = [];
|
|
207
|
+
for (const name of await this.segmentNames()) {
|
|
208
|
+
const target = node_path_1.default.join(this.directory, name);
|
|
209
|
+
const data = await node_fs_1.promises.readFile(target);
|
|
210
|
+
const records = [];
|
|
211
|
+
let offset = 0;
|
|
212
|
+
while (offset + HEADER_BYTES + CHECKSUM_BYTES <= data.length) {
|
|
213
|
+
const length = data.readUInt32BE(offset);
|
|
214
|
+
const end = offset + HEADER_BYTES + length + CHECKSUM_BYTES;
|
|
215
|
+
if (length === 0 || length > this.options.segmentBytes || end > data.length)
|
|
216
|
+
break;
|
|
217
|
+
const payload = data.subarray(offset + HEADER_BYTES, offset + HEADER_BYTES + length);
|
|
218
|
+
const expected = data.subarray(offset + HEADER_BYTES + length, end);
|
|
219
|
+
const actual = (0, node_crypto_1.createHash)('sha256').update(payload).digest();
|
|
220
|
+
if (!actual.equals(expected))
|
|
221
|
+
break;
|
|
222
|
+
try {
|
|
223
|
+
const sample = JSON.parse(payload.toString('utf8'));
|
|
224
|
+
if (!validSample(sample))
|
|
225
|
+
break;
|
|
226
|
+
records.push({ sample, start: offset, end });
|
|
227
|
+
offset = end;
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (repair && offset !== data.length)
|
|
234
|
+
await node_fs_1.promises.truncate(target, offset);
|
|
235
|
+
result.push({ name, records, bytes: repair ? offset : data.length });
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
async segmentNames() {
|
|
240
|
+
return (await node_fs_1.promises.readdir(this.directory)).filter((name) => SEGMENT_PATTERN.test(name)).sort();
|
|
241
|
+
}
|
|
242
|
+
assertOpen() {
|
|
243
|
+
if (!this.opened)
|
|
244
|
+
throw new Error('Outbox is not open');
|
|
245
|
+
}
|
|
246
|
+
exclusive(action) {
|
|
247
|
+
const result = this.operation.then(action, action);
|
|
248
|
+
this.operation = result.then(() => undefined, () => undefined);
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
exports.FileOutbox = FileOutbox;
|
|
253
|
+
function encodeRecord(sample) {
|
|
254
|
+
const payload = Buffer.from(JSON.stringify(sample), 'utf8');
|
|
255
|
+
const result = Buffer.allocUnsafe(HEADER_BYTES + payload.length + CHECKSUM_BYTES);
|
|
256
|
+
result.writeUInt32BE(payload.length, 0);
|
|
257
|
+
payload.copy(result, HEADER_BYTES);
|
|
258
|
+
(0, node_crypto_1.createHash)('sha256').update(payload).digest().copy(result, HEADER_BYTES + payload.length);
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
function segmentName(sequence) { return `segment-${String(sequence).padStart(12, '0')}.log`; }
|
|
262
|
+
function validSample(value) {
|
|
263
|
+
return value?.v === 1 && typeof value.deviceId === 'string' && positiveInteger(value.sequence) &&
|
|
264
|
+
Number.isFinite(value.capturedAt) && Number.isFinite(value.receivedAt) &&
|
|
265
|
+
Number.isFinite(value.values?.lat) && Number.isFinite(value.values?.lon);
|
|
266
|
+
}
|
|
267
|
+
function positiveInteger(value) { return Number.isSafeInteger(value) && value > 0; }
|
|
268
|
+
function nonNegativeInteger(value) { return Number.isSafeInteger(value) && value >= 0; }
|
|
269
|
+
function isMissing(error) { return error?.code === 'ENOENT'; }
|
|
270
|
+
function ignoreMissing(error) { if (!isMissing(error))
|
|
271
|
+
throw error; }
|
|
272
|
+
async function fileSize(target) { try {
|
|
273
|
+
return (await node_fs_1.promises.stat(target)).size;
|
|
274
|
+
}
|
|
275
|
+
catch (e) {
|
|
276
|
+
if (isMissing(e))
|
|
277
|
+
return 0;
|
|
278
|
+
throw e;
|
|
279
|
+
} }
|
|
280
|
+
//# sourceMappingURL=file-outbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-outbox.js","sourceRoot":"","sources":["../../src/outbox/file-outbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TelemetryDraft, TelemetrySample } from '../telemetry/types';
|
|
2
|
+
export interface OutboxStats {
|
|
3
|
+
storageBackend: 'file' | 'database';
|
|
4
|
+
messageCount: number;
|
|
5
|
+
diskBytes: number;
|
|
6
|
+
oldestCapturedAt?: number;
|
|
7
|
+
acknowledgedSequence: number;
|
|
8
|
+
currentSequence: number;
|
|
9
|
+
droppedCount: number;
|
|
10
|
+
droppedThrough: number;
|
|
11
|
+
}
|
|
12
|
+
export interface OutboxSeed {
|
|
13
|
+
currentSequence: number;
|
|
14
|
+
acknowledgedSequence: number;
|
|
15
|
+
droppedCount: number;
|
|
16
|
+
droppedThrough: number;
|
|
17
|
+
}
|
|
18
|
+
export interface OutboxOptions {
|
|
19
|
+
maxBytes: number;
|
|
20
|
+
maxAgeMs: number;
|
|
21
|
+
segmentBytes: number;
|
|
22
|
+
now?: () => number;
|
|
23
|
+
}
|
|
24
|
+
export interface OutboxStore {
|
|
25
|
+
open(): Promise<void>;
|
|
26
|
+
append(deviceId: string, draft: TelemetryDraft): Promise<TelemetrySample>;
|
|
27
|
+
pending(limit: number, maxBytes: number): Promise<TelemetrySample[]>;
|
|
28
|
+
pendingAfter(sequence: number, limit: number, maxBytes: number): Promise<TelemetrySample[]>;
|
|
29
|
+
latest(): Promise<TelemetrySample | undefined>;
|
|
30
|
+
acknowledge(sequence: number): Promise<void>;
|
|
31
|
+
stats(): Promise<OutboxStats>;
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/outbox/interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkAssociationStatus = checkAssociationStatus;
|
|
4
|
+
async function checkAssociationStatus(credentials, signal) {
|
|
5
|
+
if (!credentials.associationStatusUrl || !credentials.associationToken)
|
|
6
|
+
return 'unknown';
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
9
|
+
const abort = () => controller.abort();
|
|
10
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch(credentials.associationStatusUrl, {
|
|
13
|
+
headers: { accept: 'application/json', authorization: `Bearer ${credentials.associationToken}` },
|
|
14
|
+
signal: controller.signal
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok)
|
|
17
|
+
return 'unknown';
|
|
18
|
+
const body = await response.json();
|
|
19
|
+
if (body.v !== 1 || body.device_id !== credentials.deviceId)
|
|
20
|
+
return 'unknown';
|
|
21
|
+
return body.status === 'revoked' ? 'revoked' : body.status === 'active' ? 'active' : 'unknown';
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return 'unknown';
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
signal?.removeEventListener('abort', abort);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=association-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"association-client.js","sourceRoot":"","sources":["../../src/pairing/association-client.ts"],"names":[],"mappings":";;AAIA,wDAqBC;AArBM,KAAK,UAAU,sBAAsB,CAAC,WAA8B,EAAE,MAAoB;IAC/F,IAAI,CAAC,WAAW,CAAC,oBAAoB,IAAI,CAAC,WAAW,CAAC,gBAAgB;QAAE,OAAO,SAAS,CAAA;IACxF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAA;IAC5D,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;IACtC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACxD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,oBAAoB,EAAE;YAC7D,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,WAAW,CAAC,gBAAgB,EAAE,EAAE;YAChG,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAA;QACF,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,SAAS,CAAA;QAClC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA4D,CAAA;QAC5F,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,KAAK,WAAW,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAA;QAC7E,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAChG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAA;QACrB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type TelemetryProfile } from '../telemetry/profile';
|
|
2
|
+
export interface LegacyTelemetryProfile {
|
|
3
|
+
sample_period_ms?: number;
|
|
4
|
+
batch_size?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface OutboxBinding {
|
|
7
|
+
version: 1;
|
|
8
|
+
backend: 'file' | 'database';
|
|
9
|
+
initializedAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface DeviceCredentials {
|
|
12
|
+
version: 1;
|
|
13
|
+
deviceId: string;
|
|
14
|
+
clientId: string;
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
mqttHost: string;
|
|
18
|
+
mqttPort: number;
|
|
19
|
+
tls: boolean;
|
|
20
|
+
pairedAt: number;
|
|
21
|
+
pairingCodeFingerprint?: string;
|
|
22
|
+
telemetryProfile?: TelemetryProfile | LegacyTelemetryProfile;
|
|
23
|
+
outboxBinding?: OutboxBinding;
|
|
24
|
+
associationStatusUrl?: string;
|
|
25
|
+
associationToken?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class CredentialStore {
|
|
28
|
+
private readonly directory;
|
|
29
|
+
private readonly credentialsFile;
|
|
30
|
+
private readonly identityFile;
|
|
31
|
+
private readonly pairingStateFile;
|
|
32
|
+
constructor(directory: string);
|
|
33
|
+
installationId(): Promise<string>;
|
|
34
|
+
load(): Promise<DeviceCredentials | undefined>;
|
|
35
|
+
save(credentials: DeviceCredentials): Promise<void>;
|
|
36
|
+
lastPairingCodeFingerprint(): Promise<string | undefined>;
|
|
37
|
+
forget(): Promise<{
|
|
38
|
+
forgotten: boolean;
|
|
39
|
+
deviceId?: string;
|
|
40
|
+
}>;
|
|
41
|
+
private loadPairingState;
|
|
42
|
+
private savePairingState;
|
|
43
|
+
}
|
|
44
|
+
export declare function validateCredentials(value: DeviceCredentials): boolean;
|
|
45
|
+
export declare function fingerprintPairingCode(code: string): string;
|
|
46
|
+
export declare function shouldExchangePairingCode(credentials: DeviceCredentials | undefined, code: string | undefined, lastFingerprint?: string): code is string;
|