Also applied the new selected info structure for ServerEntity and ChannelEntity

This commit is contained in:
WolverinDEV 2018-06-20 21:05:35 +02:00
parent 6bb0179958
commit 31d8b7a56c
12 changed files with 387 additions and 291 deletions

10
css/frame/SelectInfo.css Normal file
View file

@ -0,0 +1,10 @@
.select_info_table { }
.select_info_table tr { }
.select_info_table tr td {
}
.select_info_table tr td:nth-child(1) {
font-weight: bold;
padding-right: 5px;
min-width: 20%;
}

View file

@ -103,11 +103,6 @@
flex-direction: column; flex-direction: column;
} }
.info_key {
font-weight: bold;
padding-right: 5px;
}
/* The Modal (background) */ /* The Modal (background) */
.modal { .modal {
display: none; /* Hidden by default */ display: none; /* Hidden by default */

View file

@ -31,6 +31,7 @@
<link rel="stylesheet" href="css/modals.css" type="text/css"> <link rel="stylesheet" href="css/modals.css" type="text/css">
<link rel="stylesheet" href="css/loader.css" type="text/css"> <link rel="stylesheet" href="css/loader.css" type="text/css">
<link rel="stylesheet" href="css/music/info_plate.css" type="text/css"> <link rel="stylesheet" href="css/music/info_plate.css" type="text/css">
<link rel="stylesheet" href="css/frame/SelectInfo.css" type="text/css">
<!-- https://localhost:9987/?forward_url=http%3A%2F%2Flocalhost%3A63344%2FWeb-Client%2Findex.php%3F_ijt%3D82b1uhmnh0a5l1n35nnjps5eid%26loader_ignore_age%3D1%26connect_default_host%3Dlocalhost%26default_connect_type%3Dforum%26default_connect_url%3Dtrue%26default_connect_type%3Dteamspeak%26default_connect_url%3Dlocalhost%253A9987 --> <!-- https://localhost:9987/?forward_url=http%3A%2F%2Flocalhost%3A63344%2FWeb-Client%2Findex.php%3F_ijt%3D82b1uhmnh0a5l1n35nnjps5eid%26loader_ignore_age%3D1%26connect_default_host%3Dlocalhost%26default_connect_type%3Dforum%26default_connect_url%3Dtrue%26default_connect_type%3Dteamspeak%26default_connect_url%3Dlocalhost%253A9987 -->
<!-- PHP generated properies --> <!-- PHP generated properies -->

View file

@ -227,7 +227,7 @@ class FileManager {
transfer.remotePort = json["port"]; transfer.remotePort = json["port"];
transfer.remoteHost = (json["ip"] ? json["ip"] : "").replace(/,/g, ""); transfer.remoteHost = (json["ip"] ? json["ip"] : "").replace(/,/g, "");
if(!transfer.remoteHost || transfer.remoteHost == '0.0.0.0' || transfer.remoteHost == '127.168.0.0') if(!transfer.remoteHost || transfer.remoteHost == '0.0.0.0' || transfer.remoteHost == '127.168.0.0')
transfer.remoteHost = this.handle.serverConnection._remoteHost; transfer.remoteHost = this.handle.serverConnection._remote_address.host;
(transfer["_promiseCallback"] as (val: DownloadFileTransfer) => void)(transfer); (transfer["_promiseCallback"] as (val: DownloadFileTransfer) => void)(transfer);
this.pendingDownloadTransfers.remove(transfer); this.pendingDownloadTransfers.remove(transfer);

View file

@ -91,8 +91,8 @@ class TSClient {
port = 9987; port = 9987;
} }
console.log("Start connection to " + host + ":" + port); console.log("Start connection to " + host + ":" + port);
this.channelTree.initialiseHead(addr); this.channelTree.initialiseHead(addr, {host, port});
this.serverConnection.startConnection(host, port, new HandshakeHandler(identity, name)); this.serverConnection.startConnection({host, port}, new HandshakeHandler(identity, name));
} }
@ -145,9 +145,9 @@ class TSClient {
callback += "&default_connect_type=teamspeak"; callback += "&default_connect_type=teamspeak";
break; break;
} }
callback += "&default_connect_url=" + encodeURIComponent(this.serverConnection._remoteHost + ":" + this.serverConnection._remotePort); callback += "&default_connect_url=" + encodeURIComponent(this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port);
return "https://" + this.serverConnection._remoteHost + ":" + this.serverConnection._remotePort + "/?forward_url=" + encodeURIComponent(callback); return "https://" + this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port + "/?forward_url=" + encodeURIComponent(callback);
} }
handleDisconnect(type: DisconnectReason, data: any = {}) { handleDisconnect(type: DisconnectReason, data: any = {}) {

View file

@ -31,8 +31,7 @@ class ReturnListener<T> {
class ServerConnection { class ServerConnection {
_client: TSClient; _client: TSClient;
_remoteHost: string; _remote_address: ServerAddress;
_remotePort: number;
_socket: WebSocket; _socket: WebSocket;
_connectionState: ConnectionState = ConnectionState.UNCONNECTED; _connectionState: ConnectionState = ConnectionState.UNCONNECTED;
_handshakeHandler: HandshakeHandler; _handshakeHandler: HandshakeHandler;
@ -62,19 +61,18 @@ class ServerConnection {
return (this._retCodeIdx++).toString(); return (this._retCodeIdx++).toString();
} }
startConnection(host : string, port : number, handshake: HandshakeHandler, timeout: number = 1000) { startConnection(address : ServerAddress, handshake: HandshakeHandler, timeout: number = 1000) {
if(this._connectTimeoutHandler) { if(this._connectTimeoutHandler) {
clearTimeout(this._connectTimeoutHandler); clearTimeout(this._connectTimeoutHandler);
this._connectTimeoutHandler = null; this._connectTimeoutHandler = null;
this.disconnect(); this.disconnect();
} }
this.updateConnectionState(ConnectionState.CONNECTING); this.updateConnectionState(ConnectionState.CONNECTING);
this._remoteHost = host; this._remote_address = address;
this._remotePort = port;
this._handshakeHandler = handshake; this._handshakeHandler = handshake;
this._handshakeHandler.setConnection(this); this._handshakeHandler.setConnection(this);
this._connected = false; this._connected = false;
chat.serverChat().appendMessage("Connecting to " + host + ":" + port); chat.serverChat().appendMessage("Connecting to " + address.host + ":" + address.port);
const self = this; const self = this;
try { try {
@ -83,7 +81,7 @@ class ServerConnection {
this._client.handleDisconnect(DisconnectReason.CONNECT_FAILURE); this._client.handleDisconnect(DisconnectReason.CONNECT_FAILURE);
}, timeout); }, timeout);
let sockCpy; let sockCpy;
this._socket = (sockCpy = new WebSocket('wss:' + this._remoteHost + ":" + this._remotePort)); this._socket = (sockCpy = new WebSocket('wss:' + address.host + ":" + address.port));
clearTimeout(this._connectTimeoutHandler); clearTimeout(this._connectTimeoutHandler);
this._connectTimeoutHandler = null; this._connectTimeoutHandler = null;
if(this._socket != sockCpy) return; //Connect timeouted if(this._socket != sockCpy) return; //Connect timeouted
@ -375,11 +373,19 @@ class ConnectionCommandHandler {
this.connection._client.clientId = parseInt(json["aclid"]); this.connection._client.clientId = parseInt(json["aclid"]);
this.connection._client.getClient().updateVariables({key: "client_nickname", value: json["acn"]}); this.connection._client.getClient().updateVariables({key: "client_nickname", value: json["acn"]});
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) { for(let key in json) {
if(key === "aclid") continue; if(key === "aclid") continue;
if(key === "acn") continue; if(key === "acn") continue;
this.connection._client.channelTree.server.updateProperty(key, json[key]);
updates.push({key: key, value: json[key]});
} }
this.connection._client.channelTree.server.updateVariables(...updates);
chat.serverChat().name = this.connection._client.channelTree.server.properties["virtualserver_name"]; chat.serverChat().name = this.connection._client.channelTree.server.properties["virtualserver_name"];
chat.serverChat().appendMessage("Connected as {0}", true, this.connection._client.getClient().createChatTag(true)); chat.serverChat().appendMessage("Connected as {0}", true, this.connection._client.getClient().createChatTag(true));
globalClient.onConnected(); globalClient.onConnected();
@ -712,27 +718,39 @@ class ConnectionCommandHandler {
handleNotifyServerEdited(json) { handleNotifyServerEdited(json) {
json = json[0]; json = json[0];
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) { for(let key in json) {
if(key === "invokerid") continue; if(key === "invokerid") continue;
if(key === "invokername") continue; if(key === "invokername") continue;
if(key === "invokeruid") continue; if(key === "invokeruid") continue;
if(key === "reasonid") continue; if(key === "reasonid") continue;
this.connection._client.channelTree.server.updateProperty(key, json[key]); updates.push({key: key, value: json[key]});
} }
this.connection._client.channelTree.server.updateVariables(...updates);
if(this.connection._client.selectInfo.currentSelected == this.connection._client.channelTree.server)
this.connection._client.selectInfo.update();
} }
handleNotifyServerUpdated(json) { handleNotifyServerUpdated(json) {
json = json[0]; json = json[0];
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) { for(let key in json) {
if(key === "invokerid") continue; if(key === "invokerid") continue;
if(key === "invokername") continue; if(key === "invokername") continue;
if(key === "invokeruid") continue; if(key === "invokeruid") continue;
if(key === "reasonid") continue; if(key === "reasonid") continue;
this.connection._client.channelTree.server.updateProperty(key, json[key]); updates.push({key: key, value: json[key]});
} }
this.connection._client.channelTree.server.updateVariables(...updates);
let info = this.connection._client.selectInfo; let info = this.connection._client.selectInfo;
if(info.currentSelected instanceof ServerEntry) if(info.currentSelected instanceof ServerEntry)
info.update(); info.update();

View file

@ -1,6 +1,7 @@
enum LogCategory { enum LogCategory {
CHANNEL, CHANNEL,
CLIENT, CLIENT,
SERVER,
PERMISSIONS, PERMISSIONS,
GENERAL, GENERAL,
NETWORKING NETWORKING
@ -18,6 +19,7 @@ namespace log {
let category_mapping = new Map<number, string>([ let category_mapping = new Map<number, string>([
[LogCategory.CHANNEL, "Channel "], [LogCategory.CHANNEL, "Channel "],
[LogCategory.CLIENT, "Client "], [LogCategory.CLIENT, "Client "],
[LogCategory.SERVER, "Server "],
[LogCategory.PERMISSIONS, "Permission "], [LogCategory.PERMISSIONS, "Permission "],
[LogCategory.GENERAL, "General "], [LogCategory.GENERAL, "General "],
[LogCategory.NETWORKING, "Network "] [LogCategory.NETWORKING, "Network "]

View file

@ -7,10 +7,13 @@ interface Array<T> {
interface JQuery { interface JQuery {
tmpl(values?: any) : JQuery; tmpl(values?: any) : JQuery;
render(values?: any) : string;
renderTag(values?: any) : JQuery;
} }
interface JQueryStatic<TElement extends Node = HTMLElement> { interface JQueryStatic<TElement extends Node = HTMLElement> {
spawn<K extends keyof HTMLElementTagNameMap>(tagName: K): JQuery<HTMLElementTagNameMap[K]>; spawn<K extends keyof HTMLElementTagNameMap>(tagName: K): JQuery<HTMLElementTagNameMap[K]>;
views: any;
} }
@ -51,12 +54,11 @@ if(typeof ($) !== "undefined") {
return $(document.createElement(tagName)); return $(document.createElement(tagName));
} }
} }
if(!$.prototype.tmpl) { if(!$.prototype.renderTag) {
$.prototype.tmpl = function (values?: any) : JQuery { $.prototype.renderTag = function (values?: any) : JQuery {
return this.render(values); return $(this.render(values));
} }
} }
} }
if (!String.prototype.format) { if (!String.prototype.format) {

View file

@ -5,21 +5,21 @@ abstract class InfoManagerBase {
private intervals: number[] = []; private intervals: number[] = [];
protected resetTimers() { protected resetTimers() {
for(let interval of this.intervals) for(let timer of this.timers)
clearInterval(interval); clearTimeout(timer);
} }
protected resetIntervals() { protected resetIntervals() {
for(let timer of this.timers) for(let interval of this.intervals)
clearTimeout(timer); clearInterval(interval);
} }
protected registerTimer(timer: NodeJS.Timer) { protected registerTimer(timer: NodeJS.Timer) {
this.timers.push(timer); this.timers.push(timer);
} }
protected registerInterval(interval: number) { protected registerInterval<T extends number | NodeJS.Timer>(interval: T) {
this.intervals.push(interval); this.intervals.push(interval as number);
} }
abstract available<V>(object: V) : boolean; abstract available<V>(object: V) : boolean;
@ -41,9 +41,6 @@ class InfoBar {
private current_selected?: ServerEntry | ChannelEntry | ClientEntry; private current_selected?: ServerEntry | ChannelEntry | ClientEntry;
private _htmlTag: JQuery<HTMLElement>; private _htmlTag: JQuery<HTMLElement>;
private timers: NodeJS.Timer[] = [];
private intervals: number[] = [];
private current_manager: InfoManagerBase = undefined; private current_manager: InfoManagerBase = undefined;
private managers: InfoManagerBase[] = []; private managers: InfoManagerBase[] = [];
@ -52,31 +49,30 @@ class InfoBar {
this._htmlTag = htmlTag; this._htmlTag = htmlTag;
this.managers.push(new ClientInfoManager()); this.managers.push(new ClientInfoManager());
this.managers.push(new ChannelInfoManager());
this.managers.push(new ServerInfoManager());
//TODO music client
/*
this._htmlTag.append("Im a music bot!");
let frame = $("#tmpl_music_frame" + (this.current_selected.properties.music_track_id == 0 ? "_empty" : "")).tmpl({
thumbnail: "img/loading_image.svg"
}).css("align-self", "center");
if(this.current_selected.properties.music_track_id == 0) {
} else {
} }
this._htmlTag.append(frame);
private createInfoTable(infos: any) : JQuery<HTMLElement> { */
let table = $.spawn("table");
for(let key in infos) {
console.log("Display info " + key);
let entry = $.spawn("tr");
entry.append($.spawn("td").addClass("info_key").html(key + ":"));
let value = $.spawn("td");
console.log(infos[key]);
console.log( MessageHelper.formatElement(infos[key]));
MessageHelper.formatElement(infos[key]).forEach(e => e.appendTo(value));
entry.append(value);
table.append(entry);
}
return table;
} }
setCurrentSelected<T extends ServerEntry | ChannelEntry | ClientEntry | undefined>(entry: T) { setCurrentSelected<T extends ServerEntry | ChannelEntry | ClientEntry | undefined>(entry: T) {
if(this.current_selected == entry) return; if(this.current_selected == entry) return;
if(this.current_manager) { if(this.current_manager) {
this.current_manager.finalizeFrame.call(this.current_manager, this.current_selected, this._htmlTag); (this.current_manager as InfoManager<undefined>).finalizeFrame.call(this.current_manager, this.current_selected, this._htmlTag);
this.current_manager = null; this.current_manager = null;
this.current_selected = null; this.current_selected = null;
} }
@ -90,10 +86,9 @@ class InfoBar {
} }
} }
console.log("Got info manager: %o", this.current_manager); console.log("Using info manager: %o", this.current_manager);
if(this.current_manager) { if(this.current_manager)
this.current_manager.createFrame.call(this.current_manager, this.current_selected, this._htmlTag); (this.current_manager as InfoManager<undefined>).createFrame.call(this.current_manager, this.current_selected, this._htmlTag);
} else this.buildBar(); //FIXME Remove that this is just for now (because not all types are implemented)
} }
get currentSelected() { get currentSelected() {
@ -102,204 +97,7 @@ class InfoBar {
update(){ update(){
if(this.current_manager && this.current_selected) if(this.current_manager && this.current_selected)
this.current_manager.updateFrame.call(this.current_manager, this.current_selected, this._htmlTag); (this.current_manager as InfoManager<undefined>).updateFrame.call(this.current_manager, this.current_selected, this._htmlTag);
}
private updateServerTimings() {
this._htmlTag.find(".uptime").text(formatDate((this.current_selected as ServerEntry).calculateUptime()));
}
private updateClientTimings() {
this._htmlTag.find(".online").text(formatDate((this.current_selected as ClientEntry).calculateOnlineTime()));
}
private buildBar() {
this._htmlTag.empty();
if(!this.current_selected) return;
if(this.current_selected instanceof ServerEntry) {
if(this.current_selected.shouldUpdateProperties()) this.current_selected.updateProperties();
let version = this.current_selected.properties.virtualserver_version;
if(version.startsWith("TeaSpeak ")) version = version.substr("TeaSpeak ".length);
this._htmlTag.append(this.createInfoTable({
"Name": this.current_selected.properties.virtualserver_name,
"Address": "unknown",
"Type": "TeaSpeak",
"Version": version + " on " + this.current_selected.properties.virtualserver_platform,
"Uptime": "<a class='uptime'>" + formatDate(this.current_selected.calculateUptime()) + "</a>",
"Current Channels": this.current_selected.properties.virtualserver_channelsonline,
"Current Clients": this.current_selected.properties.virtualserver_clientsonline,
"Current Queries": this.current_selected.properties.virtualserver_queryclientsonline
}));
this._htmlTag.append($.spawn("div").css("height", "100%"));
let requestUpdate = $.spawn("button");
requestUpdate.css("min-height", "16px");
requestUpdate.css("bottom", 0);
requestUpdate.text("update info");
if(this.current_selected.shouldUpdateProperties())
requestUpdate.css("color", "green");
else {
requestUpdate.attr("disabled", "true");
requestUpdate.css("color", "red");
}
this._htmlTag.append(requestUpdate);
const _server : ServerEntry = this.current_selected;
const _this = this;
requestUpdate.click(function () {
_server.updateProperties();
_this.buildBar();
});
this.timers.push(setTimeout(function () {
requestUpdate.css("color", "green");
requestUpdate.removeAttr("disabled");
}, _server.nextInfoRequest - new Date().getTime()));
this.intervals.push(setInterval(this.updateServerTimings.bind(this),1000));
} else if(this.current_selected instanceof ChannelEntry) {
let props = this.current_selected.properties;
this._htmlTag.append(this.createInfoTable({
"Name": this.current_selected.createChatTag(),
"Topic": this.current_selected.properties.channel_topic,
"Codec": this.current_selected.properties.channel_codec,
"Codec Quality": this.current_selected.properties.channel_codec_quality,
"Type": ChannelType.normalize(this.current_selected.channelType()),
"Current clients": this.current_selected.channelTree.clientsByChannel(this.current_selected).length + " / " + (props.channel_maxclients == -1 ? "Unlimited" : props.channel_maxclients),
"Subscription Status": "unknown",
"Voice Data Encryption": "unknown"
}));
} else if(this.current_selected instanceof MusicClientEntry) {
this._htmlTag.append("Im a music bot!");
let frame = $("#tmpl_music_frame" + (this.current_selected.properties.music_track_id == 0 ? "_empty" : "")).tmpl({
thumbnail: "img/loading_image.svg"
}).css("align-self", "center");
if(this.current_selected.properties.music_track_id == 0) {
} else {
}
this._htmlTag.append(frame);
//TODO
} else if(this.current_selected instanceof ClientEntry) {
this.current_selected.updateClientVariables();
let version: string = this.current_selected.properties.client_version;
if(!version) version = "";
let infos = {
"Name": this.current_selected.createChatTag(),
"Description": this.current_selected.properties.client_description,
"Version": MessageHelper.formatMessage("{0} on {1}", $.spawn("a").attr("title", version).text(version.split(" ")[0]), this.current_selected.properties.client_platform),
"Online since": $.spawn("a").addClass("online").text(formatDate(this.current_selected.calculateOnlineTime())),
"Volume": this.current_selected.audioController.volume * 100 + " %"
};
if(this.current_selected.properties.client_teaforum_id > 0) {
infos["TeaSpeak Account"] = $.spawn("a")
.attr("href", "//forum.teaspeak.de/index.php?members/" + this.current_selected.properties.client_teaforum_id)
.attr("target", "_blank")
.text(this.current_selected.properties.client_teaforum_id);
}
this._htmlTag.append(this.createInfoTable(infos));
{
let serverGroups = $.spawn("div");
serverGroups
.css("display", "flex")
.css("flex-direction", "column");
let header = $.spawn("div");
header
.css("display", "flex")
.css("margin-top", "5px")
.css("align-items", "center");
$.spawn("div").addClass("icon client-permission_server_groups").appendTo(header);
$.spawn("div").text("Server groups:").css("margin-left", "3px").css("font-weight", "bold").appendTo(header);
header.appendTo(serverGroups);
for(let groupId of this.current_selected.assignedServerGroupIds()) {
let group = this.handle.groups.serverGroup(groupId);
if(!group) continue;
let groupTag = $.spawn("div");
groupTag
.css("display", "flex")
.css("margin-top", "1px")
.css("margin-left", "10px")
.css("align-items", "center");
this.handle.fileManager.icons.generateTag(group.properties.iconid).appendTo(groupTag);
$.spawn("div").text(group.name).css("margin-left", "3px").appendTo(groupTag);
groupTag.appendTo(serverGroups);
}
this._htmlTag.append(serverGroups);
}
{
let channelGroup = $.spawn("div");
channelGroup
.css("display", "flex")
.css("flex-direction", "column")
.css("margin-bottom", "20px");
let header = $.spawn("div");
header
.css("display", "flex")
.css("margin-top", "10px")
.css("align-items", "center");
$.spawn("div").addClass("icon client-permission_channel").appendTo(header);
$.spawn("div").text("Channel group:").css("margin-left", "3px").css("font-weight", "bold").appendTo(header);
header.appendTo(channelGroup);
let group = this.handle.groups.channelGroup(this.current_selected.assignedChannelGroup());
if(group) {
let groupTag = $.spawn("div");
groupTag
.css("display", "flex")
.css("margin-top", "1px")
.css("margin-left", "10px")
.css("align-items", "center");
this.handle.fileManager.icons.generateTag(group.properties.iconid).appendTo(groupTag);
$.spawn("div").text(group.name)
.css("margin-left", "3px").appendTo(groupTag);
groupTag.appendTo(channelGroup);
}
this._htmlTag.append(channelGroup);
}
{
if(this.current_selected.properties.client_flag_avatar.length > 0)
this.handle.fileManager.avatars.generateTag(this.current_selected)
.css("max-height", "90%")
.css("max-width", "100%").appendTo(this._htmlTag);
}
{
let spawnTag = (type: string, description: string) : JQuery => {
return $.spawn("div").css("display", "inline-flex")
.append($.spawn("div").addClass("icon_x32 client-" + type).css("margin-right", "5px"))
.append($.spawn("a").text(description).css("align-self", "center"));
};
if(!this.current_selected.properties.client_output_hardware)
spawnTag("hardware_output_muted", "Speakers/Headphones disabled").appendTo(this._htmlTag);
if(!this.current_selected.properties.client_input_hardware)
spawnTag("hardware_input_muted", "Microphone disabled").appendTo(this._htmlTag);
if(this.current_selected.properties.client_output_muted)
spawnTag("output_muted", "Speakers/Headphones Muted").appendTo(this._htmlTag);
if(this.current_selected.properties.client_input_muted)
spawnTag("input_muted", "Microphone Muted").appendTo(this._htmlTag);
}
this.intervals.push(setInterval(this.updateClientTimings.bind(this),1000));
}
} }
} }
@ -314,13 +112,10 @@ class ClientInfoManager extends InfoManager<ClientEntry> {
} }
updateFrame(client: ClientEntry, html_tag: JQuery<HTMLElement>) { updateFrame(client: ClientEntry, html_tag: JQuery<HTMLElement>) {
this.resetIntervals();
html_tag.empty(); html_tag.empty();
let properties: any = {}; let properties: any = {};
let version: string = client.properties.client_version;
if(!version) version = "";
properties["client_name"] = client.createChatTag()[0]; properties["client_name"] = client.createChatTag()[0];
properties["client_onlinetime"] = formatDate(client.calculateOnlineTime()); properties["client_onlinetime"] = formatDate(client.calculateOnlineTime());
properties["sound_volume"] = client.audioController.volume * 100; properties["sound_volume"] = client.audioController.volume * 100;
@ -355,9 +150,100 @@ class ClientInfoManager extends InfoManager<ClientEntry> {
.text(client.properties.client_teaforum_id); .text(client.properties.client_teaforum_id);
} }
let rendered = $($("#tmpl_selected_client").render([properties])); let rendered = $("#tmpl_selected_client").renderTag([properties]);
rendered.find("node").each((index, element) => { $(element).replaceWith(properties[$(element).attr("key")]); }); rendered.find("node").each((index, element) => { $(element).replaceWith(properties[$(element).attr("key")]); });
html_tag.append(rendered); html_tag.append(rendered);
console.log(properties);
this.registerInterval(setInterval(() => {
html_tag.find(".update_onlinetime").text(formatDate(client.calculateOnlineTime()));
}, 1000));
} }
} }
class ServerInfoManager extends InfoManager<ServerEntry> {
createFrame(server: ServerEntry, html_tag: JQuery<HTMLElement>) {
if(server.shouldUpdateProperties()) server.updateProperties();
this.updateFrame(server, html_tag);
}
updateFrame(server: ServerEntry, html_tag: JQuery<HTMLElement>) {
this.resetIntervals();
html_tag.empty();
let properties: any = {};
properties["server_name"] = $.spawn("a").text(server.properties.virtualserver_name);
properties["server_onlinetime"] = formatDate(server.calculateUptime());
properties["server_address"] = server.remote_address.host + ":" + server.remote_address.port;
for(let key in server.properties)
properties["property_" + key] = server.properties[key];
let rendered = $("#tmpl_selected_server").renderTag([properties]);
rendered.find("node").each((index, element) => { $(element).replaceWith(properties[$(element).attr("key")]); });
html_tag.append(rendered);
this.registerInterval(setInterval(() => {
html_tag.find(".update_onlinetime").text(formatDate(server.calculateUptime()));
}, 1000));
//TODO update button
/*
let requestUpdate = $.spawn("button");
requestUpdate.css("min-height", "16px");
requestUpdate.css("bottom", 0);
requestUpdate.text("update info");
if(this.current_selected.shouldUpdateProperties())
requestUpdate.css("color", "green");
else {
requestUpdate.attr("disabled", "true");
requestUpdate.css("color", "red");
}
this._htmlTag.append(requestUpdate);
const _server : ServerEntry = this.current_selected;
const _this = this;
requestUpdate.click(function () {
_server.updateProperties();
_this.buildBar();
});
this.timers.push(setTimeout(function () {
requestUpdate.css("color", "green");
requestUpdate.removeAttr("disabled");
}, _server.nextInfoRequest - new Date().getTime()));
*/
}
available<V>(object: V): boolean {
return typeof object == "object" && object instanceof ServerEntry;
}
}
class ChannelInfoManager extends InfoManager<ChannelEntry> {
createFrame(channel: ChannelEntry, html_tag: JQuery<HTMLElement>) {
this.updateFrame(channel, html_tag);
}
updateFrame(channel: ChannelEntry, html_tag: JQuery<HTMLElement>) {
this.resetIntervals();
html_tag.empty();
let properties: any = {};
properties["channel_name"] = channel.createChatTag();
properties["channel_type"] = ChannelType.normalize(channel.channelType());
properties["channel_clients"] = channel.channelTree.clientsByChannel(channel).length;
properties["channel_subscribed"] = true; //TODO
for(let key in channel.properties)
properties["property_" + key] = channel.properties[key];
let rendered = $("#tmpl_selected_channel").renderTag([properties]);
rendered.find("node").each((index, element) => { $(element).replaceWith(properties[$(element).attr("key")]); });
html_tag.append(rendered);
}
available<V>(object: V): boolean {
return typeof object == "object" && object instanceof ChannelEntry;
}
}

View file

@ -1,27 +1,37 @@
/// <reference path="channel.ts" /> /// <reference path="channel.ts" />
class ServerEntry { class ServerProperties {
channelTree: ChannelTree; virtualserver_name: string = "";
properties: any = { virtualserver_icon_id: number = 0;
virtualserver_name: "", virtualserver_version: string = "unknown";
virtualserver_icon_id: 0, virtualserver_platform: string = "unknown";
virtualserver_version: "unknown", virtualserver_unique_identifier: string = "";
virtualserver_platform: "unknown",
virtualserver_unique_identifier: "",
virtualserver_clientsonline: 0, virtualserver_clientsonline: number = 0;
virtualserver_queryclientsonline: 0, virtualserver_queryclientsonline: number = 0;
virtualserver_channelsonline: 0, virtualserver_channelsonline: number = 0;
virtualserver_uptime: 0, virtualserver_uptime: number = 0;
virtualserver_maxclients: 0 virtualserver_maxclients: number = 0
}; }
interface ServerAddress {
host: string;
port: number;
}
class ServerEntry {
remote_address: ServerAddress;
channelTree: ChannelTree;
properties: ServerProperties;
lastInfoRequest: number = 0; lastInfoRequest: number = 0;
nextInfoRequest: number = 0; nextInfoRequest: number = 0;
private _htmlTag: JQuery<HTMLElement>; private _htmlTag: JQuery<HTMLElement>;
constructor(tree, name) { constructor(tree, name, address: ServerAddress) {
this.properties = new ServerProperties();
this.channelTree = tree; this.channelTree = tree;
this.remote_address = address;
this.properties.virtualserver_name = name; this.properties.virtualserver_name = name;
} }
@ -70,17 +80,28 @@ class ServerEntry {
); );
} }
updateProperty(key, value) : void { updateVariables(...variables: {key: string, value: string}[]) {
console.log("Updating property " + key + " => '" + value + "' for the server"); let group = log.group(log.LogType.DEBUG, LogCategory.SERVER, "Update properties (%i)", variables.length);
this.properties[key] = value;
if(key == "virtualserver_name") { for(let variable of variables) {
this.htmlTag.find(".name").text(value); if(typeof(this.properties[variable.key]) === "boolean")
} else if(key == "virtualserver_icon_id") { this.properties[variable.key] = variable.value == "true" || variable.value == "1";
else if(typeof (this.properties[variable.key]) === "number")
this.properties[variable.key] = parseInt(variable.value);
else
this.properties[variable.key] = variable.value;
group.log("Updating server " + this.properties.virtualserver_name + ". Key " + variable.key + " Value: '" + variable.value + "' (" + typeof (this.properties[variable.key]) + ")");
if(variable.key == "virtualserver_name") {
this.htmlTag.find(".name").text(variable.value);
} else if(variable.key == "virtualserver_icon_id") {
if(this.channelTree.client.fileManager && this.channelTree.client.fileManager.icons) 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")); this.htmlTag.find(".icon_property").replaceWith(this.channelTree.client.fileManager.icons.generateTag(this.properties.virtualserver_icon_id).addClass("icon_property"));
} }
} }
group.end();
}
updateProperties() { updateProperties() {
this.lastInfoRequest = new Date().getTime(); this.lastInfoRequest = new Date().getTime();
this.nextInfoRequest = this.lastInfoRequest + 10 * 1000; this.nextInfoRequest = this.lastInfoRequest + 10 * 1000;
@ -92,7 +113,7 @@ class ServerEntry {
} }
calculateUptime() : number { calculateUptime() : number {
if(this.properties.virtualserver_uptime == 0 || this.lastInfoRequest == 0) return Number.parseInt(this.properties.virtualserver_uptime); if(this.properties.virtualserver_uptime == 0 || this.lastInfoRequest == 0) return this.properties.virtualserver_uptime;
return Number.parseInt(this.properties.virtualserver_uptime) + (new Date().getTime() - this.lastInfoRequest) / 1000; return this.properties.virtualserver_uptime + (new Date().getTime() - this.lastInfoRequest) / 1000;
} }
} }

View file

@ -48,8 +48,8 @@ class ChannelTree {
); );
} }
initialiseHead(serverName: string) { initialiseHead(serverName: string, address: ServerAddress) {
this.server = new ServerEntry(this, serverName); this.server = new ServerEntry(this, serverName, address);
this.server.htmlTag.appendTo(this.htmlTree); this.server.htmlTag.appendTo(this.htmlTree);
this.server.initializeListener(); this.server.initializeListener();
} }

View file

@ -303,35 +303,55 @@
</div> </div>
</template> </template>
<!--
let spawnTag = (type: string, description: string) : JQuery => {
return $.spawn("div").css("display", "inline-flex")
.append($.spawn("div").addClass("icon_x32 client-" + type).css("margin-right", "5px"))
.append($.spawn("a").text(description).css("align-self", "center"));
};
if(!this.current_selected.properties.client_output_hardware)
spawnTag("hardware_output_muted", "Speakers/Headphones disabled").appendTo(this._htmlTag);
if(!this.current_selected.properties.client_input_hardware)
spawnTag("hardware_input_muted", "Microphone disabled").appendTo(this._htmlTag);
if(this.current_selected.properties.client_output_muted)
spawnTag("output_muted", "Speakers/Headphones Muted").appendTo(this._htmlTag);
if(this.current_selected.properties.client_input_muted)
spawnTag("input_muted", "Microphone Muted").appendTo(this._htmlTag);
-->
<script id="tmpl_selected_client" type="text/x-jsrender"> <script id="tmpl_selected_client" type="text/x-jsrender">
<table> <table class="select_info_table">
<tr> <tr>
<td>Name:</td> <td>Name:</td>
<td class="info_key"><node key="client_name"/></td> <td><node key="client_name"/></td>
</tr> </tr>
{{if property_client_description.length > 0}} {{if property_client_description.length > 0}}
<tr> <tr>
<td>Description:</td> <td>Description:</td>
<td class="info_key">{{>property_client_description}}</td> <td>{{>property_client_description}}</td>
</tr> </tr>
{{/if}} {{/if}}
<tr> <tr>
<td>Version:</td> <td>Version:</td>
<td class="info_key"><a title="{{:property_client_version}}">{{*: data.property_client_version.split(" ")[0]; }}</a> on {{:property_client_platform}}</td> <td><a title="{{>property_client_version}}">{{*: data.property_client_version.split(" ")[0]; }}</a> on {{>property_client_platform}}</td>
</tr> </tr>
<tr> <tr>
<td>Online since:</td> <td>Online since:</td>
<td class="info_key update_onlinetime">{{:client_onlinetime}}</td> <td class="update_onlinetime">{{:client_onlinetime}}</td>
</tr> </tr>
<tr> <tr>
<td>Volume:</td> <td>Volume:</td>
<td class="info_key">{{:sound_volume}}%</td> <td>{{:sound_volume}}%</td>
</tr> </tr>
{{if client_teaforum_id > 0}} {{if client_teaforum_id > 0}}
<tr> <tr>
<td>TeaSpeak Account:</td> <td>TeaSpeak Account:</td>
<td class="info_key"><a href="//forum.teaspeak.de/index.php?members/{{:property_client_teaforum_id}}" target="_blank">{{:property_client_teaforum_name}}</a></td> <td><a href="//forum.teaspeak.de/index.php?members/{{:property_client_teaforum_id}}" target="_blank">{{>property_client_teaforum_name}}</a></td>
</tr> </tr>
{{/if}} {{/if}}
</table> </table>
@ -362,6 +382,147 @@
<div style="margin-left: 3px">{{*: data["group_" + data.group_channel + "_name"]}}</div> <div style="margin-left: 3px">{{*: data["group_" + data.group_channel + "_name"]}}</div>
</div> </div>
</div> </div>
<!-- Costume tags/icons -->
<!-- Speakers/Headphones disabled -->
{{if !property_client_output_hardware}}
<div style="display: inline-flex">
<div class="icon_x32 client-hardware_output_muted" style="margin-right: 5px"></div>
<a style="align-self: center">Speakers/Headphones disabled</a>
</div>
{{/if}}
<!-- Microphone disabled -->
{{if !property_client_input_hardware}}
<div style="display: inline-flex">
<div class="icon_x32 client-hardware_input_muted" style="margin-right: 5px"></div>
<a style="align-self: center">Microphone disabled</a>
</div>
{{/if}}
<!-- Speakers/Headphones Muted -->
{{if property_client_output_muted}}
<div style="display: inline-flex">
<div class="icon_x32 client-output_muted" style="margin-right: 5px"></div>
<a style="align-self: center">Speakers/Headphones Muted</a>
</div>
{{/if}}
<!-- Microphone Muted -->
{{if property_client_input_muted}}
<div style="display: inline-flex">
<div class="icon_x32 client-input_muted" style="margin-right: 5px"></div>
<a style="align-self: center">Microphone Muted</a>
</div>
{{/if}}
</script>
<!--
let version = this.current_selected.properties.virtualserver_version;
if(version.startsWith("TeaSpeak ")) version = version.substr("TeaSpeak ".length);
this._htmlTag.append(this.createInfoTable({
"Name": this.current_selected.properties.virtualserver_name,
"Address": "unknown",
"Type": "TeaSpeak",
"Version": version + " on " + this.current_selected.properties.virtualserver_platform,
"Uptime": "<a class='uptime'>" + formatDate(this.current_selected.calculateUptime()) + "</a>",
"Current Channels": this.current_selected.properties.virtualserver_channelsonline,
"Current Clients": this.current_selected.properties.virtualserver_clientsonline,
"Current Queries": this.current_selected.properties.virtualserver_queryclientsonline
}));
-->
<script id="tmpl_selected_server" type="text/x-jsrender">
<table class="select_info_table">
<tr>
<td>Name:</td>
<td><node key="server_name"/></td>
</tr>
<tr>
<td>Address:</td>
<td>{{>server_address}}</td>
</tr>
<tr>
<td>Type:</td>
<td>TeaSpeak</td>
</tr>
<tr>
<td>Version:</td>
<td><a title="{{>property_virtualserver_version}}">{{*: data.property_virtualserver_version.split(" ")[0]; }}</a> on {{>property_virtualserver_platform}}</td>
</tr>
<tr>
<td>Uptime:</td>
<td class="update_onlinetime">{{:server_onlinetime}}</td>
</tr>
<tr>
<td>Current Channels:</td>
<td>{{:property_virtualserver_channelsonline}}</td>
</tr>
<tr>
<td>Current Clients:</td>
<td>{{:property_virtualserver_clientsonline}}</td>
</tr>
<tr>
<td>Current Queries:</td>
<td>{{:property_virtualserver_queryclientsonline}}</td>
</tr>
</table>
</script>
<script id="tmpl_selected_channel" type="text/x-jsrender">
<table class="select_info_table">
<tr>
<td>Name:</td>
<td><node key="channel_name"/></td>
</tr>
<tr>
<td>Topic:</td>
<td>{{>property_channel_topic}}</td>
</tr>
<tr>
<td>Codec:</td>
<td>{{>property_channel_codec}}</td>
</tr>
<tr>
<td>Codec Quality:</td>
<td>{{>property_channel_codec_quality}}</td>
</tr>
<tr>
<td>Type:</td>
<td>{{>channel_type}}</td>
</tr>
<tr>
<td>Current clients:</td>
<td>
{{>channel_clients}} /
{{if property_channel_maxclients == -1}}
Unlimited
{{else}}
{{>property_channel_maxclients}}
{{/if}}
</td>
</tr>
<tr>
<td>Subscription Status:</td>
<td>
{{if channel_subscribed}}
Subscribed
{{else}}
Unsubscribed
{{/if}}
</td>
</tr>
<tr>
<td>Voice Data Encryption:</td>
<td>
{{if property_channel_codec_is_unencrypted}}
Unencrypted
{{else}}
Encrypted
{{/if}}
</td>
</tr>
</table>
</script> </script>
</body> </body>
</html> </html>