TeaWeb/shared/js/connection/CommandHandler.ts

1182 lines
49 KiB
TypeScript
Raw Normal View History

import * as log from "../log";
import {LogCategory, logError} from "../log";
import {AbstractServerConnection, CommandOptions, ServerCommand} from "../connection/ConnectionBase";
import {Sound} from "../sound/Sounds";
import {CommandResult} from "../connection/ServerConnectionDeclaration";
import {createErrorModal, createInfoModal, createInputModal, createModal} from "../ui/elements/Modal";
2020-03-30 11:44:18 +00:00
import {
ClientConnectionInfo,
ClientEntry,
ClientType,
LocalClientEntry,
MusicClientEntry,
SongInfo
} from "../tree/Client";
import {ConnectionHandler, ConnectionState, DisconnectReason, ViewReasonId} from "../ConnectionHandler";
import {formatMessage} from "../ui/frames/chat";
import {spawnPoke} from "../ui/modal/ModalPoke";
import {AbstractCommandHandler, AbstractCommandHandlerBoss} from "../connection/AbstractCommandHandler";
import {batch_updates, BatchUpdateType, flush_batched_updates} from "../ui/react-elements/ReactComponentBase";
import {OutOfViewClient} from "../ui/frames/side/PrivateConversationManager";
import {renderBBCodeAsJQuery} from "../text/bbcode";
import {tr} from "../i18n/localize";
import {EventClient, EventType} from "../ui/frames/log/Definitions";
import {ErrorCode} from "../connection/ErrorCode";
2020-09-24 09:24:31 +00:00
import {server_connections} from "tc-shared/ConnectionManager";
import {ChannelEntry} from "tc-shared/tree/Channel";
2020-03-30 11:44:18 +00:00
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;
2020-03-30 11:44:18 +00:00
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(uniqueId, clientId, clientName) : EventClient | undefined {
const id = typeof clientId === "string" ? parseInt(clientId) : clientId;
if(typeof(clientId) === "undefined" || Number.isNaN(id)) {
2020-03-30 11:44:18 +00:00
return undefined;
}
2020-03-30 11:44:18 +00:00
if(id == 0) {
2020-03-30 11:44:18 +00:00
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,
};
}
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
return {
client_unique_id: uniqueId,
client_name: clientName,
client_id: clientId
2020-03-30 11:44:18 +00:00
};
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
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 == ErrorCode.SERVER_INSUFFICIENT_PERMISSIONS) { //Permission error
2020-03-30 11:44:18 +00:00
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(EventType.ERROR_PERMISSION, {
2020-03-30 11:44:18 +00:00
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 != ErrorCode.DATABASE_EMPTY_RESULT) {
this.connection_handler.log.log(EventType.ERROR_CUSTOM, {
2020-03-30 11:44:18 +00:00
message: res.extra_message.length == 0 ? res.message : res.extra_message
});
}
}
} else if(typeof(ex) === "string") {
this.connection_handler.log.log(EventType.CONNECTION_COMMAND_ERROR, {error: ex});
2020-03-30 11:44:18 +00:00
} 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]) {
/* batch all updates the command applies to the channel tree */
batch_updates(BatchUpdateType.CHANNEL_TREE);
try {
this[command.command](command.arguments);
} finally {
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
}
2020-03-30 11:44:18 +00:00
return true;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
return false;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
set_handler(command: string, handler: any) {
this[command] = handler;
}
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
unset_handler(command: string, handler?: any) {
if(handler && this[command] != handler) return;
this[command] = undefined;
}
handleCommandResult(json) {
let code : string = json[0]["return_code"];
2020-03-30 11:44:18 +00:00
if(!code || code.length == 0) {
log.warn(LogCategory.NETWORKING, tr("Invalid return code! (%o)"), json);
return;
}
let retListeners = this.connection["_retListener"] || this.connection["returnListeners"];
2020-03-30 11:44:18 +00:00
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;
2019-02-23 13:15:22 +00:00
}
}
2020-03-30 11:44:18 +00:00
handleCommandServerInit(json){
json = json[0]; //Only one bulk
2020-06-12 17:33:05 +00:00
this.connection.client.initializeLocalClient(parseInt(json["aclid"]), json["acn"]);
2020-03-30 11:44:18 +00:00
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]});
}
2020-03-30 11:44:18 +00:00
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 */
if(properties.virtualserver_hostmessage)
this.connection_handler.log.log(EventType.SERVER_HOST_MESSAGE, {
message: properties.virtualserver_hostmessage
});
2020-03-30 11:44:18 +00:00
} else {
/* create modal/create modal and quit */
if(properties.virtualserver_hostmessage || properties.virtualserver_hostmessage_mode == 3)
createModal({
header: tr("Host message"),
2020-07-19 14:34:08 +00:00
body: renderBBCodeAsJQuery(properties.virtualserver_hostmessage, { convertSingleUrls: false }),
footer: undefined
}).open();
2020-03-30 11:44:18 +00:00
if(properties.virtualserver_hostmessage_mode == 3) {
/* first let the client initialize his stuff */
setTimeout(() => {
this.connection_handler.log.log(EventType.SERVER_HOST_MESSAGE_DISCONNECT, {
2020-03-30 11:44:18 +00:00
message: properties.virtualserver_welcomemessage
});
2020-03-30 11:44:18 +00:00
this.connection.disconnect("host message disconnect");
this.connection_handler.handleDisconnect(DisconnectReason.SERVER_HOSTMESSAGE);
this.connection_handler.sound.play(Sound.CONNECTION_DISCONNECTED);
}, 100);
}
2020-03-30 11:44:18 +00:00
}
}
2020-03-30 11:44:18 +00:00
/* welcome message */
if(properties.virtualserver_welcomemessage) {
this.connection_handler.log.log(EventType.SERVER_WELCOME_MESSAGE, {
2020-03-30 11:44:18 +00:00
message: properties.virtualserver_welcomemessage
});
}
2020-03-30 11:44:18 +00:00
/* 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();
2020-03-30 11:44:18 +00:00
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();
});
2020-04-02 22:15:47 +00:00
}, { field_placeholder: tr("Enter Privilege Key") }).open();
2019-02-23 13:15:22 +00:00
}
this.connection.updateConnectionState(ConnectionState.CONNECTED);
2020-03-30 11:44:18 +00:00
}
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]);
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
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;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
client.set_connection_info(object);
}
private createChannelFromJson(json, ignoreMissingPreviousChannel: boolean = false) : ChannelEntry {
2020-03-30 11:44:18 +00:00
let tree = this.connection.client.channelTree;
2019-02-23 13:15:22 +00:00
let channelId = parseInt(json["cid"]);
let channelName = json["channel_name"];
2019-02-23 13:15:22 +00:00
let previousChannelId = parseInt(json["channel_order"]);
let parentChannelId = parseInt(json["cpid"]);
if(Number.isNaN(channelId) || Number.isNaN(previousChannelId) || Number.isNaN(parentChannelId)) {
logError(LogCategory.NETWORKING, tr("Tried to create a channel with invalid ids (%o - %o - %o)"), channelId, previousChannelId, parentChannelId);
return;
}
let parentChannel: ChannelEntry;
let previousChannel: ChannelEntry;
if(previousChannelId !== 0) {
previousChannel = tree.findChannel(previousChannelId);
if(!previousChannel && !ignoreMissingPreviousChannel) {
logError(LogCategory.NETWORKING, tr("Received a channel with an invalid order id (%d)"), previousChannelId);
/* maybe disconnect? */
}
2020-03-30 11:44:18 +00:00
}
if(parentChannelId !== 0) {
parentChannel = tree.findChannel(parentChannelId);
if(!parentChannel) {
logError(LogCategory.NETWORKING, tr("Received a channel with an invalid parent channel (%d)"), parentChannelId);
/* maybe disconnect? */
2019-02-23 13:15:22 +00:00
}
}
const channel = tree.handleChannelCreated(previousChannel, parentChannel, channelId, channelName);
2020-03-30 11:44:18 +00:00
let updates: {
key: string,
value: string
}[] = [];
2020-09-26 19:34:46 +00:00
for(let key of Object.keys(json)) {
2020-03-30 11:44:18 +00:00
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);
if(tree.channelsInitialized) {
channel.updateSubscribeMode().then(undefined);
}
return channel;
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
private batchTreeUpdateFinishedTimeout;
2020-03-30 11:44:18 +00:00
handleCommandChannelList(json) {
if(this.batchTreeUpdateFinishedTimeout) {
clearTimeout(this.batchTreeUpdateFinishedTimeout);
this.batchTreeUpdateFinishedTimeout = 0;
/* batch update is still active */
} else {
batch_updates(BatchUpdateType.CHANNEL_TREE);
}
for(let index = 0; index < json.length; index++) {
2020-03-30 11:44:18 +00:00
this.createChannelFromJson(json[index], true);
}
this.batchTreeUpdateFinishedTimeout = setTimeout(() => {
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
this.batchTreeUpdateFinishedTimeout = 0;
}, 500);
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
handleCommandChannelListFinished() {
this.connection.client.channelTree.channelsInitialized = true;
this.connection.client.channelTree.events.fire_react("notify_channel_list_received");
if(this.batchTreeUpdateFinishedTimeout) {
clearTimeout(this.batchTreeUpdateFinishedTimeout);
this.batchTreeUpdateFinishedTimeout = 0;
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleCommandChannelCreate(json) {
json = json[0];
const channel = this.createChannelFromJson(json);
if(!channel) { return; }
const ownAction = parseInt(json["invokerid"]) === this.connection.client.getClientId();
if(ownAction) {
this.connection.client.sound.play(Sound.CHANNEL_CREATED);
}
const log = this.connection.client.log;
log.log("channel.create", {
channel: channel.log_data(),
creator: this.loggable_invoker(json["invokeruid"], json["invokerid"], json["invokername"]),
ownAction: ownAction
});
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleCommandChannelShow(json) {
json = json[0];
const channel = this.createChannelFromJson(json);
const log = this.connection.client.log;
log.log("channel.show", {
channel: channel.log_data(),
});
2020-03-30 11:44:18 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleCommandChannelDelete(json) {
let tree = this.connection.client.channelTree;
const conversations = this.connection.client.side_bar.channel_conversations();
2019-08-21 08:00:01 +00:00
let playSound = false;
2020-03-30 11:44:18 +00:00
log.info(LogCategory.NETWORKING, tr("Got %d channel deletions"), json.length);
for(let index = 0; index < json.length; index++) {
conversations.destroyConversation(parseInt(json[index]["cid"]));
2020-03-30 11:44:18 +00:00
let channel = tree.findChannel(json[index]["cid"]);
if(!channel) {
logError(LogCategory.NETWORKING, tr("Invalid channel onDelete (Unknown channel)"));
2020-03-30 11:44:18 +00:00
continue;
2019-08-21 08:00:01 +00:00
}
2020-03-30 11:44:18 +00:00
tree.deleteChannel(channel);
const ownAction = parseInt(json[index]["invokerid"]) === this.connection.client.getClientId();
const log = this.connection.client.log;
log.log("channel.delete", {
channel: channel.log_data(),
deleter: this.loggable_invoker(json[index]["invokeruid"], json[index]["invokerid"], json[index]["invokername"]),
ownAction: ownAction
});
if(ownAction) {
playSound = true;
}
}
if(playSound) {
this.connection.client.sound.play(Sound.CHANNEL_DELETED);
2020-03-30 11:44:18 +00:00
}
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleCommandChannelHide(json) {
let tree = this.connection.client.channelTree;
const conversations = this.connection.client.side_bar.channel_conversations();
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
log.info(LogCategory.NETWORKING, tr("Got %d channel hides"), json.length);
for(let index = 0; index < json.length; index++) {
conversations.destroyConversation(parseInt(json[index]["cid"]));
2020-03-30 11:44:18 +00:00
let channel = tree.findChannel(json[index]["cid"]);
if(!channel) {
logError(LogCategory.NETWORKING, tr("Invalid channel on hide (Unknown channel)"));
2020-03-30 11:44:18 +00:00
continue;
}
tree.deleteChannel(channel);
const log = this.connection.client.log;
log.log("channel.hide", {
channel: channel.log_data(),
});
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleCommandClientEnterView(json) {
let tree = this.connection.client.channelTree;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let client: ClientEntry;
let channel = undefined;
let old_channel = undefined;
let reason_id, reason_msg;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let invokerid, invokername, invokeruid;
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-08-30 21:06:39 +00:00
2020-03-30 11:44:18 +00:00
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"]));
2019-08-30 21:06:39 +00:00
if(!client) {
2020-03-30 11:44:18 +00:00
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"]);
}
2019-08-30 21:06:39 +00:00
2020-07-17 21:56:20 +00:00
/* TODO: Apply all other properties here as well and than register him */
client.properties.client_unique_identifier = entry["client_unique_identifier"];
2020-03-30 11:44:18 +00:00
client.properties.client_type = parseInt(entry["client_type"]);
2020-07-17 21:56:20 +00:00
client = tree.insertClient(client, channel, { reason: reason_id, isServerJoin: parseInt(entry["cfid"]) === 0 });
2020-03-30 11:44:18 +00:00
} else {
tree.moveClient(client, channel);
}
2019-08-30 21:06:39 +00:00
2020-04-11 09:43:41 +00:00
if(this.connection_handler.areQueriesShown() || client.properties.client_type != ClientType.CLIENT_QUERY) {
2020-03-30 11:44:18 +00:00
const own_channel = this.connection.client.getClient().currentChannel();
this.connection_handler.log.log(channel == own_channel ? EventType.CLIENT_VIEW_ENTER_OWN_CHANNEL : EventType.CLIENT_VIEW_ENTER, {
2020-03-30 11:44:18 +00:00
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),
});
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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) {
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
} else {
console.warn(tr("Unknown reasonid for %o"), reason_id);
2019-02-23 13:15:22 +00:00
}
}
let updates: {
key: string,
value: string
}[] = [];
2020-03-30 11:44:18 +00:00
2020-09-07 10:42:00 +00:00
for(let key of Object.keys(entry)) {
2020-03-30 11:44:18 +00:00
if(key == "cfid") continue;
if(key == "ctid") continue;
2019-02-23 13:15:22 +00:00
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
2020-03-30 11:44:18 +00:00
updates.push({key: key, value: entry[key]});
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
client.updateVariables(...updates);
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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.setSelectedConversation(client.currentChannel().channelId);
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleCommandClientLeftView(json) {
let reason_id = -1;
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
for(const entry of json) {
reason_id = entry["reasonid"] || reason_id;
2019-02-23 13:15:22 +00:00
let tree = this.connection.client.channelTree;
2020-03-30 11:44:18 +00:00
let client = tree.findClient(entry["clid"]);
if(!client) {
log.error(LogCategory.NETWORKING, tr("Unknown client left!"));
return 0;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
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);
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
this.connection_handler.side_bar.info_frame().update_channel_talk();
return;
2019-02-23 13:15:22 +00:00
}
2020-07-17 21:56:20 +00:00
const targetChannelId = parseInt(entry["ctid"]);
2020-04-11 09:43:41 +00:00
if(this.connection_handler.areQueriesShown() || client.properties.client_type != ClientType.CLIENT_QUERY) {
2020-03-30 11:44:18 +00:00
const own_channel = this.connection.client.getClient().currentChannel();
let channel_from = tree.findChannel(entry["cfid"]);
2020-07-17 21:56:20 +00:00
let channel_to = tree.findChannel(targetChannelId);
2020-03-30 11:44:18 +00:00
const is_own_channel = channel_from == own_channel;
this.connection_handler.log.log(is_own_channel ? EventType.CLIENT_VIEW_LEAVE_OWN_CHANNEL : EventType.CLIENT_VIEW_LEAVE, {
2020-03-30 11:44:18 +00:00
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"]),
});
2020-03-30 11:44:18 +00:00
if(is_own_channel) {
2019-04-15 13:33:51 +00:00
if(reason_id == ViewReasonId.VREASON_USER_ACTION) {
2020-03-30 11:44:18 +00:00
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);
2019-04-15 13:33:51 +00:00
} else if(reason_id == ViewReasonId.VREASON_CHANNEL_KICK) {
2020-03-30 11:44:18 +00:00
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);
2019-04-15 13:33:51 +00:00
} else {
2020-03-30 11:44:18 +00:00
log.error(LogCategory.NETWORKING, tr("Unknown client left reason %d!"), reason_id);
2019-04-15 13:33:51 +00:00
}
}
2019-04-04 19:47:52 +00:00
}
2019-04-15 13:33:51 +00:00
2020-07-17 21:56:20 +00:00
tree.deleteClient(client, { reason: reason_id, message: entry["reasonmsg"], serverLeave: targetChannelId === 0 });
2020-03-27 22:36:57 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-04-04 19:47:52 +00:00
2020-03-30 11:44:18 +00:00
let channel_to = tree.findChannel(parseInt(json["ctid"]));
let channelFrom = tree.findChannel(parseInt(json["cfid"]));
2020-03-30 11:44:18 +00:00
if(!client) {
log.error(LogCategory.NETWORKING, tr("Unknown client move (Client)!"));
return 0;
}
2019-04-15 13:33:51 +00:00
2020-03-30 11:44:18 +00:00
if(!channel_to) {
log.error(LogCategory.NETWORKING, tr("Unknown client move (Channel to)!"));
return 0;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
if(!self) {
if(!channelFrom) {
2020-03-30 11:44:18 +00:00
log.error(LogCategory.NETWORKING, tr("Unknown client move (Channel from)!"));
channelFrom = client.currentChannel();
} else if(channelFrom != client.currentChannel()) {
2020-03-30 11:44:18 +00:00
log.error(LogCategory.NETWORKING,
tr("Client move from invalid source channel! Local client registered in channel %d but server send %d."),
client.currentChannel().channelId, channelFrom.channelId
2020-03-30 11:44:18 +00:00
);
2019-04-15 13:33:51 +00:00
}
2020-03-30 11:44:18 +00:00
} else {
channelFrom = client.currentChannel();
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
tree.moveClient(client, channel_to);
2019-09-12 21:59:35 +00:00
2020-03-30 11:44:18 +00:00
if(self) {
2020-09-12 12:51:03 +00:00
this.connection_handler.update_voice_status();
2019-02-23 13:15:22 +00:00
for(const entry of client.channelTree.clientsByChannel(channelFrom)) {
2020-09-07 10:42:00 +00:00
entry.getVoiceClient()?.abortReplay();
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
const side_bar = this.connection_handler.side_bar;
side_bar.info_frame().update_channel_talk();
} else {
client.speaking = false;
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
const own_channel = this.connection.client.getClient().currentChannel();
const event = self ? EventType.CLIENT_VIEW_MOVE_OWN : (channelFrom == own_channel || channel_to == own_channel ? EventType.CLIENT_VIEW_MOVE_OWN_CHANNEL : EventType.CLIENT_VIEW_MOVE);
this.connection_handler.log.log(event, {
channel_from: channelFrom ? {
channel_id: channelFrom.channelId,
channel_name: channelFrom.channelName()
2020-03-30 11:44:18 +00:00
} : undefined,
channel_from_own: channelFrom == own_channel,
2020-03-30 11:44:18 +00:00
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 == channelFrom)
2020-03-30 11:44:18 +00:00
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 == channelFrom)
2020-03-30 11:44:18 +00:00
this.connection_handler.sound.play(Sound.USER_LEFT);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
2019-08-21 08:00:01 +00:00
if(self) {
2020-03-30 11:44:18 +00:00
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 == channelFrom)
2020-03-30 11:44:18 +00:00
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
} else {
console.warn(tr("Unknown reason id %o"), json["reasonid"]);
}
}
2020-03-30 11:44:18 +00:00
handleNotifyChannelMoved(json) {
json = json[0]; //Only one bulk
2020-03-30 11:44:18 +00:00
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;
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let prev = tree.findChannel(json["order"]);
if(!prev && json["order"] != 0) {
log.error(LogCategory.NETWORKING, tr("Unknown channel move (prev)!"));
return 0;
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let parent = tree.findChannel(json["cpid"]);
if(!parent && json["cpid"] != 0) {
log.error(LogCategory.NETWORKING, tr("Unknown channel move (parent)!"));
return 0;
}
2019-08-21 08:00:01 +00:00
2020-09-26 19:34:46 +00:00
tree.moveChannel(channel, prev, parent, true);
2020-03-30 11:44:18 +00:00
}
2020-03-30 11:44:18 +00:00
handleNotifyChannelEdited(json) {
json = json[0]; //Only one bulk
2020-03-30 11:44:18 +00:00
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;
}
2020-03-30 11:44:18 +00:00
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]});
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
channel.updateVariables(...updates);
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
if(this.connection_handler.getClient().currentChannel() === channel) {
//TODO: Playback sound that your channel has been edited
this.connection_handler.update_voice_status();
}
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyTextMessage(json) {
json = json[0]; //Only one bulk
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
let mode = json["targetmode"];
if(mode == 1){
2020-07-17 21:56:20 +00:00
const targetClientId = parseInt(json["target"]);
const invokerClientId = parseInt(json["invokerid"]);
const targetClientEntry = this.connection_handler.channelTree.findClient(targetClientId);
const targetIsOwn = targetClientEntry instanceof LocalClientEntry;
2019-02-23 13:15:22 +00:00
2020-07-17 21:56:20 +00:00
if(targetIsOwn && targetClientId === invokerClientId) {
log.error(LogCategory.NETWORKING, tr("Received conversation message from our self. This should be impossible."), json);
2020-03-30 11:44:18 +00:00
return;
2019-02-23 13:15:22 +00:00
}
2020-07-17 21:56:20 +00:00
const partnerClientEntry = targetIsOwn ? this.connection.client.channelTree.findClient(invokerClientId) : targetClientEntry;
const chatPartner = partnerClientEntry ? partnerClientEntry : {
clientId: targetIsOwn ? invokerClientId : targetClientId,
nickname: targetIsOwn ? json["invokername"] : undefined,
uniqueId: targetIsOwn ? json["invokeruid"] : undefined
} as OutOfViewClient;
const conversation_manager = this.connection_handler.side_bar.private_conversations();
2020-07-17 21:56:20 +00:00
const conversation = conversation_manager.findOrCreateConversation(chatPartner);
2019-02-23 13:15:22 +00:00
2020-07-17 21:56:20 +00:00
conversation.handleIncomingMessage(chatPartner, !targetIsOwn, {
sender_database_id: targetClientEntry ? targetClientEntry.properties.client_database_id : 0,
sender_name: json["invokername"],
sender_unique_id: json["invokeruid"],
2019-09-12 21:59:35 +00:00
2020-07-17 21:56:20 +00:00
timestamp: Date.now(),
message: json["msg"]
});
if(targetIsOwn) {
2020-03-30 11:44:18 +00:00
this.connection_handler.sound.play(Sound.MESSAGE_RECEIVED, {default_volume: .5});
this.connection_handler.log.log(EventType.PRIVATE_MESSAGE_RECEIVED, {
message: json["msg"],
sender: {
client_unique_id: json["invokeruid"],
client_name: json["invokername"],
client_id: parseInt(json["invokerid"])
}
});
2020-03-30 11:44:18 +00:00
} else {
this.connection_handler.sound.play(Sound.MESSAGE_SEND, {default_volume: .5});
this.connection_handler.log.log(EventType.PRIVATE_MESSAGE_SEND, {
message: json["msg"],
target: {
client_unique_id: json["invokeruid"],
client_name: json["invokername"],
client_id: parseInt(json["invokerid"])
}
});
2020-03-30 11:44:18 +00:00
}
2020-07-17 21:56:20 +00:00
this.connection_handler.side_bar.info_frame().update_chat_counter();
2020-03-30 11:44:18 +00:00
} 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;
2020-06-12 17:33:05 +00:00
if(json["invokerid"] == this.connection.client.getClientId())
2020-03-30 11:44:18 +00:00
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});
2019-09-12 21:59:35 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
const conversations = this.connection_handler.side_bar.channel_conversations();
conversations.findOrCreateConversation(channel_id).handleIncomingMessage({
2020-03-30 11:44:18 +00:00
sender_database_id: invoker ? invoker.properties.client_database_id : 0,
sender_name: json["invokername"],
sender_unique_id: json["invokeruid"],
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
timestamp: typeof(json["timestamp"]) === "undefined" ? Date.now() : parseInt(json["timestamp"]),
2020-07-17 21:56:20 +00:00
message: json["msg"]
}, invoker instanceof LocalClientEntry);
2020-03-30 11:44:18 +00:00
} else if(mode == 3) {
const invoker = this.connection_handler.channelTree.findClient(parseInt(json["invokerid"]));
const conversations = this.connection_handler.side_bar.channel_conversations();
this.connection_handler.log.log(EventType.GLOBAL_MESSAGE, {
isOwnMessage: invoker instanceof LocalClientEntry,
2020-03-30 11:44:18 +00:00
message: json["msg"],
sender: {
client_unique_id: json["invokeruid"],
client_name: json["invokername"],
client_id: parseInt(json["invokerid"])
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
});
2019-08-21 08:00:01 +00:00
conversations.findOrCreateConversation(0).handleIncomingMessage({
2020-03-30 11:44:18 +00:00
sender_database_id: invoker ? invoker.properties.client_database_id : 0,
sender_name: json["invokername"],
sender_unique_id: json["invokeruid"],
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
timestamp: typeof(json["timestamp"]) === "undefined" ? Date.now() : parseInt(json["timestamp"]),
2020-07-17 21:56:20 +00:00
message: json["msg"]
}, invoker instanceof LocalClientEntry);
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
notifyClientChatComposing(json) {
json = json[0];
const conversation_manager = this.connection_handler.side_bar.private_conversations();
2020-07-17 21:56:20 +00:00
const conversation = conversation_manager.findConversation(json["cluid"]);
conversation?.handleRemoteComposing(parseInt(json["clid"]));
2020-03-30 11:44:18 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyClientChatClosed(json) {
json = json[0]; //Only one bulk
const conversation_manager = this.connection_handler.side_bar.private_conversations();
2020-07-17 21:56:20 +00:00
const conversation = conversation_manager.findConversation(json["cluid"]);
2020-03-30 11:44:18 +00:00
if(!conversation) {
log.warn(LogCategory.GENERAL, tr("Received chat close for client, but we haven't a chat open."));
return;
2019-02-23 13:15:22 +00:00
}
2020-07-17 21:56:20 +00:00
conversation.handleChatRemotelyClosed(parseInt(json["clid"]));
2020-03-30 11:44:18 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyClientUpdated(json) {
json = json[0]; //Only one bulk
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let client = this.connection.client.channelTree.findClient(json["clid"]);
if(!client) {
log.error(LogCategory.NETWORKING, tr("Tried to update an non existing client"));
return;
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
let updates: {
key: string,
value: string
}[] = [];
for(let key in json) {
if(key == "clid") continue;
updates.push({key: key, value: json[key]});
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
client.updateVariables(...updates);
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyServerEdited(json) {
json = json[0];
2019-08-30 21:06:39 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-08-30 21:06:39 +00:00
2020-03-30 11:44:18 +00:00
updates.push({key: key, value: json[key]});
2019-08-30 21:06:39 +00:00
}
2020-03-30 11:44:18 +00:00
this.connection.client.channelTree.server.updateVariables(false, ...updates);
}
2019-08-30 21:06:39 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyServerUpdated(json) {
json = json[0];
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
updates.push({key: key, value: json[key]});
2019-03-17 11:15:39 +00:00
}
2020-03-30 11:44:18 +00:00
this.connection.client.channelTree.server.updateVariables(true, ...updates);
}
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyMusicPlayerInfo(json) {
json = json[0];
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-03-17 11:15:39 +00:00
}
2020-03-30 11:44:18 +00:00
bot.handlePlayerInfo(json);
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyClientPoke(json) {
json = json[0];
spawnPoke(this.connection_handler, {
id: parseInt(json["invokerid"]),
name: json["invokername"],
unique_id: json["invokeruid"]
}, json["msg"]);
2019-02-23 13:15:22 +00:00
this.connection_handler.log.log(EventType.CLIENT_POKE_RECEIVED, {
sender: this.loggable_invoker(json["invokeruid"], json["invokerid"], json["invokername"]),
message: json["msg"]
});
2020-03-30 11:44:18 +00:00
this.connection_handler.sound.play(Sound.USER_POKED_SELF);
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
//TODO server chat message
handleNotifyServerGroupClientAdd(json) {
json = json[0];
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId())
this.connection_handler.sound.play(Sound.GROUP_SERVER_ASSIGNED_SELF);
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
//TODO server chat message
handleNotifyServerGroupClientRemove(json) {
json = json[0];
2020-03-30 11:44:18 +00:00
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId()) {
this.connection_handler.sound.play(Sound.GROUP_SERVER_REVOKED_SELF);
} else {
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
//TODO server chat message
handleNotifyClientChannelGroupChanged(json) {
json = json[0];
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
const self = this.connection.client.getClient();
if(json["clid"] == self.clientId()) {
this.connection_handler.sound.play(Sound.GROUP_CHANNEL_CHANGED_SELF);
2019-08-21 08:00:01 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyChannelSubscribed(json) {
batch_updates(BatchUpdateType.CHANNEL_TREE);
try {
for(const entry of json) {
const channel = this.connection.client.channelTree.findChannel(parseInt(entry["cid"]));
if(!channel) {
console.warn(tr("Received channel subscribed for not visible channel (cid: %d)"), entry['cid']);
continue;
}
2019-02-23 13:15:22 +00:00
channel.setSubscribed(true);
}
} finally {
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
2020-03-30 11:44:18 +00:00
}
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-02-23 13:15:22 +00:00
}
channel.setSubscribed(false);
for(const client of channel.clients(false)) {
2020-07-17 21:56:20 +00:00
this.connection.client.channelTree.deleteClient(client, { reason: ViewReasonId.VREASON_SYSTEM, serverLeave: false });
}
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
2019-02-23 13:15:22 +00:00
/*
2020-03-30 11:44:18 +00:00
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);
2020-03-30 11:44:18 +00:00
if(!conversation)
continue;
2020-03-27 22:36:57 +00:00
2020-03-30 11:44:18 +00:00
conversation.delete_messages(parseInt(entry["timestamp_begin"]), parseInt(entry["timestamp_end"]), parseInt(entry["cldbid"]), parseInt(entry["limit"]));
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
}
*/
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyMusicStatusUpdate(json: any[]) {
json = json[0];
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-02-23 13:15:22 +00:00
}
2020-03-30 11:44:18 +00:00
client.events.fire("music_status_update", {
player_replay_index: parseInt(json["player_replay_index"]),
player_buffered_index: parseInt(json["player_buffered_index"])
});
}
2019-02-23 13:15:22 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-02-23 13:15:22 +00:00
}
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
const song_id = parseInt(json["song_id"]);
let song: SongInfo;
if(song_id) {
song = new SongInfo();
JSON.map_to(song, json);
}
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
client.events.fire("music_song_change", {
song: song
});
}
2020-02-02 14:05:36 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyPlaylistSongAdd(json: any[]) {
json = json[0];
2020-03-27 22:36:57 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-03-17 11:15:39 +00:00
}
2020-03-30 11:44:18 +00:00
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"],
2019-03-17 11:15:39 +00:00
2020-03-30 11:44:18 +00:00
song_loaded: json["song_loaded"] == true || json["song_loaded"] == "1",
song_metadata: json["song_metadata"]
2019-03-17 11:15:39 +00:00
}
2020-03-30 11:44:18 +00:00
});
}
2020-02-02 14:05:36 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-03-17 11:15:39 +00:00
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
const song_id = parseInt(json["song_id"]);
client.events.fire("playlist_song_remove", { song_id: song_id });
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyPlaylistSongReorder(json: any[]) {
json = json[0];
2019-09-12 21:59:35 +00:00
2020-03-30 11:44:18 +00:00
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;
2019-08-21 08:00:01 +00:00
}
2020-03-30 11:44:18 +00:00
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 });
}
2019-08-21 08:00:01 +00:00
2020-03-30 11:44:18 +00:00
handleNotifyPlaylistSongLoaded(json: any[]) {
json = json[0];
2020-03-30 11:44:18 +00:00
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;
2019-08-21 08:00:01 +00:00
}
2020-03-30 11:44:18 +00:00
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"]
});
2019-02-23 13:15:22 +00:00
}
}