ts3-nodejs-library
Version:
TeamSpeak Server Query API
1,303 lines (1,140 loc) • 97.2 kB
text/typescript
import { EventEmitter } from "events"
import crc from "buffer-crc32"
import { TeamSpeakQuery } from "./transport/TeamSpeakQuery"
import { FileTransfer } from "./transport/FileTransfer"
import { ResponseError } from "./exception/ResponseError"
import { TeamSpeakClient } from "./node/Client"
import { TeamSpeakServer } from "./node/Server"
import { TeamSpeakChannel } from "./node/Channel"
import { TeamSpeakServerGroup } from "./node/ServerGroup"
import { TeamSpeakChannelGroup } from "./node/ChannelGroup"
import * as Response from "./types/ResponseTypes"
import * as Event from "./types/Events"
import * as Props from "./types/PropertyTypes"
import { Command } from "./transport/Command"
import { Context, SelectType } from "./types/context"
import { EventError } from "./exception/EventError"
import { ClientType, ReasonIdentifier, TextMessageTargetMode, TokenType, LogLevel } from "./types/enum"
import { Permission } from "./util/Permission"
/**
* missing Query Commands
* @todo
* channelclientaddperm
* channelclientdelperm
* servergroupautoaddperm
* servergroupautodelperm
* tokenadd
* tokendelete
* tokenlist
* tokenuse
* clientfind
*/
declare type NodeType = TeamSpeakClient|TeamSpeakChannel|TeamSpeakChannelGroup|TeamSpeakServer|TeamSpeakServerGroup
type NodeConstructable<T> = new(parent: TeamSpeak, props: {}) => T
export interface TeamSpeak {
on(event: "error", listener: (error: Error) => void): this
on(event: "ready", listener: () => void): this
on(event: "close", listener: (error?: Error) => void): this
on(event: "flooding", listener: (error: ResponseError) => void): this
on(event: "debug", listener: (event: Event.Debug) => void): this
on(event: "clientconnect", listener: (event: Event.ClientConnect) => void): this
on(event: "clientdisconnect", listener: (event: Event.ClientDisconnect) => void): this
on(event: "tokenused", listener: (event: Event.TokenUsed) => void): this
on(event: "textmessage", listener: (event: Event.TextMessage) => void): this
on(event: "clientmoved", listener: (event: Event.ClientMoved) => void): this
on(event: "serveredit", listener: (event: Event.ServerEdit) => void): this
on(event: "channeledit", listener: (event: Event.ChannelEdit) => void): this
on(event: "channelcreate", listener: (event: Event.ChannelCreate) => void): this
on(event: "channelmoved", listener: (event: Event.ChannelMove) => void): this
on(event: "channeldelete", listener: (event: Event.ChannelDelete) => void): this
}
export class TeamSpeak extends EventEmitter {
readonly config: TeamSpeak.ConnectionParams
private serverVersion: Response.Version|undefined
private clients: Record<string, TeamSpeakClient> = {}
private servers: Record<string, TeamSpeakServer> = {}
private servergroups: Record<string, TeamSpeakServerGroup> = {}
private channels: Record<string, TeamSpeakChannel> = {}
private channelgroups: Record<string, TeamSpeakChannelGroup> = {}
private priorizeNextCommand: boolean = false
private query: TeamSpeakQuery
private context: Context = {
selectType: SelectType.NONE,
selected: 0,
events: []
}
constructor(config: Partial<TeamSpeak.ConnectionParams>) {
super()
this.config = {
protocol: TeamSpeak.QueryProtocol.RAW,
host: "127.0.0.1",
queryport: config.protocol === TeamSpeak.QueryProtocol.SSH ? 10022 : 10011,
readyTimeout: 10000,
ignoreQueries: false,
keepAlive: true,
keepAliveTimeout: 250,
autoConnect: true,
...config
}
this.query = new TeamSpeakQuery(this.config)
this.query.on("cliententerview", this.evcliententerview.bind(this))
this.query.on("clientleftview", this.evclientleftview.bind(this))
this.query.on("tokenused", this.evtokenused.bind(this))
this.query.on("serveredited", this.evserveredited.bind(this))
this.query.on("channeledited", this.evchanneledited.bind(this))
this.query.on("channelmoved", this.evchannelmoved.bind(this))
this.query.on("channeldeleted", this.evchanneldeleted.bind(this))
this.query.on("channelcreated", this.evchannelcreated.bind(this))
this.query.on("clientmoved", this.evclientmoved.bind(this))
this.query.on("textmessage", this.evtextmessage.bind(this))
this.query.on("ready", this.handleReady.bind(this))
this.query.on("close", (e?: string) => super.emit("close", e))
this.query.on("error", (e: Error) => super.emit("error", e))
this.query.on("flooding", (e: ResponseError) => super.emit("flooding", e))
this.query.on("debug", (data: Event.Debug) => super.emit("debug", data))
//@ts-ignore
this.on("newListener", this.handleNewListener.bind(this))
if (this.config.autoConnect)
/** can be dropped silently since errors are getting emitted via the error event */
this.connect().catch(() => null)
}
/**
* connects via a Promise wrapper
* @param config config options to connect
*/
static connect(config: Partial<TeamSpeak.ConnectionParams>): Promise<TeamSpeak> {
return new TeamSpeak({
...config,
autoConnect: false
}).connect()
}
/**
* attempts a reconnect to the teamspeak server with full context features
* @param attempts the amount of times it should try to reconnect (-1 = try forever)
* @param timeout time in ms to wait inbetween reconnect
*/
async reconnect(attempts: number = 1, timeout: number = 2000) {
let attempt = 0
let error: Error|null = null
while (attempts === -1 || attempt++ < attempts) {
try {
await TeamSpeak.wait(timeout)
if (this.query.isConnected()) throw new Error("already connected")
await this.connect()
return this
} catch (e) {
error = e
}
}
throw error ? error : new Error(`reconnecting failed after ${attempts} attempt(s)`)
}
/**
* waits a set time of ms
* @param time time in ms to wait
*/
static wait(time: number) {
return new Promise(fulfill => setTimeout(fulfill, time))
}
/**
* connects to the TeamSpeak Server
*/
connect(): Promise<TeamSpeak> {
return new Promise((fulfill, reject) => {
const removeListeners = () => {
this.removeListener("ready", readyCallback)
this.removeListener("error", errorCallback)
this.removeListener("close", closeCallback)
}
const readyCallback = () => {
removeListeners()
fulfill(this)
}
const errorCallback = (error: Error) => {
removeListeners()
this.forceQuit()
reject(error)
}
const closeCallback = (error?: Error) => {
removeListeners()
if (error instanceof Error) return reject(error)
reject(new Error("TeamSpeak Server prematurely closed the connection"))
}
this.once("ready", readyCallback)
this.once("error", errorCallback)
this.once("close", closeCallback)
this.query.connect()
})
}
/** subscribes to some query events if necessary */
private handleNewListener(event: string) {
const commands: Promise<any>[] = []
switch (event) {
case "clientconnect":
case "clientdisconnect":
case "serveredit":
if (this.isSubscribedToEvent("server")) break
commands.push(this.registerEvent("server"))
break
case "tokenused":
if (this.isSubscribedToEvent("tokenused")) break
commands.push(this.registerEvent("tokenused"))
break
case "channeledit":
case "channelmoved":
case "channeldelete":
case "channelcreate":
case "clientmoved":
if (this.isSubscribedToEvent("channel", "0")) break
commands.push(this.registerEvent("channel", "0"))
break
case "textmessage":
if (!this.isSubscribedToEvent("textserver")) commands.push(this.registerEvent("textserver"))
if (!this.isSubscribedToEvent("textchannel")) commands.push(this.registerEvent("textchannel"))
if (!this.isSubscribedToEvent("textprivate")) commands.push(this.registerEvent("textprivate"))
}
Promise.all(commands).catch(e => this.emit("error", e))
}
/** handles initial commands after successfully connecting to a TeamSpeak Server */
private handleReady() {
const exec: Promise<any>[] = []
if (this.context.login && this.config.protocol === TeamSpeak.QueryProtocol.RAW) {
exec.push(this.priorize().login(this.context.login.username, this.context.login.password))
} else if (this.config.username && this.config.password && this.config.protocol === TeamSpeak.QueryProtocol.RAW) {
exec.push(this.priorize().login(this.config.username, this.config.password))
}
if (this.context.selectType !== SelectType.NONE) {
if (this.context.selectType === SelectType.PORT) {
exec.push(this.priorize().useByPort(this.context.selected, this.context.clientNickname || this.config.nickname))
} else if (this.context.selectType === SelectType.SID) {
exec.push(this.priorize().useBySid(this.context.selected, this.context.clientNickname || this.config.nickname))
}
} else if (this.config.serverport) {
exec.push(this.priorize().useByPort(this.config.serverport, this.config.nickname))
}
exec.push(...this.context.events.map(ev => this.priorize().registerEvent(ev.event, ev.id)))
exec.push(this.priorize().version())
this.query.pause(false)
return Promise.all(exec)
.then(() => super.emit("ready"))
.catch(e => super.emit("error", e))
}
/**
* Gets called when a client connects to the TeamSpeak Server
* @param event the raw teamspeak event
*/
private evcliententerview(event: TeamSpeakQuery.ResponseEntry) {
this.clientList().then(clients => {
const client = clients.find(client => client.clid === event.clid)
if (!client) throw new EventError(`could not fetch client with id ${event.clid}`, "cliententerview")
if (this.ignoreQueryClient(client.type)) return
super.emit("clientconnect", { client, cid: event.ctid })
})
.catch(error => this.emit("error", error))
}
/**
* Gets called when a client discconnects from the TeamSpeak Server
* @param event the raw teamspeak event
*/
private evclientleftview(event: TeamSpeakQuery.ResponseEntry) {
const { clid } = event
const client = this.clients[clid as string]
if (client && this.ignoreQueryClient(client.type)) return
super.emit("clientdisconnect", { client, event })
Reflect.deleteProperty(this.clients, clid as string)
}
/**
* Gets called when a client uses a privilege key
* @param event the raw teamspeak event
*/
private evtokenused(event: TeamSpeakQuery.ResponseEntry) {
this.getClientById(event.clid as string).then(client => {
if (!client) throw new EventError(`could not fetch client with id ${event.clid}`, "tokenused")
if (this.ignoreQueryClient(client.type)) return
super.emit("tokenused", {client, token: event.token, token1: event.token1, token2: event.token2, tokencustomset: event.tokencustomset })
}).catch(e => super.emit("error", e))
}
/**
* Gets called when a chat message gets received
* @param event the raw teamspeak event
*/
private evtextmessage(event: TeamSpeakQuery.ResponseEntry) {
this.getClientById(event.invokerid as string).then(invoker => {
if (!invoker) throw new EventError(`could not fetch client with id ${event.invokerid}`, "textmessage")
if (this.ignoreQueryClient(invoker.type)) return
super.emit("textmessage", { invoker, msg: event.msg, targetmode: event.targetmode })
}).catch(e => super.emit("error", e))
}
/**
* Gets called when a client moves to a different channel
* @param event the raw teamspeak event
*/
private evclientmoved(event: TeamSpeakQuery.ResponseEntry) {
Promise.all([
this.getClientById(event.clid as string),
this.getChannelById(event.ctid as string)
]).then(([client, channel]) => {
if (!client) throw new EventError(`could not fetch client with id ${event.clid}`, "clientmoved")
if (!channel) throw new EventError(`could not fetch channel with id ${event.ctid}`, "clientmoved")
if (this.ignoreQueryClient(client.type)) return
this.emit("clientmoved", { client, channel, reasonid: event.reasonid })
}).catch(e => this.emit("error", e))
}
/**
* Gets called when the server has been edited
* @param event the raw teamspeak event
*/
private async evserveredited(event: TeamSpeakQuery.ResponseEntry) {
this.getClientById(event.invokerid as string).then(invoker => {
if (!invoker) throw new EventError(`could not fetch client with id ${event.invokerid}`, "serveredited")
if (this.ignoreQueryClient(invoker.type)) return
const modified: TeamSpeakQuery.ResponseEntry = {}
Object.keys(event)
.filter(k => k.startsWith("virtualserver"))
.forEach(k => modified[k] = event[k])
this.emit("serveredit", { invoker, modified, reasonid: event.reasonid })
}).catch(e => this.emit("error", e))
}
/**
* Gets called when a channel gets edited
* @param event the raw teamspeak event
*/
private evchanneledited(event: TeamSpeakQuery.ResponseEntry) {
Promise.all([
this.getClientById(event.invokerid as string),
this.getChannelById(event.cid as string)
]).then(([invoker, channel]) => {
if (!invoker) throw new EventError(`could not fetch client with id ${event.invokerid}`, "channeledited")
if (this.ignoreQueryClient(invoker.type)) return
if (!channel) throw new EventError(`could not fetch channel with id ${event.cid}`, "channeledited")
const modified: TeamSpeakQuery.ResponseEntry = {}
Object.keys(event)
.filter(k => k.startsWith("channel"))
.forEach(k => modified[k] = event[k])
this.emit("channeledit", {
invoker,
channel,
modified,
reasonid: event.reasonid
})
}).catch(e => this.emit("error", e))
}
/**
* Gets called when a channel gets edited
* @param event the raw teamspeak event
*/
private evchannelcreated(event: TeamSpeakQuery.ResponseEntry) {
Promise.all([
this.getClientById(event.invokerid as string),
this.getChannelById(event.cid as string)
]).then(([invoker, channel]) => {
if (!invoker) throw new EventError(`could not fetch client with id ${event.invokerid}`, "channelcreated")
if (this.ignoreQueryClient(invoker.type)) return
if (!channel) throw new EventError(`could not fetch channel with id ${event.cid}`, "channelcreated")
const modified: TeamSpeakQuery.ResponseEntry = {}
Object.keys(event)
.filter(k => k.startsWith("channel"))
.forEach(k => modified[k] = event[k])
this.emit("channelcreate", {
invoker,
channel,
modified,
cpid: event.cpid
})
}).catch(e => this.emit("error", e))
}
/**
* Gets called when a channel gets moved
* @param event the raw teamspeak event
*/
private evchannelmoved(event: TeamSpeakQuery.ResponseEntry) {
Promise.all([
this.getClientById(event.invokerid as string),
this.getChannelById(event.cid as string),
this.getChannelById(event.cpid as string)
]).then(([invoker, channel, parent]) => {
if (!invoker) throw new EventError(`could not fetch client with id ${event.invokerid}`, "channelmoved")
if (this.ignoreQueryClient(invoker.type)) return
if (!channel) throw new EventError(`could not fetch channel with id ${event.cid}`, "channelmoved")
this.emit("channelmoved", { invoker, channel, parent, order: event.order })
}).catch(e => this.emit("error", e))
}
/**
* Gets called when a channel gets deleted
* @param event the raw teamspeak event
*/
private async evchanneldeleted(event: TeamSpeakQuery.ResponseEntry) {
this.getClientById(event.invokerid as string).then(invoker => {
if (invoker && this.ignoreQueryClient(invoker.type)) return
this.emit("channeldelete", { invoker, cid: event.cid })
})
.catch(e => this.emit("error", e))
}
/** priorizes the next command, this commands will be first in execution */
priorize() {
this.priorizeNextCommand = true
return this
}
/**
* Sends a raw command to the TeamSpeak Server.
* @param {...any} args the command which should get executed on the teamspeak server
* @example
* ts3.execute("clientlist", ["-ip"])
* ts3.execute("use", [9987], { clientnickname: "test" })
*/
execute<
T extends (TeamSpeakQuery.ResponseEntry|TeamSpeakQuery.Response) = []
>(cmd: string, ...args: TeamSpeakQuery.executeArgs[]): Promise<T> {
if (this.priorizeNextCommand) {
this.priorizeNextCommand = false
return <any>this.query.executePrio(cmd, ...args)
} else {
return <any>this.query.execute(cmd, ...args)
}
}
/**
* Adds a new query client login, or enables query login for existing clients.
* When no virtual server has been selected, the command will create global query logins.
* Otherwise the command enables query login for existing client, and cldbid must be specified.
* @param clientLoginName the login name
* @param client optional database id or teamspeak client
*/
queryLoginAdd(clientLoginName: string, client?: TeamSpeakClient.ClientType) {
return this.execute<Response.QueryLoginAdd>("queryloginadd", {
clientLoginName,
cldbid: TeamSpeakClient.getDbid(client)
}).then(TeamSpeak.singleResponse)
}
/**
* Deletes an existing server query login on selected server.
* When no virtual server has been selected, deletes global query logins instead.
* @param client client database id or teamspeak client object
*/
queryLoginDel(client: TeamSpeakClient.ClientType) {
return this.execute("querylogindel", { cldbid: TeamSpeakClient.getDbid(client) })
}
/**
* List existing query client logins.
* The pattern parameter can include regular characters and SQL wildcard characters (e.g. %).
* Only displays query logins of the selected virtual server, or all query logins when no virtual server have been selected.
* @param pattern the pattern to filter for client login names
* @param start the offset from where clients should be listed
* @param duration how many clients should be listed
*/
queryLoginList(pattern?: string, start?: number, duration?: number) {
return this.execute<Response.QueryLoginList>("queryloginlist", { pattern, start, duration }, ["-count"])
.then(TeamSpeak.toArray)
}
apiKeyAdd(props: Props.ApiKeyAdd) {
return this.execute<Response.ApiKeyAdd>("apikeyadd", props)
.then(TeamSpeak.singleResponse)
}
/**
* Lists all apikeys owned by the user, or of all users using cldbid=*.
* Usage of cldbid=... requires bVirtualserverApikeyManage.
*/
apiKeyList(props: Props.ApiKeyList = {}) {
return this.execute<Response.ApiKeyList>("apikeylist", props, ["-count"])
.then(TeamSpeak.toArray)
}
/**
* Deletes an apikey. Any apikey owned by the current user, can always be deleted
* Deleting apikeys from other requires bVirtualserverApikeyManage
* @param id the key id to delete
*/
apiKeyDel(id: string) {
return this.execute("apikeydel", { id })
}
/**
* Updates your own ServerQuery login credentials using a specified username.
* The password will be auto-generated.
* @param name
*/
clientSetServerQueryLogin(name: string) {
return this.execute<Response.ClientSetServerQueryLogin>("clientsetserverquerylogin", { clientLoginName: name })
.then(TeamSpeak.singleResponse)
}
/**
* Change your ServerQuery clients settings using given properties.
* @param props the properties which should be changed
*/
clientUpdate(props: Props.ClientUpdate) {
return this.execute("clientupdate", props)
.then(this.updateContextResolve({
clientNickname: props.clientNickname ? props.clientNickname : this.context.clientNickname
}))
}
/**
* Subscribes to an Event
* @param event the event on which should be subscribed
* @param id the channel id, only required when subscribing to the "channel" event
*/
registerEvent(event: string, id?: string) {
return this.execute("servernotifyregister", { event, id })
.then(this.updateContextResolve({ events: [{ event, id }] }))
}
/**
* Subscribes to an Event.
*/
unregisterEvent() {
return this.execute("servernotifyunregister")
.then(this.updateContextResolve({ events: [] }))
}
/**
* Authenticates with the TeamSpeak 3 Server instance using given ServerQuery login credentials.
* @param username the username which you want to login with
* @param password the password you want to login with
*/
login(username: string, password: string) {
return this.execute("login", [username, password])
.then(this.updateContextResolve({ login: { username, password }}))
.catch(this.updateContextReject({ login: undefined }))
}
/** Deselects the active virtual server and logs out from the server instance. */
logout() {
return this.execute("logout")
.then(this.updateContextResolve({
selectType: SelectType.NONE,
clientNickname: this.config.nickname,
login: undefined,
events: []
}))
}
/**
* Displays the servers version information including platform and build number.
* @param refresh if this parameter has been set it will send a command to the server otherwise will use the cached info
*/
async version(refresh: boolean = false) {
if (refresh || !this.serverVersion) {
this.serverVersion = await this.execute<Response.Version>("version").then(TeamSpeak.singleResponse)
}
return this.serverVersion
}
/**
* Displays detailed connection information about the server instance including uptime,
* number of virtual servers online, traffic information, etc.
*/
hostInfo() {
return this.execute<Response.HostInfo>("hostinfo")
.then(TeamSpeak.singleResponse)
}
/**
* Displays the server instance configuration including database revision number,
* the file transfer port, default group IDs, etc.
*/
instanceInfo() {
return this.execute<Response.InstanceInfo>("instanceinfo")
.then(TeamSpeak.singleResponse)
}
/**
* Changes the server instance configuration using given properties.
* @param properties the props you want to change
*/
instanceEdit(properties: Props.InstanceEdit) {
return this.execute("instanceedit", properties)
}
/** returns a list of IP addresses used by the server instance on multi-homed machines. */
bindingList() {
return this.execute<Response.BindingList>("bindinglist")
.then(TeamSpeak.toArray)
}
/**
* Selects the virtual server specified with the port to allow further interaction.
* @param port the port the server runs on
* @param clientNickname set nickname when selecting a server
*/
useByPort(port: number, clientNickname?: string) {
return this.execute("use", { port, clientNickname }, ["-virtual"])
.then(this.updateContextResolve({
selectType: SelectType.PORT,
selected: port,
clientNickname,
events: []
}))
.catch(this.updateContextReject({ selectType: SelectType.NONE }))
}
/**
* Selects the virtual server specified with the sid to allow further interaction.
* @param server the server id
* @param clientNickname set nickname when selecting a server
*/
useBySid(server: TeamSpeakServer.ServerType, clientNickname?: string) {
return this.execute("use", [TeamSpeakServer.getId(server), "-virtual"], { clientNickname })
.then(this.updateContextResolve({
selectType: SelectType.SID,
selected: TeamSpeakServer.getId(server),
clientNickname,
events: []
}))
}
/** returns information about your current ServerQuery connection including your loginname, etc. */
whoami() {
return this.execute<Response.Whoami>("whoami")
.then(TeamSpeak.singleResponse)
}
/** retrieves the own query client as TeamSpeakClient instance */
async self() {
const { clientId } = await this.whoami()
let client: TeamSpeakClient|undefined = this.clients[clientId]
if (client) return client
client = await this.getClientById(clientId)
if (client) return client
throw new Error("could not find own query client")
}
/**
* Displays detailed configuration information about the selected virtual server
* including unique ID, number of clients online, configuration, etc.
*/
serverInfo() {
return this.execute<Response.ServerInfo>("serverinfo")
.then(TeamSpeak.singleResponse)
}
/**
* Displays the database ID of the virtual server running on the UDP port
* @param virtualserverPort the server port where data should be retrieved
*/
serverIdGetByPort(virtualserverPort: number) {
return this.execute<Response.ServerIdGetByPort>("serveridgetbyport", { virtualserverPort })
.then(TeamSpeak.singleResponse)
}
/**
* Changes the selected virtual servers configuration using given properties.
* Note that this command accepts multiple properties which means that you're able to change all settings of the selected virtual server at once.
*/
serverEdit(properties: Props.ServerEdit) {
return this.execute("serveredit", properties)
}
/**
* Stops the entire TeamSpeak 3 Server instance by shutting down the process.
* @param reasonmsg specifies a text message that is sent to the clients before the client disconnects (requires TeamSpeak Server 3.2.0 or newer).
*/
serverProcessStop(reasonmsg?: string) {
return this.execute("serverprocessstop", { reasonmsg })
}
/**
* returns detailed connection information about the selected virtual server including uptime, traffic information, etc.
*/
connectionInfo() {
return this.execute<Response.ServerRequestConnectionInfo>("serverrequestconnectioninfo")
.then(TeamSpeak.singleResponse)
}
/**
* Creates a new virtual server using the given properties and displays its ID, port and initial administrator privilege key.
* If virtualserverPort is not specified, the server will test for the first unused UDP port
* @param properties the server properties
*/
serverCreate(properties: Props.ServerEdit): Promise<Response.ServerCreate> {
let servertoken = ""
return this.execute<{ token: string, sid: string }>("servercreate", properties)
.then(TeamSpeak.singleResponse)
.then(({ token, sid }) => {
servertoken = token
return this.serverList({ virtualserverId: sid })
})
.then(([server]) => ({ server, token: servertoken }))
}
/**
* deletes the teamspeak server
* @param server the server id to delete
*/
serverDelete(server: TeamSpeakServer.ServerType) {
return this.execute("serverdelete", { sid: TeamSpeakServer.getId(server) })
}
/**
* Starts the virtual server. Depending on your permissions,
* you're able to start either your own virtual server only or all virtual servers in the server instance.
* @param server the server id to start
*/
serverStart(server: TeamSpeakServer.ServerType) {
return this.execute("serverstart", { sid: TeamSpeakServer.getId(server) })
}
/**
* Stops the virtual server. Depending on your permissions,
* you're able to stop either your own virtual server only or all virtual servers in the server instance.
* @param server the server id to stop
* @param reasonmsg Specifies a text message that is sent to the clients before the client disconnects (requires TeamSpeak Server 3.2.0 or newer).
*/
serverStop(server: TeamSpeakServer.ServerType, reasonmsg?: string) {
return this.execute("serverstop", { sid: TeamSpeakServer.getId(server), reasonmsg })
}
/**
* Creates a new server group using the name specified with name.
* The optional type parameter can be used to create ServerQuery groups and template groups.
* @param name the name of the servergroup
* @param type type of the servergroup
*/
serverGroupCreate(name: string, type: number = 1): Promise<TeamSpeakServerGroup> {
return this.execute<{ sgid: string }>("servergroupadd", { name, type })
.then(TeamSpeak.singleResponse)
.then(({sgid}) => this.serverGroupList({ sgid }))
.then(group => group[0])
}
/**
* returns the IDs of all clients currently residing in the server group.
* @param group the servergroup id
*/
serverGroupClientList(group: TeamSpeakServerGroup.GroupType) {
return this.execute<Response.ServerGroupClientList>("servergroupclientlist", {sgid: TeamSpeakServerGroup.getId(group) }, ["-names"])
.then(TeamSpeak.toArray)
}
/**
* Adds one or more clients to a server group specified with sgid.
* Please note that a client cannot be added to default groups or template groups
* @param client one or more client database ids which should be added
* @param group the servergroup id which the client(s) should be added to
*/
serverGroupAddClient(client: TeamSpeakClient.MultiClientType, group: TeamSpeakServerGroup.GroupType) {
return this.execute("servergroupaddclient", {
sgid: TeamSpeakServerGroup.getId(group),
cldbid: TeamSpeakClient.getMultipleDbids(client)
})
}
/**
* Removes one or more clients from the server group specified with sgid.
* @param client one or more client database ids which should be added
* @param group the servergroup id which the client(s) should be removed from
*/
serverGroupDelClient(client: TeamSpeakClient.MultiClientType, group: TeamSpeakServerGroup.GroupType) {
return this.execute("servergroupdelclient", {
sgid: TeamSpeakServerGroup.getId(group),
cldbid: TeamSpeakClient.getMultipleDbids(client)
})
}
/**
* displays all server groups the client specified with cldbid is currently residing in
* @param client the client database id to check
*/
serverGroupsByClientId(client: TeamSpeakClient.ClientType) {
return this.execute<Response.ServerGroupsByClientId>("servergroupsbyclientid", { cldbid: TeamSpeakClient.getMultipleDbids(client) })
.then(TeamSpeak.toArray)
}
/**
* Adds one or more servergroups to a client.
* Please note that a client cannot be added to default groups or template groups
* @param client one or more client database ids which should be added
* @param group one or more servergroup ids which the client should be added to
*/
clientAddServerGroup(client: TeamSpeakClient.ClientType, group: TeamSpeakServerGroup.MultiGroupType) {
return this.execute("clientaddservergroup", {
cldbid: TeamSpeakClient.getDbid(client),
sgid: TeamSpeakServerGroup.getMultipleIds(group)
})
}
/**
* Removes one or more servergroups from the client.
* @param client one or more client database ids which should be added
* @param groups one or more servergroup ids which the client should be removed from
*/
clientDelServerGroup(client: TeamSpeakClient.ClientType, groups: TeamSpeakServerGroup.MultiGroupType) {
return this.execute("clientdelservergroup", {
cldbid: TeamSpeakClient.getDbid(client),
sgid: TeamSpeakServerGroup.getMultipleIds(groups)
})
}
/**
* Deletes the server group. If force is set to 1, the server group will be deleted even if there are clients within.
* @param group the servergroup id
* @param force if set to 1 the servergoup will be deleted even when clients stil belong to this group
*/
serverGroupDel(group: TeamSpeakServerGroup.GroupType, force: boolean = false) {
return this.execute("servergroupdel", {sgid: TeamSpeakServerGroup.getId(group), force})
}
/**
* Creates a copy of the server group specified with ssgid.
* If tsgid is set to 0, the server will create a new group.
* To overwrite an existing group, simply set tsgid to the ID of a designated target group.
* If a target group is set, the name parameter will be ignored.
* @param sourceGroup the source ServerGroup
* @param targetGroup the target ServerGroup, 0 to create a new Group
* @param type the type of the servergroup (0 = Query Group | 1 = Normal Group)
* @param name name of the group
*/
serverGroupCopy(
sourceGroup: TeamSpeakServerGroup.GroupType,
targetGroup: TeamSpeakServerGroup.GroupType = "0",
type: number = 1,
name: string = "foo"
) {
return this.execute<Response.ServerGroupCopy[]>("servergroupcopy", {
ssgid: TeamSpeakServerGroup.getId(sourceGroup),
tsgid: TeamSpeakServerGroup.getId(targetGroup),
type,
name
}).then(TeamSpeak.singleResponse)
}
/**
* Changes the name of the server group
* @param group the servergroup id
* @param name new name of the servergroup
*/
serverGroupRename(group: TeamSpeakServerGroup.GroupType, name: string) {
return this.execute("servergrouprename", { sgid: TeamSpeakServerGroup.getId(group), name })
}
/**
* Displays a list of permissions assigned to the server group specified with sgid.
* @param sgid the servergroup id
* @param permsid if the permsid option is set to true the output will contain the permission names
*/
serverGroupPermList(group: TeamSpeakServerGroup.GroupType, permsid: boolean = false) {
const sgid = TeamSpeakServerGroup.getId(group)
return this.execute<Response.PermList>(
"servergrouppermlist", { sgid }, [ permsid ? "-permsid" : null ]
).then(response => {
return response.map(perm => {
return this.createServerGroupPermBuilder(sgid)
.perm(perm.permsid! || perm.permid!)
.value(perm.permvalue)
.skip(perm.permskip)
.negate(perm.permnegated)
})
})
}
/**
* Adds a specified permissions to the server group.
* A permission can be specified by permid or permsid.
* @param group the serverGroup id
* @param perm the permission object
*/
serverGroupAddPerm(group: TeamSpeakServerGroup.GroupType, perm: undefined): Permission
serverGroupAddPerm(group: TeamSpeakServerGroup.GroupType, perm: Permission.PermType): Promise<[]>
serverGroupAddPerm(group: TeamSpeakServerGroup.GroupType, perm?: Permission.PermType) {
const builder = this.createServerGroupPermBuilder(TeamSpeakServerGroup.getId(group))
if (!perm) return builder
if (perm.permskip) builder.skip(perm.permskip)
if (perm.permnegated) builder.negate(perm.permnegated)
return builder.perm(perm.permname).value(perm.permvalue).update()
}
/**
* Removes a set of specified permissions from the server group.
* A permission can be specified by permid or permsid.
* @param group the servergroup id
* @param perm the permid or permsid
*/
serverGroupDelPerm(group: TeamSpeakServerGroup.GroupType, perm: string|number) {
const properties = { sgid: TeamSpeakServerGroup.getId(group) }
properties[typeof perm === "string" ? "permsid" : "permid"] = perm
return this.execute("servergroupdelperm", properties)
}
/**
* Sets a new temporary server password specified with pw. The temporary
* password will be valid for the number of seconds specified with duration. The
* client connecting with this password will automatically join the channel
* specified with tcid. If tcid is set to 0, the client will join the default
* channel.
*/
serverTempPasswordAdd(props: Props.ServerTempPasswordAdd) {
return this.execute("servertemppasswordadd", { tcid: "0", tcpw: "", desc: "", ...props })
}
/**
* Deletes the temporary server password specified with pw.
* @param pw the password to delete
*/
serverTempPasswordDel(pw: string) {
return this.execute("servertemppassworddel", { pw })
}
/**
* Returns a list of active temporary server passwords. The output contains the
* clear-text password, the nickname and unique identifier of the creating
* client.
*/
serverTempPasswordList() {
return this.execute<Response.ServerTempPasswordList>("servertemppasswordlist")
.then(TeamSpeak.toArray)
}
/**
* Creates a new channel using the given properties.
* Note that this command accepts multiple properties which means that you're able to specifiy all settings of the new channel at once.
* @param name the name of the channel
* @param properties properties of the channel
*/
channelCreate(name: string, properties: Props.ChannelEdit = {}) {
properties.channelName = name
return this.execute<{ cid: string }>("channelcreate", properties)
.then(TeamSpeak.singleResponse)
.then(({cid}) => this.channelList({ cid }))
.then(([channel]) => channel)
}
/**
* Creates a new channel group using a given name.
* The optional type parameter can be used to create ServerQuery groups and template groups.
* @param name the name of the channelgroup
* @param type type of the channelgroup
*/
channelGroupCreate(name: string, type: number = 1) {
return this.execute<{ cgid: string }>("channelgroupadd", { name, type })
.then(TeamSpeak.singleResponse)
.then(({cgid}) => this.channelGroupList({ cgid }))
.then(([group]) => group)
}
/**
* Retrieves a Single Channel by the given Channel ID
* @param channel the channel id
*/
getChannelById(channel: TeamSpeakChannel.ChannelType): Promise<TeamSpeakChannel|undefined> {
return this.channelList({ cid: TeamSpeakChannel.getId(channel) }).then(([channel]) => channel)
}
/**
* Retrieves a Single Channel by the given Channel Name
* @param channelName the name of the channel
*/
getChannelByName(channelName: string): Promise<TeamSpeakChannel|undefined> {
return this.channelList({ channelName }).then(([channel]) => channel)
}
/**
* displays a list of channels matching a given name pattern
* @param pattern the channel name pattern to search for
*/
channelFind(pattern: string) {
return this.execute<Response.ChannelFind>("channelfind", { pattern }).then(TeamSpeak.toArray)
}
/**
* Displays detailed configuration information about a channel including ID, topic, description, etc.
* @param channel the channel id
*/
channelInfo(channel: TeamSpeakChannel.ChannelType) {
return this.execute<Response.ChannelInfo>("channelinfo", { cid: TeamSpeakChannel.getId(channel) }).then(TeamSpeak.singleResponse)
}
/**
* Moves a channel to a new parent channel with the ID cpid.
* If order is specified, the channel will be sorted right under the channel with the specified ID.
* If order is set to 0, the channel will be sorted right below the new parent.
* @param channel the channel id
* @param parent channel parent id
* @param order channel sort order
*/
channelMove(channel: TeamSpeakChannel.ChannelType, parent: TeamSpeakChannel.ChannelType, order: number = 0) {
return this.execute("channelmove", {
cid: TeamSpeakChannel.getId(channel),
cpid: TeamSpeakChannel.getId(parent),
order
})
}
/**
* Deletes an existing channel by ID.
* If force is set to 1, the channel will be deleted even if there are clients within.
* The clients will be kicked to the default channel with an appropriate reason message.
* @param channel the channel id
* @param force if set to 1 the channel will be deleted even when client are in it
*/
channelDelete(channel: TeamSpeakChannel.ChannelType, force: boolean = false) {
return this.execute("channeldelete", { cid: TeamSpeakChannel.getId(channel), force})
}
/**
* Changes a channels configuration using given properties.
* Note that this command accepts multiple properties which means that you're able to change all settings of the channel specified with cid at once.
* @param channel the channel id
* @param properties the properties of the channel which should get changed
*/
async channelEdit(channel: TeamSpeakChannel.ChannelType, properties: Props.ChannelEdit = {}) {
const cid = TeamSpeakChannel.getId(channel)
if (typeof properties.channelName === "string") {
if (!this.isSubscribedToEvent("server") || Object.keys(this.channels).length === 0) await this.channelList()
const c = await this.channels[cid]
if (c && properties.channelName === c.name) delete properties.channelName
if (Object.keys(properties).length === 0) return [] as []
}
properties.cid = cid
return this.execute("channeledit", properties)
}
/**
* Displays a list of permissions defined for a channel.
* @param channel the channel id
* @param permsid whether the permsid should be displayed aswell
*/
channelPermList(channel: TeamSpeakChannel.ChannelType, permsid: boolean = false) {
const cid = TeamSpeakChannel.getId(channel)
return this.execute<Response.PermList>(
"channelpermlist", { cid }, [permsid ? "-permsid" : null]
).then(response => {
return response.map(perm => {
return this.createChannelPermBuilder(cid)
.perm(perm.permsid! || perm.permid!)
.value(perm.permvalue)
})
})
}
/**
* Adds a set of specified permissions to a channel.
* @param channel the channel id
* @param perm the permission object
*/
channelSetPerm(channel: TeamSpeakChannel.ChannelType, perm: undefined): Permission
channelSetPerm(channel: TeamSpeakChannel.ChannelType, perm: Permission.PermType): Promise<[]>
channelSetPerm(channel: TeamSpeakChannel.ChannelType, perm?: Permission.PermType) {
const builder = this.createChannelPermBuilder(TeamSpeakChannel.getId(channel))
if (!perm) return builder
return builder.perm(perm.permname).value(perm.permvalue).update()
}
/**
* Adds a set of specified permissions to a channel.
* A permission can be specified by permid or permsid.
* @param channel the channel id
* @param permissions the permissions to assign
* @example
* TeamSpeak.channelSetPerms(5, [{ permsid: "i_channel_needed_modify_power", permvalue: 75 }])
*/
channelSetPerms(
channel: TeamSpeakChannel.ChannelType,
permissions: { permid?: number, permsid?: string, permvalue: number }[]
) {
return this.execute("channeladdperm", { cid: TeamSpeakChannel.getId(channel) }, permissions)
}
/**
* Removes a set of specified permissions from a channel.
* Multiple permissions can be removed at once.
* A permission can be specified by permid or permsid.
* @param channel the channel id
* @param perm the permid or permsid
*/
channelDelPerm(channel: TeamSpeakChannel.ChannelType, perm: string|number) {
const prop: Record<string, any> = { cid: TeamSpeakChannel.getId(channel) }
prop[typeof perm === "string" ? "permsid" : "permid"] = perm
return this.execute("channeldelperm", prop)
}
/**
* Retrieves a Single Client by the given Client ID
* @param client the client id
*/
getClientById(client: TeamSpeakClient.ClientType): Promise<TeamSpeakClient|undefined> {
return this.clientList({ clid: TeamSpeakClient.getId(client) })
.then(([client]) => client)
}
/**
* Retrieves a Single Client by the given Client Database ID
* @param client the client database Id
*/
getClientByDbid(client: TeamSpeakClient.ClientType): Promise<TeamSpeakClient|undefined> {
return this.clientList({ clientDatabaseId: TeamSpeakClient.getDbid(client) })
.then(([client]) => client)
}
/**
* Retrieves a Single Client by the given Client Unique Identifier
* @param client the client unique identifier
*/
getClientByUid(client: TeamSpeakClient.ClientType): Promise<TeamSpeakClient|undefined> {
return this.clientList({ clientUniqueIdentifier: TeamSpeakClient.getUid(client) })
.then(([client]) => client)
}
/**
* Retrieves a Single Client by the given Client Unique Identifier
* @param clientNickname the nickname of the client
*/
getClientByName(clientNickname: string): Promise<TeamSpeakClient|undefined> {
return this.clientList({ clientNickname })
.then(([client]) => client)
}
/**
* Returns General Info of the Client, requires the Client to be online
* @param clients one or more client ids to get
*/
clientInfo(clients: TeamSpeakClient.MultiClientType) {
return this.execute<Response.ClientInfo>("clientinfo", { clid: TeamSpeakClient.getMultipleIds(clients) })
.then(TeamSpeak.toArray)
}
/**
* Returns the Clients Database List
* @param start start offset
* @param duration amount of entries which should get retrieved
* @param count retrieve the count of entries
*/
clientDbList(start: number = 0, duration: number = 1000, count: boolean = true) {
return this.execute<Response.ClientDBList>("clientdblist", { start, duration }, [count ? "-count" : null])
.then(TeamSpeak.toArray)
}
/**
* Returns the Clients Database Info
* @param clients one or more client database ids to get
*/
clientDbInfo(clients: TeamSpeakClient.MultiClientType) {
return this.execute<Response.ClientDBInfo>("clientdbinfo", { cldbid: TeamSpeakClient.getMultipleDbids(clients) })
.then(TeamSpeak.toArray)
}
/**
* Kicks the Client from the Server
* @param client the client id
* @param reasonid the reasonid
* @param reasonmsg the message the client should receive when getting kicked
* @param continueOnError ignore errors
*/
clientKick(
client: TeamSpeakClient.ClientType,
reasonid: ReasonIdentifier,
reasonmsg: string,
continueOnError: boolean = false
) {
const flags: string[] = []
if (continueOnError) flags.push("-continueonerror")
return this.execute("clientkick", {
clid: TeamSpeakClient.getId(client),
reasonid,
reasonmsg
}, flags)
}
/**
* Moves the Client to a different Channel
* @param client the client id
* @param channel channel id in which the client should get moved
* @param cpw the channel password
* @param continueOnError ignore errors
*/
clientMove(
client: TeamSpeakClient.ClientType,
channel: TeamSpeakChannel.ChannelType,
cpw?: string,
continueOnError: boolean = false
) {
const flags: string[] = []
if (continueOnError) flags.push("-continueonerror")
return this.execute("clientmove", {
clid: TeamSpeakClient.getId(client),
cid: TeamSpeakChannel.getId(channel),
cpw
}, flags)
}
/**
* Pokes the Client with a certain message
* @param client the client id
* @param msg the message the client should receive
*/
clientPoke(client: TeamSpeakClient.ClientType, msg: string) {
return this.execute("clientpoke", { clid: TeamSpeakClient.getId(client), msg })
}
/**
* Displays a list of permissions defined for a client
* @param client the client database id
* @param permsid if the permsid option is set to true the output will contain the permission names
*/
clientPermList(client: TeamSpeakClient.ClientType, permsid: boolean = false) {
const cldbid = TeamSpeakClient.getDbid(client)
return this.execute<Response.PermList>(
"clientpermlist", { cldbid }, [permsid ? "-permsid" : null]
).then(response => {
return response.map(perm => {
return this.createClientPermBuilder(cldbid)
.perm(perm.permsid! || perm.permid!)
.value(perm.permvalue)
.skip(perm.permskip)
.negate(perm.permnegated)
})
})
}
/**
* Adds a set of specified permissions to a client.
* Multiple permissions can be added by providing the three parameters of each permission.
* A permission can be specified by permid or permsid.
* @param client the client database id
* @param perm the permission object
*/
clientAddPerm(client: TeamSpeakClient.ClientType, perm: undefined): Permission
clientAddPerm(client: TeamSpeakClient.ClientType, perm: Permission.PermType): Promise<[]>
clientAddPerm(client: TeamSpeakClient.ClientType, perm?: Permission.PermType) {
const builder = this.createClientPermBuilder(TeamSpeakClient.getDbid(client))
if (!perm) return builder
if (perm.permskip) builder.skip(perm.permskip)
if (perm.permnegated) builder.negate(perm.permnegated)
return builder.perm(perm.permname).value(perm.permvalue).update()
}
/**
* Removes a set of specified permissions from a client.
* Multiple permissions can be removed at once.
* A permission can be specified by permid or permsid
* @param client the client database