import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler"; import { ClientForumInfo, ClientInfoType, ClientStatusInfo, ClientVersionInfo } from "tc-shared/ui/frames/side/ClientInfoDefinitions"; import {ClientEntry, ClientType, LocalClientEntry} from "tc-shared/tree/Client"; import {Registry} from "tc-shared/events"; import * as i18nc from "./i18n/CountryFlag"; export type CachedClientInfoCategory = "name" | "description" | "online-state" | "country" | "volume" | "status" | "forum-account" | "group-channel" | "groups-server" | "version"; export type CachedClientInfo = { type: ClientInfoType; name: string, uniqueId: string, databaseId: number, clientId: number, description: string, joinTimestamp: number, leaveTimestamp: number, country: { name: string, flag: string }, volume: { volume: number, muted: boolean }, status: ClientStatusInfo, forumAccount: ClientForumInfo | undefined, channelGroup: number, channelGroupInheritedChannel: number, serverGroups: number[], version: ClientVersionInfo } export interface ClientInfoManagerEvents { notify_client_changed: { newClient: ClientEntry | undefined }, notify_cache_changed: { category: CachedClientInfoCategory }, } export class SelectedClientInfo { readonly events: Registry; private readonly connection: ConnectionHandler; private readonly listenerConnection: (() => void)[]; private listenerClient: (() => void)[]; private currentClient: ClientEntry | undefined; private currentClientStatus: CachedClientInfo | undefined; constructor(connection: ConnectionHandler) { this.connection = connection; this.events = new Registry(); this.listenerClient = []; this.listenerConnection = []; this.listenerConnection.push(connection.channelTree.events.on("notify_client_leave_view", event => { if(event.client !== this.currentClient) { return; } this.currentClientStatus.leaveTimestamp = Date.now() / 1000; this.currentClientStatus.clientId = 0; this.currentClient = undefined; this.unregisterClientEvents(); this.events.fire("notify_cache_changed", { category: "online-state" }); })); this.listenerConnection.push(connection.events().on("notify_connection_state_changed", event => { if(event.newState !== ConnectionState.CONNECTED && this.currentClientStatus) { this.currentClient = undefined; this.currentClientStatus.leaveTimestamp = Date.now() / 1000; this.events.fire("notify_cache_changed", { category: "online-state" }); } })); } destroy() { this.listenerConnection.forEach(callback => callback()); this.listenerConnection.splice(0, this.listenerConnection.length); this.unregisterClientEvents(); } getInfo() : CachedClientInfo { return this.currentClientStatus; } setClient(client: ClientEntry | undefined) { if(this.currentClient === client) { return; } if(client.channelTree.client !== this.connection) { throw tr("client does not belong to current connection handler"); } this.unregisterClientEvents(); this.currentClient = client; this.currentClientStatus = undefined; if(this.currentClient) { this.currentClient.updateClientVariables().then(undefined); this.registerClientEvents(this.currentClient); this.initializeClientInfo(this.currentClient); } this.events.fire("notify_client_changed", { newClient: client }); } getClient() : ClientEntry | undefined { return this.currentClient; } private unregisterClientEvents() { this.listenerClient.forEach(callback => callback()); this.listenerClient = []; } private registerClientEvents(client: ClientEntry) { const events = this.listenerClient; events.push(client.events.on("notify_properties_updated", event => { if('client_nickname' in event.updated_properties) { this.currentClientStatus.name = event.client_properties.client_nickname; this.events.fire("notify_cache_changed", { category: "name" }); } if('client_description' in event.updated_properties) { this.currentClientStatus.description = event.client_properties.client_description; this.events.fire("notify_cache_changed", { category: "description" }); } if('client_channel_group_id' in event.updated_properties || 'client_channel_group_inherited_channel_id' in event.updated_properties) { this.updateChannelGroup(client); this.events.fire("notify_cache_changed", { category: "group-channel" }); } if('client_servergroups' in event.updated_properties) { this.currentClientStatus.serverGroups = client.assignedServerGroupIds(); this.events.fire("notify_cache_changed", { category: "groups-server" }); } /* Can happen since that variable isn't in view on client appearance */ if('client_lastconnected' in event.updated_properties) { this.currentClientStatus.joinTimestamp = event.client_properties.client_lastconnected; this.events.fire("notify_cache_changed", { category: "online-state" }); } if('client_country' in event.updated_properties) { this.updateCachedCountry(client); this.events.fire("notify_cache_changed", { category: "country" }); } for(const key of ["client_away", "client_away_message", "client_input_muted", "client_input_hardware", "client_output_muted", "client_output_hardware"]) { if(key in event.updated_properties) { this.updateCachedClientStatus(client); this.events.fire("notify_cache_changed", { category: "status" }); break; } } if('client_platform' in event.updated_properties || 'client_version' in event.updated_properties) { this.currentClientStatus.version = { platform: client.properties.client_platform, version: client.properties.client_version }; this.events.fire("notify_cache_changed", { category: "version" }); } if('client_teaforo_flags' in event.updated_properties || 'client_teaforo_name' in event.updated_properties || 'client_teaforo_id' in event.updated_properties) { this.updateForumAccount(client); this.events.fire("notify_cache_changed", { category: "forum-account" }); } })); events.push(client.events.on("notify_audio_level_changed", () => { this.updateCachedVolume(client); this.events.fire("notify_cache_changed", { category: "volume" }); })); events.push(client.events.on("notify_mute_state_change", () => { this.updateCachedVolume(client); this.events.fire("notify_cache_changed", { category: "volume" }); })); } private updateCachedClientStatus(client: ClientEntry) { this.currentClientStatus.status = { away: client.properties.client_away ? client.properties.client_away_message ? client.properties.client_away_message : true : false, microphoneMuted: client.properties.client_input_muted, microphoneDisabled: !client.properties.client_input_hardware, speakerMuted: client.properties.client_output_muted, speakerDisabled: !client.properties.client_output_hardware }; } private updateCachedCountry(client: ClientEntry) { this.currentClientStatus.country = { flag: client.properties.client_country, name: i18nc.getCountryName(client.properties.client_country.toUpperCase()), }; } private updateCachedVolume(client: ClientEntry) { this.currentClientStatus.volume = { volume: client.getAudioVolume(), muted: client.isMuted() } } private updateForumAccount(client: ClientEntry) { if(client.properties.client_teaforo_id) { this.currentClientStatus.forumAccount = { flags: client.properties.client_teaforo_flags, nickname: client.properties.client_teaforo_name, userId: client.properties.client_teaforo_id }; } else { this.currentClientStatus.forumAccount = undefined; } } private updateChannelGroup(client: ClientEntry) { this.currentClientStatus.channelGroup = client.properties.client_channel_group_id; this.currentClientStatus.channelGroupInheritedChannel = client.properties.client_channel_group_inherited_channel_id; if(this.currentClientStatus.channelGroupInheritedChannel === client.currentChannel().channelId) { this.currentClientStatus.channelGroupInheritedChannel = 0; } } private initializeClientInfo(client: ClientEntry) { this.currentClientStatus = { type: client instanceof LocalClientEntry ? "self" : client.getClientType() === ClientType.CLIENT_QUERY ? "query" : "voice", name: client.properties.client_nickname, databaseId: client.properties.client_database_id, uniqueId: client.properties.client_unique_identifier, clientId: client.clientId(), description: client.properties.client_description, channelGroup: 0, channelGroupInheritedChannel: 0, serverGroups: client.assignedServerGroupIds(), country: undefined, forumAccount: undefined, joinTimestamp: client.properties.client_lastconnected, leaveTimestamp: 0, status: undefined, volume: undefined, version: { platform: client.properties.client_platform, version: client.properties.client_version } }; this.updateChannelGroup(client); this.updateCachedClientStatus(client); this.updateCachedCountry(client); this.updateCachedVolume(client); this.updateForumAccount(client); } }