homebridge-http-advanced-platform 2.0.0-alpha.6
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/LICENSE +176 -0
- package/README.md +175 -0
- package/config.schema.json +449 -0
- package/dist/accessory.d.ts +27 -0
- package/dist/accessory.js +164 -0
- package/dist/accessory.js.map +1 -0
- package/dist/actions.d.ts +8 -0
- package/dist/actions.js +47 -0
- package/dist/actions.js.map +1 -0
- package/dist/compatibility.d.ts +3 -0
- package/dist/compatibility.js +26 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +81 -0
- package/dist/config.js.map +1 -0
- package/dist/coordinator.d.ts +51 -0
- package/dist/coordinator.js +145 -0
- package/dist/coordinator.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mappers.d.ts +3 -0
- package/dist/mappers.js +116 -0
- package/dist/mappers.js.map +1 -0
- package/dist/metadata.d.ts +5 -0
- package/dist/metadata.js +8 -0
- package/dist/metadata.js.map +1 -0
- package/dist/platform.d.ts +18 -0
- package/dist/platform.js +129 -0
- package/dist/platform.js.map +1 -0
- package/dist/runtime.d.ts +54 -0
- package/dist/runtime.js +376 -0
- package/dist/runtime.js.map +1 -0
- package/dist/settings.d.ts +21 -0
- package/dist/settings.js +51 -0
- package/dist/settings.js.map +1 -0
- package/dist/transport.d.ts +25 -0
- package/dist/transport.js +139 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/ui-config.d.ts +27 -0
- package/dist/ui-config.js +208 -0
- package/dist/ui-config.js.map +1 -0
- package/docs/alpha-release-notes.md +19 -0
- package/docs/legacy-reference.md +678 -0
- package/docs/migration.md +43 -0
- package/docs/modernization.md +211 -0
- package/docs/performance.md +37 -0
- package/docs/service-support.md +47 -0
- package/homebridge-ui/public/index.html +74 -0
- package/homebridge-ui/public/settings.js +132 -0
- package/homebridge-ui/server.js +17 -0
- package/package.json +83 -0
- package/sample-config.json +39 -0
package/dist/platform.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { DeviceAdapter, serviceConstructor } from './accessory.js';
|
|
2
|
+
import { validateDevice } from './config.js';
|
|
3
|
+
import { sharedRuntime } from './runtime.js';
|
|
4
|
+
import { validateSettings } from './settings.js';
|
|
5
|
+
import { pluginName, platformName, platformUUIDNamespace } from './metadata.js';
|
|
6
|
+
export { pluginName, platformName } from './metadata.js';
|
|
7
|
+
export class HTTPPlatform {
|
|
8
|
+
log;
|
|
9
|
+
config;
|
|
10
|
+
api;
|
|
11
|
+
cached = new Map();
|
|
12
|
+
constructor(log, config, api) {
|
|
13
|
+
this.log = log;
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.api = api;
|
|
16
|
+
api.on('didFinishLaunching', () => this.discover());
|
|
17
|
+
}
|
|
18
|
+
configureAccessory(accessory) { this.cached.set(accessory.UUID, accessory); }
|
|
19
|
+
unavailable() {
|
|
20
|
+
const fail = () => { throw new this.api.hap.HapStatusError(-70402 /* this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */); };
|
|
21
|
+
for (const accessory of this.cached.values()) {
|
|
22
|
+
for (const service of accessory.services) {
|
|
23
|
+
if (service.UUID === this.api.hap.Service.AccessoryInformation.UUID)
|
|
24
|
+
continue;
|
|
25
|
+
for (const characteristic of service.characteristics) {
|
|
26
|
+
if (characteristic.UUID === this.api.hap.Characteristic.Name.UUID)
|
|
27
|
+
continue;
|
|
28
|
+
if (characteristic.props.perms.includes("pr" /* this.api.hap.Perms.PAIRED_READ */))
|
|
29
|
+
characteristic.onGet(fail);
|
|
30
|
+
if (characteristic.props.perms.includes("pw" /* this.api.hap.Perms.PAIRED_WRITE */))
|
|
31
|
+
characteristic.onSet(fail);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
discover() {
|
|
37
|
+
// disabling a platform retains its configuration and cached HomeKit identities
|
|
38
|
+
if (this.config.enabled === false) {
|
|
39
|
+
this.unavailable();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (this.config.enabled !== undefined && typeof this.config.enabled !== 'boolean') {
|
|
43
|
+
this.unavailable();
|
|
44
|
+
this.log.error('HTTP Advanced platform enabled must be true or false; cached accessories retained');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// validate the whole inventory before reconciling so malformed configuration cannot remove devices
|
|
48
|
+
const devices = this.config.devices;
|
|
49
|
+
if (!Array.isArray(devices)) {
|
|
50
|
+
this.unavailable();
|
|
51
|
+
this.log.error('HTTP Advanced platform requires a devices array');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const desired = new Map();
|
|
55
|
+
try {
|
|
56
|
+
for (const device of devices) {
|
|
57
|
+
validateDevice(device);
|
|
58
|
+
serviceConstructor(this.api, device.service);
|
|
59
|
+
const id = device.id ?? device.name;
|
|
60
|
+
if (typeof id !== 'string' || !id.trim())
|
|
61
|
+
throw new Error();
|
|
62
|
+
const UUID = this.api.hap.uuid.generate(`${platformUUIDNamespace}:${this.config.name ?? platformName}:${id}`);
|
|
63
|
+
if (desired.has(UUID))
|
|
64
|
+
throw new Error();
|
|
65
|
+
desired.set(UUID, device);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.unavailable();
|
|
70
|
+
const unsupported = error instanceof Error && error.message.startsWith('HTTP Advanced unsupported HomeKit service:');
|
|
71
|
+
this.log.error(unsupported ? `${error.message}; cached accessories retained` : 'HTTP Advanced platform inventory invalid or contains duplicate IDs; cached accessories retained');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const runtime = sharedRuntime(this.api, this.log);
|
|
75
|
+
try {
|
|
76
|
+
if (this.config.coordinator !== undefined)
|
|
77
|
+
validateSettings({ coordinator: this.config.coordinator });
|
|
78
|
+
runtime.coordinator.configure(this.config.coordinator ?? {});
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
this.unavailable();
|
|
82
|
+
this.log.error('HTTP Advanced invalid coordinator limits; cached accessories retained');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
let failed = false;
|
|
86
|
+
for (const [UUID, device] of desired) {
|
|
87
|
+
try {
|
|
88
|
+
const cached = this.cached.get(UUID);
|
|
89
|
+
const accessory = cached ?? new this.api.platformAccessory(device.name, UUID);
|
|
90
|
+
const Constructor = serviceConstructor(this.api, device.service);
|
|
91
|
+
const existing = accessory.services.find(service => service.UUID === Constructor.UUID);
|
|
92
|
+
const adapter = new DeviceAdapter(this.api, runtime, device, `platform:${UUID}`, existing);
|
|
93
|
+
if (!existing)
|
|
94
|
+
accessory.addService(adapter.service);
|
|
95
|
+
// remove obsolete primary services only after the new definition was successfully attached
|
|
96
|
+
for (const service of accessory.services.slice()) {
|
|
97
|
+
if (service.UUID !== this.api.hap.Service.AccessoryInformation.UUID && service !== adapter.service)
|
|
98
|
+
accessory.removeService(service);
|
|
99
|
+
}
|
|
100
|
+
accessory.displayName = device.name;
|
|
101
|
+
accessory.getService(this.api.hap.Service.AccessoryInformation)
|
|
102
|
+
.setCharacteristic(this.api.hap.Characteristic.Name, device.name)
|
|
103
|
+
.setCharacteristic(this.api.hap.Characteristic.Manufacturer, device.manufacturer ?? 'Custom Manufacturer')
|
|
104
|
+
.setCharacteristic(this.api.hap.Characteristic.Model, device.model ?? 'HTTP Accessory Model')
|
|
105
|
+
.setCharacteristic(this.api.hap.Characteristic.SerialNumber, device.id ?? 'HTTP Accessory Serial Number');
|
|
106
|
+
// context stores no configuration, URLs, bodies, usernames or passwords
|
|
107
|
+
accessory.context = { schemaVersion: 1 };
|
|
108
|
+
if (cached)
|
|
109
|
+
this.api.updatePlatformAccessories([accessory]);
|
|
110
|
+
else
|
|
111
|
+
this.api.registerPlatformAccessories(pluginName, platformName, [accessory]);
|
|
112
|
+
this.cached.set(UUID, accessory);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
failed = true;
|
|
116
|
+
this.log.error('HTTP Advanced device initialization failed; cached accessories retained');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!failed) {
|
|
120
|
+
const removed = [...this.cached.values()].filter(a => !desired.has(a.UUID));
|
|
121
|
+
if (removed.length)
|
|
122
|
+
this.api.unregisterPlatformAccessories(pluginName, platformName, removed);
|
|
123
|
+
for (const accessory of removed)
|
|
124
|
+
this.cached.delete(accessory.UUID);
|
|
125
|
+
}
|
|
126
|
+
runtime.start();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { API, CharacteristicValue, Logging } from 'homebridge';
|
|
2
|
+
import { Coordinator } from './coordinator.js';
|
|
3
|
+
import { Transport } from './transport.js';
|
|
4
|
+
import { Actions } from './actions.js';
|
|
5
|
+
import { type GlobalSettings } from './settings.js';
|
|
6
|
+
import { type CacheEntry, type CoordinatorConfig, type DeviceConfig, type PendingWrite, type State } from './types.js';
|
|
7
|
+
export declare const fingerprint: (value: unknown) => string;
|
|
8
|
+
export declare class Runtime {
|
|
9
|
+
readonly log: Logging;
|
|
10
|
+
readonly settings: GlobalSettings;
|
|
11
|
+
readonly coordinator: Coordinator;
|
|
12
|
+
readonly transport: Transport;
|
|
13
|
+
readonly actions: Actions;
|
|
14
|
+
readonly entries: Map<string, CacheEntry>;
|
|
15
|
+
readonly setters: Map<string, NodeJS.Timeout>;
|
|
16
|
+
private readonly persisted;
|
|
17
|
+
private readonly owners;
|
|
18
|
+
private readonly recovering;
|
|
19
|
+
private timer?;
|
|
20
|
+
private persistenceTimer?;
|
|
21
|
+
private stopped;
|
|
22
|
+
private started;
|
|
23
|
+
private savePath?;
|
|
24
|
+
private dirty;
|
|
25
|
+
readonly stats: {
|
|
26
|
+
changes: number;
|
|
27
|
+
mapperFailures: number;
|
|
28
|
+
restored: number;
|
|
29
|
+
reads: number;
|
|
30
|
+
failedRefreshes: number;
|
|
31
|
+
};
|
|
32
|
+
constructor(log: Logging, options?: CoordinatorConfig, persistPath?: string, settings?: GlobalSettings);
|
|
33
|
+
register(owner: string, actionName: string, config: DeviceConfig, state: State, convert: CacheEntry['convert'], update: CacheEntry['update']): CacheEntry;
|
|
34
|
+
start(): void;
|
|
35
|
+
interval(entry: CacheEntry, now?: number): number;
|
|
36
|
+
read(entry: CacheEntry): CharacteristicValue;
|
|
37
|
+
tick(now?: number): void;
|
|
38
|
+
refresh(entry: CacheEntry): Promise<void>;
|
|
39
|
+
private ownerFor;
|
|
40
|
+
private originFor;
|
|
41
|
+
private pauseOrigin;
|
|
42
|
+
private reportRecovery;
|
|
43
|
+
private finishRecovery;
|
|
44
|
+
beginWrite(entry: CacheEntry, value: CharacteristicValue): PendingWrite;
|
|
45
|
+
private expireWrite;
|
|
46
|
+
publish(entry: CacheEntry): void;
|
|
47
|
+
set(config: DeviceConfig, state: State, actionName: string, value: CharacteristicValue, entry?: CacheEntry, intent?: PendingWrite): Promise<void>;
|
|
48
|
+
debounce(key: string, delay: number, work: () => Promise<void>, onFailure?: () => void): void;
|
|
49
|
+
snapshot(): object;
|
|
50
|
+
private debugSnapshot;
|
|
51
|
+
persist(): void;
|
|
52
|
+
shutdown(): void;
|
|
53
|
+
}
|
|
54
|
+
export declare function sharedRuntime(api: API, log: Logging): Runtime;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { Coordinator } from './coordinator.js';
|
|
5
|
+
import { Transport } from './transport.js';
|
|
6
|
+
import { Actions } from './actions.js';
|
|
7
|
+
import { readGlobalSettings } from './settings.js';
|
|
8
|
+
import { pluginVersion } from './metadata.js';
|
|
9
|
+
import { ActionError } from './types.js';
|
|
10
|
+
const temporaryFailure = (category) => category !== undefined && ['network', 'timeout', 'inconclusive', 'unavailable'].includes(category);
|
|
11
|
+
export const fingerprint = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
12
|
+
export class Runtime {
|
|
13
|
+
log;
|
|
14
|
+
settings;
|
|
15
|
+
coordinator;
|
|
16
|
+
transport;
|
|
17
|
+
actions;
|
|
18
|
+
entries = new Map();
|
|
19
|
+
setters = new Map();
|
|
20
|
+
persisted = {};
|
|
21
|
+
owners = new Set();
|
|
22
|
+
recovering = new Map();
|
|
23
|
+
timer;
|
|
24
|
+
persistenceTimer;
|
|
25
|
+
stopped = false;
|
|
26
|
+
started = false;
|
|
27
|
+
savePath;
|
|
28
|
+
dirty = false;
|
|
29
|
+
stats = { changes: 0, mapperFailures: 0, restored: 0, reads: 0, failedRefreshes: 0 };
|
|
30
|
+
constructor(log, options = {}, persistPath, settings = {}) {
|
|
31
|
+
this.log = log;
|
|
32
|
+
this.settings = settings;
|
|
33
|
+
this.coordinator = new Coordinator({ ...settings.coordinator, ...options });
|
|
34
|
+
this.transport = new Transport(this.coordinator, settings);
|
|
35
|
+
this.actions = new Actions(this.transport);
|
|
36
|
+
if (persistPath) {
|
|
37
|
+
this.savePath = join(persistPath, 'http-advanced-state-v1');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
register(owner, actionName, config, state, convert, update) {
|
|
41
|
+
const key = fingerprint([owner, config, actionName]);
|
|
42
|
+
if (this.entries.has(key))
|
|
43
|
+
throw new ActionError('config');
|
|
44
|
+
this.owners.add(owner);
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const entry = { key, actionName, config, state, known: false, lastSuccess: 0, lastAttempt: 0, lastChange: 0, lastDemand: now, inFlight: false, failures: 0, nextEligible: now + Math.random() * 1000, generation: 0, convert, update };
|
|
47
|
+
if (this.savePath) {
|
|
48
|
+
try {
|
|
49
|
+
const saved = JSON.parse(readFileSync(join(this.savePath, key + '.json'), 'utf8'));
|
|
50
|
+
if (saved && typeof saved === 'object')
|
|
51
|
+
this.persisted[key] = saved;
|
|
52
|
+
}
|
|
53
|
+
catch { /* missing or corrupt optional state cannot block startup */ }
|
|
54
|
+
}
|
|
55
|
+
const saved = this.persisted[key];
|
|
56
|
+
if (saved && Number.isFinite(saved.lastSuccess) && saved.lastSuccess > 0 && saved.lastSuccess <= now) {
|
|
57
|
+
try {
|
|
58
|
+
entry.value = convert(saved.value);
|
|
59
|
+
entry.known = true;
|
|
60
|
+
entry.lastSuccess = saved.lastSuccess;
|
|
61
|
+
entry.lastChange = saved.lastChange;
|
|
62
|
+
entry.stateValue = ['string', 'boolean', 'number'].includes(typeof saved.stateValue) ? saved.stateValue : entry.value;
|
|
63
|
+
state[actionName] = entry.stateValue;
|
|
64
|
+
update(entry.value);
|
|
65
|
+
this.stats.restored++;
|
|
66
|
+
}
|
|
67
|
+
catch { /* invalid values are ignored; the getter reports not-ready until refreshed */ }
|
|
68
|
+
}
|
|
69
|
+
this.entries.set(key, entry);
|
|
70
|
+
return entry;
|
|
71
|
+
}
|
|
72
|
+
start() {
|
|
73
|
+
if (this.started || this.stopped)
|
|
74
|
+
return;
|
|
75
|
+
this.started = true;
|
|
76
|
+
this.log.info(`HTTP Advanced ${pluginVersion}: ${this.owners.size} devices, ${this.entries.size} cached getters, ${this.stats.restored} restored; concurrency ${this.coordinator.limits.concurrency}/${this.coordinator.limits.perOrigin}`);
|
|
77
|
+
this.timer = setInterval(() => this.tick(), 100);
|
|
78
|
+
this.timer.unref();
|
|
79
|
+
this.persistenceTimer = setInterval(() => { this.persist(); this.debugSnapshot(); }, 30000);
|
|
80
|
+
this.persistenceTimer.unref();
|
|
81
|
+
this.tick();
|
|
82
|
+
}
|
|
83
|
+
interval(entry, now = Date.now()) {
|
|
84
|
+
if (entry.config.forceRefreshDelay)
|
|
85
|
+
return entry.config.forceRefreshDelay * 1000;
|
|
86
|
+
const options = { ...this.settings.refresh, ...entry.config.refresh };
|
|
87
|
+
return now - entry.lastDemand > (options.idleAfter ?? 60) * 1000
|
|
88
|
+
? (options.idleInterval ?? 60) * 1000 : (options.activeInterval ?? 5) * 1000;
|
|
89
|
+
}
|
|
90
|
+
read(entry) {
|
|
91
|
+
this.stats.reads++;
|
|
92
|
+
entry.lastDemand = Date.now();
|
|
93
|
+
this.expireWrite(entry, entry.lastDemand);
|
|
94
|
+
if (entry.pendingWrite)
|
|
95
|
+
return entry.pendingWrite.value;
|
|
96
|
+
// demand only marks work eligible; the scheduler starts it on a separate turn
|
|
97
|
+
if (!entry.config.forceRefreshDelay && entry.failures === 0 && entry.lastDemand - entry.lastSuccess >= this.interval(entry)) {
|
|
98
|
+
entry.nextEligible = Math.min(entry.nextEligible, entry.lastDemand);
|
|
99
|
+
}
|
|
100
|
+
if (!entry.known || entry.value === undefined)
|
|
101
|
+
throw new ActionError('inconclusive');
|
|
102
|
+
return entry.value;
|
|
103
|
+
}
|
|
104
|
+
tick(now = Date.now()) {
|
|
105
|
+
if (this.stopped)
|
|
106
|
+
return;
|
|
107
|
+
this.reportRecovery(now);
|
|
108
|
+
// expiry must still reach HomeKit when the endpoint or request queue is blocked
|
|
109
|
+
for (const entry of this.entries.values())
|
|
110
|
+
this.expireWrite(entry, now);
|
|
111
|
+
for (const entry of [...this.entries.values()].sort((a, b) => a.nextEligible - b.nextEligible)) {
|
|
112
|
+
if (!this.coordinator.available)
|
|
113
|
+
break;
|
|
114
|
+
if (entry.pendingWrite && entry.pendingWrite.expires === undefined)
|
|
115
|
+
continue;
|
|
116
|
+
const origin = this.originFor(entry);
|
|
117
|
+
if (origin && !this.coordinator.backgroundReady(origin, now))
|
|
118
|
+
continue;
|
|
119
|
+
if (!entry.inFlight && entry.nextEligible <= now)
|
|
120
|
+
void this.refresh(entry);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async refresh(entry) {
|
|
124
|
+
if (this.stopped || entry.inFlight)
|
|
125
|
+
return;
|
|
126
|
+
entry.inFlight = true;
|
|
127
|
+
entry.lastAttempt = Date.now();
|
|
128
|
+
const generation = entry.generation;
|
|
129
|
+
try {
|
|
130
|
+
let fallbackError;
|
|
131
|
+
let fallbackRetryAfter;
|
|
132
|
+
const raw = await this.actions.get(entry.config.urls[entry.actionName], entry.config, this.ownerFor(entry), entry.state, new Set(), (category, retryAfter) => { fallbackError = category; fallbackRetryAfter = retryAfter; });
|
|
133
|
+
if (this.stopped || generation !== entry.generation || (entry.pendingWrite && entry.pendingWrite.expires === undefined))
|
|
134
|
+
return;
|
|
135
|
+
// an unusable response (including a gateway timeout page) is not a broken mapper
|
|
136
|
+
if (raw === 'inconclusive')
|
|
137
|
+
throw new ActionError('inconclusive');
|
|
138
|
+
let value;
|
|
139
|
+
try {
|
|
140
|
+
value = entry.convert(raw);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
// valid mapping code can still receive a temporary non-value from an older server
|
|
144
|
+
if (error instanceof ActionError && error.category === 'mapper')
|
|
145
|
+
throw new ActionError('inconclusive');
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
// an error fallback is not confirmation of a command, even if its value matches
|
|
149
|
+
if (entry.pendingWrite && fallbackError)
|
|
150
|
+
throw new ActionError(fallbackError, fallbackRetryAfter);
|
|
151
|
+
if (entry.pendingWrite && (value === entry.pendingWrite.value || Date.now() >= entry.pendingWrite.expires))
|
|
152
|
+
delete entry.pendingWrite;
|
|
153
|
+
const changed = !entry.known || value !== entry.value;
|
|
154
|
+
entry.value = value;
|
|
155
|
+
entry.known = true;
|
|
156
|
+
if (!fallbackError)
|
|
157
|
+
entry.lastSuccess = Date.now();
|
|
158
|
+
// legacy on-demand state holds mapper output; polling converts only numeric HAP formats
|
|
159
|
+
entry.stateValue = entry.config.forceRefreshDelay && typeof value === 'number' ? value : raw;
|
|
160
|
+
entry.state[entry.actionName] = entry.stateValue;
|
|
161
|
+
if (changed) {
|
|
162
|
+
entry.lastChange = Date.now();
|
|
163
|
+
this.stats.changes++;
|
|
164
|
+
}
|
|
165
|
+
// also clear a prior HAP error without calling any setter
|
|
166
|
+
entry.update(entry.pendingWrite?.value ?? value);
|
|
167
|
+
this.dirty = true;
|
|
168
|
+
if (fallbackError)
|
|
169
|
+
throw new ActionError(fallbackError, fallbackRetryAfter);
|
|
170
|
+
this.persisted[entry.key] = { value, stateValue: entry.stateValue, lastSuccess: entry.lastSuccess, lastChange: entry.lastChange };
|
|
171
|
+
this.finishRecovery(entry);
|
|
172
|
+
entry.failures = 0;
|
|
173
|
+
entry.lastError = undefined;
|
|
174
|
+
entry.nextEligible = Date.now() + this.interval(entry) * (1 + Math.random() * 0.1);
|
|
175
|
+
if (entry.pendingWrite)
|
|
176
|
+
entry.nextEligible = Math.min(entry.nextEligible, Date.now() + 1000, entry.pendingWrite.expires);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (this.stopped || generation !== entry.generation)
|
|
180
|
+
return;
|
|
181
|
+
if (error instanceof ActionError && error.category === 'deferred') {
|
|
182
|
+
entry.nextEligible = Date.now() + Math.max(100, error.retryAfter ?? 0);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.expireWrite(entry, Date.now());
|
|
186
|
+
entry.failures++;
|
|
187
|
+
this.stats.failedRefreshes++;
|
|
188
|
+
entry.lastError = error instanceof ActionError ? error.category : 'mapper';
|
|
189
|
+
if (entry.lastError === 'mapper')
|
|
190
|
+
this.stats.mapperFailures++;
|
|
191
|
+
entry.nextEligible = Date.now() + Math.min(300000, Math.max(this.interval(entry), 1000) * 2 ** Math.min(entry.failures - 1, 8)) * (1 + Math.random() * 0.1);
|
|
192
|
+
if (temporaryFailure(entry.lastError)) {
|
|
193
|
+
this.pauseOrigin(entry, error instanceof ActionError ? error.retryAfter : undefined);
|
|
194
|
+
}
|
|
195
|
+
else if (entry.failures === 1) {
|
|
196
|
+
this.log.warn(`HTTP Advanced action ${entry.key.slice(0, 12)} ${entry.actionName}: ${entry.lastError}; keeping cached state where available; retrying in background`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
entry.inFlight = false;
|
|
201
|
+
// a SET that raced an old GET must be verified again after that GET leaves
|
|
202
|
+
if (generation !== entry.generation && !this.stopped)
|
|
203
|
+
entry.nextEligible = Date.now();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
ownerFor(entry) { return fingerprint(entry.config); }
|
|
207
|
+
originFor(entry) {
|
|
208
|
+
try {
|
|
209
|
+
return new URL(entry.config.urls[entry.actionName].url).origin;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
pauseOrigin(entry, retryAfter = 0) {
|
|
216
|
+
const origin = this.originFor(entry);
|
|
217
|
+
if (!origin)
|
|
218
|
+
return;
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
const recovery = this.recovering.get(origin) ?? { since: now, nextProbe: 0, attempts: 0, lastWarning: 0, category: entry.lastError };
|
|
221
|
+
// failures from requests already in flight belong to the same attempt
|
|
222
|
+
if (now >= recovery.nextProbe) {
|
|
223
|
+
recovery.attempts++;
|
|
224
|
+
recovery.nextProbe = now + Math.min((this.settings.recovery?.maxRetryInterval ?? 30) * 1000, (this.settings.recovery?.retryInterval ?? 5) * 1000 * 2 ** Math.min(recovery.attempts - 1, 20));
|
|
225
|
+
}
|
|
226
|
+
recovery.nextProbe = Math.max(recovery.nextProbe, now + retryAfter);
|
|
227
|
+
recovery.category = entry.lastError;
|
|
228
|
+
this.recovering.set(origin, recovery);
|
|
229
|
+
this.coordinator.pauseOrigin(origin, recovery.nextProbe);
|
|
230
|
+
entry.nextEligible = recovery.nextProbe;
|
|
231
|
+
this.reportRecovery(now);
|
|
232
|
+
}
|
|
233
|
+
reportRecovery(now) {
|
|
234
|
+
for (const [origin, recovery] of this.recovering) {
|
|
235
|
+
if (now - recovery.since < (this.settings.recovery?.quietPeriod ?? 90) * 1000 || (recovery.lastWarning && now - recovery.lastWarning < (this.settings.recovery?.reminderInterval ?? 300) * 1000))
|
|
236
|
+
continue;
|
|
237
|
+
recovery.lastWarning = now;
|
|
238
|
+
this.log.warn(`HTTP Advanced endpoint ${fingerprint(origin).slice(0, 12)}: waiting for usable responses for ${Math.round((now - recovery.since) / 1000)}s (${recovery.category}); keeping cached state where available; retrying one background request at a time`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
finishRecovery(entry) {
|
|
242
|
+
const origin = this.originFor(entry);
|
|
243
|
+
if (!origin)
|
|
244
|
+
return;
|
|
245
|
+
const recovery = this.recovering.get(origin);
|
|
246
|
+
if (!recovery)
|
|
247
|
+
return;
|
|
248
|
+
this.recovering.delete(origin);
|
|
249
|
+
this.coordinator.resumeOrigin(origin);
|
|
250
|
+
const message = `HTTP Advanced endpoint ${fingerprint(origin).slice(0, 12)}: responses recovered after ${Math.round((Date.now() - recovery.since) / 1000)}s; refreshing cached state`;
|
|
251
|
+
if (recovery.lastWarning)
|
|
252
|
+
this.log.info(message);
|
|
253
|
+
else
|
|
254
|
+
this.log.debug(message);
|
|
255
|
+
// a successful probe releases siblings from outage backoff, retaining normal queue limits
|
|
256
|
+
for (const sibling of this.entries.values()) {
|
|
257
|
+
if (temporaryFailure(sibling.lastError) && this.originFor(sibling) === origin) {
|
|
258
|
+
sibling.failures = 0;
|
|
259
|
+
sibling.lastError = undefined;
|
|
260
|
+
sibling.nextEligible = Date.now() + Math.random() * 1000;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
beginWrite(entry, value) {
|
|
265
|
+
const intent = { value: entry.convert(value) };
|
|
266
|
+
entry.generation++;
|
|
267
|
+
entry.pendingWrite = intent;
|
|
268
|
+
entry.lastDemand = Date.now();
|
|
269
|
+
return intent;
|
|
270
|
+
}
|
|
271
|
+
expireWrite(entry, now) {
|
|
272
|
+
if (entry.pendingWrite?.expires === undefined || now < entry.pendingWrite.expires)
|
|
273
|
+
return;
|
|
274
|
+
delete entry.pendingWrite;
|
|
275
|
+
this.publish(entry);
|
|
276
|
+
}
|
|
277
|
+
publish(entry) {
|
|
278
|
+
if (this.stopped)
|
|
279
|
+
return;
|
|
280
|
+
if (entry.pendingWrite?.expires !== undefined && Date.now() >= entry.pendingWrite.expires)
|
|
281
|
+
delete entry.pendingWrite;
|
|
282
|
+
entry.update(entry.pendingWrite?.value ?? (entry.known ? entry.value : undefined) ?? new ActionError('inconclusive'));
|
|
283
|
+
}
|
|
284
|
+
async set(config, state, actionName, value, entry, intent) {
|
|
285
|
+
if (this.stopped)
|
|
286
|
+
throw new ActionError('aborted');
|
|
287
|
+
const action = config.urls?.[actionName];
|
|
288
|
+
if (!action)
|
|
289
|
+
return;
|
|
290
|
+
intent ??= entry ? this.beginWrite(entry, value) : undefined;
|
|
291
|
+
try {
|
|
292
|
+
await this.actions.set(action, config, fingerprint(config), state, value);
|
|
293
|
+
if (entry && entry.pendingWrite === intent)
|
|
294
|
+
intent.expires = Date.now() + (config.writeConfirmationTimeout ?? this.settings.writeConfirmationTimeout ?? 10000);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
if (entry && entry.pendingWrite === intent) {
|
|
298
|
+
delete entry.pendingWrite;
|
|
299
|
+
this.publish(entry);
|
|
300
|
+
}
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
if (entry) {
|
|
305
|
+
// also invalidate reads started while the write was in progress
|
|
306
|
+
entry.generation++;
|
|
307
|
+
entry.nextEligible = Date.now();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
debounce(key, delay, work, onFailure) {
|
|
312
|
+
clearTimeout(this.setters.get(key));
|
|
313
|
+
const timer = setTimeout(() => {
|
|
314
|
+
this.setters.delete(key);
|
|
315
|
+
void work().catch(() => { this.log.warn('HTTP Advanced delayed SET failed'); onFailure?.(); });
|
|
316
|
+
}, delay);
|
|
317
|
+
this.setters.set(key, timer);
|
|
318
|
+
}
|
|
319
|
+
snapshot() {
|
|
320
|
+
const now = Date.now();
|
|
321
|
+
return { ...this.stats, queue: this.coordinator.queue.length, inFlight: this.coordinator.active.size, limits: this.coordinator.limits,
|
|
322
|
+
requests: { ...this.coordinator.stats, durations: [...this.coordinator.stats.durations] }, transport: { ...this.transport.stats },
|
|
323
|
+
cache: [...this.entries.values()].map(e => ({ id: e.key.slice(0, 12), known: e.known, age: e.known ? now - e.lastSuccess : null, failures: e.failures, lastError: e.lastError, nextRefresh: Math.max(0, e.nextEligible - now), inFlight: e.inFlight })),
|
|
324
|
+
recovering: [...this.recovering].map(([origin, recovery]) => ({ id: fingerprint(origin).slice(0, 12), age: now - recovery.since, nextProbe: Math.max(0, recovery.nextProbe - now), attempts: recovery.attempts, category: recovery.category })),
|
|
325
|
+
origins: [...this.coordinator.originStats].map(([origin, stats]) => ({ id: fingerprint(origin).slice(0, 12), ...stats, inFlight: this.coordinator.origins.get(origin) ?? 0 })) };
|
|
326
|
+
}
|
|
327
|
+
debugSnapshot() {
|
|
328
|
+
if ([...this.entries.values()].some(e => e.config.debug))
|
|
329
|
+
this.log.info(`HTTP Advanced diagnostics ${JSON.stringify(this.snapshot())}`);
|
|
330
|
+
}
|
|
331
|
+
persist() {
|
|
332
|
+
if (!this.savePath || !this.dirty)
|
|
333
|
+
return;
|
|
334
|
+
try {
|
|
335
|
+
mkdirSync(this.savePath, { recursive: true });
|
|
336
|
+
// separate hashed entries prevent one child bridge overwriting another's cache
|
|
337
|
+
for (const e of this.entries.values())
|
|
338
|
+
if (this.persisted[e.key]) {
|
|
339
|
+
const path = join(this.savePath, e.key + '.json');
|
|
340
|
+
const temporary = path + `.${process.pid}.tmp`;
|
|
341
|
+
writeFileSync(temporary, JSON.stringify(this.persisted[e.key]), { mode: 0o600 });
|
|
342
|
+
renameSync(temporary, path);
|
|
343
|
+
}
|
|
344
|
+
this.dirty = false;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
this.log.warn('HTTP Advanced could not persist state cache');
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
shutdown() {
|
|
351
|
+
this.stopped = true;
|
|
352
|
+
clearInterval(this.timer);
|
|
353
|
+
clearInterval(this.persistenceTimer);
|
|
354
|
+
for (const timer of this.setters.values())
|
|
355
|
+
clearTimeout(timer);
|
|
356
|
+
this.setters.clear();
|
|
357
|
+
this.transport.shutdown();
|
|
358
|
+
this.persist();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const runtimes = new WeakMap();
|
|
362
|
+
export function sharedRuntime(api, log) {
|
|
363
|
+
let runtime = runtimes.get(api);
|
|
364
|
+
if (!runtime) {
|
|
365
|
+
// Homebridge's Logging methods use their receiver's public prefix and log method
|
|
366
|
+
// copy them onto a separate callable so accessory-specific logging stays untouched
|
|
367
|
+
const sharedLog = Object.assign((message, ...parameters) => sharedLog.info(message, ...parameters), log, { prefix: 'HTTP Advanced' });
|
|
368
|
+
runtime = new Runtime(sharedLog, {}, api.user.persistPath(), readGlobalSettings(api, sharedLog));
|
|
369
|
+
runtimes.set(api, runtime);
|
|
370
|
+
const instance = runtime;
|
|
371
|
+
api.on('didFinishLaunching', () => { setImmediate(() => instance.start()); });
|
|
372
|
+
api.on('shutdown', () => instance.shutdown());
|
|
373
|
+
}
|
|
374
|
+
return runtime;
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { API, Logging } from 'homebridge';
|
|
2
|
+
import { ActionError, type CoordinatorConfig, type RefreshConfig } from './types.js';
|
|
3
|
+
export interface GlobalSettings {
|
|
4
|
+
requestTimeout?: number;
|
|
5
|
+
uriCallsDelay?: number;
|
|
6
|
+
setterDelay?: number;
|
|
7
|
+
writeConfirmationTimeout?: number;
|
|
8
|
+
refresh?: RefreshConfig;
|
|
9
|
+
coordinator?: CoordinatorConfig;
|
|
10
|
+
recovery?: {
|
|
11
|
+
retryInterval?: number;
|
|
12
|
+
maxRetryInterval?: number;
|
|
13
|
+
quietPeriod?: number;
|
|
14
|
+
reminderInterval?: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare class SettingsValidationError extends ActionError {
|
|
18
|
+
constructor(field: string, requirement: string);
|
|
19
|
+
}
|
|
20
|
+
export declare function validateSettings(value: unknown): asserts value is GlobalSettings;
|
|
21
|
+
export declare function readGlobalSettings(api: API, log: Logging): GlobalSettings;
|