UNPKG

4.95 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.IdentifierCache = void 0;
4const tslib_1 = require("tslib");
5const crypto_1 = tslib_1.__importDefault(require("crypto"));
6const util_1 = tslib_1.__importDefault(require("util"));
7const HAPStorage_1 = require("./HAPStorage");
8/**
9 * IdentifierCache is a model class that manages a system of associating HAP "Accessory IDs" and "Instance IDs"
10 * with other values that don't usually change. HomeKit Clients use Accessory/Instance IDs as a primary key of
11 * sorts, so the IDs need to remain "stable". For instance, if you create a HomeKit "Scene" called "Leaving Home"
12 * that sets your Alarm System's "Target Alarm State" Characteristic to "Arm Away", that Scene will store whatever
13 * "Instance ID" it was given for the "Target Alarm State" Characteristic. If the ID changes later on this server,
14 * the scene will stop working.
15 * @group Model
16 */
17class IdentifierCache {
18 username;
19 _cache = {}; // cache[key:string] = id:number
20 _usedCache = null; // for usage tracking and expiring old keys
21 _savedCacheHash = ""; // for checking if new cache need to be saved
22 constructor(username) {
23 this.username = username;
24 }
25 startTrackingUsage() {
26 this._usedCache = {};
27 }
28 stopTrackingUsageAndExpireUnused() {
29 // simply rotate in the new cache that was built during our normal getXYZ() calls.
30 this._cache = this._usedCache || this._cache;
31 this._usedCache = null;
32 }
33 getCache(key) {
34 const value = this._cache[key];
35 // track this cache item if needed
36 if (this._usedCache && typeof value !== "undefined") {
37 this._usedCache[key] = value;
38 }
39 return value;
40 }
41 setCache(key, value) {
42 this._cache[key] = value;
43 // track this cache item if needed
44 if (this._usedCache) {
45 this._usedCache[key] = value;
46 }
47 return value;
48 }
49 getAID(accessoryUUID) {
50 const key = accessoryUUID;
51 // ensure that our "next AID" field is not expired
52 this.getCache("|nextAID");
53 return this.getCache(key) || this.setCache(key, this.getNextAID());
54 }
55 getIID(accessoryUUID, serviceUUID, serviceSubtype, characteristicUUID) {
56 const key = accessoryUUID
57 + "|" + serviceUUID
58 + (serviceSubtype ? "|" + serviceSubtype : "")
59 + (characteristicUUID ? "|" + characteristicUUID : "");
60 // ensure that our "next IID" field for this accessory is not expired
61 this.getCache(accessoryUUID + "|nextIID");
62 return this.getCache(key) || this.setCache(key, this.getNextIID(accessoryUUID));
63 }
64 getNextAID() {
65 const key = "|nextAID";
66 const nextAID = this.getCache(key) || 2; // start at 2 because the root Accessory or Bridge must be 1
67 this.setCache(key, nextAID + 1); // increment
68 return nextAID;
69 }
70 getNextIID(accessoryUUID) {
71 const key = accessoryUUID + "|nextIID";
72 const nextIID = this.getCache(key) || 2; // iid 1 is reserved for the Accessory Information service
73 this.setCache(key, nextIID + 1); // increment
74 return nextIID;
75 }
76 save() {
77 const newCacheHash = crypto_1.default.createHash("sha1").update(JSON.stringify(this._cache)).digest("hex"); //calculate hash of new cache
78 if (newCacheHash !== this._savedCacheHash) { //check if cache need to be saved and proceed accordingly
79 const saved = {
80 cache: this._cache,
81 };
82 const key = IdentifierCache.persistKey(this.username);
83 HAPStorage_1.HAPStorage.storage().setItemSync(key, saved);
84 this._savedCacheHash = newCacheHash; //update hash of saved cache for future use
85 }
86 }
87 /**
88 * Persisting to File System
89 */
90 // Gets a key for storing this IdentifierCache in the filesystem, like "IdentifierCache.CC223DE3CEF3.json"
91 static persistKey(username) {
92 return util_1.default.format("IdentifierCache.%s.json", username.replace(/:/g, "").toUpperCase());
93 }
94 static load(username) {
95 const key = IdentifierCache.persistKey(username);
96 const saved = HAPStorage_1.HAPStorage.storage().getItem(key);
97 if (saved) {
98 const info = new IdentifierCache(username);
99 info._cache = saved.cache;
100 // calculate hash of the saved hash to decide in future if saving of new cache is needed
101 info._savedCacheHash = crypto_1.default.createHash("sha1").update(JSON.stringify(info._cache)).digest("hex");
102 return info;
103 }
104 else {
105 return null;
106 }
107 }
108 static remove(username) {
109 const key = this.persistKey(username);
110 HAPStorage_1.HAPStorage.storage().removeItemSync(key);
111 }
112}
113exports.IdentifierCache = IdentifierCache;
114//# sourceMappingURL=IdentifierCache.js.map
\No newline at end of file