UNPKG

@jsxc/jsxc

Version:

Real-time XMPP chat application with video calls, file transfer and encrypted communication

180 lines (137 loc) 5.21 kB
import Log from './util/Log'; import * as defaultOptions from './OptionsDefault'; import IStorage from './Storage.interface'; import Utils from '@util/Utils'; import Storage from './Storage'; import { IJID } from './JID.interface'; import Client from './Client'; const KEY = 'options'; interface IOptionData { [key: string]: any; } export default class Options { private static defaults: IOptionData = defaultOptions; public static overwriteDefaults(options: IOptionData) { let optionKeys = Object.keys(options); let defaultKeys = Object.keys(Options.defaults); let unknownOptionKeys = optionKeys.filter(e => defaultKeys.indexOf(e) < 0); if (optionKeys.indexOf('storage') > -1) { // We have to make sure the storage is already set before we call e.g. Log.warn. Options.defaults.storage = options.storage; } if (unknownOptionKeys.length > 0) { Log.warn("I don't know the following options and therefore I will ignore them.", unknownOptionKeys); for (let unknownKey of unknownOptionKeys) { delete options[unknownKey]; } } Object.assign(Options.defaults, options); } public static addDefaults(options: IOptionData) { let optionKeys = Object.keys(options); let defaultKeys = Object.keys(Options.defaults); let knownOptionKeys = optionKeys.filter(e => defaultKeys.indexOf(e) > -1); if (knownOptionKeys.length > 0) { Log.debug('I already know the following options: ', knownOptionKeys); for (let knownKey of knownOptionKeys) { delete options[knownKey]; } } Object.assign(Options.defaults, options); } public static async load(username: string, password: string, jid?: IJID) { if (typeof Options.defaults.loadOptions !== 'function') { return; } let optionData; try { optionData = await Options.defaults.loadOptions(username, password); } catch (err) { Log.warn('Error while loading options', err); return; } for (let id in optionData) { if ( id !== 'client' && id !== 'current' && jid && id !== jid.bare && !Client.getAccountManager().getAccount(id) ) { Log.info(`Skip option block with id "${id}"`); continue; } if (id === 'current') { if (!jid) { Log.info(`Skip option block with id "current", because no jid is provided`); continue; } id = jid.bare; } let storage = new Storage(id); let options = new Options(storage); for (let key in optionData[id]) { Log.debug(`Set option "${key}"`, optionData[id][key]); options.set(key, optionData[id][key], true); } storage.destroy(); } } public static getDefault(key: string) { return Options.defaults[key]; } constructor(private storage: IStorage) {} public getId(): string { return this.storage.getName() || 'client'; } public get(keyChain: string): any { function get(keys: string[], primary: any = {}, secondary: any = {}) { let key = keys.shift(); if (keys.length) { return get(keys, primary[key], secondary[key]); } else if (typeof primary[key] !== 'undefined') { return Utils.isObject(primary[key]) && Utils.isObject(secondary[key]) ? { ...secondary[key], ...primary[key] } : primary[key]; } else if (typeof secondary[key] !== 'undefined') { return secondary[key]; } Log.debug(`I don't know any "${keyChain}" option.`); return undefined; } return get(keyChain.split('.'), this.storage.getItem(KEY), Options.defaults); } public set(keyChain: string, value: any, preventOnChange: boolean = false) { let subKeys = keyChain.split('.'); let options = this.storage.getItem(KEY) || {}; function set(keys: string[], data: any = {}) { let key = keys.shift(); if (keys.length) { data[key] = set(keys, data[key]); } else { if (Utils.isObject(data[key]) && Utils.isObject(value)) { Utils.mergeDeep(data[key], value); } else { data[key] = value; } } return data; } this.storage.setItem(KEY, set(subKeys, options)); if (typeof Options.defaults.onOptionChange === 'function' && !preventOnChange) { Options.defaults.onOptionChange(this.getId(), keyChain, value, () => this.export()); } } public registerHook(key: string, func: (newValue: any, oldValue?: any) => void) { this.storage.registerHook(KEY, (newData, oldData) => { let n = newData[key]; let o = oldData && typeof oldData[key] !== 'undefined' ? oldData[key] : Options.defaults[key]; if (n !== o) { func(n, o); } }); } public export(): IOptionData { return this.storage.getItem(KEY) || {}; } }