1179 lines
49 KiB
TypeScript
1179 lines
49 KiB
TypeScript
import * as log from "tc-shared/log";
|
|
import * as server_log from "tc-shared/ui/frames/server_log";
|
|
import {
|
|
AbstractServerConnection, CommandOptions, ServerCommand
|
|
} from "tc-shared/connection/ConnectionBase";
|
|
import {Sound} from "tc-shared/sound/Sounds";
|
|
import {CommandResult, ErrorID} from "tc-shared/connection/ServerConnectionDeclaration";
|
|
import {LogCategory} from "tc-shared/log";
|
|
import {createErrorModal, createInfoModal, createInputModal, createModal} from "tc-shared/ui/elements/Modal";
|
|
import {
|
|
ClientConnectionInfo,
|
|
ClientEntry,
|
|
ClientType,
|
|
LocalClientEntry,
|
|
MusicClientEntry,
|
|
SongInfo
|
|
} from "tc-shared/ui/client";
|
|
import {ChannelEntry} from "tc-shared/ui/channel";
|
|
import {ConnectionHandler, DisconnectReason, ViewReasonId} from "tc-shared/ConnectionHandler";
|
|
import {bbcode_chat, formatMessage} from "tc-shared/ui/frames/chat";
|
|
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
|
|
import {spawnPoke} from "tc-shared/ui/modal/ModalPoke";
|
|
import {PrivateConversationState} from "tc-shared/ui/frames/side/private_conversations";
|
|
import {Conversation} from "tc-shared/ui/frames/side/conversations";
|
|
import {AbstractCommandHandler, AbstractCommandHandlerBoss} from "tc-shared/connection/AbstractCommandHandler";
|
|
|
|
export class ServerConnectionCommandBoss extends AbstractCommandHandlerBoss {
|
|
constructor(connection: AbstractServerConnection) {
|
|
super(connection);
|
|
}
|
|
}
|
|
|
|
export class ConnectionCommandHandler extends AbstractCommandHandler {
|
|
readonly connection: AbstractServerConnection;
|
|
readonly connection_handler: ConnectionHandler;
|
|
|
|
constructor(connection: AbstractServerConnection) {
|
|
super(connection);
|
|
this.connection_handler = connection.client;
|
|
|
|
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["notifyserverconnectioninfo"] = this.handleNotifyServerConnectionInfo;
|
|
this["notifyconnectioninfo"] = this.handleNotifyConnectionInfo;
|
|
|
|
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["notifyclientchatcomposing"] = this.notifyClientChatComposing;
|
|
this["notifyclientchatclosed"] = this.handleNotifyClientChatClosed;
|
|
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;
|
|
|
|
this["notifychannelsubscribed"] = this.handleNotifyChannelSubscribed;
|
|
this["notifychannelunsubscribed"] = this.handleNotifyChannelUnsubscribed;
|
|
|
|
this["notifyconversationhistory"] = this.handleNotifyConversationHistory;
|
|
this["notifyconversationmessagedelete"] = this.handleNotifyConversationMessageDelete;
|
|
|
|
this["notifymusicstatusupdate"] = this.handleNotifyMusicStatusUpdate;
|
|
this["notifymusicplayersongchange"] = this.handleMusicPlayerSongChange;
|
|
|
|
this["notifyplaylistsongadd"] = this.handleNotifyPlaylistSongAdd;
|
|
this["notifyplaylistsongremove"] = this.handleNotifyPlaylistSongRemove;
|
|
this["notifyplaylistsongreorder"] = this.handleNotifyPlaylistSongReorder;
|
|
this["notifyplaylistsongloaded"] = this.handleNotifyPlaylistSongLoaded;
|
|
}
|
|
|
|
private loggable_invoker(unique_id, client_id, name) : server_log.base.Client | undefined {
|
|
const id = parseInt(client_id);
|
|
if(typeof(client_id) === "undefined" || Number.isNaN(id))
|
|
return undefined;
|
|
|
|
if(id == 0)
|
|
return {
|
|
client_id: 0,
|
|
client_unique_id: this.connection_handler.channelTree.server.properties.virtualserver_unique_identifier,
|
|
client_name: this.connection_handler.channelTree.server.properties.virtualserver_name,
|
|
};
|
|
|
|
return {
|
|
client_unique_id: unique_id,
|
|
client_name: name,
|
|
client_id: client_id
|
|
};
|
|
}
|
|
|
|
proxy_command_promise(promise: Promise<CommandResult>, options: CommandOptions) {
|
|
if(!options.process_result)
|
|
return promise;
|
|
|
|
return promise.catch(ex => {
|
|
if(options.process_result) {
|
|
if(ex instanceof CommandResult) {
|
|
let res = ex;
|
|
if(!res.success) {
|
|
if(res.id == ErrorID.PERMISSION_ERROR) { //Permission error
|
|
const permission = this.connection_handler.permissions.resolveInfo(res.json["failed_permid"] as number);
|
|
res.message = tr("Insufficient client permissions. Failed on permission ") + (permission ? permission.name : "unknown");
|
|
this.connection_handler.log.log(server_log.Type.ERROR_PERMISSION, {
|
|
permission: this.connection_handler.permissions.resolveInfo(res.json["failed_permid"] as number)
|
|
});
|
|
this.connection_handler.sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS);
|
|
} else if(res.id != ErrorID.EMPTY_RESULT) {
|
|
this.connection_handler.log.log(server_log.Type.ERROR_CUSTOM, {
|
|
message: res.extra_message.length == 0 ? res.message : res.extra_message
|
|
});
|
|
}
|
|
}
|
|
} else if(typeof(ex) === "string") {
|
|
this.connection_handler.log.log(server_log.Type.CONNECTION_COMMAND_ERROR, {error: ex});
|
|
} else {
|
|
log.error(LogCategory.NETWORKING, tr("Invalid promise result type: %s. Result: %o"), typeof (ex), ex);
|
|
}
|
|
}
|
|
|
|
return Promise.reject(ex);
|
|
});
|
|
}
|
|
|
|
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 || code.length == 0) {
|
|
log.warn(LogCategory.NETWORKING, 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
|
|
if(this.connection.support_voice()) {
|
|
log.debug(LogCategory.NETWORKING, tr("Setting up voice"));
|
|
} else {
|
|
log.debug(LogCategory.NETWORKING, tr("Skipping voice setup (No voice bridge available)"));
|
|
}
|
|
|
|
|
|
json = json[0]; //Only one bulk
|
|
|
|
this.connection_handler.channelTree.registerClient(this.connection_handler.getClient());
|
|
this.connection.client.side_bar.channel_conversations().reset();
|
|
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);
|
|
|
|
const properties = this.connection.client.channelTree.server.properties;
|
|
/* host message */
|
|
if(properties.virtualserver_hostmessage_mode > 0) {
|
|
if(properties.virtualserver_hostmessage_mode == 1) {
|
|
/* show in log */
|
|
this.connection_handler.log.log(server_log.Type.SERVER_HOST_MESSAGE, {
|
|
message: properties.virtualserver_hostmessage
|
|
});
|
|
} else {
|
|
/* create modal/create modal and quit */
|
|
createModal({
|
|
header: tr("Host message"),
|
|
body: bbcode_chat(properties.virtualserver_hostmessage),
|
|
footer: undefined
|
|
}).open();
|
|
|
|
if(properties.virtualserver_hostmessage_mode == 3) {
|
|
/* first let the client initialize his stuff */
|
|
setTimeout(() => {
|
|
this.connection_handler.log.log(server_log.Type.SERVER_HOST_MESSAGE_DISCONNECT, {
|
|
message: properties.virtualserver_welcomemessage
|
|
});
|
|
|
|
this.connection.disconnect("host message disconnect");
|
|
this.connection_handler.handleDisconnect(DisconnectReason.SERVER_HOSTMESSAGE);
|
|
this.connection_handler.sound.play(Sound.CONNECTION_DISCONNECTED);
|
|
}, 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* welcome message */
|
|
if(properties.virtualserver_welcomemessage) {
|
|
this.connection_handler.log.log(server_log.Type.SERVER_WELCOME_MESSAGE, {
|
|
message: properties.virtualserver_welcomemessage
|
|
});
|
|
}
|
|
|
|
/* priviledge key */
|
|
if(properties.virtualserver_ask_for_privilegekey) {
|
|
createInputModal(tr("Use a privilege key"), tr("This is a newly created server for which administrator privileges have not yet been claimed.<br>Please enter the \"privilege key\" that was automatically generated when this server was created to gain administrator permissions."), message => message.length > 0, result => {
|
|
if(!result) return;
|
|
const scon = server_connections.active_connection_handler();
|
|
|
|
if(scon.serverConnection.connected)
|
|
scon.serverConnection.send_command("tokenuse", {
|
|
token: result
|
|
}).then(() => {
|
|
createInfoModal(tr("Use privilege key"), tr("Privilege key successfully used!")).open();
|
|
}).catch(error => {
|
|
createErrorModal(tr("Use privilege key"), formatMessage(tr("Failed to use privilege key: {}"), error instanceof CommandResult ? error.message : error)).open();
|
|
});
|
|
}, { field_placeholder: 'Enter Privilege Key' }).open();
|
|
}
|
|
|
|
this.connection_handler.log.log(server_log.Type.CONNECTION_CONNECTED, {
|
|
own_client: this.connection_handler.getClient().log_data()
|
|
});
|
|
this.connection_handler.sound.play(Sound.CONNECTION_CONNECTED);
|
|
this.connection.client.onConnected();
|
|
}
|
|
|
|
handleNotifyServerConnectionInfo(json) {
|
|
json = json[0];
|
|
|
|
/* everything is a number, so lets parse it */
|
|
for(const key of Object.keys(json))
|
|
json[key] = parseFloat(json[key]);
|
|
|
|
this.connection_handler.channelTree.server.set_connection_info(json);
|
|
}
|
|
|
|
handleNotifyConnectionInfo(json) {
|
|
json = json[0];
|
|
|
|
const object = new ClientConnectionInfo();
|
|
/* everything is a number (except ip), so lets parse it */
|
|
for(const key of Object.keys(json)) {
|
|
if(key === "connection_client_ip")
|
|
object[key] = json[key];
|
|
else
|
|
object[key] = parseFloat(json[key]);
|
|
}
|
|
|
|
const client = this.connection_handler.channelTree.findClient(parseInt(json["clid"]));
|
|
if(!client) {
|
|
log.warn(LogCategory.NETWORKING, tr("Received client connection info for unknown client (%o)"), json["clid"]);
|
|
return;
|
|
}
|
|
|
|
client.set_connection_info(object);
|
|
}
|
|
|
|
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) {
|
|
log.error(LogCategory.NETWORKING, tr("Invalid channel order id!"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
let parent = tree.findChannel(json["cpid"]);
|
|
if(!parent && json["cpid"] != 0) {
|
|
log.error(LogCategory.NETWORKING, 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 */
|
|
log.debug(LogCategory.NETWORKING, 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;
|
|
const conversations = this.connection.client.side_bar.channel_conversations();
|
|
|
|
log.info(LogCategory.NETWORKING, tr("Got %d channel deletions"), json.length);
|
|
for(let index = 0; index < json.length; index++) {
|
|
conversations.delete_conversation(parseInt(json[index]["cid"]));
|
|
let channel = tree.findChannel(json[index]["cid"]);
|
|
if(!channel) {
|
|
log.error(LogCategory.NETWORKING, tr("Invalid channel onDelete (Unknown channel)"));
|
|
continue;
|
|
}
|
|
tree.deleteChannel(channel);
|
|
}
|
|
}
|
|
|
|
handleCommandChannelHide(json) {
|
|
let tree = this.connection.client.channelTree;
|
|
const conversations = this.connection.client.side_bar.channel_conversations();
|
|
|
|
log.info(LogCategory.NETWORKING, tr("Got %d channel hides"), json.length);
|
|
for(let index = 0; index < json.length; index++) {
|
|
conversations.delete_conversation(parseInt(json[index]["cid"]));
|
|
let channel = tree.findChannel(json[index]["cid"]);
|
|
if(!channel) {
|
|
log.error(LogCategory.NETWORKING, tr("Invalid channel on hide (Unknown channel)"));
|
|
continue;
|
|
}
|
|
tree.deleteChannel(channel);
|
|
}
|
|
}
|
|
|
|
handleCommandClientEnterView(json) {
|
|
let tree = this.connection.client.channelTree;
|
|
|
|
let client: ClientEntry;
|
|
let channel = undefined;
|
|
let old_channel = undefined;
|
|
let reason_id, reason_msg;
|
|
|
|
let invokerid, invokername, invokeruid;
|
|
|
|
for(const entry of json) {
|
|
/* attempt to update properties if given */
|
|
channel = typeof(entry["ctid"]) !== "undefined" ? tree.findChannel(parseInt(entry["ctid"])) : channel;
|
|
old_channel = typeof(entry["cfid"]) !== "undefined" ? tree.findChannel(parseInt(entry["cfid"])) : old_channel;
|
|
reason_id = typeof(entry["reasonid"]) !== "undefined" ? entry["reasonid"] : reason_id;
|
|
reason_msg = typeof(entry["reason_msg"]) !== "undefined" ? entry["reason_msg"] : reason_msg;
|
|
|
|
invokerid = typeof(entry["invokerid"]) !== "undefined" ? parseInt(entry["invokerid"]) : invokerid;
|
|
invokername = typeof(entry["invokername"]) !== "undefined" ? entry["invokername"] : invokername;
|
|
invokeruid = typeof(entry["invokeruid"]) !== "undefined" ? entry["invokeruid"] : invokeruid;
|
|
|
|
client = tree.findClient(parseInt(entry["clid"]));
|
|
|
|
if(!client) {
|
|
if(parseInt(entry["client_type_exact"]) == ClientType.CLIENT_MUSIC) {
|
|
client = new MusicClientEntry(parseInt(entry["clid"]), entry["client_nickname"]);
|
|
} else {
|
|
client = new ClientEntry(parseInt(entry["clid"]), entry["client_nickname"]);
|
|
}
|
|
|
|
client.properties.client_type = parseInt(entry["client_type"]);
|
|
client = tree.insertClient(client, channel);
|
|
} else {
|
|
tree.moveClient(client, channel);
|
|
}
|
|
|
|
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
|
|
const own_channel = this.connection.client.getClient().currentChannel();
|
|
this.connection_handler.log.log(server_log.Type.CLIENT_VIEW_ENTER, {
|
|
channel_from: old_channel ? old_channel.log_data() : undefined,
|
|
channel_to: channel ? channel.log_data() : undefined,
|
|
client: client.log_data(),
|
|
invoker: this.loggable_invoker(invokeruid, invokerid, invokername),
|
|
message:reason_msg,
|
|
reason: parseInt(reason_id),
|
|
own_channel: channel == own_channel
|
|
});
|
|
|
|
if(reason_id == ViewReasonId.VREASON_USER_ACTION) {
|
|
if(own_channel == channel)
|
|
if(old_channel)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED);
|
|
else
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED_CONNECT);
|
|
} else if(reason_id == ViewReasonId.VREASON_MOVED) {
|
|
if(own_channel == channel)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED_MOVED);
|
|
} else if(reason_id == ViewReasonId.VREASON_CHANNEL_KICK) {
|
|
if(own_channel == channel)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED_KICKED);
|
|
} else if(reason_id == ViewReasonId.VREASON_SYSTEM) {
|
|
|
|
} else {
|
|
console.warn(tr("Unknown reasonid for %o"), reason_id);
|
|
}
|
|
}
|
|
|
|
let updates: {
|
|
key: string,
|
|
value: string
|
|
}[] = [];
|
|
|
|
for(let key in entry) {
|
|
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: entry[key]});
|
|
}
|
|
|
|
client.updateVariables(...updates);
|
|
|
|
/* if its a new client join, or a system reason (like we joined) */
|
|
if(!old_channel || reason_id == 2) {
|
|
/* client new join */
|
|
const conversation_manager = this.connection_handler.side_bar.private_conversations();
|
|
const conversation = conversation_manager.find_conversation({
|
|
unique_id: client.properties.client_unique_identifier,
|
|
client_id: client.clientId(),
|
|
name: client.clientNickName()
|
|
}, {
|
|
create: false,
|
|
attach: true
|
|
});
|
|
if(conversation)
|
|
client.flag_text_unread = conversation.is_unread();
|
|
}
|
|
|
|
if(client instanceof LocalClientEntry) {
|
|
client.initializeListener();
|
|
this.connection_handler.update_voice_status();
|
|
this.connection_handler.side_bar.info_frame().update_channel_talk();
|
|
const conversations = this.connection.client.side_bar.channel_conversations();
|
|
conversations.set_current_channel(client.currentChannel().channelId);
|
|
}
|
|
}
|
|
}
|
|
|
|
handleCommandClientLeftView(json) {
|
|
let reason_id = -1;
|
|
|
|
for(const entry of json) {
|
|
reason_id = entry["reasonid"] || reason_id;
|
|
let tree = this.connection.client.channelTree;
|
|
let client = tree.findClient(entry["clid"]);
|
|
if(!client) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown client left!"));
|
|
return 0;
|
|
}
|
|
if(client == this.connection.client.getClient()) {
|
|
if(reason_id == ViewReasonId.VREASON_BAN) {
|
|
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_BANNED, entry);
|
|
} else if(reason_id == ViewReasonId.VREASON_SERVER_KICK) {
|
|
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, entry);
|
|
} else if(reason_id == ViewReasonId.VREASON_SERVER_SHUTDOWN) {
|
|
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, entry);
|
|
} else if(reason_id == ViewReasonId.VREASON_SERVER_STOPPED) {
|
|
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, entry);
|
|
} else {
|
|
this.connection.client.handleDisconnect(DisconnectReason.UNKNOWN, entry);
|
|
}
|
|
this.connection_handler.side_bar.info_frame().update_channel_talk();
|
|
return;
|
|
}
|
|
|
|
|
|
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
|
|
const own_channel = this.connection.client.getClient().currentChannel();
|
|
let channel_from = tree.findChannel(entry["cfid"]);
|
|
let channel_to = tree.findChannel(entry["ctid"]);
|
|
|
|
const is_own_channel = channel_from == own_channel;
|
|
this.connection_handler.log.log(server_log.Type.CLIENT_VIEW_LEAVE, {
|
|
channel_from: channel_from ? channel_from.log_data() : undefined,
|
|
channel_to: channel_to ? channel_to.log_data() : undefined,
|
|
client: client.log_data(),
|
|
invoker: this.loggable_invoker(entry["invokeruid"], entry["invokerid"], entry["invokername"]),
|
|
message: entry["reasonmsg"],
|
|
reason: parseInt(entry["reasonid"]),
|
|
ban_time: parseInt(entry["bantime"]),
|
|
own_channel: is_own_channel
|
|
});
|
|
|
|
if(is_own_channel) {
|
|
if(reason_id == ViewReasonId.VREASON_USER_ACTION) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT);
|
|
} else if(reason_id == ViewReasonId.VREASON_SERVER_LEFT) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_DISCONNECT);
|
|
} else if(reason_id == ViewReasonId.VREASON_SERVER_KICK) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_SERVER);
|
|
} else if(reason_id == ViewReasonId.VREASON_CHANNEL_KICK) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
|
|
} else if(reason_id == ViewReasonId.VREASON_BAN) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_BANNED);
|
|
} else if(reason_id == ViewReasonId.VREASON_TIMEOUT) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_TIMEOUT);
|
|
} else if(reason_id == ViewReasonId.VREASON_MOVED) {
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_MOVED);
|
|
} else {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown client left reason %d!"), reason_id);
|
|
}
|
|
}
|
|
|
|
if(!channel_to) {
|
|
/* client left the server */
|
|
const conversation_manager = this.connection_handler.side_bar.private_conversations();
|
|
const conversation = conversation_manager.find_conversation({
|
|
unique_id: client.properties.client_unique_identifier,
|
|
client_id: client.clientId(),
|
|
name: client.clientNickName()
|
|
}, {
|
|
create: false,
|
|
attach: false
|
|
});
|
|
if(conversation) {
|
|
conversation.set_state(PrivateConversationState.DISCONNECTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
tree.deleteClient(client);
|
|
}
|
|
}
|
|
|
|
handleNotifyClientMoved(json) {
|
|
json = json[0]; //Only one bulk
|
|
let tree = this.connection.client.channelTree;
|
|
let client = tree.findClient(json["clid"]);
|
|
let self = client instanceof LocalClientEntry;
|
|
|
|
let channel_to = tree.findChannel(parseInt(json["ctid"]));
|
|
let channel_from = tree.findChannel(parseInt(json["cfid"]));
|
|
|
|
if(!client) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown client move (Client)!"));
|
|
return 0;
|
|
}
|
|
|
|
if(!channel_to) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown client move (Channel to)!"));
|
|
return 0;
|
|
}
|
|
|
|
if(!self) {
|
|
if(!channel_from) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown client move (Channel from)!"));
|
|
channel_from = client.currentChannel();
|
|
} else if(channel_from != client.currentChannel()) {
|
|
log.error(LogCategory.NETWORKING,
|
|
tr("Client move from invalid source channel! Local client registered in channel %d but server send %d."),
|
|
client.currentChannel().channelId, channel_from.channelId
|
|
);
|
|
}
|
|
} else {
|
|
channel_from = client.currentChannel();
|
|
}
|
|
|
|
tree.moveClient(client, channel_to);
|
|
|
|
if(self) {
|
|
this.connection_handler.update_voice_status(channel_to);
|
|
|
|
for(const entry of client.channelTree.clientsByChannel(channel_from)) {
|
|
if(entry !== client && entry.get_audio_handle()) {
|
|
entry.get_audio_handle().abort_replay();
|
|
entry.speaking = false;
|
|
}
|
|
}
|
|
|
|
const side_bar = this.connection_handler.side_bar;
|
|
side_bar.info_frame().update_channel_talk();
|
|
|
|
const conversation_to = side_bar.channel_conversations().conversation(channel_to.channelId, false);
|
|
if(conversation_to)
|
|
conversation_to.update_private_state();
|
|
|
|
if(channel_from) {
|
|
const conversation_from = side_bar.channel_conversations().conversation(channel_from.channelId, false);
|
|
if(conversation_from)
|
|
conversation_from.update_private_state();
|
|
}
|
|
|
|
side_bar.channel_conversations().update_chat_box();
|
|
}
|
|
|
|
const own_channel = this.connection.client.getClient().currentChannel();
|
|
this.connection_handler.log.log(server_log.Type.CLIENT_VIEW_MOVE, {
|
|
channel_from: channel_from ? {
|
|
channel_id: channel_from.channelId,
|
|
channel_name: channel_from.channelName()
|
|
} : undefined,
|
|
channel_from_own: channel_from == own_channel,
|
|
|
|
channel_to: channel_to ? {
|
|
channel_id: channel_to.channelId,
|
|
channel_name: channel_to.channelName()
|
|
} : undefined,
|
|
channel_to_own: channel_to == own_channel,
|
|
|
|
client: {
|
|
client_id: client.clientId(),
|
|
client_name: client.clientNickName(),
|
|
client_unique_id: client.properties.client_unique_identifier
|
|
},
|
|
client_own: self,
|
|
|
|
invoker: this.loggable_invoker(json["invokeruid"], json["invokerid"], json["invokername"]),
|
|
|
|
message: json["reasonmsg"],
|
|
reason: parseInt(json["reasonid"]),
|
|
});
|
|
if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
|
|
if(self)
|
|
this.connection_handler.sound.play(Sound.USER_MOVED_SELF);
|
|
else if(own_channel == channel_to)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED_MOVED);
|
|
else if(own_channel == channel_from)
|
|
this.connection_handler.sound.play(Sound.USER_LEFT_MOVED);
|
|
} else if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
|
|
if(self) {} //If we do an action we wait for the error response
|
|
else if(own_channel == channel_to)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED);
|
|
else if(own_channel == channel_from)
|
|
this.connection_handler.sound.play(Sound.USER_LEFT);
|
|
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
|
|
if(self) {
|
|
this.connection_handler.sound.play(Sound.CHANNEL_KICKED);
|
|
} else if(own_channel == channel_to)
|
|
this.connection_handler.sound.play(Sound.USER_ENTERED_KICKED);
|
|
else if(own_channel == channel_from)
|
|
this.connection_handler.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
|
|
|
|
let tree = this.connection.client.channelTree;
|
|
let channel = tree.findChannel(json["cid"]);
|
|
if(!channel) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown channel move (Channel)!"));
|
|
return 0;
|
|
}
|
|
|
|
let prev = tree.findChannel(json["order"]);
|
|
if(!prev && json["order"] != 0) {
|
|
log.error(LogCategory.NETWORKING, tr("Unknown channel move (prev)!"));
|
|
return 0;
|
|
}
|
|
|
|
let parent = tree.findChannel(json["cpid"]);
|
|
if(!parent && json["cpid"] != 0) {
|
|
log.error(LogCategory.NETWORKING, 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) {
|
|
log.error(LogCategory.NETWORKING, 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);
|
|
|
|
if(this.connection_handler.getClient().currentChannel() === channel) {
|
|
//TODO: Playback sound that your channel has been edited
|
|
this.connection_handler.update_voice_status();
|
|
}
|
|
}
|
|
|
|
handleNotifyTextMessage(json) {
|
|
json = json[0]; //Only one bulk
|
|
|
|
let mode = json["targetmode"];
|
|
if(mode == 1){
|
|
//json["invokerid"], json["invokername"], json["invokeruid"]
|
|
const target_client_id = parseInt(json["target"]);
|
|
const target_own = target_client_id === this.connection.client.getClientId();
|
|
|
|
if(target_own && target_client_id === json["invokerid"]) {
|
|
log.error(LogCategory.NETWORKING, tr("Received conversation message from invalid client id. Data: %o"), json);
|
|
return;
|
|
}
|
|
|
|
const conversation_manager = this.connection_handler.side_bar.private_conversations();
|
|
const conversation = conversation_manager.find_conversation({
|
|
client_id: target_own ? parseInt(json["invokerid"]) : target_client_id,
|
|
unique_id: target_own ? json["invokeruid"] : undefined,
|
|
name: target_own ? json["invokername"] : undefined
|
|
}, {
|
|
create: target_own,
|
|
attach: target_own
|
|
});
|
|
if(!conversation) {
|
|
log.error(LogCategory.NETWORKING, tr("Received conversation message for unknown conversation! (%s)"), target_own ? tr("Remote message") : tr("Own message"));
|
|
return;
|
|
}
|
|
|
|
conversation.append_message(json["msg"], {
|
|
type: target_own ? "partner" : "self",
|
|
name: json["invokername"],
|
|
unique_id: json["invokeruid"],
|
|
client_id: parseInt(json["invokerid"])
|
|
});
|
|
|
|
if(target_own) {
|
|
this.connection_handler.sound.play(Sound.MESSAGE_RECEIVED, {default_volume: .5});
|
|
const client = this.connection_handler.channelTree.findClient(parseInt(json["invokerid"]));
|
|
if(client) /* the client itself might be invisible */
|
|
client.flag_text_unread = conversation.is_unread();
|
|
} else {
|
|
this.connection_handler.sound.play(Sound.MESSAGE_SEND, {default_volume: .5});
|
|
}
|
|
} else if(mode == 2) {
|
|
const invoker = this.connection_handler.channelTree.findClient(parseInt(json["invokerid"]));
|
|
const own_channel_id = this.connection.client.getClient().currentChannel().channelId;
|
|
const channel_id = typeof(json["cid"]) !== "undefined" ? parseInt(json["cid"]) : own_channel_id;
|
|
const channel = this.connection_handler.channelTree.findChannel(channel_id) || this.connection_handler.getClient().currentChannel();
|
|
|
|
if(json["invokerid"] == this.connection.client.clientId)
|
|
this.connection_handler.sound.play(Sound.MESSAGE_SEND, {default_volume: .5});
|
|
else if(channel_id == own_channel_id) {
|
|
this.connection_handler.sound.play(Sound.MESSAGE_RECEIVED, {default_volume: .5});
|
|
}
|
|
|
|
const conversations = this.connection_handler.side_bar.channel_conversations();
|
|
const conversation = conversations.conversation(channel_id);
|
|
conversation.register_new_message({
|
|
sender_database_id: invoker ? invoker.properties.client_database_id : 0,
|
|
sender_name: json["invokername"],
|
|
sender_unique_id: json["invokeruid"],
|
|
|
|
timestamp: typeof(json["timestamp"]) === "undefined" ? Date.now() : parseInt(json["timestamp"]),
|
|
message: json["msg"]
|
|
});
|
|
if(conversation.is_unread() && channel)
|
|
channel.flag_text_unread = true;
|
|
} else if(mode == 3) {
|
|
this.connection_handler.log.log(server_log.Type.GLOBAL_MESSAGE, {
|
|
message: json["msg"],
|
|
sender: {
|
|
client_unique_id: json["invokeruid"],
|
|
client_name: json["invokername"],
|
|
client_id: parseInt(json["invokerid"])
|
|
}
|
|
});
|
|
|
|
const invoker = this.connection_handler.channelTree.findClient(parseInt(json["invokerid"]));
|
|
const conversations = this.connection_handler.side_bar.channel_conversations();
|
|
const conversation = conversations.conversation(0);
|
|
conversation.register_new_message({
|
|
sender_database_id: invoker ? invoker.properties.client_database_id : 0,
|
|
sender_name: json["invokername"],
|
|
sender_unique_id: json["invokeruid"],
|
|
|
|
timestamp: typeof(json["timestamp"]) === "undefined" ? Date.now() : parseInt(json["timestamp"]),
|
|
message: json["msg"]
|
|
});
|
|
this.connection_handler.channelTree.server.flag_text_unread = conversation.is_unread();
|
|
}
|
|
}
|
|
|
|
notifyClientChatComposing(json) {
|
|
json = json[0];
|
|
|
|
const conversation_manager = this.connection_handler.side_bar.private_conversations();
|
|
const conversation = conversation_manager.find_conversation({
|
|
client_id: parseInt(json["clid"]),
|
|
unique_id: json["cluid"],
|
|
name: undefined
|
|
}, {
|
|
create: false,
|
|
attach: false
|
|
});
|
|
if(!conversation)
|
|
return;
|
|
|
|
conversation.trigger_typing();
|
|
}
|
|
|
|
handleNotifyClientChatClosed(json) {
|
|
json = json[0]; //Only one bulk
|
|
|
|
//Chat partner has closed the conversation
|
|
|
|
//clid: "6"
|
|
//cluid: "YoWmG+dRGKD+Rxb7SPLAM5+B9tY="
|
|
|
|
const conversation_manager = this.connection_handler.side_bar.private_conversations();
|
|
const conversation = conversation_manager.find_conversation({
|
|
client_id: parseInt(json["clid"]),
|
|
unique_id: json["cluid"],
|
|
name: undefined
|
|
}, {
|
|
create: false,
|
|
attach: false
|
|
});
|
|
if(!conversation) {
|
|
log.warn(LogCategory.GENERAL, tr("Received chat close for client, but we haven't a chat open."));
|
|
return;
|
|
}
|
|
conversation.set_state(PrivateConversationState.CLOSED);
|
|
}
|
|
|
|
handleNotifyClientUpdated(json) {
|
|
json = json[0]; //Only one bulk
|
|
|
|
let client = this.connection.client.channelTree.findClient(json["clid"]);
|
|
if(!client) {
|
|
log.error(LogCategory.NETWORKING, 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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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];
|
|
spawnPoke(this.connection_handler, {
|
|
id: parseInt(json["invokerid"]),
|
|
name: json["invokername"],
|
|
unique_id: json["invokeruid"]
|
|
}, json["msg"]);
|
|
|
|
this.connection_handler.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())
|
|
this.connection_handler.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()) {
|
|
this.connection_handler.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()) {
|
|
this.connection_handler.sound.play(Sound.GROUP_CHANNEL_CHANGED_SELF);
|
|
}
|
|
}
|
|
|
|
handleNotifyChannelSubscribed(json) {
|
|
for(const entry of json) {
|
|
const channel = this.connection.client.channelTree.findChannel(entry["cid"]);
|
|
if(!channel) {
|
|
console.warn(tr("Received channel subscribed for not visible channel (cid: %d)"), entry['cid']);
|
|
continue;
|
|
}
|
|
|
|
channel.flag_subscribed = true;
|
|
}
|
|
}
|
|
|
|
handleNotifyChannelUnsubscribed(json) {
|
|
for(const entry of json) {
|
|
const channel = this.connection.client.channelTree.findChannel(entry["cid"]);
|
|
if(!channel) {
|
|
console.warn(tr("Received channel unsubscribed for not visible channel (cid: %d)"), entry['cid']);
|
|
continue;
|
|
}
|
|
|
|
channel.flag_subscribed = false;
|
|
for(const client of channel.clients(false))
|
|
this.connection.client.channelTree.deleteClient(client);
|
|
}
|
|
}
|
|
|
|
handleNotifyConversationHistory(json: any[]) {
|
|
const conversations = this.connection.client.side_bar.channel_conversations();
|
|
const conversation = conversations.conversation(parseInt(json[0]["cid"]));
|
|
if(!conversation) {
|
|
log.warn(LogCategory.NETWORKING, tr("Received conversation history for invalid or unknown conversation (%o)"), json[0]["cid"]);
|
|
return;
|
|
}
|
|
|
|
for(const entry of json) {
|
|
conversation.register_new_message({
|
|
message: entry["msg"],
|
|
sender_unique_id: entry["sender_unique_id"],
|
|
sender_name: entry["sender_name"],
|
|
timestamp: parseInt(entry["timestamp"]),
|
|
sender_database_id: parseInt(entry["sender_database_id"])
|
|
}, false);
|
|
}
|
|
|
|
/* now update the boxes */
|
|
/* No update needed because the command which triggers this notify should update the chat box on success
|
|
conversation.fix_scroll(true);
|
|
conversation.handle.update_chat_box();
|
|
*/
|
|
}
|
|
|
|
handleNotifyConversationMessageDelete(json: any[]) {
|
|
let conversation: Conversation;
|
|
const conversations = this.connection.client.side_bar.channel_conversations();
|
|
for(const entry of json) {
|
|
if(typeof(entry["cid"]) !== "undefined")
|
|
conversation = conversations.conversation(parseInt(entry["cid"]), false);
|
|
if(!conversation)
|
|
continue;
|
|
|
|
conversation.delete_messages(parseInt(entry["timestamp_begin"]), parseInt(entry["timestamp_end"]), parseInt(entry["cldbid"]), parseInt(entry["limit"]));
|
|
}
|
|
}
|
|
|
|
handleNotifyMusicStatusUpdate(json: any[]) {
|
|
json = json[0];
|
|
|
|
const bot_id = parseInt(json["bot_id"]);
|
|
const client = this.connection.client.channelTree.find_client_by_dbid(bot_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received music bot status update for unknown bot (%d)"), bot_id);
|
|
return;
|
|
}
|
|
|
|
client.events.fire("music_status_update", {
|
|
player_replay_index: parseInt(json["player_replay_index"]),
|
|
player_buffered_index: parseInt(json["player_buffered_index"])
|
|
});
|
|
}
|
|
|
|
handleMusicPlayerSongChange(json: any[]) {
|
|
json = json[0];
|
|
|
|
const bot_id = parseInt(json["bot_id"]);
|
|
const client = this.connection.client.channelTree.find_client_by_dbid(bot_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received music bot status update for unknown bot (%d)"), bot_id);
|
|
return;
|
|
}
|
|
|
|
const song_id = parseInt(json["song_id"]);
|
|
let song: SongInfo;
|
|
if(song_id) {
|
|
song = new SongInfo();
|
|
JSON.map_to(song, json);
|
|
}
|
|
|
|
client.events.fire("music_song_change", {
|
|
song: song
|
|
});
|
|
}
|
|
|
|
handleNotifyPlaylistSongAdd(json: any[]) {
|
|
json = json[0];
|
|
|
|
const playlist_id = parseInt(json["playlist_id"]);
|
|
const client = this.connection.client.channelTree.clients.find(e => e instanceof MusicClientEntry && e.properties.client_playlist_id === playlist_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received playlist song add event, but we've no music bot for the playlist (%d)"), playlist_id);
|
|
return;
|
|
}
|
|
|
|
client.events.fire("playlist_song_add", {
|
|
song: {
|
|
song_id: parseInt(json["song_id"]),
|
|
song_invoker: json["song_invoker"],
|
|
song_previous_song_id: parseInt(json["song_previous_song_id"]),
|
|
song_url: json["song_url"],
|
|
song_url_loader: json["song_url_loader"],
|
|
|
|
song_loaded: json["song_loaded"] == true || json["song_loaded"] == "1",
|
|
song_metadata: json["song_metadata"]
|
|
}
|
|
});
|
|
}
|
|
|
|
handleNotifyPlaylistSongRemove(json: any[]) {
|
|
json = json[0];
|
|
|
|
const playlist_id = parseInt(json["playlist_id"]);
|
|
const client = this.connection.client.channelTree.clients.find(e => e instanceof MusicClientEntry && e.properties.client_playlist_id === playlist_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received playlist song remove event, but we've no music bot for the playlist (%d)"), playlist_id);
|
|
return;
|
|
}
|
|
|
|
const song_id = parseInt(json["song_id"]);
|
|
client.events.fire("playlist_song_remove", { song_id: song_id });
|
|
}
|
|
|
|
handleNotifyPlaylistSongReorder(json: any[]) {
|
|
json = json[0];
|
|
|
|
const playlist_id = parseInt(json["playlist_id"]);
|
|
const client = this.connection.client.channelTree.clients.find(e => e instanceof MusicClientEntry && e.properties.client_playlist_id === playlist_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received playlist song reorder event, but we've no music bot for the playlist (%d)"), playlist_id);
|
|
return;
|
|
}
|
|
|
|
const song_id = parseInt(json["song_id"]);
|
|
const previous_song_id = parseInt(json["song_previous_song_id"]);
|
|
client.events.fire("playlist_song_reorder", { song_id: song_id, previous_song_id: previous_song_id });
|
|
}
|
|
|
|
handleNotifyPlaylistSongLoaded(json: any[]) {
|
|
json = json[0];
|
|
|
|
const playlist_id = parseInt(json["playlist_id"]);
|
|
const client = this.connection.client.channelTree.clients.find(e => e instanceof MusicClientEntry && e.properties.client_playlist_id === playlist_id);
|
|
if(!client) {
|
|
log.warn(LogCategory.CLIENT, tr("Received playlist song loaded event, but we've no music bot for the playlist (%d)"), playlist_id);
|
|
return;
|
|
}
|
|
|
|
const song_id = parseInt(json["song_id"]);
|
|
client.events.fire("playlist_song_loaded", {
|
|
song_id: song_id,
|
|
success: json["success"] == 1,
|
|
error_msg: json["load_error_msg"],
|
|
metadata: json["song_metadata"]
|
|
});
|
|
}
|
|
} |