TeaWeb/shared/js/settings.ts

782 lines
26 KiB
TypeScript
Raw Normal View History

import * as log from "./log";
import {LogCategory} from "./log";
2020-03-30 11:44:18 +00:00
import * as loader from "tc-loader";
import {Stage} from "tc-loader";
import {Registry} from "./events";
2018-03-24 22:38:01 +00:00
2020-08-09 12:30:17 +00:00
type ConfigValueTypes = boolean | number | string | object;
type ConfigValueTypeNames = "boolean" | "number" | "string" | "object";
type ValueTypeMapping<T> = T extends boolean ? "boolean" :
T extends number ? "number" :
T extends string ? "string" :
T extends object ? "object" : never;
2020-07-19 16:49:00 +00:00
export interface SettingsKey<ValueType extends ConfigValueTypes> {
2019-03-17 11:15:39 +00:00
key: string;
2020-08-09 12:30:17 +00:00
valueType: ValueTypeMapping<ValueType>;
2020-07-19 16:49:00 +00:00
defaultValue?: ValueType;
fallbackKeys?: string | string[];
fallbackImports?: {[key: string]:(value: string) => ValueType};
2019-03-17 11:15:39 +00:00
description?: string;
2019-08-21 08:00:01 +00:00
2020-07-19 16:49:00 +00:00
requireRestart?: boolean;
}
export interface ValuedSettingsKey<ValueType extends ConfigValueTypes> extends SettingsKey<ValueType> {
defaultValue: ValueType;
2019-03-17 11:15:39 +00:00
}
2020-07-19 16:49:00 +00:00
const kNoValuePresent = "--- no value present ---";
2020-03-30 11:44:18 +00:00
export class SettingsBase {
2019-04-04 19:47:52 +00:00
protected static readonly UPDATE_DIRECT: boolean = true;
2018-02-27 16:20:49 +00:00
2020-07-19 16:49:00 +00:00
protected static decodeValueFromString<T extends ConfigValueTypes, DT>(input: string | undefined, type: ConfigValueTypeNames, defaultValue: DT) : T | DT {
if(input === undefined || input === null)
return defaultValue;
switch (type) {
case "string":
return input as any;
case "boolean":
return (input === "1" || input === "true") as any;
2019-03-17 11:15:39 +00:00
2020-07-19 16:49:00 +00:00
case "number":
return parseFloat(input) as any;
2020-08-09 12:30:17 +00:00
case "object":
try {
return JSON.parse(input);
} catch (error) {
return {} as any;
}
2020-07-19 16:49:00 +00:00
default:
return defaultValue;
}
2018-04-19 17:46:47 +00:00
}
2020-07-19 16:49:00 +00:00
protected static encodeValueToString<T extends ConfigValueTypes>(input: T | undefined) : string | undefined {
if(input === undefined || input === null)
return undefined;
switch (typeof input) {
case "string":
return input;
case "boolean":
return input ? "1" : "0";
2018-02-27 16:20:49 +00:00
2020-07-19 16:49:00 +00:00
case "number":
return input.toString();
2020-08-09 12:30:17 +00:00
case "object":
return JSON.stringify(input);
2020-07-19 16:49:00 +00:00
default:
return undefined;
}
2018-04-19 17:46:47 +00:00
}
2018-02-27 16:20:49 +00:00
2020-07-19 16:49:00 +00:00
protected static resolveKey<ValueType extends ConfigValueTypes,
DefaultType>(key: SettingsKey<ValueType>,
resolver: (key: string) => string | undefined,
defaultValueType: ConfigValueTypeNames,
defaultValue: DefaultType) : ValueType | DefaultType {
2019-03-17 11:15:39 +00:00
let value = resolver(key.key);
2020-07-19 16:49:00 +00:00
if(value === undefined && key.fallbackKeys) {
/* trying fallback values */
for(const fallback of key.fallbackKeys) {
2019-03-17 11:15:39 +00:00
value = resolver(fallback);
2020-07-19 16:49:00 +00:00
if(value === undefined)
continue;
if(!key.fallbackImports)
2019-03-17 11:15:39 +00:00
break;
2020-07-19 16:49:00 +00:00
/* fallback key succeeded */
const fallbackValueImporter = key.fallbackImports[fallback];
if(fallbackValueImporter)
return fallbackValueImporter(value);
break;
2019-03-17 11:15:39 +00:00
}
}
2020-07-19 16:49:00 +00:00
return this.decodeValueFromString(value, defaultValueType, defaultValue) as any;
2019-03-17 11:15:39 +00:00
}
2019-04-04 19:47:52 +00:00
}
2020-03-30 11:44:18 +00:00
export class StaticSettings extends SettingsBase {
2019-04-04 19:47:52 +00:00
private static _instance: StaticSettings;
static get instance() : StaticSettings {
if(!this._instance)
this._instance = new StaticSettings(true);
return this._instance;
}
2019-03-17 11:15:39 +00:00
2018-04-19 17:46:47 +00:00
protected _handle: StaticSettings;
protected staticValues = {};
2018-04-16 18:38:35 +00:00
2018-04-19 17:46:47 +00:00
protected constructor(_reserved = undefined) {
2019-04-04 19:47:52 +00:00
super();
2018-04-19 17:46:47 +00:00
if(_reserved && !StaticSettings._instance) {
this.initializeStatic();
} else {
this._handle = StaticSettings.instance;
}
2018-04-16 18:38:35 +00:00
}
private initializeStatic() {
2019-04-04 19:47:52 +00:00
let search;
if(window.opener && window.opener !== window) {
search = new URL(window.location.href).search;
} else {
search = location.search;
}
search.substr(1).split("&").forEach(part => {
2018-04-16 18:38:35 +00:00
let item = part.split("=");
this.staticValues[item[0]] = decodeURIComponent(item[1]);
2018-04-16 18:38:35 +00:00
});
}
2020-07-19 16:49:00 +00:00
static<V extends ConfigValueTypes, DV>(key: SettingsKey<V>, defaultValue: DV) : V | DV;
static<V extends ConfigValueTypes>(key: ValuedSettingsKey<V>, defaultValue?: V) : V;
2018-02-27 16:20:49 +00:00
2020-07-19 16:49:00 +00:00
static<V extends ConfigValueTypes, DV>(key: SettingsKey<V>, defaultValue: DV) : V | DV {
2018-04-19 17:46:47 +00:00
if(this._handle) {
2020-07-19 16:49:00 +00:00
return this._handle.static<V, DV>(key, defaultValue);
2018-04-19 17:46:47 +00:00
}
2019-03-17 11:15:39 +00:00
return StaticSettings.resolveKey(key, key => this.staticValues[key], key.valueType, arguments.length > 1 ? defaultValue : key.defaultValue);
2018-04-19 17:46:47 +00:00
}
}
export interface SettingsEvents {
notify_setting_changed: {
setting: string,
mode: "global" | "server",
oldValue: string,
2020-09-07 10:42:00 +00:00
newValue: string,
newCastedValue: any
}
}
2020-03-30 11:44:18 +00:00
export class Settings extends StaticSettings {
2020-07-19 16:49:00 +00:00
static readonly KEY_USER_IS_NEW: ValuedSettingsKey<boolean> = {
2020-03-27 15:15:15 +00:00
key: 'user_is_new_user',
2020-07-19 16:49:00 +00:00
valueType: "boolean",
defaultValue: true
};
static readonly KEY_LOG_LEVEL: SettingsKey<number> = {
key: 'log.level',
valueType: "number"
2020-03-27 15:15:15 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_COSMETIC_SLOWDOWN: ValuedSettingsKey<boolean> = {
2019-06-26 12:06:20 +00:00
key: 'disable_cosmetic_slowdown',
2020-07-19 16:49:00 +00:00
description: 'Disable the cosmetic slowdows in some processes, like icon upload.',
valueType: "boolean",
defaultValue: false
2019-06-26 12:06:20 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_CONTEXT_MENU: ValuedSettingsKey<boolean> = {
2019-03-17 11:15:39 +00:00
key: 'disableContextMenu',
description: 'Disable the context menu for the channel tree which allows to debug the DOM easier',
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
2019-03-17 11:15:39 +00:00
};
2019-08-21 08:00:01 +00:00
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_GLOBAL_CONTEXT_MENU: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'disableGlobalContextMenu',
description: 'Disable the general context menu prevention',
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_UNLOAD_DIALOG: ValuedSettingsKey<boolean> = {
2019-03-17 11:15:39 +00:00
key: 'disableUnloadDialog',
2020-07-19 16:49:00 +00:00
description: 'Disables the unload popup on side closing',
valueType: "boolean",
defaultValue: false
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_VOICE: ValuedSettingsKey<boolean> = {
2019-03-17 11:15:39 +00:00
key: 'disableVoice',
2020-07-19 16:49:00 +00:00
description: 'Disables the voice bridge. If disabled, the audio and codec workers aren\'t required anymore',
valueType: "boolean",
defaultValue: false
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_DISABLE_MULTI_SESSION: ValuedSettingsKey<boolean> = {
2019-04-04 19:47:52 +00:00
key: 'disableMultiSession',
2020-07-19 16:49:00 +00:00
defaultValue: false,
requireRestart: true,
valueType: "boolean",
2019-04-04 19:47:52 +00:00
};
2019-03-17 11:15:39 +00:00
2020-07-19 16:49:00 +00:00
static readonly KEY_LOAD_DUMMY_ERROR: ValuedSettingsKey<boolean> = {
2019-03-25 19:04:04 +00:00
key: 'dummy_load_error',
2020-07-19 16:49:00 +00:00
description: 'Triggers a loading error at the end of the loading process.',
valueType: "boolean",
defaultValue: false
};
static readonly KEY_I18N_DEFAULT_REPOSITORY: ValuedSettingsKey<string> = {
key: 'i18n.default_repository',
valueType: "string",
defaultValue: "https://web.teaspeak.de/i18n/"
2019-03-25 19:04:04 +00:00
};
/* Default client states */
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_STATE_MICROPHONE_MUTED: ValuedSettingsKey<boolean> = {
key: 'client_state_microphone_muted',
2020-07-19 16:49:00 +00:00
defaultValue: false,
fallbackKeys: ["mute_input"],
valueType: "boolean",
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_STATE_SPEAKER_MUTED: ValuedSettingsKey<boolean> = {
key: 'client_state_speaker_muted',
2020-07-19 16:49:00 +00:00
defaultValue: false,
fallbackKeys: ["mute_output"],
valueType: "boolean",
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_STATE_QUERY_SHOWN: ValuedSettingsKey<boolean> = {
key: 'client_state_query_shown',
2020-07-19 16:49:00 +00:00
defaultValue: false,
fallbackKeys: ["show_server_queries"],
valueType: "boolean",
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_STATE_SUBSCRIBE_ALL_CHANNELS: ValuedSettingsKey<boolean> = {
key: 'client_state_subscribe_all_channels',
2020-07-19 16:49:00 +00:00
defaultValue: true,
fallbackKeys: ["channel_subscribe_all"],
valueType: "boolean",
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_STATE_AWAY: ValuedSettingsKey<boolean> = {
key: 'client_state_away',
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CLIENT_AWAY_MESSAGE: ValuedSettingsKey<string> = {
key: 'client_away_message',
2020-07-19 16:49:00 +00:00
defaultValue: "",
valueType: "string"
2019-03-17 11:15:39 +00:00
};
/* Connect parameters */
2020-07-19 16:49:00 +00:00
static readonly KEY_FLAG_CONNECT_DEFAULT: ValuedSettingsKey<boolean> = {
key: 'connect_default',
valueType: "boolean",
defaultValue: false
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CONNECT_ADDRESS: ValuedSettingsKey<string> = {
key: 'connect_address',
valueType: "string",
defaultValue: undefined
2019-03-17 11:15:39 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CONNECT_PROFILE: ValuedSettingsKey<string> = {
key: 'connect_profile',
2020-07-19 16:49:00 +00:00
defaultValue: 'default',
valueType: "string",
};
static readonly KEY_CONNECT_USERNAME: ValuedSettingsKey<string> = {
key: 'connect_username',
valueType: "string",
defaultValue: undefined
};
static readonly KEY_CONNECT_PASSWORD: ValuedSettingsKey<string> = {
key: 'connect_password',
valueType: "string",
defaultValue: undefined
};
static readonly KEY_FLAG_CONNECT_PASSWORD: ValuedSettingsKey<boolean> = {
key: 'connect_password_hashed',
valueType: "boolean",
defaultValue: false
};
static readonly KEY_CONNECT_HISTORY: ValuedSettingsKey<string> = {
key: 'connect_history',
valueType: "string",
defaultValue: ""
};
static readonly KEY_CONNECT_SHOW_HISTORY: ValuedSettingsKey<boolean> = {
key: 'connect_show_last_servers',
valueType: "boolean",
defaultValue: false
};
static readonly KEY_CONNECT_NO_SINGLE_INSTANCE: ValuedSettingsKey<boolean> = {
2020-06-15 14:56:05 +00:00
key: 'connect_no_single_instance',
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
2020-06-15 14:56:05 +00:00
};
2019-03-17 11:15:39 +00:00
2020-07-19 16:49:00 +00:00
static readonly KEY_CONNECT_NO_DNSPROXY: ValuedSettingsKey<boolean> = {
2019-11-24 00:16:07 +00:00
key: 'connect_no_dnsproxy',
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
2019-11-24 00:16:07 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CERTIFICATE_CALLBACK: ValuedSettingsKey<string> = {
key: 'certificate_callback',
valueType: "string",
defaultValue: undefined
2019-04-04 19:47:52 +00:00
};
2019-04-29 16:49:01 +00:00
/* sounds */
2020-07-19 16:49:00 +00:00
static readonly KEY_SOUND_MASTER: ValuedSettingsKey<number> = {
2019-08-21 08:00:01 +00:00
key: 'audio_master_volume',
2020-07-19 16:49:00 +00:00
defaultValue: 100,
valueType: "number",
2019-04-29 16:49:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_SOUND_MASTER_SOUNDS: ValuedSettingsKey<number> = {
2019-08-21 08:00:01 +00:00
key: 'audio_master_volume_sounds',
2020-07-19 16:49:00 +00:00
defaultValue: 100,
valueType: "number",
};
static readonly KEY_SOUND_VOLUMES: SettingsKey<string> = {
key: 'sound_volume',
valueType: "string",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_FIXED_TIMESTAMPS: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_fixed_timestamps',
2020-07-19 16:49:00 +00:00
defaultValue: false,
description: 'Enables fixed timestamps for chat messages and disabled the updating once (2 seconds ago... etc)',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_COLLOQUIAL_TIMESTAMPS: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_colloquial_timestamps',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Enabled colloquial timestamp formatting like "Yesterday at ..." or "Today at ..."',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_COLORED_EMOJIES: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_colored_emojies',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Enables colored emojies powered by Twemoji',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_TAG_URLS: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_tag_urls',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Automatically link urls with [url]',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_ENABLE_MARKDOWN: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_enable_markdown',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Enabled markdown chat support.',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_ENABLE_BBCODE: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'chat_enable_bbcode',
2020-07-19 16:49:00 +00:00
defaultValue: false,
description: 'Enabled bbcode support in chat.',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHAT_IMAGE_WHITELIST_REGEX: ValuedSettingsKey<string> = {
key: 'chat_image_whitelist_regex',
2020-07-19 16:49:00 +00:00
defaultValue: JSON.stringify([]),
valueType: "string",
};
2020-07-19 16:49:00 +00:00
static readonly KEY_SWITCH_INSTANT_CHAT: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'switch_instant_chat',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Directly switch to channel chat on channel select',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_SWITCH_INSTANT_CLIENT: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'switch_instant_client',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: 'Directly switch to client info on client select',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_HOSTBANNER_BACKGROUND: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'hostbanner_background',
2020-07-19 16:49:00 +00:00
defaultValue: false,
description: 'Enables a default background begind the hostbanner',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_CHANNEL_EDIT_ADVANCED: ValuedSettingsKey<boolean> = {
2019-08-21 08:00:01 +00:00
key: 'channel_edit_advanced',
2020-07-19 16:49:00 +00:00
defaultValue: false,
description: 'Edit channels in advanced mode with a lot more settings',
valueType: "boolean",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_PERMISSIONS_SHOW_ALL: ValuedSettingsKey<boolean> = {
key: 'permissions_show_all',
2020-07-19 16:49:00 +00:00
defaultValue: false,
description: 'Show all permissions even thou they dont make sense for the server/channel group',
valueType: "boolean",
};
2020-07-19 16:49:00 +00:00
static readonly KEY_TEAFORO_URL: ValuedSettingsKey<string> = {
2019-08-21 08:00:01 +00:00
key: "teaforo_url",
2020-07-19 16:49:00 +00:00
defaultValue: "https://forum.teaspeak.de/",
valueType: "string",
2019-08-21 08:00:01 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_FONT_SIZE: ValuedSettingsKey<number> = {
key: "font_size",
valueType: "number",
defaultValue: 14
2019-04-29 16:49:01 +00:00
};
2019-10-19 15:13:40 +00:00
2020-07-19 16:49:00 +00:00
static readonly KEY_ICON_SIZE: ValuedSettingsKey<number> = {
2019-10-19 15:13:40 +00:00
key: "icon_size",
2020-07-19 16:49:00 +00:00
defaultValue: 100,
valueType: "number",
2019-10-19 15:13:40 +00:00
};
2019-04-29 16:49:01 +00:00
2020-07-19 16:49:00 +00:00
static readonly KEY_KEYCONTROL_DATA: ValuedSettingsKey<string> = {
2020-04-10 18:57:50 +00:00
key: "keycontrol_data",
2020-07-19 16:49:00 +00:00
defaultValue: "{}",
valueType: "string",
2020-04-10 18:57:50 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_LAST_INVITE_LINK_TYPE: ValuedSettingsKey<string> = {
2019-10-13 19:33:07 +00:00
key: "last_invite_link_type",
2020-07-19 16:49:00 +00:00
defaultValue: "tea-web",
valueType: "string",
2019-10-13 19:33:07 +00:00
};
2020-07-19 16:49:00 +00:00
static readonly KEY_TRANSFERS_SHOW_FINISHED: ValuedSettingsKey<boolean> = {
key: 'transfers_show_finished',
2020-07-19 16:49:00 +00:00
defaultValue: true,
description: "Show finished file transfers in the file transfer list",
valueType: "boolean",
};
static readonly KEY_TRANSFER_DOWNLOAD_FOLDER: SettingsKey<string> = {
key: "transfer_download_folder",
description: "The download folder for the file transfer downloads",
2020-07-19 16:49:00 +00:00
valueType: "string",
/* defaultValue: <users download directory> */
};
static readonly KEY_IPC_REMOTE_ADDRESS: SettingsKey<string> = {
key: "ipc-address",
valueType: "string"
};
static readonly KEY_W2G_SIDEBAR_COLLAPSED: ValuedSettingsKey<boolean> = {
key: 'w2g_sidebar_collapsed',
defaultValue: false,
valueType: "boolean",
};
2020-09-07 10:42:00 +00:00
static readonly KEY_VOICE_ECHO_TEST_ENABLED: ValuedSettingsKey<boolean> = {
key: 'voice_echo_test_enabled',
defaultValue: true,
valueType: "boolean",
};
2020-07-19 16:49:00 +00:00
static readonly FN_LOG_ENABLED: (category: string) => SettingsKey<boolean> = category => {
return {
key: "log." + category.toLowerCase() + ".enabled",
valueType: "boolean",
}
};
static readonly FN_SEPARATOR_STATE: (separator: string) => SettingsKey<string> = separator => {
return {
key: "separator-settings-" + separator,
valueType: "string",
fallbackKeys: ["seperator-settings-" + separator]
}
};
static readonly FN_LOG_LEVEL_ENABLED: (category: string) => SettingsKey<boolean> = category => {
return {
key: "log.level." + category.toLowerCase() + ".enabled",
2020-08-09 12:30:17 +00:00
valueType: "boolean"
2020-07-19 16:49:00 +00:00
}
};
2019-10-13 19:33:07 +00:00
static readonly FN_INVITE_LINK_SETTING: (name: string) => SettingsKey<string> = name => {
return {
2020-07-19 16:49:00 +00:00
key: 'invite_link_setting_' + name,
valueType: "string",
2019-10-13 19:33:07 +00:00
}
};
2019-08-31 16:31:01 +00:00
static readonly FN_SERVER_CHANNEL_SUBSCRIBE_MODE: (channel_id: number) => SettingsKey<number> = channel => {
2019-03-17 11:15:39 +00:00
return {
2020-07-19 16:49:00 +00:00
key: 'channel_subscribe_mode_' + channel,
valueType: "number",
2019-03-17 11:15:39 +00:00
}
};
2020-07-19 16:49:00 +00:00
static readonly FN_SERVER_CHANNEL_COLLAPSED: (channel_id: number) => ValuedSettingsKey<boolean> = channel => {
2020-04-18 19:31:13 +00:00
return {
key: 'channel_collapsed_' + channel,
2020-07-19 16:49:00 +00:00
defaultValue: false,
valueType: "boolean",
2020-04-18 19:31:13 +00:00
}
};
2020-08-09 12:30:17 +00:00
static readonly FN_PROFILE_RECORD: (name: string) => SettingsKey<object> = name => {
return {
2020-07-19 16:49:00 +00:00
key: 'profile_record' + name,
2020-08-09 12:30:17 +00:00
valueType: "object",
}
};
static readonly FN_CHANNEL_CHAT_READ: (id: number) => SettingsKey<number> = id => {
return {
2020-07-19 16:49:00 +00:00
key: 'channel_chat_read_' + id,
valueType: "number",
}
};
static readonly FN_CLIENT_MUTED: (clientUniqueId: string) => SettingsKey<boolean> = clientUniqueId => {
return {
key: "client_" + clientUniqueId + "_muted",
valueType: "boolean",
fallbackKeys: ["mute_client_" + clientUniqueId]
}
};
static readonly FN_CLIENT_VOLUME: (clientUniqueId: string) => SettingsKey<number> = clientUniqueId => {
return {
key: "client_" + clientUniqueId + "_volume",
valueType: "number",
fallbackKeys: ["volume_client_" + clientUniqueId]
}
};
static readonly FN_EVENTS_NOTIFICATION_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "event_notification_" + event + "_enabled",
valueType: "boolean"
}
};
static readonly FN_EVENTS_LOG_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "event_log_" + event + "_enabled",
valueType: "boolean"
}
};
static readonly FN_EVENTS_FOCUS_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "event_focus_" + event + "_enabled",
valueType: "boolean"
}
};
2019-03-17 11:15:39 +00:00
static readonly KEYS = (() => {
const result = [];
2020-07-19 16:49:00 +00:00
for(const key of Object.keys(Settings)) {
2019-03-17 11:15:39 +00:00
if(!key.toUpperCase().startsWith("KEY_"))
continue;
result.push(key);
}
return result;
})();
2018-04-19 17:46:47 +00:00
2019-08-31 16:31:01 +00:00
static initialize() {
settings = new Settings();
(window as any).settings = settings;
(window as any).Settings = Settings;
2019-08-31 16:31:01 +00:00
}
readonly events: Registry<SettingsEvents>;
private readonly cacheGlobal = {};
private saveWorker: number;
2018-04-19 17:46:47 +00:00
private updated: boolean = false;
constructor() {
super();
this.events = new Registry<SettingsEvents>();
const json = localStorage.getItem("settings.global");
try {
this.cacheGlobal = JSON.parse(json);
} catch(error) {
log.error(LogCategory.GENERAL, tr("Failed to load global settings!\nJson: %s\nError: %o"), json, error);
const show_popup = () => {
//FIXME: Readd this
//createErrorModal(tr("Failed to load global settings"), tr("Failed to load global client settings!\nLookup console for more information.")).open();
};
if(!loader.finished())
loader.register_task(loader.Stage.LOADED, {
priority: 0,
name: "Settings error",
function: async () => show_popup()
});
else
show_popup();
}
2018-04-19 17:46:47 +00:00
if(!this.cacheGlobal) this.cacheGlobal = {};
this.saveWorker = setInterval(() => {
if(this.updated)
this.save();
}, 5 * 1000);
2018-04-16 18:38:35 +00:00
}
2020-07-19 16:49:00 +00:00
static_global<V extends ConfigValueTypes>(key: ValuedSettingsKey<V>, defaultValue?: V) : V;
static_global<V extends ConfigValueTypes, DV>(key: SettingsKey<V>, defaultValue: DV) : V | DV;
static_global<V extends ConfigValueTypes, DV>(key: SettingsKey<V> | ValuedSettingsKey<V>, defaultValue: DV) : V | DV {
const staticValue = this.static(key, kNoValuePresent);
if(staticValue !== kNoValuePresent)
return staticValue;
2019-08-21 08:00:01 +00:00
2020-07-19 16:49:00 +00:00
if(arguments.length > 1)
return this.global(key, defaultValue);
return this.global(key as ValuedSettingsKey<V>);
}
2020-07-19 16:49:00 +00:00
global<V extends ConfigValueTypes, DV>(key: SettingsKey<V>, defaultValue: DV) : V | DV;
global<V extends ConfigValueTypes>(key: ValuedSettingsKey<V>, defaultValue?: V) : V;
global<V extends ConfigValueTypes, DV>(key: SettingsKey<V>, defaultValue: DV) : V | DV {
return StaticSettings.resolveKey(key, key => this.cacheGlobal[key], key.valueType, arguments.length > 1 ? defaultValue : key.defaultValue);
2018-02-27 16:20:49 +00:00
}
2020-07-19 16:49:00 +00:00
changeGlobal<T extends ConfigValueTypes>(key: SettingsKey<T>, value?: T){
if(this.cacheGlobal[key.key] === value)
return;
2018-03-07 18:06:52 +00:00
2018-02-27 16:20:49 +00:00
this.updated = true;
const oldValue = this.cacheGlobal[key.key];
2020-07-19 16:49:00 +00:00
this.cacheGlobal[key.key] = StaticSettings.encodeValueToString(value);
this.events.fire("notify_setting_changed", {
mode: "global",
newValue: this.cacheGlobal[key.key],
oldValue: oldValue,
2020-09-07 10:42:00 +00:00
setting: key.key,
newCastedValue: value
});
2018-02-27 16:20:49 +00:00
if(Settings.UPDATE_DIRECT)
this.save();
}
2020-09-07 10:42:00 +00:00
globalChangeListener<T extends ConfigValueTypes>(key: SettingsKey<T>, listener: (newValue: T) => void) : () => void {
return this.events.on("notify_setting_changed", event => {
if(event.setting === key.key && event.mode === "global") {
listener(event.newCastedValue);
}
})
}
2019-04-04 19:47:52 +00:00
save() {
this.updated = false;
let global = JSON.stringify(this.cacheGlobal);
localStorage.setItem("settings.global", global);
2019-04-15 13:33:51 +00:00
if(localStorage.save)
localStorage.save();
2019-04-04 19:47:52 +00:00
}
}
2020-03-30 11:44:18 +00:00
export class ServerSettings extends SettingsBase {
2019-04-04 19:47:52 +00:00
private cacheServer = {};
2019-08-31 16:31:01 +00:00
private _server_unique_id: string;
private _server_save_worker: number;
2019-04-04 19:47:52 +00:00
private _server_settings_updated: boolean = false;
2019-08-21 08:00:01 +00:00
private _destroyed = false;
2019-04-04 19:47:52 +00:00
constructor() {
super();
this._server_save_worker = setInterval(() => {
if(this._server_settings_updated)
this.save();
}, 5 * 1000);
}
2019-08-21 08:00:01 +00:00
destroy() {
this._destroyed = true;
2019-08-31 16:31:01 +00:00
this._server_unique_id = undefined;
2019-08-21 08:00:01 +00:00
this.cacheServer = undefined;
clearInterval(this._server_save_worker);
this._server_save_worker = undefined;
}
2020-07-19 16:49:00 +00:00
server<V extends ConfigValueTypes, DV extends V | undefined = undefined>(key: SettingsKey<V>, defaultValue?: DV) : V | DV {
if(this._destroyed)
throw "destroyed";
return StaticSettings.resolveKey(key, key => this.cacheServer[key], key.valueType, arguments.length > 1 ? defaultValue : key.defaultValue);
2019-04-04 19:47:52 +00:00
}
2020-07-19 16:49:00 +00:00
changeServer<T extends ConfigValueTypes>(key: SettingsKey<T>, value?: T) {
2019-08-21 08:00:01 +00:00
if(this._destroyed) throw "destroyed";
2019-03-17 11:15:39 +00:00
2020-07-19 16:49:00 +00:00
if(this.cacheServer[key.key] === value)
return;
2018-03-07 18:06:52 +00:00
2019-04-04 19:47:52 +00:00
this._server_settings_updated = true;
2020-07-19 16:49:00 +00:00
this.cacheServer[key.key] = StaticSettings.encodeValueToString(value);
2018-02-27 16:20:49 +00:00
if(Settings.UPDATE_DIRECT)
this.save();
}
2019-08-31 16:31:01 +00:00
setServer(server_unique_id: string) {
2019-08-21 08:00:01 +00:00
if(this._destroyed) throw "destroyed";
2019-08-31 16:31:01 +00:00
if(this._server_unique_id) {
2018-04-16 18:38:35 +00:00
this.save();
2018-03-07 18:06:52 +00:00
this.cacheServer = {};
2019-08-31 16:31:01 +00:00
this._server_unique_id = undefined;
2018-04-16 18:38:35 +00:00
}
2019-08-31 16:31:01 +00:00
this._server_unique_id = server_unique_id;
2018-04-16 18:38:35 +00:00
2019-08-31 16:31:01 +00:00
if(this._server_unique_id) {
const json = localStorage.getItem("settings.server_" + server_unique_id);
try {
this.cacheServer = JSON.parse(json);
} catch(error) {
log.error(LogCategory.GENERAL, tr("Failed to load server settings for server %s!\nJson: %s\nError: %o"), server_unique_id, json, error);
}
2018-04-16 18:38:35 +00:00
if(!this.cacheServer)
this.cacheServer = {};
2018-03-07 18:06:52 +00:00
}
2018-02-27 16:20:49 +00:00
}
save() {
2019-08-21 08:00:01 +00:00
if(this._destroyed) throw "destroyed";
2019-04-04 19:47:52 +00:00
this._server_settings_updated = false;
2018-02-27 16:20:49 +00:00
2019-08-31 16:31:01 +00:00
if(this._server_unique_id) {
2018-03-07 18:06:52 +00:00
let server = JSON.stringify(this.cacheServer);
2019-08-31 16:31:01 +00:00
localStorage.setItem("settings.server_" + this._server_unique_id, server);
2019-04-15 13:33:51 +00:00
if(localStorage.save)
localStorage.save();
2018-03-07 18:06:52 +00:00
}
2018-02-27 16:20:49 +00:00
}
2019-08-31 16:31:01 +00:00
}
export let settings: Settings = null;
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
priority: 1000,
name: "Settings initialize",
function: async () => Settings.initialize()
})