TeaWeb/shared/js/ui/server.ts

419 lines
17 KiB
TypeScript
Raw Normal View History

2020-03-30 13:44:18 +02:00
import {ChannelTree} from "tc-shared/ui/view";
import {Settings, settings} from "tc-shared/settings";
import * as contextmenu from "tc-shared/ui/elements/ContextMenu";
import * as log from "tc-shared/log";
import {LogCategory, LogType} from "tc-shared/log";
import {Sound} from "tc-shared/sound/Sounds";
import * as bookmarks from "tc-shared/bookmarks";
import {spawnInviteEditor} from "tc-shared/ui/modal/ModalInvite";
import {openServerInfo} from "tc-shared/ui/modal/ModalServerInfo";
import {createServerModal} from "tc-shared/ui/modal/ModalServerEdit";
import {spawnIconSelect} from "tc-shared/ui/modal/ModalIconSelect";
import {spawnAvatarList} from "tc-shared/ui/modal/ModalAvatarList";
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
import {control_bar} from "tc-shared/ui/frames/ControlBar";
import {connection_log} from "tc-shared/ui/modal/ModalConnect";
import * as top_menu from "./frames/MenuBar";
export class ServerProperties {
2018-08-11 15:02:11 +02:00
virtualserver_host: string = "";
virtualserver_port: number = 0;
virtualserver_name: string = "";
2018-08-13 13:06:42 +02:00
virtualserver_name_phonetic: string = "";
virtualserver_icon_id: number = 0;
virtualserver_version: string = "unknown";
virtualserver_platform: string = "unknown";
virtualserver_unique_identifier: string = "";
virtualserver_clientsonline: number = 0;
virtualserver_queryclientsonline: number = 0;
virtualserver_channelsonline: number = 0;
virtualserver_uptime: number = 0;
2019-08-30 23:06:39 +02:00
virtualserver_created: number = 0;
2018-08-11 15:02:11 +02:00
virtualserver_maxclients: number = 0;
virtualserver_reserved_slots: number = 0;
virtualserver_password: string = "";
virtualserver_flag_password: boolean = false;
2019-08-21 10:00:01 +02:00
virtualserver_ask_for_privilegekey: boolean = false;
2018-08-11 15:02:11 +02:00
virtualserver_welcomemessage: string = "";
virtualserver_hostmessage: string = "";
virtualserver_hostmessage_mode: number = 0;
virtualserver_hostbanner_url: string = "";
virtualserver_hostbanner_gfx_url: string = "";
virtualserver_hostbanner_gfx_interval: number = 0;
virtualserver_hostbanner_mode: number = 0;
virtualserver_hostbutton_tooltip: string = "";
virtualserver_hostbutton_url: string = "";
virtualserver_hostbutton_gfx_url: string = "";
2018-08-13 13:06:42 +02:00
virtualserver_codec_encryption_mode: number = 0;
virtualserver_default_music_group: number = 0;
2018-08-13 13:06:42 +02:00
virtualserver_default_server_group: number = 0;
virtualserver_default_channel_group: number = 0;
virtualserver_default_channel_admin_group: number = 0;
//Special requested properties
virtualserver_default_client_description: string = "";
virtualserver_default_channel_description: string = "";
virtualserver_default_channel_topic: string = "";
virtualserver_antiflood_points_tick_reduce: number = 0;
virtualserver_antiflood_points_needed_command_block: number = 0;
virtualserver_antiflood_points_needed_ip_block: number = 0;
2018-08-13 13:06:42 +02:00
2019-08-21 10:00:01 +02:00
virtualserver_country_code: string = "XX";
2018-08-13 13:06:42 +02:00
virtualserver_complain_autoban_count: number = 0;
virtualserver_complain_autoban_time: number = 0;
virtualserver_complain_remove_time: number = 0;
virtualserver_needed_identity_security_level: number = 8;
virtualserver_weblist_enabled: boolean = false;
virtualserver_min_clients_in_channel_before_forced_silence: number = 0;
2019-08-21 10:00:01 +02:00
virtualserver_channel_temp_delete_delay_default: number = 60;
virtualserver_priority_speaker_dimm_modificator: number = -18;
2018-11-04 14:20:38 +01:00
virtualserver_max_upload_total_bandwidth: number = 0;
virtualserver_upload_quota: number = 0;
virtualserver_max_download_total_bandwidth: number = 0;
virtualserver_download_quota: number = 0;
2019-08-21 10:00:01 +02:00
virtualserver_month_bytes_downloaded: number = 0;
virtualserver_month_bytes_uploaded: number = 0;
virtualserver_total_bytes_downloaded: number = 0;
virtualserver_total_bytes_uploaded: number = 0;
}
2020-03-30 13:44:18 +02:00
export interface ServerConnectionInfo {
2019-08-21 10:00:01 +02:00
connection_filetransfer_bandwidth_sent: number;
connection_filetransfer_bandwidth_received: number;
connection_filetransfer_bytes_sent_total: number;
connection_filetransfer_bytes_received_total: number;
connection_filetransfer_bytes_sent_month: number;
connection_filetransfer_bytes_received_month: number;
connection_packets_sent_total: number;
connection_bytes_sent_total: number;
connection_packets_received_total: number;
connection_bytes_received_total: number;
connection_bandwidth_sent_last_second_total: number;
connection_bandwidth_sent_last_minute_total: number;
connection_bandwidth_received_last_second_total: number;
connection_bandwidth_received_last_minute_total: number;
connection_connected_time: number;
connection_packetloss_total: number;
connection_ping: number;
}
2020-03-30 13:44:18 +02:00
export interface ServerAddress {
host: string;
port: number;
}
2020-03-30 13:44:18 +02:00
export class ServerEntry {
remote_address: ServerAddress;
2018-02-27 17:20:49 +01:00
channelTree: ChannelTree;
properties: ServerProperties;
2018-02-27 17:20:49 +01:00
private info_request_promise: Promise<void> = undefined;
private info_request_promise_resolve: any = undefined;
private info_request_promise_reject: any = undefined;
2019-08-21 10:00:01 +02:00
private _info_connection_promise: Promise<ServerConnectionInfo>;
private _info_connection_promise_timestamp: number;
private _info_connection_promise_resolve: any;
private _info_connection_promise_reject: any;
2018-02-27 17:20:49 +01:00
lastInfoRequest: number = 0;
nextInfoRequest: number = 0;
private _htmlTag: JQuery<HTMLElement>;
2019-08-21 10:00:01 +02:00
private _destroyed = false;
2018-02-27 17:20:49 +01:00
constructor(tree, name, address: ServerAddress) {
this.properties = new ServerProperties();
2018-02-27 17:20:49 +01:00
this.channelTree = tree;
2019-08-21 10:00:01 +02:00
this.remote_address = Object.assign({}, address); /* close the address because it might get changed due to the DNS resolve */
2018-02-27 17:20:49 +01:00
this.properties.virtualserver_name = name;
}
get htmlTag() {
2019-08-21 10:00:01 +02:00
if(this._destroyed) throw "destoryed";
2018-02-27 17:20:49 +01:00
if(this._htmlTag) return this._htmlTag;
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
2019-02-17 16:08:10 +01:00
let tag = $.spawn("div").addClass("tree-entry server");
2019-09-19 01:25:57 +02:00
/* unread marker */
{
tag.append(
$.spawn("div")
.addClass("marker-text-unread hidden")
.attr("conversation", 0)
);
}
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
2019-02-17 16:08:10 +01:00
tag.append(
$.spawn("div")
.addClass("server_type icon client-server_green")
);
tag.append(
$.spawn("div")
.addClass("name")
.text(this.properties.virtualserver_name)
);
tag.append(
$.spawn("div")
.addClass("icon_property icon_empty")
);
2018-02-27 17:20:49 +01:00
return this._htmlTag = tag;
}
2019-08-21 10:00:01 +02:00
destroy() {
this._destroyed = true;
if(this._htmlTag) {
this._htmlTag.remove();
this._htmlTag = undefined;
}
this.info_request_promise = undefined;
this.info_request_promise_resolve = undefined;
this.info_request_promise_reject = undefined;
this.channelTree = undefined;
this.remote_address = undefined;
}
2018-02-27 17:20:49 +01:00
initializeListener(){
2019-09-12 23:59:35 +02:00
this._htmlTag.on('click' ,() => {
this.channelTree.onSelect(this);
2019-09-12 23:59:35 +02:00
this.updateProperties(); /* just prepare to show some server info */
2018-02-27 17:20:49 +01:00
});
2018-04-16 20:38:35 +02:00
if(!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) {
this.htmlTag.on("contextmenu", (event) => {
2018-04-16 20:38:35 +02:00
event.preventDefault();
if($.isArray(this.channelTree.currently_selected)) { //Multiselect
(this.channelTree.currently_selected_context_callback || ((_) => null))(event);
return;
}
this.channelTree.onSelect(this, true);
this.spawnContextMenu(event.pageX, event.pageY, () => { this.channelTree.onSelect(undefined, true); });
2018-04-16 20:38:35 +02:00
});
}
2018-02-27 17:20:49 +01:00
}
2018-04-16 20:38:35 +02:00
spawnContextMenu(x: number, y: number, on_close: () => void = () => {}) {
2019-03-07 15:30:53 +01:00
let trigger_close = true;
contextmenu.spawn_context_menu(x, y, {
type: contextmenu.MenuEntryType.ENTRY,
2019-03-07 15:30:53 +01:00
name: tr("Show server info"),
callback: () => {
trigger_close = false;
2020-03-30 13:44:18 +02:00
openServerInfo(this);
2019-03-07 15:30:53 +01:00
},
2019-08-30 23:06:39 +02:00
icon_class: "client-about"
}, {
type: contextmenu.MenuEntryType.ENTRY,
icon_class: "client-invite_buddy",
name: tr("Invite buddy"),
2020-03-30 13:44:18 +02:00
callback: () => spawnInviteEditor(this.channelTree.client)
2019-08-30 23:06:39 +02:00
}, {
type: contextmenu.MenuEntryType.HR,
name: ''
2019-08-21 10:00:01 +02:00
}, {
type: contextmenu.MenuEntryType.ENTRY,
icon_class: "client-channel_switch",
name: tr("Join server text channel"),
callback: () => {
this.channelTree.client.side_bar.channel_conversations().set_current_channel(0);
this.channelTree.client.side_bar.show_channel_conversations();
},
visible: !settings.static_global(Settings.KEY_SWITCH_INSTANT_CHAT)
2019-03-07 15:30:53 +01:00
}, {
type: contextmenu.MenuEntryType.ENTRY,
icon_class: "client-virtualserver_edit",
name: tr("Edit"),
2018-08-11 15:02:11 +02:00
callback: () => {
2020-03-30 13:44:18 +02:00
createServerModal(this, properties => {
log.info(LogCategory.SERVER, tr("Changing server properties %o"), properties);
console.log(tr("Changed properties: %o"), properties);
2019-08-21 10:00:01 +02:00
if (properties) {
if(Object.keys(properties)) {
return this.channelTree.client.serverConnection.send_command("serveredit", properties).then(() => {
this.channelTree.client.sound.play(Sound.SERVER_EDITED_SELF);
});
}
}
return Promise.resolve();
2018-08-11 15:02:11 +02:00
});
}
2019-08-30 23:06:39 +02:00
}, {
type: contextmenu.MenuEntryType.HR,
visible: true,
name: ''
2019-03-25 20:04:04 +01:00
}, {
type: contextmenu.MenuEntryType.ENTRY,
icon_class: "client-iconviewer",
2019-03-25 20:04:04 +01:00
name: tr("View icons"),
2020-03-30 13:44:18 +02:00
callback: () => spawnIconSelect(this.channelTree.client)
2019-03-25 20:04:04 +01:00
}, {
type: contextmenu.MenuEntryType.ENTRY,
icon_class: 'client-iconsview',
2019-03-25 20:04:04 +01:00
name: tr("View avatars"),
2019-10-13 21:33:07 +02:00
visible: false, //TODO: Enable again as soon the new design is finished
2020-03-30 13:44:18 +02:00
callback: () => spawnAvatarList(this.channelTree.client)
2018-02-27 17:20:49 +01:00
},
2019-09-01 17:24:06 +02:00
contextmenu.Entry.CLOSE(() => trigger_close ? on_close() : {})
2018-02-27 17:20:49 +01:00
);
}
updateVariables(is_self_notify: boolean, ...variables: {key: string, value: string}[]) {
let group = log.group(log.LogType.DEBUG, LogCategory.SERVER, tr("Update properties (%i)"), variables.length);
2019-03-25 20:04:04 +01:00
{
const entries = [];
for(const variable of variables)
entries.push({
key: variable.key,
value: variable.value,
type: typeof (this.properties[variable.key])
});
2019-08-30 23:06:39 +02:00
log.table(LogType.DEBUG, LogCategory.PERMISSIONS, "Server update properties", entries);
2019-03-25 20:04:04 +01:00
}
2019-08-21 10:00:01 +02:00
let update_bannner = false, update_button = false;
for(let variable of variables) {
2018-08-10 21:30:58 +02:00
JSON.map_field_to(this.properties, variable.value, variable.key);
if(variable.key == "virtualserver_name") {
this.htmlTag.find(".name").text(variable.value);
2019-04-04 21:47:52 +02:00
this.channelTree.client.tag_connection_handler.find(".server-name").text(variable.value);
server_connections.update_ui();
} else if(variable.key == "virtualserver_icon_id") {
2019-04-25 20:21:50 +02:00
/* For more detail lookup client::updateVariables and client_icon_id!
* ATTENTION: This is required!
*/
this.properties.virtualserver_icon_id = variable.value as any >>> 0;
2019-08-21 10:00:01 +02:00
const bmarks = bookmarks.bookmarks_flat()
.filter(e => e.server_properties.server_address === this.remote_address.host && e.server_properties.server_port == this.remote_address.port)
.filter(e => e.last_icon_id !== this.properties.virtualserver_icon_id);
if(bmarks.length > 0) {
bmarks.forEach(e => {
e.last_icon_id = this.properties.virtualserver_icon_id;
});
bookmarks.save_bookmark();
top_menu.rebuild_bookmarks();
control_bar.update_bookmarks();
}
if(this.channelTree.client.fileManager && this.channelTree.client.fileManager.icons)
this.htmlTag.find(".icon_property").replaceWith(this.channelTree.client.fileManager.icons.generateTag(this.properties.virtualserver_icon_id).addClass("icon_property"));
} else if(variable.key.indexOf('hostbanner') != -1) {
update_bannner = true;
2019-08-21 10:00:01 +02:00
} else if(variable.key.indexOf('hostbutton') != -1) {
update_button = true;
}
2018-02-27 17:20:49 +01:00
}
if(update_bannner)
2019-08-21 10:00:01 +02:00
this.channelTree.client.hostbanner.update();
if(update_button)
if(control_bar.current_connection_handler() === this.channelTree.client)
control_bar.apply_server_hostbutton();
group.end();
if(is_self_notify && this.info_request_promise_resolve) {
this.info_request_promise_resolve();
this.info_request_promise = undefined;
this.info_request_promise_reject = undefined;
this.info_request_promise_resolve = undefined;
}
2019-08-21 10:00:01 +02:00
connection_log.update_address_info({
hostname: this.remote_address.host,
port: this.remote_address.port
}, {
clients_online: this.properties.virtualserver_clientsonline,
clients_total: this.properties.virtualserver_maxclients,
country: this.properties.virtualserver_country_code,
flag_password: this.properties.virtualserver_flag_password,
name: this.properties.virtualserver_name,
icon_id: this.properties.virtualserver_icon_id,
password_hash: undefined /* we've here no clue */
});
2018-02-27 17:20:49 +01:00
}
2019-08-21 10:00:01 +02:00
/* this result !must! be cached for at least a second */
updateProperties() : Promise<void> {
if(this.info_request_promise && Date.now() - this.lastInfoRequest < 1000) return this.info_request_promise;
this.lastInfoRequest = Date.now();
2018-02-27 17:20:49 +01:00
this.nextInfoRequest = this.lastInfoRequest + 10 * 1000;
2019-02-23 14:15:22 +01:00
this.channelTree.client.serverConnection.send_command("servergetvariables").catch(error => {
this.info_request_promise_reject(error);
this.info_request_promise = undefined;
this.info_request_promise_reject = undefined;
this.info_request_promise_resolve = undefined;
});
return this.info_request_promise = new Promise<void>((resolve, reject) => {
this.info_request_promise_reject = reject;
this.info_request_promise_resolve = resolve;
});
2018-02-27 17:20:49 +01:00
}
2019-08-21 10:00:01 +02:00
/* max 1s ago, so we could update every second */
request_connection_info() : Promise<ServerConnectionInfo> {
if(Date.now() - 900 < this._info_connection_promise_timestamp && this._info_connection_promise)
return this._info_connection_promise;
if(this._info_connection_promise_reject)
this._info_connection_promise_resolve("timeout");
let _local_reject; /* to ensure we're using the right resolve! */
this._info_connection_promise = new Promise<ServerConnectionInfo>((resolve, reject) => {
this._info_connection_promise_resolve = resolve;
this._info_connection_promise_reject = reject;
_local_reject = reject;
});
this._info_connection_promise_timestamp = Date.now();
2019-08-30 23:06:39 +02:00
this.channelTree.client.serverConnection.send_command("serverrequestconnectioninfo", {}, {process_result: false}).catch(error => _local_reject(error));
2019-08-21 10:00:01 +02:00
return this._info_connection_promise;
}
set_connection_info(info: ServerConnectionInfo) {
if(!this._info_connection_promise_resolve)
return;
this._info_connection_promise_resolve(info);
this._info_connection_promise_resolve = undefined;
this._info_connection_promise_reject = undefined;
}
2018-02-27 17:20:49 +01:00
shouldUpdateProperties() : boolean {
2018-04-30 23:57:21 +02:00
return this.nextInfoRequest < Date.now();
2018-02-27 17:20:49 +01:00
}
calculateUptime() : number {
if(this.properties.virtualserver_uptime == 0 || this.lastInfoRequest == 0) return this.properties.virtualserver_uptime;
return this.properties.virtualserver_uptime + (new Date().getTime() - this.lastInfoRequest) / 1000;
2018-02-27 17:20:49 +01:00
}
2019-09-19 01:25:57 +02:00
set flag_text_unread(flag: boolean) {
this._htmlTag.find(".marker-text-unread").toggleClass("hidden", !flag);
}
2018-02-27 17:20:49 +01:00
}