node-red-contrib-smartnora
Version:
Google Smart Home integration via Smart Nora https://smart-nora.eu/
139 lines (138 loc) • 5.67 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const app_1 = require("firebase/app");
const auth_1 = require("firebase/auth");
const database_1 = require("firebase/database");
const rxjs_1 = require("rxjs");
const config_1 = require("./config");
const ENCODE_MAP = new Map([
['.', '%2E'],
['#', '%23'],
['$', '%24'],
['[', '%5B'],
[']', '%5D'],
['/', '%2F'],
]);
const DECODE_MAP = new Map([
['%2E', '.'],
['%23', '#'],
['%24', '$'],
['%5B', '['],
['%5D', ']'],
['%2F', '/'],
]);
class FirebaseContextStorage {
constructor(config) {
this.config = config;
this.context = {};
}
async open() {
this.close();
const get$ = new rxjs_1.Observable(observer => {
const app = (0, app_1.initializeApp)(config_1.FIREBASE_CONFIG, 'app-context');
observer.next(app);
return () => (0, app_1.deleteApp)(app);
}).pipe((0, rxjs_1.switchMap)(async (app) => {
var _a;
const auth = (0, auth_1.getAuth)(app);
const { user } = await (0, auth_1.signInWithEmailAndPassword)(auth, this.config.email, this.config.password);
this.db = (0, database_1.getDatabase)(app);
this.contextReferece = (0, database_1.ref)(this.db, `context_store/${user.uid}/${this.encode((_a = this.config.group) !== null && _a !== void 0 ? _a : 'default')}`);
return this.contextReferece;
}), (0, rxjs_1.switchMap)(ctxRef => new rxjs_1.Observable(observer => (0, database_1.onValue)(ctxRef, data => {
var _a;
this.context = (_a = data.val()) !== null && _a !== void 0 ? _a : {};
observer.next(this.context);
}))), (0, rxjs_1.retry)({
delay: _err => (0, rxjs_1.timer)(5000),
}), (0, rxjs_1.share)());
const subscription = get$.subscribe();
await (0, rxjs_1.firstValueFrom)(get$);
this.cleanup = () => subscription.unsubscribe();
}
close() {
var _a;
(_a = this === null || this === void 0 ? void 0 : this.cleanup) === null || _a === void 0 ? void 0 : _a.call(this);
delete this.cleanup;
}
get(scope, key, callback) {
const getValue = (singleKey) => { var _a; return this.parse((_a = this.context[this.encode(scope)]) === null || _a === void 0 ? void 0 : _a[this.encode(singleKey)]); };
if (Array.isArray(key)) {
const values = key.map(k => getValue(k));
callback === null || callback === void 0 ? void 0 : callback(null, ...values);
return values;
}
else {
const value = getValue(key);
callback === null || callback === void 0 ? void 0 : callback(null, value);
return value;
}
}
set(scope, key, value, callback) {
const encodedScope = this.encode(scope);
const scopeUpdate = {};
const updateValue = (singleKey, singleValue) => {
var _a, _b;
var _c;
const encodedKey = this.encode(singleKey);
if (singleValue === null || singleValue === undefined) {
scopeUpdate[encodedKey] = null;
(_a = this.context[encodedScope]) === null || _a === void 0 ? true : delete _a[encodedKey];
}
else {
singleValue = JSON.stringify(singleValue);
(_b = (_c = this.context)[encodedScope]) !== null && _b !== void 0 ? _b : (_c[encodedScope] = {});
this.context[encodedScope][encodedKey] = singleValue;
scopeUpdate[encodedKey] = singleValue;
}
};
if (Array.isArray(key)) {
for (const [index, k] of key.entries()) {
updateValue(k, value[index]);
}
}
else {
updateValue(key, value);
}
const reference = (0, database_1.child)(this.contextReferece, encodedScope);
(0, database_1.update)(reference, scopeUpdate)
.then(() => callback === null || callback === void 0 ? void 0 : callback(null))
.catch(err => callback === null || callback === void 0 ? void 0 : callback(err));
}
keys(scope, callback) {
var _a;
const encodedScope = this.encode(scope);
const keys = Object.keys((_a = this.context[encodedScope]) !== null && _a !== void 0 ? _a : {}).map(k => this.decode(k));
callback === null || callback === void 0 ? void 0 : callback(null, keys);
return keys;
}
async delete(scope) {
const encodedScope = this.encode(scope);
const reference = (0, database_1.child)(this.contextReferece, encodedScope);
delete this.context[encodedScope];
await (0, database_1.remove)(reference);
}
async clean(activeNodes) {
const keepScopes = ['global', ...activeNodes].map(n => this.encode(n));
const scopes = Object.keys(this.context)
.filter(key => !keepScopes.some(e => key.startsWith(e)));
await Promise.all(scopes.map(scope => this.delete(scope)));
}
encode(value) {
return value.replace(/[/.#$[\]]/g, m => { var _a; return (_a = ENCODE_MAP.get(m)) !== null && _a !== void 0 ? _a : m; });
}
decode(value) {
return value.replace(/%[\dA-F]{2}/g, m => { var _a; return (_a = DECODE_MAP.get(m)) !== null && _a !== void 0 ? _a : m; });
}
parse(value) {
try {
return value && JSON.parse(value);
}
catch (_a) {
return null;
}
}
}
module.exports = function (config) {
return new FirebaseContextStorage(config);
};