Restructuring of the connection part

canary
WolverinDEV 2019-02-23 14:15:22 +01:00
parent fbf820377c
commit e75bbeabef
30 changed files with 1917 additions and 1519 deletions

View File

@ -20,8 +20,5 @@ jobs:
- "ls -lah /tmp/build/"
- "ls -lah /tmp/build/logs/"
- "ls -lah /tmp/build/packages/"
- >
mkdir -p /tmp/build/packages/;
echo "XXXX" > /tmp/build/packages/xxxxx;
./scripts/travis_deploy.sh
- "./scripts/travis_deploy.sh"
if: branch = master

View File

@ -109,7 +109,7 @@ class DownloadFileTransfer {
}
}
class FileManager {
class FileManager extends connection.AbstractCommandHandler {
handle: TSClient;
icons: IconManager;
avatars: AvatarManager;
@ -119,13 +119,28 @@ class FileManager {
private downloadCounter : number = 0;
constructor(client: TSClient) {
super(client.serverConnection);
this.handle = client;
this.icons = new IconManager(this);
this.avatars = new AvatarManager(this);
this.handle.serverConnection.commandHandler["notifyfilelist"] = this.notifyFileList.bind(this);
this.handle.serverConnection.commandHandler["notifyfilelistfinished"] = this.notifyFileListFinished.bind(this);
this.handle.serverConnection.commandHandler["notifystartdownload"] = this.notifyStartDownload.bind(this);
this.connection.command_handler_boss().register_handler(this);
}
handle_command(command: connection.ServerCommand): boolean {
switch (command.command) {
case "notifyfilelist":
this.notifyFileList(command.arguments);
return true;
case "notifyfilelistfinished":
this.notifyFileListFinished(command.arguments);
return true;
case "notifystartdownload":
this.notifyStartDownload(command.arguments);
return true;
}
return false;
}
@ -140,7 +155,7 @@ class FileManager {
req.callback = accept;
_this.listRequests.push(req);
_this.handle.serverConnection.sendCommand("ftgetfilelist", {"path": path, "cid": (channel ? channel.channelId : "0"), "cpw": (password ? password : "")}).then(() => {}).catch(reason => {
_this.handle.serverConnection.send_command("ftgetfilelist", {"path": path, "cid": (channel ? channel.channelId : "0"), "cpw": (password ? password : "")}).then(() => {}).catch(reason => {
_this.listRequests.remove(req);
if(reason instanceof CommandResult) {
if(reason.id == 0x0501) {
@ -197,7 +212,7 @@ class FileManager {
this.pendingDownloadTransfers.push(transfer);
return new Promise<DownloadFileTransfer>((resolve, reject) => {
transfer["_promiseCallback"] = resolve;
_this.handle.serverConnection.sendCommand("ftinitdownload", {
_this.handle.serverConnection.send_command("ftinitdownload", {
"path": path,
"name": file,
"cid": (channel ? channel.channelId : "0"),

View File

@ -354,7 +354,13 @@ class ChatBox {
chat.serverChat().appendError(tr("Could not send chant message (Not connected)"));
return;
}
globalClient.serverConnection.sendMessage(text, ChatType.SERVER);
globalClient.serverConnection.command_helper.sendMessage(text, ChatType.SERVER).catch(error => {
if(error instanceof CommandResult)
return;
chat.serverChat().appendMessage(tr("Failed to send text message."));
console.error(tr("Failed to send server text message: %o"), error);
});
};
this.serverChat().name = tr("Server chat");
@ -364,7 +370,10 @@ class ChatBox {
return;
}
globalClient.serverConnection.sendMessage(text, ChatType.CHANNEL, globalClient.getClient().currentChannel());
globalClient.serverConnection.command_helper.sendMessage(text, ChatType.CHANNEL, globalClient.getClient().currentChannel()).catch(error => {
chat.channelChat().appendMessage(tr("Failed to send text message."));
console.error(tr("Failed to send channel text message: %o"), error);
});
};
this.channelChat().name = tr("Channel chat");

View File

@ -2,7 +2,6 @@
/// <reference path="voice/AudioController.ts" />
/// <reference path="proto.ts" />
/// <reference path="ui/view.ts" />
/// <reference path="connection.ts" />
/// <reference path="settings.ts" />
/// <reference path="ui/frames/SelectedItemInfo.ts" />
/// <reference path="FileManager.ts" />
@ -49,7 +48,7 @@ enum ViewReasonId {
class TSClient {
channelTree: ChannelTree;
serverConnection: ServerConnection;
serverConnection: connection.ServerConnection;
voiceConnection: VoiceConnection;
fileManager: FileManager;
selectInfo: InfoBar;
@ -65,7 +64,7 @@ class TSClient {
constructor() {
this.selectInfo = new InfoBar(this, $("#select_info"));
this.channelTree = new ChannelTree(this, $("#channelTree"));
this.serverConnection = new ServerConnection(this);
this.serverConnection = new connection.ServerConnection(this);
this.fileManager = new FileManager(this);
this.permissions = new PermissionManager(this);
this.groups = new GroupManager(this);
@ -101,12 +100,15 @@ class TSClient {
if(password && !password.hashed) {
helpers.hashPassword(password.password).then(password => {
this.serverConnection.startConnection({host, port}, new HandshakeHandler(profile, name, password));
/* errors will be already handled via the handle disconnect thing */
this.serverConnection.connect({host, port}, new connection.HandshakeHandler(profile, name, password));
}).catch(error => {
createErrorModal(tr("Error while hashing password"), tr("Failed to hash server password!<br>") + error).open();
})
} else
this.serverConnection.startConnection({host, port}, new HandshakeHandler(profile, name, password ? password.password : undefined));
} else {
/* errors will be already handled via the handle disconnect thing */
this.serverConnection.connect({host, port}, new connection.HandshakeHandler(profile, name, password ? password.password : undefined));
}
}
@ -122,7 +124,7 @@ class TSClient {
return this._clientId;
}
getServerConnection() : ServerConnection { return this.serverConnection; }
getServerConnection() : connection.ServerConnection { return this.serverConnection; }
/**
@ -133,7 +135,7 @@ class TSClient {
this.channelTree.registerClient(this._ownEntry);
settings.setServer(this.channelTree.server);
this.permissions.requestPermissionList();
this.serverConnection.sendCommand("channelsubscribeall");
this.serverConnection.send_command("channelsubscribeall");
if(this.groups.serverGroups.length == 0)
this.groups.requestGroups();
this.controlBar.updateProperties();
@ -142,7 +144,7 @@ class TSClient {
}
get connected() : boolean {
return !!this.serverConnection && this.serverConnection.connected;
return this.serverConnection && this.serverConnection.connected();
}
private certAcceptUrl() {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,649 @@
namespace connection {
export class ServerConnectionCommandBoss extends AbstractCommandHandlerBoss {
constructor(connection: AbstractServerConnection) {
super(connection);
}
}
export class ConnectionCommandHandler extends AbstractCommandHandler {
readonly connection: ServerConnection;
constructor(connection: ServerConnection) {
super(connection);
this["error"] = this.handleCommandResult;
this["channellist"] = this.handleCommandChannelList;
this["channellistfinished"] = this.handleCommandChannelListFinished;
this["notifychannelcreated"] = this.handleCommandChannelCreate;
this["notifychanneldeleted"] = this.handleCommandChannelDelete;
this["notifychannelhide"] = this.handleCommandChannelHide;
this["notifychannelshow"] = this.handleCommandChannelShow;
this["notifycliententerview"] = this.handleCommandClientEnterView;
this["notifyclientleftview"] = this.handleCommandClientLeftView;
this["notifyclientmoved"] = this.handleNotifyClientMoved;
this["initserver"] = this.handleCommandServerInit;
this["notifychannelmoved"] = this.handleNotifyChannelMoved;
this["notifychanneledited"] = this.handleNotifyChannelEdited;
this["notifytextmessage"] = this.handleNotifyTextMessage;
this["notifyclientupdated"] = this.handleNotifyClientUpdated;
this["notifyserveredited"] = this.handleNotifyServerEdited;
this["notifyserverupdated"] = this.handleNotifyServerUpdated;
this["notifyclientpoke"] = this.handleNotifyClientPoke;
this["notifymusicplayerinfo"] = this.handleNotifyMusicPlayerInfo;
this["notifyservergroupclientadded"] = this.handleNotifyServerGroupClientAdd;
this["notifyservergroupclientdeleted"] = this.handleNotifyServerGroupClientRemove;
this["notifyclientchannelgroupchanged"] = this.handleNotifyClientChannelGroupChanged;
}
handle_command(command: ServerCommand) : boolean {
if(this[command.command]) {
this[command.command](command.arguments);
return true;
}
return false;
}
set_handler(command: string, handler: any) {
this[command] = handler;
}
unset_handler(command: string, handler?: any) {
if(handler && this[command] != handler) return;
this[command] = undefined;
}
handleCommandResult(json) {
json = json[0]; //Only one bulk
let code : string = json["return_code"];
if(code.length == 0) {
console.log(tr("Invalid return code! (%o)"), json);
return;
}
let retListeners = this.connection["_retListener"];
for(let e of retListeners) {
if(e.code != code) continue;
retListeners.remove(e);
let result = new CommandResult(json);
if(result.success)
e.resolve(result);
else
e.reject(result);
break;
}
}
handleCommandServerInit(json){
//We could setup the voice channel
console.log(tr("Setting up voice"));
this.connection.client.voiceConnection.createSession();
json = json[0]; //Only one bulk
this.connection.client.clientId = parseInt(json["aclid"]);
this.connection.client.getClient().updateVariables({key: "client_nickname", value: json["acn"]});
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key === "aclid") continue;
if(key === "acn") continue;
updates.push({key: key, value: json[key]});
}
this.connection.client.channelTree.server.updateVariables(false, ...updates);
chat.serverChat().name = this.connection.client.channelTree.server.properties["virtualserver_name"];
chat.serverChat().appendMessage(tr("Connected as {0}"), true, this.connection.client.getClient().createChatTag(true));
sound.play(Sound.CONNECTION_CONNECTED);
globalClient.onConnected();
}
private createChannelFromJson(json, ignoreOrder: boolean = false) {
let tree = this.connection.client.channelTree;
let channel = new ChannelEntry(parseInt(json["cid"]), json["channel_name"], tree.findChannel(json["cpid"]));
tree.insertChannel(channel);
if(json["channel_order"] !== "0") {
let prev = tree.findChannel(json["channel_order"]);
if(!prev && json["channel_order"] != 0) {
if(!ignoreOrder) {
console.error(tr("Invalid channel order id!"));
return;
}
}
let parent = tree.findChannel(json["cpid"]);
if(!parent && json["cpid"] != 0) {
console.error(tr("Invalid channel parent"));
return;
}
tree.moveChannel(channel, prev, parent); //TODO test if channel exists!
}
if(ignoreOrder) {
for(let ch of tree.channels) {
if(ch.properties.channel_order == channel.channelId) {
tree.moveChannel(ch, channel, channel.parent); //Corrent the order :)
}
}
}
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key === "cid") continue;
if(key === "cpid") continue;
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: json[key]});
}
channel.updateVariables(...updates);
}
handleCommandChannelList(json) {
this.connection.client.channelTree.hide_channel_tree(); /* dont perform channel inserts on the dom to prevent style recalculations */
console.log(tr("Got %d new channels"), json.length);
for(let index = 0; index < json.length; index++)
this.createChannelFromJson(json[index], true);
}
handleCommandChannelListFinished(json) {
this.connection.client.channelTree.show_channel_tree();
}
handleCommandChannelCreate(json) {
this.createChannelFromJson(json[0]);
}
handleCommandChannelShow(json) {
this.createChannelFromJson(json[0]); //TODO may chat?
}
handleCommandChannelDelete(json) {
let tree = this.connection.client.channelTree;
console.log(tr("Got %d channel deletions"), json.length);
for(let index = 0; index < json.length; index++) {
let channel = tree.findChannel(json[index]["cid"]);
if(!channel) {
console.error(tr("Invalid channel onDelete (Unknown channel)"));
continue;
}
tree.deleteChannel(channel);
}
}
handleCommandChannelHide(json) {
let tree = this.connection.client.channelTree;
console.log(tr("Got %d channel hides"), json.length);
for(let index = 0; index < json.length; index++) {
let channel = tree.findChannel(json[index]["cid"]);
if(!channel) {
console.error(tr("Invalid channel on hide (Unknown channel)"));
continue;
}
tree.deleteChannel(channel);
}
}
handleCommandClientEnterView(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let client: ClientEntry;
let channel = tree.findChannel(json["ctid"]);
let old_channel = tree.findChannel(json["cfid"]);
client = tree.findClient(json["clid"]);
if(!client) {
if(parseInt(json["client_type_exact"]) == ClientType.CLIENT_MUSIC) {
client = new MusicClientEntry(parseInt(json["clid"]), json["client_nickname"]);
} else {
client = new ClientEntry(parseInt(json["clid"]), json["client_nickname"]);
}
client.properties.client_type = parseInt(json["client_type"]);
client = tree.insertClient(client, channel);
} else {
if(client == this.connection.client.getClient())
chat.channelChat().name = channel.channelName();
tree.moveClient(client, channel);
}
if(this.connection.client.controlBar.query_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
const own_channel = this.connection.client.getClient().currentChannel();
if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
if(own_channel == channel)
if(old_channel)
sound.play(Sound.USER_ENTERED);
else
sound.play(Sound.USER_ENTERED_CONNECT);
if(old_channel) {
chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}"), true, client.createChatTag(true), old_channel.generate_tag(true), channel.generate_tag(true));
} else {
chat.serverChat().appendMessage(tr("{0} connected to channel {1}"), true, client.createChatTag(true), channel.generate_tag(true));
}
} else if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
if(own_channel == channel)
sound.play(Sound.USER_ENTERED_MOVED);
chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, moved by {3}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
if(own_channel == channel)
sound.play(Sound.USER_ENTERED_KICKED);
chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, kicked by {3}{4}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] > 0 ? " (" + json["msg"] + ")" : ""
);
} else {
console.warn(tr("Unknown reasonid for %o"), json["reasonid"]);
}
}
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key == "cfid") continue;
if(key == "ctid") continue;
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: json[key]});
}
client.updateVariables(...updates);
if(client instanceof LocalClientEntry)
this.connection.client.controlBar.updateVoice();
}
handleCommandClientLeftView(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let client = tree.findClient(json["clid"]);
if(!client) {
console.error(tr("Unknown client left!"));
return 0;
}
if(client == this.connection.client.getClient()) {
if(json["reasonid"] == ViewReasonId.VREASON_BAN) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_BANNED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_SHUTDOWN) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_STOPPED) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
} else
this.connection.client.handleDisconnect(DisconnectReason.UNKNOWN, json);
return;
}
if(this.connection.client.controlBar.query_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
const own_channel = this.connection.client.getClient().currentChannel();
let channel_from = tree.findChannel(json["cfid"]);
let channel_to = tree.findChannel(json["ctid"]);
if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
chat.serverChat().appendMessage(tr("{0} disappeared from {1} to {2}"), true, client.createChatTag(true), channel_from.generate_tag(true), channel_to.generate_tag(true));
if(channel_from == own_channel)
sound.play(Sound.USER_LEFT);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_LEFT) {
chat.serverChat().appendMessage(tr("{0} left the server{1}"), true,
client.createChatTag(true),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
sound.play(Sound.USER_LEFT_DISCONNECT);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
chat.serverChat().appendError(tr("{0} was kicked from the server by {1}.{2}"),
client.createChatTag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
sound.play(Sound.USER_LEFT_KICKED_SERVER);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
chat.serverChat().appendError(tr("{0} was kicked from your channel by {1}.{2}"),
client.createChatTag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
} else if(json["reasonid"] == ViewReasonId.VREASON_BAN) {
//"Mulus" was banned for 1 second from the server by "WolverinDEV" (Sry brauchte kurz ein opfer :P <3 (Nohomo))
let duration = "permanently";
if(json["bantime"])
duration = "for " + formatDate(Number.parseInt(json["bantime"]));
chat.serverChat().appendError(tr("{0} was banned {1} by {2}.{3}"),
client.createChatTag(true),
duration,
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
sound.play(Sound.USER_LEFT_BANNED);
} else {
console.error(tr("Unknown client left reason!"));
}
}
tree.deleteClient(client);
}
handleNotifyClientMoved(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let client = tree.findClient(json["clid"]);
let channel_to = tree.findChannel(json["ctid"]);
let channel_from = tree.findChannel(json["cfid"]);
if(!client) {
console.error(tr("Unknown client move (Client)!"));
return 0;
}
if(!channel_to) {
console.error(tr("Unknown client move (Channel to)!"));
return 0;
}
if(!channel_from) //Not critical
console.error(tr("Unknown client move (Channel from)!"));
let self = client instanceof LocalClientEntry;
let current_clients;
if(self) {
chat.channelChat().name = channel_to.channelName();
current_clients = client.channelTree.clientsByChannel(client.currentChannel())
this.connection.client.controlBar.updateVoice(channel_to);
}
tree.moveClient(client, channel_to);
for(const entry of current_clients || [])
if(entry !== client) entry.getAudioController().stopAudio(true);
const own_channel = this.connection.client.getClient().currentChannel();
if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
chat.serverChat().appendMessage(self ? tr("You was moved by {3} from channel {1} to {2}") : tr("{0} was moved from channel {1} to {2} by {3}"), true,
client.createChatTag(true),
channel_from ? channel_from.generate_tag(true) : undefined,
channel_to.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"])
);
if(self)
sound.play(Sound.USER_MOVED_SELF);
else if(own_channel == channel_to)
sound.play(Sound.USER_ENTERED_MOVED);
else if(own_channel == channel_from)
sound.play(Sound.USER_LEFT_MOVED);
} else if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
chat.serverChat().appendMessage(self ? tr("You switched from channel {1} to {2}") : tr("{0} switched from channel {1} to {2}"), true,
client.createChatTag(true),
channel_from ? channel_from.generate_tag(true) : undefined,
channel_to.generate_tag(true)
);
if(self) {} //If we do an action we wait for the error response
else if(own_channel == channel_to)
sound.play(Sound.USER_ENTERED);
else if(own_channel == channel_from)
sound.play(Sound.USER_LEFT);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
chat.serverChat().appendMessage(self ? tr("You got kicked out of the channel {1} to channel {2} by {3}{4}") : tr("{0} got kicked from channel {1} to {2} by {3}{4}"), true,
client.createChatTag(true),
channel_from ? channel_from.generate_tag(true) : undefined,
channel_to.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(self) {
sound.play(Sound.CHANNEL_KICKED);
} else if(own_channel == channel_to)
sound.play(Sound.USER_ENTERED_KICKED);
else if(own_channel == channel_from)
sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
} else {
console.warn(tr("Unknown reason id %o"), json["reasonid"]);
}
}
handleNotifyChannelMoved(json) {
json = json[0]; //Only one bulk
for(let key in json)
console.log("Key: " + key + " Value: " + json[key]);
let tree = this.connection.client.channelTree;
let channel = tree.findChannel(json["cid"]);
if(!channel) {
console.error(tr("Unknown channel move (Channel)!"));
return 0;
}
let prev = tree.findChannel(json["order"]);
if(!prev && json["order"] != 0) {
console.error(tr("Unknown channel move (prev)!"));
return 0;
}
let parent = tree.findChannel(json["cpid"]);
if(!parent && json["cpid"] != 0) {
console.error(tr("Unknown channel move (parent)!"));
return 0;
}
tree.moveChannel(channel, prev, parent);
}
handleNotifyChannelEdited(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let channel = tree.findChannel(json["cid"]);
if(!channel) {
console.error(tr("Unknown channel edit (Channel)!"));
return 0;
}
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key === "cid") continue;
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: json[key]});
}
channel.updateVariables(...updates);
}
handleNotifyTextMessage(json) {
json = json[0]; //Only one bulk
//TODO chat format?
let mode = json["targetmode"];
if(mode == 1){
let invoker = this.connection.client.channelTree.findClient(json["invokerid"]);
let target = this.connection.client.channelTree.findClient(json["target"]);
if(!invoker) { //TODO spawn chat (Client is may invisible)
console.error(tr("Got private message from invalid client!"));
return;
}
if(!target) { //TODO spawn chat (Client is may invisible)
console.error(tr("Got private message from invalid client!"));
return;
}
if(invoker == this.connection.client.getClient()) {
sound.play(Sound.MESSAGE_SEND, {default_volume: .5});
target.chat(true).appendMessage("{0}: {1}", true, this.connection.client.getClient().createChatTag(true), MessageHelper.bbcode_chat(json["msg"]));
} else {
sound.play(Sound.MESSAGE_RECEIVED, {default_volume: .5});
invoker.chat(true).appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"]));
}
} else if(mode == 2) {
if(json["invokerid"] == this.connection.client.clientId)
sound.play(Sound.MESSAGE_SEND, {default_volume: .5});
else
sound.play(Sound.MESSAGE_RECEIVED, {default_volume: .5});
chat.channelChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"]))
} else if(mode == 3) {
chat.serverChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), MessageHelper.bbcode_chat(json["msg"]));
}
}
handleNotifyClientUpdated(json) {
json = json[0]; //Only one bulk
let client = this.connection.client.channelTree.findClient(json["clid"]);
if(!client) {
console.error(tr("Tried to update an non existing client"));
return;
}
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key == "clid") continue;
updates.push({key: key, value: json[key]});
}
client.updateVariables(...updates);
if(this.connection.client.selectInfo.currentSelected == client)
this.connection.client.selectInfo.update();
}
handleNotifyServerEdited(json) {
json = json[0];
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: json[key]});
}
this.connection.client.channelTree.server.updateVariables(false, ...updates);
if(this.connection.client.selectInfo.currentSelected == this.connection.client.channelTree.server)
this.connection.client.selectInfo.update();
}
handleNotifyServerUpdated(json) {
json = json[0];
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: json[key]});
}
this.connection.client.channelTree.server.updateVariables(true, ...updates);
let info = this.connection.client.selectInfo;
if(info.currentSelected instanceof ServerEntry)
info.update();
}
handleNotifyMusicPlayerInfo(json) {
json = json[0];
let bot = this.connection.client.channelTree.find_client_by_dbid(json["bot_id"]);
if(!bot || !(bot instanceof MusicClientEntry)) {
log.warn(LogCategory.CLIENT, tr("Got music player info for unknown or invalid bot! (ID: %i, Entry: %o)"), json["bot_id"], bot);
return;
}
bot.handlePlayerInfo(json);
}
handleNotifyClientPoke(json) {
json = json[0];
Modals.spawnPoke({
id: parseInt(json["invokerid"]),
name: json["invokername"],
unique_id: json["invokeruid"]
}, json["msg"]);
sound.play(Sound.USER_POKED_SELF);
}
//TODO server chat message
handleNotifyServerGroupClientAdd(json) {
json = json[0];
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId())
sound.play(Sound.GROUP_SERVER_ASSIGNED_SELF);
}
//TODO server chat message
handleNotifyServerGroupClientRemove(json) {
json = json[0];
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId()) {
sound.play(Sound.GROUP_SERVER_REVOKED_SELF);
} else {
}
}
//TODO server chat message
handleNotifyClientChannelGroupChanged(json) {
json = json[0];
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId()) {
sound.play(Sound.GROUP_CHANNEL_CHANGED_SELF);
}
}
}
}

View File

@ -0,0 +1,311 @@
namespace connection {
export class CommandHelper extends AbstractCommandHandler {
private _callbacks_namefromuid: ClientNameFromUid[] = [];
private _who_am_i: any;
constructor(connection) {
super(connection);
this.volatile_handler_boss = false;
this.ignore_consumed = true;
}
initialize() {
this.connection.command_handler_boss().register_handler(this);
/* notifyquerylist */
}
handle_command(command: connection.ServerCommand): boolean {
if(command.command == "notifyclientnamefromuid")
this.handle_notifyclientnamefromuid(command.arguments);
else
return false;
return true;
}
joinChannel(channel: ChannelEntry, password?: string) : Promise<CommandResult> {
return this.connection.send_command("clientmove", {
"clid": this.connection.client.getClientId(),
"cid": channel.getChannelId(),
"cpw": password || ""
});
}
sendMessage(message: string, type: ChatType, target?: ChannelEntry | ClientEntry) : Promise<CommandResult> {
if(type == ChatType.SERVER)
return this.connection.send_command("sendtextmessage", {"targetmode": 3, "target": 0, "msg": message});
else if(type == ChatType.CHANNEL)
return this.connection.send_command("sendtextmessage", {"targetmode": 2, "target": (target as ChannelEntry).getChannelId(), "msg": message});
else if(type == ChatType.CLIENT)
return this.connection.send_command("sendtextmessage", {"targetmode": 1, "target": (target as ClientEntry).clientId(), "msg": message});
}
updateClient(key: string, value: string) : Promise<CommandResult> {
let data = {};
data[key] = value;
return this.connection.send_command("clientupdate", data);
}
info_from_uid(...uid: string[]) : Promise<ClientNameInfo[]> {
let uids = [...uid];
for(let p of this._callbacks_namefromuid)
if(p.keys == uids) return p.promise;
let req: ClientNameFromUid = {} as any;
req.keys = uids;
req.response = new Array(uids.length);
req.promise = new LaterPromise<ClientNameInfo[]>();
for(let uid of uids) {
this.connection.send_command("clientgetnamefromuid", {
cluid: uid
}).catch(req.promise.function_rejected());
}
this._callbacks_namefromuid.push(req);
return req.promise;
}
request_query_list(server_id: number = undefined) : Promise<QueryList> {
return new Promise<QueryList>((resolve, reject) => {
const single_handler = {
command: "notifyquerylist",
function: command => {
const json = command.arguments;
const result = {} as QueryList;
result.flag_all = json[0]["flag_all"];
result.flag_own = json[0]["flag_own"];
result.queries = [];
for(const entry of json) {
const rentry = {} as QueryListEntry;
rentry.bounded_server = entry["client_bounded_server"];
rentry.username = entry["client_login_name"];
rentry.unique_id = entry["client_unique_identifier"];
result.queries.push(rentry);
}
resolve(result);
return true;
}
};
this.handler_boss.register_single_handler(single_handler);
let data = {};
if(server_id !== undefined)
data["server_id"] = server_id;
this.connection.send_command("querylist", data).catch(error => {
this.handler_boss.remove_single_handler(single_handler);
if(error instanceof CommandResult) {
if(error.id == ErrorID.EMPTY_RESULT) {
resolve(undefined);
return;
}
}
reject(error);
});
});
}
request_playlist_list() : Promise<Playlist[]> {
return new Promise((resolve, reject) => {
const single_handler: SingleCommandHandler = {
command: "notifyplaylistlist",
function: command => {
const json = command.arguments;
const result: Playlist[] = [];
for(const entry of json) {
try {
result.push({
playlist_id: parseInt(entry["playlist_id"]),
playlist_bot_id: parseInt(entry["playlist_bot_id"]),
playlist_title: entry["playlist_title"],
playlist_type: parseInt(entry["playlist_type"]),
playlist_owner_dbid: parseInt(entry["playlist_owner_dbid"]),
playlist_owner_name: entry["playlist_owner_name"],
needed_power_modify: parseInt(entry["needed_power_modify"]),
needed_power_permission_modify: parseInt(entry["needed_power_permission_modify"]),
needed_power_delete: parseInt(entry["needed_power_delete"]),
needed_power_song_add: parseInt(entry["needed_power_song_add"]),
needed_power_song_move: parseInt(entry["needed_power_song_move"]),
needed_power_song_remove: parseInt(entry["needed_power_song_remove"])
});
} catch(error) {
log.error(LogCategory.NETWORKING, tr("Failed to parse playlist entry: %o"), error);
}
}
resolve(result);
return true;
}
};
this.handler_boss.register_single_handler(single_handler);
this.connection.send_command("playlistlist").catch(error => {
this.handler_boss.remove_single_handler(single_handler);
if(error instanceof CommandResult) {
if(error.id == ErrorID.EMPTY_RESULT) {
resolve([]);
return;
}
}
reject(error);
})
});
}
request_playlist_songs(playlist_id: number) : Promise<PlaylistSong[]> {
return new Promise((resolve, reject) => {
const single_handler: SingleCommandHandler = {
command: "notifyplaylistsonglist",
function: command => {
const json = command.arguments;
if(json[0]["playlist_id"] != playlist_id) {
log.error(LogCategory.NETWORKING, tr("Received invalid notification for playlist songs"));
return false;
}
const result: PlaylistSong[] = [];
for(const entry of json) {
try {
result.push({
song_id: parseInt(entry["song_id"]),
song_invoker: entry["song_invoker"],
song_previous_song_id: parseInt(entry["song_previous_song_id"]),
song_url: entry["song_url"],
song_url_loader: entry["song_url_loader"],
song_loaded: entry["song_loaded"] == true || entry["song_loaded"] == "1",
song_metadata: entry["song_metadata"]
});
} catch(error) {
log.error(LogCategory.NETWORKING, tr("Failed to parse playlist song entry: %o"), error);
}
}
resolve(result);
return true;
}
};
this.handler_boss.register_single_handler(single_handler);
this.connection.send_command("playlistsonglist", {playlist_id: playlist_id}).catch(error => {
this.handler_boss.remove_single_handler(single_handler);
if(error instanceof CommandResult) {
if(error.id == ErrorID.EMPTY_RESULT) {
resolve([]);
return;
}
}
reject(error);
})
});
}
request_playlist_info(playlist_id: number) : Promise<PlaylistInfo> {
return new Promise((resolve, reject) => {
const single_handler: SingleCommandHandler = {
command: "notifyplaylistinfo",
function: command => {
const json = command.arguments[0];
if (json["playlist_id"] != playlist_id) {
log.error(LogCategory.NETWORKING, tr("Received invalid notification for playlist info"));
return;
}
try {
//resolve
resolve({
playlist_id: parseInt(json["playlist_id"]),
playlist_title: json["playlist_title"],
playlist_description: json["playlist_description"],
playlist_type: parseInt(json["playlist_type"]),
playlist_owner_dbid: parseInt(json["playlist_owner_dbid"]),
playlist_owner_name: json["playlist_owner_name"],
playlist_flag_delete_played: json["playlist_flag_delete_played"] == true || json["playlist_flag_delete_played"] == "1",
playlist_flag_finished: json["playlist_flag_finished"] == true || json["playlist_flag_finished"] == "1",
playlist_replay_mode: parseInt(json["playlist_replay_mode"]),
playlist_current_song_id: parseInt(json["playlist_current_song_id"]),
});
} catch (error) {
log.error(LogCategory.NETWORKING, tr("Failed to parse playlist info: %o"), error);
reject("failed to parse info");
}
return true;
}
};
this.handler_boss.register_single_handler(single_handler);
this.connection.send_command("playlistinfo", {playlist_id: playlist_id}).catch(error => {
this.handler_boss.remove_single_handler(single_handler);
reject(error);
})
});
}
/**
* @deprecated
* Its just a workaround for the query management.
* There is no garante that the whoami trick will work forever
*/
current_virtual_server_id() : Promise<number> {
if(this._who_am_i)
return Promise.resolve(parseInt(this._who_am_i["virtualserver_id"]));
return new Promise<number>((resolve, reject) => {
const single_handler: SingleCommandHandler = {
function: command => {
if(command.command != "")
return false;
this._who_am_i = command.arguments[0];
resolve(parseInt(this._who_am_i["virtualserver_id"]));
return true;
}
};
this.handler_boss.register_single_handler(single_handler);
this.connection.send_command("whoami").catch(error => {
this.handler_boss.remove_single_handler(single_handler);
reject(error);
});
});
}
private handle_notifyclientnamefromuid(json: any[]) {
for(let entry of json) {
let info: ClientNameInfo = {} as any;
info.client_unique_id = entry["cluid"];
info.client_nickname = entry["clname"];
info.client_database_id = parseInt(entry["cldbid"]);
for(let elm of this._callbacks_namefromuid.slice(0)) {
let unset = 0;
for(let index = 0; index < elm.keys.length; index++) {
if(elm.keys[index] == info.client_unique_id) {
elm.response[index] = info;
}
if(elm.response[index] == undefined) unset++;
}
if(unset == 0) {
this._callbacks_namefromuid.remove(elm);
elm.promise.resolved(elm.response);
}
}
}
}
}
}

View File

@ -0,0 +1,148 @@
namespace connection {
export interface CommandOptions {
flagset?: string[]; /* default: [] */
process_result?: boolean; /* default: true */
timeout?: number /* default: 1000 */;
}
export const CommandOptionDefaults: CommandOptions = {
flagset: [],
process_result: true,
timeout: 1000
};
export abstract class AbstractServerConnection {
readonly client: TSClient;
readonly command_helper: CommandHelper;
protected constructor(client: TSClient) {
this.client = client;
this.command_helper = new CommandHelper(this);
}
/* resolved as soon a connection has been established. This does not means that the authentication had yet been done! */
abstract connect(address: ServerAddress, handshake: HandshakeHandler, timeout?: number) : Promise<void>;
abstract connected() : boolean;
abstract disconnect(reason?: string) : Promise<void>;
abstract support_voice() : boolean;
abstract voice_connection() : AbstractVoiceConnection | undefined;
abstract command_handler_boss() : AbstractCommandHandlerBoss;
abstract send_command(command: string, data?: any | any[], options?: CommandOptions) : Promise<CommandResult>;
}
export abstract class AbstractVoiceConnection {
readonly connection: AbstractServerConnection;
protected constructor(connection: AbstractServerConnection) {
this.connection = connection;
}
abstract connected() : boolean;
}
export class ServerCommand {
command: string;
arguments: any[];
}
export abstract class AbstractCommandHandler {
readonly connection: AbstractServerConnection;
handler_boss: AbstractCommandHandlerBoss | undefined;
volatile_handler_boss: boolean = false; /* if true than the command handler could be registered twice to two or more handlers */
ignore_consumed: boolean = false;
protected constructor(connection: AbstractServerConnection) {
this.connection = connection;
}
/**
* @return If the command should be consumed
*/
abstract handle_command(command: ServerCommand) : boolean;
}
export interface SingleCommandHandler {
name?: string;
command?: string;
timeout?: number;
/* if the return is true then the command handler will be removed */
function: (command: ServerCommand) => boolean;
}
export abstract class AbstractCommandHandlerBoss {
readonly connection: AbstractServerConnection;
protected command_handlers: AbstractCommandHandler[] = [];
/* TODO: Timeout */
protected single_command_handler: SingleCommandHandler[] = [];
protected constructor(connection: AbstractServerConnection) {
this.connection = connection;
}
register_handler(handler: AbstractCommandHandler) {
if(!handler.volatile_handler_boss && handler.handler_boss)
throw "handler already registered";
this.command_handlers.remove(handler); /* just to be sure */
this.command_handlers.push(handler);
handler.handler_boss = this;
}
unregister_handler(handler: AbstractCommandHandler) {
if(!handler.volatile_handler_boss && handler.handler_boss !== this) {
console.warn(tr("Tried to unregister command handler which does not belong to the handler boss"));
return;
}
this.command_handlers.remove(handler);
handler.handler_boss = undefined;
}
register_single_handler(handler: SingleCommandHandler) {
this.single_command_handler.push(handler);
}
remove_single_handler(handler: SingleCommandHandler) {
this.single_command_handler.remove(handler);
}
handlers() : AbstractCommandHandler[] {
return this.command_handlers;
}
invoke_handle(command: ServerCommand) : boolean {
let flag_consumed = false;
for(const handler of this.command_handlers) {
try {
if(!flag_consumed || handler.ignore_consumed)
flag_consumed = flag_consumed || handler.handle_command(command);
} catch(error) {
console.error(tr("Failed to invoke command handler. Invocation results in an exception: %o"), error);
}
}
for(const handler of [...this.single_command_handler]) {
if(handler.command && handler.command != command.command)
continue;
try {
if(handler.function(command))
this.single_command_handler.remove(handler);
} catch(error) {
console.error(tr("Failed to invoke single command handler. Invocation results in an exception: %o"), error);
}
}
return flag_consumed;
}
}
}

View File

@ -0,0 +1,108 @@
namespace connection {
export interface HandshakeIdentityHandler {
connection: AbstractServerConnection;
start_handshake();
register_callback(callback: (success: boolean, message?: string) => any);
}
export class HandshakeHandler {
private connection: ServerConnection;
private handshake_handler: HandshakeIdentityHandler;
private failed = false;
readonly profile: profiles.ConnectionProfile;
readonly name: string;
readonly server_password: string;
constructor(profile: profiles.ConnectionProfile, name: string, password: string) {
this.profile = profile;
this.server_password = password;
this.name = name;
}
setConnection(con: ServerConnection) {
this.connection = con;
}
startHandshake() {
this.handshake_handler = this.profile.spawn_identity_handshake_handler(this.connection);
if(!this.handshake_handler) {
this.handshake_failed("failed to create identity handler");
return;
}
this.handshake_handler.register_callback((flag, message) => {
if(flag)
this.handshake_finished();
else
this.handshake_failed(message);
});
this.handshake_handler.start_handshake();
}
private handshake_failed(message: string) {
if(this.failed) return;
this.failed = true;
this.connection.client.handleDisconnect(DisconnectReason.HANDSHAKE_FAILED, message);
}
private handshake_finished(version?: string) {
if(native_client && window["native"] && native.client_version && !version) {
native.client_version()
.then( this.handshake_finished.bind(this))
.catch(error => {
console.error(tr("Failed to get version:"));
console.error(error);
this.handshake_finished("?.?.?");
});
return;
}
const git_version = settings.static_global("version", "unknown");
const browser_name = (navigator.browserSpecs || {})["name"] || " ";
let data = {
//TODO variables!
client_nickname: this.name,
client_platform: (browser_name ? browser_name + " " : "") + navigator.platform,
client_version: "TeaWeb " + git_version + " (" + navigator.userAgent + ")",
client_server_password: this.server_password,
client_browser_engine: navigator.product
};
if(version) {
data.client_version = "TeaClient ";
data.client_version += " " + version;
const os = require("os");
const arch_mapping = {
"x32": "32bit",
"x64": "64bit"
};
data.client_version += " " + (arch_mapping[os.arch()] || os.arch());
const os_mapping = {
"win32": "Windows",
"linux": "Linux"
};
data.client_platform = (os_mapping[os.platform()] || os.platform());
}
this.connection.send_command("clientinit", data).catch(error => {
this.connection.disconnect();
if(error instanceof CommandResult) {
if(error.id == 1028) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_REQUIRES_PASSWORD);
} else {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, error);
}
}
});
}
}
}

View File

@ -0,0 +1,377 @@
enum ErrorID {
PERMISSION_ERROR = 2568,
EMPTY_RESULT = 0x0501,
PLAYLIST_IS_IN_USE = 0x2103
}
class CommandResult {
success: boolean;
id: number;
message: string;
extra_message: string;
json: any;
constructor(json) {
this.json = json;
this.id = json["id"];
this.message = json["msg"];
this.extra_message = "";
if(json["extra_msg"]) this.extra_message = json["extra_msg"];
this.success = this.id == 0;
}
}
class ReturnListener<T> {
resolve: (value?: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
code: string;
timeout: NodeJS.Timer;
}
namespace connection {
export class ServerConnection extends AbstractServerConnection {
_remote_address: ServerAddress;
_socket: WebSocket;
_connectionState: ConnectionState = ConnectionState.UNCONNECTED;
_handshakeHandler: HandshakeHandler;
private _command_boss: ServerConnectionCommandBoss;
private _command_handler_default: ConnectionCommandHandler;
private _command_handler_handshake: AbstractCommandHandler; //The new handshake handler :)
private _connect_timeout_timer: NodeJS.Timer = undefined;
private _connected: boolean = false;
private _retCodeIdx: number;
private _retListener: ReturnListener<CommandResult>[];
constructor(client : TSClient) {
super(client);
this._socket = null;
this._retCodeIdx = 0;
this._retListener = [];
this._command_boss = new ServerConnectionCommandBoss(this);
this._command_handler_default = new ConnectionCommandHandler(this);
this._command_boss.register_handler(this._command_handler_default);
this.command_helper.initialize();
}
on_connect: () => void = () => {
console.log(tr("Socket connected"));
chat.serverChat().appendMessage(tr("Logging in..."));
this._handshakeHandler.startHandshake();
};
private generateReturnCode() : string {
return (this._retCodeIdx++).toString();
}
async connect(address : ServerAddress, handshake: HandshakeHandler, timeout?: number) : Promise<void> {
timeout = typeof(timeout) === "number" ? timeout : 0;
if(this._connect_timeout_timer) {
clearTimeout(this._connect_timeout_timer);
this._connect_timeout_timer = null;
try {
await this.disconnect()
} catch(error) {
console.error(tr("Failed to close old connection properly. Error: %o"), error);
throw "failed to cleanup old connection";
}
}
this.updateConnectionState(ConnectionState.CONNECTING);
this._remote_address = address;
this._handshakeHandler = handshake;
this._handshakeHandler.setConnection(this);
this._connected = false;
chat.serverChat().appendMessage(tr("Connecting to {0}:{1}"), true, address.host, address.port);
const self = this;
try {
let local_socket: WebSocket;
let local_timeout_timer: NodeJS.Timer;
local_timeout_timer = setTimeout(async () => {
console.log(tr("Connect timeout triggered!"));
try {
await this.disconnect();
} catch(error) {
log.warn(LogCategory.NETWORKING, tr("Failed to close connection after timeout had been triggered! (%o)"), error);
}
this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE);
}, timeout);
this._connect_timeout_timer = local_timeout_timer;
this._socket = (local_socket = new WebSocket('wss://' + address.host + ":" + address.port)); /* this may hangs */
clearTimeout(local_timeout_timer);
if(this._connect_timeout_timer == local_timeout_timer)
this._connect_timeout_timer = undefined;
if(this._socket != local_socket) return; /* something had changed and we dont use this connection anymore! */
local_socket.onopen = () => {
if(this._socket != local_socket) return; /* this socket isn't from interest anymore */
this._connected = true;
this.on_connect();
};
local_socket.onclose = event => {
if(this._socket != local_socket) return; /* this socket isn't from interest anymore */
this.client.handleDisconnect(this._connected ? DisconnectReason.CONNECTION_CLOSED : DisconnectReason.CONNECT_FAILURE, {
code: event.code,
reason: event.reason,
event: event
});
};
local_socket.onerror = e => {
if(this._socket != local_socket) return; /* this socket isn't from interest anymore */
console.log(tr("Received web socket error: (%o)"), e);
};
local_socket.onmessage = msg => {
if(this._socket != local_socket) return; /* this socket isn't from interest anymore */
self.handle_socket_message(msg.data);
};
this.updateConnectionState(ConnectionState.INITIALISING);
} catch (e) {
try {
await this.disconnect();
} catch(error) {
log.warn(LogCategory.NETWORKING, tr("Failed to close connection after connect attempt failed (%o)"), error);
}
this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE, e);
}
}
updateConnectionState(state: ConnectionState) {
this._connectionState = state;
this.client.controlBar.update_connection_state();
}
async disconnect(reason?: string) : Promise<void> {
if(typeof(reason) === "string") {
//TODO send disconnect reason
}
if(this._connectionState == ConnectionState.UNCONNECTED)
return;
this.updateConnectionState(ConnectionState.UNCONNECTED);
if(this._socket)
this._socket.close(3000 + 0xFF, tr("request disconnect"));
this._socket = null;
for(let future of this._retListener)
future.reject(tr("Connection closed"));
this._retListener = [];
this._retCodeIdx = 0;
this._connected = false;
}
private handle_socket_message(data) {
if(typeof(data) === "string") {
let json;
try {
json = JSON.parse(data);
} catch(e) {
console.error(tr("Could not parse message json!"));
alert(e); // error in the above string (in this case, yes)!
return;
}
if(json["type"] === undefined) {
console.log(tr("Missing data type!"));
return;
}
if(json["type"] === "command") {
let group = log.group(log.LogType.DEBUG, LogCategory.NETWORKING, tr("Handling command '%s'"), json["command"]);
group.log(tr("Handling command '%s'"), json["command"]);
group.group(log.LogType.TRACE, tr("Json:")).collapsed(true).log("%o", json).end();
this._command_boss.invoke_handle({
command: json["command"],
arguments: json["data"]
});
group.end();
} else if(json["type"] === "WebRTC") this.client.voiceConnection.handleControlPacket(json);
else {
console.log(tr("Unknown command type %o"), json["type"]);
}
} else {
log.warn(LogCategory.NETWORKING, tr("Received unknown message of type %s. Dropping message"), typeof(data));
}
}
sendData(data: any) {
if(!this._socket || this._socket.readyState != 1) {
log.warn(LogCategory.NETWORKING, tr("Tried to send on a invalid socket (%s)"), this._socket ? "invalid state (" + this._socket.readyState + ")" : "invalid socket");
return;
}
this._socket.send(data);
}
private commandiefy(input: any) : string {
return JSON.stringify(input, (key, value) => {
switch (typeof value) {
case "boolean": return value == true ? "1" : "0";
case "function": return value();
default:
return value;
}
});
}
send_command(command: string, data?: any | any[], _options?: CommandOptions) : Promise<CommandResult> {
if(!this._socket || !this.connected()) {
console.warn(tr("Tried to send a command without a valid connection."));
return;
}
const options: CommandOptions = {};
Object.assign(options, CommandOptionDefaults);
Object.assign(options, _options);
data = $.isArray(data) ? data : [data || {}];
const _this = this;
let result = new Promise<CommandResult>((resolve, failed) => {
let _data = $.isArray(data) ? data : [data];
let retCode = _data[0]["return_code"] !== undefined ? _data[0].return_code : _this.generateReturnCode();
_data[0].return_code = retCode;
let listener = new ReturnListener<CommandResult>();
listener.resolve = resolve;
listener.reject = failed;
listener.code = retCode;
listener.timeout = setTimeout(() => {
_this._retListener.remove(listener);
listener.reject("timeout");
}, 1500);
this._retListener.push(listener);
this._socket.send(this.commandiefy({
"type": "command",
"command": command,
"data": _data,
"flags": options.flagset.filter(entry => entry.length != 0)
}));
});
return new Promise<CommandResult>((resolve, failed) => {
result.then(resolve).catch(ex => {
if(options.process_result) {
if(ex instanceof CommandResult) {
let res = ex;
if(!res.success) {
if(res.id == 2568) { //Permission error
res.message = tr("Insufficient client permissions. Failed on permission ") + this.client.permissions.resolveInfo(res.json["failed_permid"] as number).name;
chat.serverChat().appendError(tr("Insufficient client permissions. Failed on permission {}"), this.client.permissions.resolveInfo(res.json["failed_permid"] as number).name);
sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS);
} else {
chat.serverChat().appendError(res.extra_message.length == 0 ? res.message : res.extra_message);
}
}
} else if(typeof(ex) === "string") {
chat.serverChat().appendError(tr("Command execution results in ") + ex);
} else {
console.error(tr("Invalid promise result type: %o. Result:"), typeof (ex));
console.error(ex);
}
}
failed(ex);
})
});
}
connected() : boolean {
return this._socket && this._socket.readyState == WebSocket.OPEN;
}
support_voice(): boolean {
return false;
}
voice_connection(): connection.AbstractVoiceConnection | undefined {
return undefined;
}
command_handler_boss(): connection.AbstractCommandHandlerBoss {
return this._command_boss;
}
}
}
interface ClientNameInfo {
//cluid=tYzKUryn\/\/Y8VBMf8PHUT6B1eiE= name=Exp clname=Exp cldbid=9
client_unique_id: string;
client_nickname: string;
client_database_id: number;
}
interface ClientNameFromUid {
promise: LaterPromise<ClientNameInfo[]>,
keys: string[],
response: ClientNameInfo[]
}
interface QueryListEntry {
username: string;
unique_id: string;
bounded_server: number;
}
interface QueryList {
flag_own: boolean;
flag_all: boolean;
queries: QueryListEntry[];
}
interface Playlist {
playlist_id: number;
playlist_bot_id: number;
playlist_title: string;
playlist_type: number;
playlist_owner_dbid: number;
playlist_owner_name: string;
needed_power_modify: number;
needed_power_permission_modify: number;
needed_power_delete: number;
needed_power_song_add: number;
needed_power_song_move: number;
needed_power_song_remove: number;
}
interface PlaylistInfo {
playlist_id: number,
playlist_title: string,
playlist_description: string,
playlist_type: number,
playlist_owner_dbid: number,
playlist_owner_name: string,
playlist_flag_delete_played: boolean,
playlist_flag_finished: boolean,
playlist_replay_mode: number,
playlist_current_song_id: number,
}
interface PlaylistSong {
song_id: number;
song_previous_song_id: number;
song_invoker: string;
song_url: string;
song_url_loader: string;
song_loaded: boolean;
song_metadata: string;
}

View File

@ -470,6 +470,11 @@ const loader_javascript = {
})
}
/* load some extends classes */
await loader.load_scripts([
["js/connection/ConnectionBase.js"]
]);
/* load the main app */
await loader.load_scripts([
//Load general API's
@ -539,11 +544,16 @@ const loader_javascript = {
"js/settings.js",
"js/bookmarks.js",
"js/contextMenu.js",
"js/connection.js",
"js/FileManager.js",
"js/client.js",
"js/chat.js",
//Connection
"js/connection/CommandHandler.js",
"js/connection/CommandHelper.js",
"js/connection/HandshakeHandler.js",
"js/connection/ServerConnection.js",
"js/PPTListener.js",

View File

@ -58,7 +58,7 @@ class Group {
}
}
class GroupManager {
class GroupManager extends connection.AbstractCommandHandler {
readonly handle: TSClient;
serverGroups: Group[] = [];
@ -66,18 +66,29 @@ class GroupManager {
private requests_group_permissions: GroupPermissionRequest[] = [];
constructor(client: TSClient) {
super(client.serverConnection);
client.serverConnection.command_handler_boss().register_handler(this);
this.handle = client;
}
this.handle.serverConnection.commandHandler["notifyservergrouplist"] = this.onServerGroupList.bind(this);
this.handle.serverConnection.commandHandler["notifychannelgrouplist"] = this.onServerGroupList.bind(this);
this.handle.serverConnection.commandHandler["notifyservergrouppermlist"] = this.onPermissionList.bind(this);
this.handle.serverConnection.commandHandler["notifychannelgrouppermlist"] = this.onPermissionList.bind(this);
handle_command(command: connection.ServerCommand): boolean {
switch (command.command) {
case "notifyservergrouplist":
case "notifychannelgrouplist":
this.handle_grouplist(command.arguments);
return true;
case "notifyservergrouppermlist":
case "notifychannelgrouppermlist":
this.handle_group_permission_list(command.arguments);
return true;
}
return false;
}
requestGroups(){
this.handle.serverConnection.sendCommand("servergrouplist");
this.handle.serverConnection.sendCommand("channelgrouplist");
this.handle.serverConnection.send_command("servergrouplist");
this.handle.serverConnection.send_command("channelgrouplist");
}
static sorter() : (a: Group, b: Group) => number {
@ -107,7 +118,7 @@ class GroupManager {
return undefined;
}
private onServerGroupList(json) {
private handle_grouplist(json) {
let target : GroupTarget;
if(json[0]["sgid"]) target = GroupTarget.SERVER;
else if(json[0]["cgid"]) target = GroupTarget.CHANNEL;
@ -167,7 +178,7 @@ class GroupManager {
req.promise = new LaterPromise<PermissionValue[]>();
this.requests_group_permissions.push(req);
this.handle.serverConnection.sendCommand(group.target == GroupTarget.SERVER ? "servergrouppermlist" : "channelgrouppermlist", {
this.handle.serverConnection.send_command(group.target == GroupTarget.SERVER ? "servergrouppermlist" : "channelgrouppermlist", {
cgid: group.id,
sgid: group.id
}).catch(error => {
@ -179,7 +190,7 @@ class GroupManager {
return req.promise;
}
private onPermissionList(json: any[]) {
private handle_group_permission_list(json: any[]) {
let group = json[0]["sgid"] ? this.serverGroup(parseInt(json[0]["sgid"])) : this.channelGroup(parseInt(json[0]["cgid"]));
if(!group) {
log.error(LogCategory.PERMISSIONS, tr("Got group permissions for group %o/%o, but its not a registered group!"), json[0]["sgid"], json[0]["cgid"]);

View File

@ -416,7 +416,7 @@ class TeaPermissionRequest {
promise: LaterPromise<PermissionValue[]>;
}
class PermissionManager {
class PermissionManager extends connection.AbstractCommandHandler {
readonly handle: TSClient;
permissionList: PermissionInfo[] = [];
@ -505,14 +505,34 @@ class PermissionManager {
}
constructor(client: TSClient) {
super(client.serverConnection);
//FIXME? Dont register the handler like this?
this.volatile_handler_boss = true;
client.serverConnection.command_handler_boss().register_handler(this);
this.handle = client;
}
this.handle.serverConnection.commandHandler["notifyclientneededpermissions"] = this.onNeededPermissions.bind(this);
this.handle.serverConnection.commandHandler["notifypermissionlist"] = this.onPermissionList.bind(this);
this.handle.serverConnection.commandHandler["notifychannelpermlist"] = this.onChannelPermList.bind(this);
this.handle.serverConnection.commandHandler["notifyclientpermlist"] = this.onClientPermList.bind(this);
this.handle.serverConnection.commandHandler["notifyplaylistpermlist"] = this.onPlaylistPermList.bind(this);
handle_command(command: connection.ServerCommand): boolean {
switch (command.command) {
case "notifyclientneededpermissions":
this.onNeededPermissions(command.arguments);
return true;
case "notifypermissionlist":
this.onPermissionList(command.arguments);
return true;
case "notifychannelpermlist":
this.onChannelPermList(command.arguments);
return true;
case "notifyclientpermlist":
this.onClientPermList(command.arguments);
return true;
case "notifyplaylistpermlist":
this.onPlaylistPermList(command.arguments);
return true;
}
return false;
}
initialized() : boolean {
@ -520,7 +540,7 @@ class PermissionManager {
}
public requestPermissionList() {
this.handle.serverConnection.sendCommand("permissionlist");
this.handle.serverConnection.send_command("permissionlist");
}
private onPermissionList(json) {
@ -648,7 +668,7 @@ class PermissionManager {
request = new ChannelPermissionRequest();
request.requested = Date.now();
request.channel_id = channelId;
this.handle.serverConnection.sendCommand("channelpermlist", {"cid": channelId});
this.handle.serverConnection.send_command("channelpermlist", {"cid": channelId});
this.requests_channel_permissions.push(request);
}
request.callback_error.push(reject);
@ -676,7 +696,7 @@ class PermissionManager {
request.client_id = client_id;
request.promise = new LaterPromise<PermissionValue[]>();
this.handle.serverConnection.sendCommand("clientpermlist", {cldbid: client_id}).catch(error => {
this.handle.serverConnection.send_command("clientpermlist", {cldbid: client_id}).catch(error => {
if(error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT)
request.promise.resolved([]);
else
@ -697,7 +717,7 @@ class PermissionManager {
request.channel_id = channel_id;
request.promise = new LaterPromise<PermissionValue[]>();
this.handle.serverConnection.sendCommand("channelclientpermlist", {cldbid: client_id, cid: channel_id}).catch(error => {
this.handle.serverConnection.send_command("channelclientpermlist", {cldbid: client_id, cid: channel_id}).catch(error => {
if(error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT)
request.promise.resolved([]);
else
@ -730,7 +750,7 @@ class PermissionManager {
request.playlist_id = playlist_id;
request.promise = new LaterPromise<PermissionValue[]>();
this.handle.serverConnection.sendCommand("playlistpermlist", {playlist_id: playlist_id}).catch(error => {
this.handle.serverConnection.send_command("playlistpermlist", {playlist_id: playlist_id}).catch(error => {
if(error instanceof CommandResult && error.id == ErrorID.EMPTY_RESULT)
request.promise.resolved([]);
else

View File

@ -38,7 +38,7 @@ namespace profiles {
this.identities[identities.IdentitifyType[type].toLowerCase()] = identity;
}
spawn_identity_handshake_handler?(connection: ServerConnection) : HandshakeIdentityHandler {
spawn_identity_handshake_handler?(connection: connection.AbstractServerConnection) : connection.HandshakeIdentityHandler {
const identity = this.selected_identity();
if(!identity)
return undefined;

View File

@ -15,7 +15,7 @@ namespace profiles.identities {
encode?() : string;
decode(data: string) : Promise<void>;
spawn_identity_handshake_handler(connection: ServerConnection) : HandshakeIdentityHandler;
spawn_identity_handshake_handler(connection: connection.AbstractServerConnection) : connection.HandshakeIdentityHandler;
}
export async function decode_identity(type: IdentitifyType, data: string) : Promise<Identity> {
@ -61,12 +61,33 @@ namespace profiles.identities {
return identity;
}
export abstract class AbstractHandshakeIdentityHandler implements HandshakeIdentityHandler {
connection: ServerConnection;
export class HandshakeCommandHandler<T extends AbstractHandshakeIdentityHandler> extends connection.AbstractCommandHandler {
readonly handle: T;
constructor(connection: connection.AbstractServerConnection, handle: T) {
super(connection);
this.handle = handle;
}
handle_command(command: connection.ServerCommand): boolean {
if($.isFunction(this[command.command]))
this[command.command](command.arguments);
else if(command.command == "error") {
return false;
} else {
console.warn(tr("Received unknown command while handshaking (%o)"), command);
}
return true;
}
}
export abstract class AbstractHandshakeIdentityHandler implements connection.HandshakeIdentityHandler {
connection: connection.AbstractServerConnection;
protected callbacks: ((success: boolean, message?: string) => any)[] = [];
protected constructor(connection: ServerConnection) {
protected constructor(connection: connection.AbstractServerConnection) {
this.connection = connection;
}

View File

@ -3,16 +3,19 @@
namespace profiles.identities {
class NameHandshakeHandler extends AbstractHandshakeIdentityHandler {
readonly identity: NameIdentity;
handler: HandshakeCommandHandler<NameHandshakeHandler>;
constructor(connection: ServerConnection, identity: profiles.identities.NameIdentity) {
constructor(connection: connection.AbstractServerConnection, identity: profiles.identities.NameIdentity) {
super(connection);
this.identity = identity;
this.handler = new HandshakeCommandHandler(connection, this);
this.handler["handshakeidentityproof"] = () => this.trigger_fail("server requested unexpected proof");
}
start_handshake() {
this.connection.commandHandler["handshakeidentityproof"] = () => this.trigger_fail("server requested unexpected proof");
this.connection.sendCommand("handshakebegin", {
this.connection.command_handler_boss().register_handler(this.handler);
this.connection.send_command("handshakebegin", {
intention: 0,
authentication_method: this.identity.type(),
client_nickname: this.identity.name()
@ -24,6 +27,16 @@ namespace profiles.identities {
this.trigger_fail("failed to execute begin (" + error + ")");
}).then(() => this.trigger_success());
}
protected trigger_fail(message: string) {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_fail(message);
}
protected trigger_success() {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_success();
}
}
export class NameIdentity implements Identity {
@ -67,7 +80,7 @@ namespace profiles.identities {
});
}
spawn_identity_handshake_handler(connection: ServerConnection) : HandshakeIdentityHandler {
spawn_identity_handshake_handler(connection: connection.AbstractServerConnection) : connection.HandshakeIdentityHandler {
return new NameHandshakeHandler(connection, this);
}
}

View File

@ -3,16 +3,18 @@
namespace profiles.identities {
class TeaForumHandshakeHandler extends AbstractHandshakeIdentityHandler {
readonly identity: TeaForumIdentity;
handler: HandshakeCommandHandler<TeaForumHandshakeHandler>;
constructor(connection: ServerConnection, identity: profiles.identities.TeaForumIdentity) {
constructor(connection: connection.AbstractServerConnection, identity: profiles.identities.TeaForumIdentity) {
super(connection);
this.identity = identity;
this.handler = new HandshakeCommandHandler(connection, this);
this.handler["handshakeidentityproof"] = this.handle_proof.bind(this);
}
start_handshake() {
this.connection.commandHandler["handshakeidentityproof"] = this.handle_proof.bind(this);
this.connection.sendCommand("handshakebegin", {
this.connection.command_handler_boss().register_handler(this.handler);
this.connection.send_command("handshakebegin", {
intention: 0,
authentication_method: this.identity.type(),
data: this.identity.data_json()
@ -27,7 +29,7 @@ namespace profiles.identities {
private handle_proof(json) {
this.connection.sendCommand("handshakeindentityproof", {
this.connection.send_command("handshakeindentityproof", {
proof: this.identity.data_sign()
}).catch(error => {
console.error(tr("Failed to proof the identity. Error: %o"), error);
@ -37,6 +39,16 @@ namespace profiles.identities {
this.trigger_fail("failed to execute proof (" + error + ")");
}).then(() => this.trigger_success());
}
protected trigger_fail(message: string) {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_fail(message);
}
protected trigger_success() {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_success();
}
}
export class TeaForumIdentity implements Identity {
@ -104,7 +116,7 @@ namespace profiles.identities {
});
}
spawn_identity_handshake_handler(connection: ServerConnection) : HandshakeIdentityHandler {
spawn_identity_handshake_handler(connection: connection.AbstractServerConnection) : connection.HandshakeIdentityHandler {
return new TeaForumHandshakeHandler(connection, this);
}
}

View File

@ -198,16 +198,18 @@ namespace profiles.identities {
class TeaSpeakHandshakeHandler extends AbstractHandshakeIdentityHandler {
identity: TeaSpeakIdentity;
handler: HandshakeCommandHandler<TeaSpeakHandshakeHandler>;
constructor(connection: ServerConnection, identity: TeaSpeakIdentity) {
constructor(connection: connection.AbstractServerConnection, identity: TeaSpeakIdentity) {
super(connection);
this.identity = identity;
this.handler = new HandshakeCommandHandler(connection, this);
this.handler["handshakeidentityproof"] = this.handle_proof.bind(this);
}
start_handshake() {
this.connection.commandHandler["handshakeidentityproof"] = this.handle_proof.bind(this);
this.connection.sendCommand("handshakebegin", {
this.connection.command_handler_boss().register_handler(this.handler);
this.connection.send_command("handshakebegin", {
intention: 0,
authentication_method: this.identity.type(),
publicKey: this.identity.public_key
@ -227,7 +229,7 @@ namespace profiles.identities {
}
this.identity.sign_message(json[0]["message"], json[0]["digest"]).then(proof => {
this.connection.sendCommand("handshakeindentityproof", {proof: proof}).catch(error => {
this.connection.send_command("handshakeindentityproof", {proof: proof}).catch(error => {
console.error(tr("Failed to proof the identity. Error: %o"), error);
if(error instanceof CommandResult)
@ -238,6 +240,16 @@ namespace profiles.identities {
this.trigger_fail("failed to sign message");
});
}
protected trigger_fail(message: string) {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_fail(message);
}
protected trigger_success() {
this.connection.command_handler_boss().unregister_handler(this.handler);
super.trigger_success();
}
}
class IdentityPOWWorker {
@ -831,7 +843,7 @@ namespace profiles.identities {
return base64ArrayBuffer(buffer.subarray(0, index));
}
spawn_identity_handshake_handler(connection: ServerConnection): HandshakeIdentityHandler {
spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler {
return new TeaSpeakHandshakeHandler(connection, this);
}
}

View File

@ -94,7 +94,7 @@ class ChannelEntry {
if(this._cached_channel_description) return new Promise<string>(resolve => resolve(this._cached_channel_description));
if(this._cached_channel_description_promise) return this._cached_channel_description_promise;
this.channelTree.client.serverConnection.sendCommand("channelgetdescription", {cid: this.channelId}).catch(error => {
this.channelTree.client.serverConnection.send_command("channelgetdescription", {cid: this.channelId}).catch(error => {
this._cached_channel_description_promise_reject(error);
});
@ -440,7 +440,7 @@ class ChannelEntry {
Modals.createChannelModal(this, undefined, this.channelTree.client.permissions, (changes?, permissions?) => {
if(changes) {
changes["cid"] = this.channelId;
this.channelTree.client.serverConnection.sendCommand("channeledit", changes);
this.channelTree.client.serverConnection.send_command("channeledit", changes);
log.info(LogCategory.CHANNEL, tr("Changed channel properties of channel %s: %o"), this.channelName(), changes);
}
@ -456,7 +456,9 @@ class ChannelEntry {
}
perms[0]["cid"] = this.channelId;
this.channelTree.client.serverConnection.sendCommand("channeladdperm", perms, ["continueonerror"]).then(() => {
this.channelTree.client.serverConnection.send_command("channeladdperm", perms, {
flagset: ["continueonerror"]
}).then(() => {
sound.play(Sound.CHANNEL_EDITED_SELF);
});
}
@ -469,7 +471,7 @@ class ChannelEntry {
name: tr("Delete channel"),
invalidPermission: !flagDelete,
callback: () => {
this.channelTree.client.serverConnection.sendCommand("channeldelete", {cid: this.channelId}).then(() => {
this.channelTree.client.serverConnection.send_command("channeldelete", {cid: this.channelId}).then(() => {
sound.play(Sound.CHANNEL_DELETED);
})
}
@ -480,7 +482,7 @@ class ChannelEntry {
icon: "client-addon-collection",
name: tr("Create music bot"),
callback: () => {
this.channelTree.client.serverConnection.sendCommand("musicbotcreate", {cid: this.channelId}).then(() => {
this.channelTree.client.serverConnection.send_command("musicbotcreate", {cid: this.channelId}).then(() => {
createInfoModal(tr("Bot successfully created"), tr("Bot has been successfully created.")).open();
}).catch(error => {
if(error instanceof CommandResult) {
@ -692,7 +694,7 @@ class ChannelEntry {
});
}).open();
} else if(this.channelTree.client.getClient().currentChannel() != this)
this.channelTree.client.getServerConnection().joinChannel(this, this._cachedPassword).then(() => {
this.channelTree.client.getServerConnection().command_helper.joinChannel(this, this._cachedPassword).then(() => {
sound.play(Sound.CHANNEL_JOINED);
}).catch(error => {
if(error instanceof CommandResult) {

View File

@ -146,7 +146,7 @@ class ClientEntry {
const source = client._channel;
const self = this.channelTree.client.getClient();
this.channelTree.client.serverConnection.sendCommand("clientmove", {
this.channelTree.client.serverConnection.send_command("clientmove", {
clid: client.clientId(),
cid: target.getChannelId()
}).then(event => {
@ -179,7 +179,7 @@ class ClientEntry {
entry.name = group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]";
if(this.groupAssigned(group)) {
entry.callback = () => {
this.channelTree.client.serverConnection.sendCommand("servergroupdelclient", {
this.channelTree.client.serverConnection.send_command("servergroupdelclient", {
sgid: group.id,
cldbid: this.properties.client_database_id
});
@ -187,7 +187,7 @@ class ClientEntry {
entry.disabled = !this.channelTree.client.permissions.neededPermission(PermissionType.I_GROUP_MEMBER_ADD_POWER).granted(group.requiredMemberRemovePower);
} else {
entry.callback = () => {
this.channelTree.client.serverConnection.sendCommand("servergroupaddclient", {
this.channelTree.client.serverConnection.send_command("servergroupaddclient", {
sgid: group.id,
cldbid: this.properties.client_database_id
});
@ -211,7 +211,7 @@ class ClientEntry {
}
entry.name = group.name + " [" + (group.properties.savedb ? "perm" : "tmp") + "]";
entry.callback = () => {
this.channelTree.client.serverConnection.sendCommand("setclientchannelgroup", {
this.channelTree.client.serverConnection.send_command("setclientchannelgroup", {
cldbid: this.properties.client_database_id,
cgid: group.id,
cid: this.currentChannel().channelId
@ -234,12 +234,12 @@ class ClientEntry {
callback: () => {
Modals.createServerGroupAssignmentModal(this, (group, flag) => {
if(flag) {
return this.channelTree.client.serverConnection.sendCommand("servergroupaddclient", {
return this.channelTree.client.serverConnection.send_command("servergroupaddclient", {
sgid: group.id,
cldbid: this.properties.client_database_id
}).then(result => true);
} else
return this.channelTree.client.serverConnection.sendCommand("servergroupdelclient", {
return this.channelTree.client.serverConnection.send_command("servergroupdelclient", {
sgid: group.id,
cldbid: this.properties.client_database_id
}).then(result => true);
@ -286,7 +286,7 @@ class ClientEntry {
if(typeof(result) === "string") {
//TODO tr
console.log("Poking client " + _this.clientNickName() + " with message " + result);
_this.channelTree.client.serverConnection.sendCommand("clientpoke", {
_this.channelTree.client.serverConnection.send_command("clientpoke", {
clid: _this.clientId(),
msg: result
});
@ -303,7 +303,7 @@ class ClientEntry {
if(typeof(result) === "string") {
//TODO tr
console.log("Changing " + _this.clientNickName() + "'s description to " + result);
_this.channelTree.client.serverConnection.sendCommand("clientedit", {
_this.channelTree.client.serverConnection.send_command("clientedit", {
clid: _this.clientId(),
client_description: result
});
@ -319,7 +319,7 @@ class ClientEntry {
icon: "client-move_client_to_own_channel",
name: tr("Move client to your channel"),
callback: () => {
this.channelTree.client.serverConnection.sendCommand("clientmove", {
this.channelTree.client.serverConnection.send_command("clientmove", {
clid: this.clientId(),
cid: this.channelTree.client.getClient().currentChannel().getChannelId()
});
@ -333,7 +333,7 @@ class ClientEntry {
if(result) {
//TODO tr
console.log("Kicking client " + _this.clientNickName() + " from channel with reason " + result);
_this.channelTree.client.serverConnection.sendCommand("clientkick", {
_this.channelTree.client.serverConnection.send_command("clientkick", {
clid: _this.clientId(),
reasonid: ViewReasonId.VREASON_CHANNEL_KICK,
reasonmsg: result
@ -351,7 +351,7 @@ class ClientEntry {
if(result) {
//TODO tr
console.log("Kicking client " + _this.clientNickName() + " from server with reason " + result);
_this.channelTree.client.serverConnection.sendCommand("clientkick", {
_this.channelTree.client.serverConnection.send_command("clientkick", {
clid: _this.clientId(),
reasonid: ViewReasonId.VREASON_SERVER_KICK,
reasonmsg: result
@ -367,11 +367,13 @@ class ClientEntry {
invalidPermission: !this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1),
callback: () => {
Modals.spawnBanClient(this.properties.client_nickname, (data) => {
this.channelTree.client.serverConnection.sendCommand("banclient", {
this.channelTree.client.serverConnection.send_command("banclient", {
uid: this.properties.client_unique_identifier,
banreason: data.reason,
time: data.length
}, [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]).then(() => {
}, {
flagset: [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]
}).then(() => {
sound.play(Sound.USER_BANNED);
});
});
@ -386,7 +388,7 @@ class ClientEntry {
invalidPermission: true, //!this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1),
callback: () => {
Modals.spawnBanClient(this.properties.client_nickname, (duration, reason) => {
this.channelTree.client.serverConnection.sendCommand("banclient", {
this.channelTree.client.serverConnection.send_command("banclient", {
uid: this.properties.client_unique_identifier,
banreason: reason,
time: duration
@ -653,7 +655,7 @@ class ClientEntry {
updateClientVariables(){
if(this.lastVariableUpdate == 0 || new Date().getTime() - 10 * 60 * 1000 > this.lastVariableUpdate){ //Cache these only 10 min
this.lastVariableUpdate = new Date().getTime();
this.channelTree.client.serverConnection.sendCommand("clientgetvariables", {clid: this.clientId()});
this.channelTree.client.serverConnection.send_command("clientgetvariables", {clid: this.clientId()});
}
}
@ -667,12 +669,12 @@ class ClientEntry {
const _this = this;
c.onMessageSend = function (text: string) {
_this.channelTree.client.serverConnection.sendMessage(text, ChatType.CLIENT, _this);
_this.channelTree.client.serverConnection.command_helper.sendMessage(text, ChatType.CLIENT, _this);
};
c.onClose = function () : boolean {
//TODO check online?
_this.channelTree.client.serverConnection.sendCommand("clientchatclosed", {"clid": _this.clientId()});
_this.channelTree.client.serverConnection.send_command("clientchatclosed", {"clid": _this.clientId()});
return true;
}
}
@ -797,7 +799,7 @@ class LocalClientEntry extends ClientEntry {
createInputModal(tr("Change own description"), tr("New description:<br>"), text => true, result => {
if(result) {
console.log(tr("Changing own description to %s"), result);
_self.channelTree.client.serverConnection.sendCommand("clientedit", {
_self.channelTree.client.serverConnection.send_command("clientedit", {
clid: _self.clientId(),
client_description: result
});
@ -853,7 +855,7 @@ class LocalClientEntry extends ClientEntry {
if(_self.clientNickName() == text) return;
elm.text(_self.clientNickName());
_self.handle.serverConnection.updateClient("client_nickname", text).then((e) => {
_self.handle.serverConnection.command_helper.updateClient("client_nickname", text).then((e) => {
chat.serverChat().appendMessage(tr("Nickname successfully changed"));
}).catch((e: CommandResult) => {
chat.serverChat().appendError(tr("Could not change nickname ({})"), e.extra_message);
@ -915,7 +917,7 @@ class MusicClientEntry extends ClientEntry {
callback: () => {
createInputModal(tr("Change music bots nickname"), tr("New nickname:<br>"), text => text.length >= 3 && text.length <= 31, result => {
if(result) {
this.channelTree.client.serverConnection.sendCommand("clientedit", {
this.channelTree.client.serverConnection.send_command("clientedit", {
clid: this.clientId(),
client_nickname: result
});
@ -931,7 +933,7 @@ class MusicClientEntry extends ClientEntry {
callback: () => {
createInputModal(tr("Change music bots description"), tr("New description:<br>"), text => true, result => {
if(typeof(result) === 'string') {
this.channelTree.client.serverConnection.sendCommand("clientedit", {
this.channelTree.client.serverConnection.send_command("clientedit", {
clid: this.clientId(),
client_description: result
});
@ -955,7 +957,7 @@ class MusicClientEntry extends ClientEntry {
icon: "client-edit",
disabled: false,
callback: () => {
this.channelTree.client.serverConnection.helper.request_playlist_list().then(lists => {
this.channelTree.client.serverConnection.command_helper.request_playlist_list().then(lists => {
for(const entry of lists) {
if(entry.playlist_id == this.properties.client_playlist_id) {
Modals.spawnPlaylistEdit(this.channelTree.client, entry);
@ -976,7 +978,7 @@ class MusicClientEntry extends ClientEntry {
callback: () => {
createInputModal(tr("Please enter the URL"), tr("URL:"), text => true, result => {
if(result) {
this.channelTree.client.serverConnection.sendCommand("musicbotqueueadd", {
this.channelTree.client.serverConnection.send_command("musicbotqueueadd", {
bot_id: this.properties.client_database_id,
type: "yt", //Its a hint not a force!
url: result
@ -999,7 +1001,7 @@ class MusicClientEntry extends ClientEntry {
icon: "client-move_client_to_own_channel",
name: tr("Move client to your channel"),
callback: () => {
this.channelTree.client.serverConnection.sendCommand("clientmove", {
this.channelTree.client.serverConnection.send_command("clientmove", {
clid: this.clientId(),
cid: this.channelTree.client.getClient().currentChannel().getChannelId()
});
@ -1012,7 +1014,7 @@ class MusicClientEntry extends ClientEntry {
createInputModal(tr("Kick client from channel"), tr("Kick reason:<br>"), text => true, result => {
if(result) {
console.log(tr("Kicking client %o from channel with reason %o"), this.clientNickName(), result);
this.channelTree.client.serverConnection.sendCommand("clientkick", {
this.channelTree.client.serverConnection.send_command("clientkick", {
clid: this.clientId(),
reasonid: ViewReasonId.VREASON_CHANNEL_KICK,
reasonmsg: result
@ -1045,7 +1047,7 @@ class MusicClientEntry extends ClientEntry {
max_volume = 100;
Modals.spawnChangeRemoteVolume(this.properties.player_volume, max_volume / 100, value => {
this.channelTree.client.serverConnection.sendCommand("clientedit", {
this.channelTree.client.serverConnection.send_command("clientedit", {
clid: this.clientId(),
player_volume: value,
}).then(() => {
@ -1064,7 +1066,7 @@ class MusicClientEntry extends ClientEntry {
const tag = $.spawn("div").append(MessageHelper.formatMessage(tr("Do you really want to delete {0}"), this.createChatTag(false)));
Modals.spawnYesNo(tr("Are you sure?"), $.spawn("div").append(tag), result => {
if(result) {
this.channelTree.client.serverConnection.sendCommand("musicbotdelete", {
this.channelTree.client.serverConnection.send_command("musicbotdelete", {
bot_id: this.properties.client_database_id
});
}
@ -1105,7 +1107,7 @@ class MusicClientEntry extends ClientEntry {
this._info_promise_resolve = resolve;
});
this.channelTree.client.serverConnection.sendCommand("musicbotplayerinfo", {bot_id: this.properties.client_database_id });
this.channelTree.client.serverConnection.send_command("musicbotplayerinfo", {bot_id: this.properties.client_database_id });
return this._info_promise;
}
}

View File

@ -137,7 +137,7 @@ class ControlBar {
if(this.handle.serverConnection.connected)
this.handle.serverConnection.sendCommand("clientupdate", {
this.handle.serverConnection.send_command("clientupdate", {
client_input_muted: this._muteInput
});
settings.changeGlobal("mute_input", this._muteInput);
@ -162,7 +162,7 @@ class ControlBar {
}
if(this.handle.serverConnection.connected)
this.handle.serverConnection.sendCommand("clientupdate", {
this.handle.serverConnection.send_command("clientupdate", {
client_output_muted: this._muteOutput
});
settings.changeGlobal("mute_output", this._muteOutput);
@ -187,7 +187,7 @@ class ControlBar {
}
if(this.handle.serverConnection.connected)
this.handle.serverConnection.sendCommand("clientupdate", {
this.handle.serverConnection.send_command("clientupdate", {
client_away: this._away,
client_away_message: this._awayMessage
});
@ -201,7 +201,7 @@ class ControlBar {
updateProperties() {
if(this.handle.serverConnection.connected)
this.handle.serverConnection.sendCommand("clientupdate", {
this.handle.serverConnection.send_command("clientupdate", {
client_input_muted: this._muteInput,
client_output_muted: this._muteOutput,
client_away: this._away,
@ -221,7 +221,7 @@ class ControlBar {
this.htmlTag.find(".btn_mute_input").prop("disabled", !this.codec_supported|| !this.support_playback || !this.support_record);
this.htmlTag.find(".btn_mute_output").prop("disabled", !this.codec_supported || !this.support_playback);
this.handle.serverConnection.sendCommand("clientupdate", {
this.handle.serverConnection.send_command("clientupdate", {
client_input_hardware: this.codec_supported && this.support_record,
client_output_hardware: this.codec_supported && this.support_playback
});
@ -273,7 +273,7 @@ class ControlBar {
createInputModal(tr("Use token"), tr("Please enter your token/priviledge key"), message => message.length > 0, result => {
if(!result) return;
if(this.handle.serverConnection.connected)
this.handle.serverConnection.sendCommand("tokenuse", {
this.handle.serverConnection.send_command("tokenuse", {
token: result
}).then(() => {
createInfoModal(tr("Use token"), tr("Toke successfully used!")).open();

View File

@ -412,7 +412,7 @@ enum MusicPlayerState {
}
class MusicInfoManager extends ClientInfoManager {
notify_status: (json) => any;
single_handler: connection.SingleCommandHandler;
createFrame<_>(handle: InfoBar<_>, channel: MusicClientEntry, html_tag: JQuery<HTMLElement>) {
super.createFrame(handle, channel, html_tag);
@ -420,9 +420,9 @@ class MusicInfoManager extends ClientInfoManager {
}
updateFrame(bot: MusicClientEntry, html_tag: JQuery<HTMLElement>) {
if(this.notify_status) {
this.handle.handle.serverConnection.commandHandler.unset_handler("notifymusicstatusupdate", this.notify_status);
this.notify_status = undefined;
if(this.single_handler) {
this.handle.handle.serverConnection.command_handler_boss().remove_single_handler(this.single_handler);
this.single_handler = undefined;
}
this.resetIntervals();
@ -459,7 +459,7 @@ class MusicInfoManager extends ClientInfoManager {
let button_stop = frame.find('.button_stop');
button_play.click(handler => {
if(!button_play.hasClass("active")) {
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: 1
}).then(updated => this.triggerUpdate()).catch(error => {
@ -472,7 +472,7 @@ class MusicInfoManager extends ClientInfoManager {
});
button_pause.click(handler => {
if(!button_pause.hasClass("active")) {
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: 2
}).then(updated => this.triggerUpdate()).catch(error => {
@ -484,7 +484,7 @@ class MusicInfoManager extends ClientInfoManager {
button_pause.hide();
});
button_stop.click(handler => {
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: 0
}).then(updated => this.triggerUpdate()).catch(error => {
@ -507,7 +507,7 @@ class MusicInfoManager extends ClientInfoManager {
{ /* Button functions */
_frame.find(".btn-forward").click(() => {
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: 3
}).then(updated => this.triggerUpdate()).catch(error => {
@ -516,7 +516,7 @@ class MusicInfoManager extends ClientInfoManager {
});
});
_frame.find(".btn-rewind").click(() => {
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: 4
}).then(updated => this.triggerUpdate()).catch(error => {
@ -525,7 +525,7 @@ class MusicInfoManager extends ClientInfoManager {
});
});
_frame.find(".btn-settings").click(() => {
this.handle.handle.serverConnection.helper.request_playlist_list().then(lists => {
this.handle.handle.serverConnection.command_helper.request_playlist_list().then(lists => {
for(const entry of lists) {
if(entry.playlist_id == bot.properties.client_playlist_id) {
Modals.spawnPlaylistEdit(bot.channelTree.client, entry);
@ -581,7 +581,7 @@ class MusicInfoManager extends ClientInfoManager {
slider.prop("edited", true);
let current_timestamp = info.player_replay_index + Date.now() - timestamp;
this.handle.handle.serverConnection.sendCommand("musicbotplayeraction", {
this.handle.handle.serverConnection.send_command("musicbotplayeraction", {
bot_id: bot.properties.client_database_id,
action: current_timestamp > target_timestamp ? 6 : 5,
units: current_timestamp < target_timestamp ? target_timestamp - current_timestamp : current_timestamp - target_timestamp
@ -627,17 +627,23 @@ class MusicInfoManager extends ClientInfoManager {
update_handler();
/* register subscription */
this.handle.handle.serverConnection.sendCommand("musicbotsetsubscription", {bot_id: bot.properties.client_database_id}).catch(error => {
this.handle.handle.serverConnection.send_command("musicbotsetsubscription", {bot_id: bot.properties.client_database_id}).catch(error => {
console.error("Failed to subscribe to displayed music bot! Using pseudo timeline");
}).then(() => {
clearInterval(interval);
});
this.notify_status = json => {
json = json[0];
this.single_handler = {
command: "notifymusicstatusupdate",
function: command => {
const json = command.arguments[0];
update_handler(parseInt(json["player_replay_index"]), parseInt(json["player_buffered_index"]));
return false; /* do not unregister me! */
}
};
this.handle.handle.serverConnection.commandHandler.set_handler("notifymusicstatusupdate", this.notify_status);
this.handle.handle.serverConnection.command_handler_boss().register_single_handler(this.single_handler);
}
});
}
@ -718,9 +724,9 @@ class MusicInfoManager extends ClientInfoManager {
}
finalizeFrame(object: ClientEntry, frame: JQuery<HTMLElement>) {
if(this.notify_status) {
this.handle.handle.serverConnection.commandHandler.unset_handler("notifymusicstatusupdate", this.notify_status);
this.notify_status = undefined;
if(this.single_handler) {
this.handle.handle.serverConnection.command_handler_boss().remove_single_handler(this.single_handler);
this.single_handler = undefined;
}
super.finalizeFrame(object, frame);

View File

@ -34,7 +34,7 @@ namespace Modals {
if(result.server_id < 0) result.server_id = undefined;
console.log(tr("Adding ban %o"), result);
client.serverConnection.sendCommand("banadd", {
client.serverConnection.send_command("banadd", {
ip: result.ip,
name: result.name,
uid: result.unique_id,
@ -55,7 +55,7 @@ namespace Modals {
console.log(tr("Apply edit changes %o"), result);
if(result.server_id < 0) result.server_id = undefined;
client.serverConnection.sendCommand("banedit", {
client.serverConnection.send_command("banedit", {
banid: result.banid,
ip: result.ip,
name: result.name,
@ -73,7 +73,7 @@ namespace Modals {
});
}, ban => {
console.log(tr("Deleting ban %o"), ban);
client.serverConnection.sendCommand("bandel", {
client.serverConnection.send_command("bandel", {
banid: ban.banid,
sid: ban.server_id
}).then(() => {
@ -140,8 +140,8 @@ namespace Modals {
//TODO test permission
modal.clear();
client.serverConnection.sendCommand("banlist", { sid: 0 }); //Global ban list
client.serverConnection.sendCommand("banlist").catch(error => {
client.serverConnection.send_command("banlist", { sid: 0 }); //Global ban list
client.serverConnection.send_command("banlist").catch(error => {
if(error instanceof CommandResult) {
} else {
console.error(error);

View File

@ -665,7 +665,7 @@ namespace Modals {
permission.id,
);
return globalClient.serverConnection.sendCommand("channelclientdelperm", {
return globalClient.serverConnection.send_command("channelclientdelperm", {
cldbid: current_cldbid,
cid: current_channel.channelId,
permid: permission.id,
@ -677,7 +677,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channelclientdelperm", {
return globalClient.serverConnection.send_command("channelclientdelperm", {
cldbid: current_cldbid,
cid: current_channel.channelId,
permid: permission.id_grant(),
@ -694,7 +694,7 @@ namespace Modals {
value.flag_negate
);
return globalClient.serverConnection.sendCommand("channelclientaddperm", {
return globalClient.serverConnection.send_command("channelclientaddperm", {
cldbid: current_cldbid,
cid: current_channel.channelId,
permid: permission.id,
@ -709,7 +709,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channelclientaddperm", {
return globalClient.serverConnection.send_command("channelclientaddperm", {
cldbid: current_cldbid,
cid: current_channel.channelId,
permid: permission.id_grant(),
@ -821,7 +821,7 @@ namespace Modals {
permission.id,
);
return globalClient.serverConnection.sendCommand("clientaddperm", {
return globalClient.serverConnection.send_command("clientaddperm", {
cldbid: current_cldbid,
permid: permission.id,
});
@ -832,7 +832,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("clientaddperm", {
return globalClient.serverConnection.send_command("clientaddperm", {
cldbid: current_cldbid,
permid: permission.id_grant(),
});
@ -848,7 +848,7 @@ namespace Modals {
value.flag_negate
);
return globalClient.serverConnection.sendCommand("clientaddperm", {
return globalClient.serverConnection.send_command("clientaddperm", {
cldbid: current_cldbid,
permid: permission.id,
permvalue: value.value,
@ -862,7 +862,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("clientaddperm", {
return globalClient.serverConnection.send_command("clientaddperm", {
cldbid: current_cldbid,
permid: permission.id_grant(),
permvalue: value.granted,
@ -956,7 +956,7 @@ namespace Modals {
permission.id,
);
return globalClient.serverConnection.sendCommand("channeldelperm", {
return globalClient.serverConnection.send_command("channeldelperm", {
cid: current_channel.channelId,
permid: permission.id,
});
@ -968,7 +968,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channeldelperm", {
return globalClient.serverConnection.send_command("channeldelperm", {
cid: current_channel.channelId,
permid: permission.id_grant(),
});
@ -984,7 +984,7 @@ namespace Modals {
value.flag_negate
);
return globalClient.serverConnection.sendCommand("channeladdperm", {
return globalClient.serverConnection.send_command("channeladdperm", {
cid: current_channel.channelId,
permid: permission.id,
permvalue: value.value,
@ -999,7 +999,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channeladdperm", {
return globalClient.serverConnection.send_command("channeladdperm", {
cid: current_channel.channelId,
permid: permission.id_grant(),
permvalue: value.granted,
@ -1058,7 +1058,7 @@ namespace Modals {
permission.id,
);
return globalClient.serverConnection.sendCommand("channelgroupdelperm", {
return globalClient.serverConnection.send_command("channelgroupdelperm", {
cgid: current_group.id,
permid: permission.id,
});
@ -1069,7 +1069,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channelgroupdelperm", {
return globalClient.serverConnection.send_command("channelgroupdelperm", {
cgid: current_group.id,
permid: permission.id_grant(),
});
@ -1085,7 +1085,7 @@ namespace Modals {
value.flag_negate
);
return globalClient.serverConnection.sendCommand("channelgroupaddperm", {
return globalClient.serverConnection.send_command("channelgroupaddperm", {
cgid: current_group.id,
permid: permission.id,
permvalue: value.value,
@ -1099,7 +1099,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("channelgroupaddperm", {
return globalClient.serverConnection.send_command("channelgroupaddperm", {
cgid: current_group.id,
permid: permission.id_grant(),
permvalue: value.granted,
@ -1218,7 +1218,7 @@ namespace Modals {
permission.id,
);
return globalClient.serverConnection.sendCommand("servergroupdelperm", {
return globalClient.serverConnection.send_command("servergroupdelperm", {
sgid: current_group.id,
permid: permission.id,
});
@ -1229,7 +1229,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("servergroupdelperm", {
return globalClient.serverConnection.send_command("servergroupdelperm", {
sgid: current_group.id,
permid: permission.id_grant(),
});
@ -1245,7 +1245,7 @@ namespace Modals {
value.flag_negate
);
return globalClient.serverConnection.sendCommand("servergroupaddperm", {
return globalClient.serverConnection.send_command("servergroupaddperm", {
sgid: current_group.id,
permid: permission.id,
permvalue: value.value,
@ -1259,7 +1259,7 @@ namespace Modals {
value.granted,
);
return globalClient.serverConnection.sendCommand("servergroupaddperm", {
return globalClient.serverConnection.send_command("servergroupaddperm", {
sgid: current_group.id,
permid: permission.id_grant(),
permvalue: value.granted,

View File

@ -99,7 +99,7 @@ namespace Modals {
template.find(".buttons .button-save").on('click', event => {
if(Object.keys(changed_properties).length != 0) {
changed_properties["playlist_id"] = playlist.playlist_id;
client.serverConnection.sendCommand("playlistedit", changed_properties).then(() => {
client.serverConnection.send_command("playlistedit", changed_properties).then(() => {
changed_properties = {};
update_save();
}).catch(error => {
@ -121,7 +121,7 @@ namespace Modals {
}
array[0]["playlist_id"] = playlist.playlist_id;
client.serverConnection.sendCommand("playlistaddperm", array).then(() => {
client.serverConnection.send_command("playlistaddperm", array).then(() => {
changed_permissions = {};
update_save();
}).catch(error => {
@ -193,7 +193,7 @@ namespace Modals {
button_delete.detach();
else
button_delete.on('click', event => {
client.serverConnection.sendCommand("playlistsongremove", {
client.serverConnection.send_command("playlistsongremove", {
playlist_id: playlist.playlist_id,
song_id: song.song_id
}).then(() => {
@ -236,7 +236,7 @@ namespace Modals {
song_tag.find(".button-song-add").on('click', event => {
spawnSongAdd(playlist, (url, loader) => {
//playlist_id invoker previous url
client.serverConnection.sendCommand("playlistsongadd", {
client.serverConnection.send_command("playlistsongadd", {
playlist_id: playlist.playlist_id,
invoker: loader,
url: url

View File

@ -108,7 +108,7 @@ namespace Modals {
});
};
client.serverConnection.commandHandler.set_handler("notifyplaylistcreated", notify_handler);
client.serverConnection.sendCommand("playlistcreate").catch(error => {
client.serverConnection.send_command("playlistcreate").catch(error => {
client.serverConnection.commandHandler.unset_handler("notifyplaylistcreated", notify_handler);
if(error instanceof CommandResult)
error = error.extra_message || error.message;
@ -126,7 +126,7 @@ namespace Modals {
Modals.spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this playlist?"), result => {
if(result) {
client.serverConnection.sendCommand("playlistdelete", {playlist_id: selected_playlist.playlist_id}).then(() => {
client.serverConnection.send_command("playlistdelete", {playlist_id: selected_playlist.playlist_id}).then(() => {
createInfoModal(tr("Playlist deleted successful"), tr("This playlist has been deleted successfully.")).open();
update_list();
}).catch(error => {

View File

@ -19,8 +19,8 @@ namespace Modals {
const update_list = () => {
const info_tag = modal.htmlTag.find(".footer .info a");
info_tag.text("loading...");
client.serverConnection.helper.current_virtual_server_id().then(server_id => {
client.serverConnection.helper.request_query_list(server_id).then(result => {
client.serverConnection.command_helper.current_virtual_server_id().then(server_id => {
client.serverConnection.command_helper.request_query_list(server_id).then(result => {
selected_query = undefined;
const entries_tag = modal.htmlTag.find(".query-list-entries");
@ -73,7 +73,7 @@ namespace Modals {
createInputModal(tr("Change account name"), tr("Enter the new name for the login:<br>"), text => text.length >= 3, result => {
if(result) {
client.serverConnection.sendCommand("queryrename", {
client.serverConnection.send_command("queryrename", {
client_login_name: selected_query.username,
client_new_login_name: result
}).catch(error => {
@ -92,23 +92,28 @@ namespace Modals {
createInputModal(tr("Change account's password"), tr("Enter a new password (leave blank for auto generation):<br>"), text => true, result => {
if(result !== false) {
client.serverConnection.sendCommand("querychangepassword", {
const single_handler: connection.SingleCommandHandler = {
command: "notifyquerypasswordchanges",
function: command => {
Modals.spawnQueryCreated({
username: command.arguments[0]["client_login_name"],
password: command.arguments[0]["client_login_password"]
}, false);
return true;
}
};
client.serverConnection.command_handler_boss().register_single_handler(single_handler);
client.serverConnection.send_command("querychangepassword", {
client_login_name: selected_query.username,
client_login_password: result
}).catch(error => {
client.serverConnection.command_handler_boss().remove_single_handler(single_handler);
if(error instanceof CommandResult)
error = error.extra_message || error.message;
createErrorModal(tr("Unable to change password"), tr("Failed to change password<br>Message: ") + error).open();
});
client.serverConnection.commandHandler["notifyquerypasswordchanges"] = json => {
Modals.spawnQueryCreated({
username: json[0]["client_login_name"],
password: json[0]["client_login_password"]
}, false);
client.serverConnection.commandHandler["notifyquerypasswordchanges"] = undefined;
};
}
}).open();
});
@ -117,7 +122,7 @@ namespace Modals {
Modals.spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this account?"), result => {
if(result) {
client.serverConnection.sendCommand("querydelete", {
client.serverConnection.send_command("querydelete", {
client_login_name: selected_query.username
}).catch(error => {
if(error instanceof CommandResult)

View File

@ -144,7 +144,7 @@ class ServerEntry {
log.info(LogCategory.SERVER, tr("Changing server properties %o"), properties);
console.log(tr("Changed properties: %o"), properties);
if (properties)
this.channelTree.client.serverConnection.sendCommand("serveredit", properties).then(() => {
this.channelTree.client.serverConnection.send_command("serveredit", properties).then(() => {
sound.play(Sound.SERVER_EDITED_SELF);
});
});
@ -200,7 +200,7 @@ class ServerEntry {
if(this.info_request_promise && Date.now() - this.lastInfoRequest < 1000) return this.info_request_promise;
this.lastInfoRequest = Date.now();
this.nextInfoRequest = this.lastInfoRequest + 10 * 1000;
this.channelTree.client.serverConnection.sendCommand("servergetvariables").catch(error => {
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;

View File

@ -450,7 +450,7 @@ class ChannelTree {
createInputModal(tr("Poke clients"), tr("Poke message:<br>"), text => true, result => {
if (typeof(result) === "string") {
for (const client of this.currently_selected as ClientEntry[])
this.client.serverConnection.sendCommand("clientpoke", {
this.client.serverConnection.send_command("clientpoke", {
clid: client.clientId(),
msg: result
});
@ -467,7 +467,7 @@ class ChannelTree {
callback: () => {
const target = this.client.getClient().currentChannel().getChannelId();
for(const client of clients)
this.client.serverConnection.sendCommand("clientmove", {
this.client.serverConnection.send_command("clientmove", {
clid: client.clientId(),
cid: target
});
@ -483,7 +483,7 @@ class ChannelTree {
createInputModal(tr("Kick clients from channel"), tr("Kick reason:<br>"), text => true, result => {
if (result) {
for (const client of clients)
this.client.serverConnection.sendCommand("clientkick", {
this.client.serverConnection.send_command("clientkick", {
clid: client.clientId(),
reasonid: ViewReasonId.VREASON_CHANNEL_KICK,
reasonmsg: result
@ -503,7 +503,7 @@ class ChannelTree {
createInputModal(tr("Kick clients from server"), tr("Kick reason:<br>"), text => true, result => {
if (result) {
for (const client of clients)
this.client.serverConnection.sendCommand("clientkick", {
this.client.serverConnection.send_command("clientkick", {
clid: client.clientId(),
reasonid: ViewReasonId.VREASON_SERVER_KICK,
reasonmsg: result
@ -520,11 +520,13 @@ class ChannelTree {
callback: () => {
Modals.spawnBanClient((clients).map(entry => entry.clientNickName()), (data) => {
for (const client of clients)
this.client.serverConnection.sendCommand("banclient", {
this.client.serverConnection.send_command("banclient", {
uid: client.properties.client_unique_identifier,
banreason: data.reason,
time: data.length
}, [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]).then(() => {
}, {
flagset: [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]
}).then(() => {
sound.play(Sound.USER_BANNED);
});
});
@ -545,7 +547,7 @@ class ChannelTree {
Modals.spawnYesNo(tr("Are you sure?"), tag_container, result => {
if(result) {
for(const client of clients)
this.client.serverConnection.sendCommand("musicbotdelete", {
this.client.serverConnection.send_command("musicbotdelete", {
botid: client.properties.client_database_id
});
}
@ -595,7 +597,7 @@ class ChannelTree {
if(!properties) return;
properties["cpid"] = parent ? parent.channelId : 0;
log.debug(LogCategory.CHANNEL, tr("Creating a new channel.\nProperties: %o\nPermissions: %o"), properties);
this.client.serverConnection.sendCommand("channelcreate", properties).then(() => {
this.client.serverConnection.send_command("channelcreate", properties).then(() => {
let channel = this.find_channel_by_name(properties.channel_name, parent, true);
if(!channel) {
log.error(LogCategory.CHANNEL, tr("Failed to resolve channel after creation. Could not apply permissions!"));
@ -613,7 +615,9 @@ class ChannelTree {
}
perms[0]["cid"] = channel.channelId;
return this.client.serverConnection.sendCommand("channeladdperm", perms, ["continueonerror"]).then(() => new Promise<ChannelEntry>(resolve => { resolve(channel); }));
return this.client.serverConnection.send_command("channeladdperm", perms, {
flagset: ["continueonerror"]
}).then(() => new Promise<ChannelEntry>(resolve => { resolve(channel); }));
}
return new Promise<ChannelEntry>(resolve => { resolve(channel); })

View File

@ -151,7 +151,7 @@ class AudioController {
private playQueue() {
let buffer: AudioBuffer;
while(buffer = this.audioCache.pop_front()) {
while((buffer = this.audioCache.pop_front())) {
if(this.playingAudioCache.length >= this._latencyBufferLength * 1.5 + 3) {
console.log(tr("Dropping buffer because playing queue grows to much"));
continue; /* drop the data (we're behind) */