mumble-客户端
一个简单的模糊客户端,用于管理模糊服务器
功能
- 通过TLS连接到任何Mumble服务器
- 管理通道:创建、删除、链接/解除链接、获取acl
- 管理用户: 移动,静音/耳聋,注册/注销,重命名
- 发送和接收私人短信;读取证书哈希值和客户端IP地址
- 渠道权限查询
- 具有完整TypeScript支持的事件驱动架构
- 自动保持活ping
安装
npm i @tf2pickup-org/mumble-client
快速启动
import { Client } from '@tf2pickup-org/mumble-client';
const client = new Client({
host: 'mumble.example.com',
port: 64738,
username: 'my-bot',
rejectUnauthorized: false,
});
await client.connect();
console.log(`Connected! Welcome message: ${client.welcomeText}`);
console.log(`Logged in as ${client.self?.name}`);
// ... do work ...
client.disconnect();
示例
使用密码和访问令牌进行连接
const client = new Client({
host: 'mumble.example.com',
port: 64738,
username: 'my-bot',
password: 'server-password',
tokens: ['token-for-acl-group'],
clientName: 'my-awesome-bot',
rejectUnauthorized: false,
});
await client.connect();
列出所有频道
import { type Channel } from '@tf2pickup-org/mumble-client';
function printChannel(channel: Channel, level = 0) {
if (channel.name) {
console.log(' '.repeat(level * 2) + channel.name);
}
for (const subChannel of channel.subChannels) {
printChannel(subChannel, level + 1);
}
}
printChannel(client.channels.root);
找一个频道
// by name
const lobby = client.channels.byName('Lobby');
// by path (from root)
const redTeam = client.channels.byPath('Match 1', 'RED');
// by custom predicate
const tempChannels = client.channels.findAll(ch => ch.temporary);
创建和管理渠道
const root = client.channels.root;
// create a sub-channel under root
const matchChannel = await root.createSubChannel('Match 1');
// create team channels
const red = await matchChannel.createSubChannel('RED');
const blu = await matchChannel.createSubChannel('BLU');
// link two channels together
await red.link(blu);
// unlink them
await red.unlink(blu);
// remove a channel (and all its sub-channels)
await matchChannel.remove();
在不同渠道之间移动用户
const user = client.users.byName('PlayerOne');
const targetChannel = client.channels.byName('RED');
if (user && targetChannel) {
await user.moveToChannel(targetChannel.id);
}
使自己静音/耳聋
// self-mute
await client.self.setSelfMute(true);
// self-deafen
await client.self.setSelfDeaf(true);
// unmute
await client.self.setSelfMute(false);
注册和管理用户
// register the currently logged-in user
await client.self.register();
// fetch all registered users from the server
const registeredUsers = await client.fetchRegisteredUsers();
for (const user of registeredUsers) {
console.log(`${user.userId}: ${user.name}`);
}
// rename a registered user (does not need to be online)
await client.renameRegisteredUser(userId, 'NewName');
// deregister a user (does not need to be online)
await client.deregisterUser(userId);
短信、证书哈希和地址
client.on('textMessage', async ({ sender, message, isPrivate }) => {
if (sender && isPrivate) {
await sender.sendMessage(`you said: ${message}`);
}
});
// message everyone in a channel
await client.channels.byName('Lobby')?.sendMessage('hello');
// SHA1 hash of the user's certificate, sent for every user
console.log(user.hash);
// IP address; needs the Ban permission on the root channel
console.log(await user.fetchAddress());
检查通道权限
const channel = client.channels.byName('Lobby');
if (channel) {
const permissions = await channel.getPermissions();
console.log('Can join:', permissions.canJoinChannel);
console.log('Can create sub-channels:', permissions.canCreateChannel);
console.log('Can remove:', permissions.canRemoveChannel);
console.log('Can link:', permissions.canLinkChannel);
}
听事件
// user connected
client.on('userCreate', user => {
console.log(`${user.name} connected`);
});
// user disconnected
client.on('userRemove', user => {
console.log(`${user.name} disconnected`);
});
// user state changed (e.g. moved channel, muted, etc.)
client.on('userUpdate', (user, changes) => {
if (changes.channelId) {
const from = client.channels.byId(changes.channelId.previousValue);
const to = client.channels.byId(changes.channelId.currentValue);
console.log(`${user.name} moved from ${from?.name} to ${to?.name}`);
}
});
// channel created
client.on('channelCreate', channel => {
console.log(`Channel created: ${channel.name}`);
});
// channel removed
client.on('channelRemove', channel => {
console.log(`Channel removed: ${channel.name}`);
});
// speaking state changes
client.on('speakingStateChange', ({ user, speaking }) => {
console.log(`${user.name} ${speaking ? 'started' : 'stopped'} speaking`);
});
// disconnected from server
client.on('disconnect', payload => {
console.log(`Disconnected: ${payload?.reason ?? 'unknown reason'}`);
});
错误处理
import {
Client,
ClientDisconnectedError,
ConnectionRejectedError,
PermissionDeniedError,
} from '@tf2pickup-org/mumble-client';
try {
await client.connect();
} catch (error) {
if (error instanceof ConnectionRejectedError) {
console.error('Connection rejected by server');
} else if (error instanceof ClientDisconnectedError) {
// the server dropped the connection during the handshake,
// or another connect() call superseded this one
console.error('Connection lost');
}
}
// background errors, e.g. a failed keep-alive ping; without a listener
// Node.js throws on an 'error' event
client.on('error', error => {
console.error('Client error:', error);
});
try {
await client.channels.root.createSubChannel('test');
} catch (error) {
if (error instanceof PermissionDeniedError) {
console.error('Insufficient permissions to create channel');
}
}
API概述
Client
主要入口点。连接到服务器并提供对通道、用户和事件的访问。
| 属性/方法 | 描述 |
channels | ChannelManager 用于查找频道的实例 |
users | UserManager 查找用户的实例 |
self | 当前登录的 User |
session | 当前登录用户的会话ID |
welcomeText | 服务器欢迎信息 |
serverVersion | 服务器版本信息 |
serverConfig | 服务器配置 (最大用户数、消息长度…) |
socket | 底层套接字,for 音频; undefined 当断开连接 |
connect() | 连接到Mumble服务器; 如果已连接,请先断开连接 |
disconnect() | 断开与服务器的连接;不连接时什么都不做 |
isConnected() | 返回 true 如果已连接 |
fetchRegisteredUsers() | 获取所有注册用户 |
deregisterUser(userId) | 按ID取消注册用户 |
renameRegisteredUser(userId, name) | 重命名已注册用户 |
ChannelManager
| 方法 | 描述 |
root | 根通道 |
byId(channelId) | 按ID查找频道 |
byName(name) | 按名称查找频道 |
byPath(...path) | 按路径段查找通道 |
find(predicate) | 找到第一个匹配通道 |
findAll(predicate) | 找到所有匹配的频道 |
Channel
| 属性/方法 | 描述 |
id | 通道标识 |
name | 频道名称 |
temporary | 通道是否为临时通道 |
users | 当前在此通道中的用户 |
subChannels | 直接子信道 |
linkedChannels | 链接渠道 |
createSubChannel(name) | 创建子通道 |
remove() | 删除此通道 |
link(channel) | 与另一个频道连接 |
unlink(channel) | 从另一个通道取消链接 |
getPermissions() | 获取该通道的权限 |
fetchAcl() | 获取通道ACL |
saveAcl(acl) | 保存通道ACL |
UserManager
| 方法 | 描述 |
bySession(session) | 根据会话ID查找用户 |
byName(name) | 按名称查找用户 |
findAll(predicate) | 查找所有匹配的用户 |
User
| 属性/方法 | 描述 |
session | 会话ID |
name | 用户名 |
channel | 当前频道 |
channelId | 当前通道ID |
isRegistered | 用户是否已注册 |
mute / deaf / suppress | 服务器静音/聋哑/抑制状态 |
selfMute / selfDeaf | Self-mute /聋状态 |
moveToChannel(channelId) | 将用户移动到频道 |
setSelfMute(mute) | 设置自静音状态 |
setSelfDeaf(deaf) | 设置自聋状态 |
register() | 注册用户 |
deregister() | 注销用户 |
rename(name) | 重命名已注册用户 |
Permissions
| 属性/方法 | 描述 |
canJoinChannel | 可以加入/进入频道吗 |
canCreateChannel | 可以创建子通道 |
canRemoveChannel | 可以去除通道 |
canLinkChannel | 可以链接频道 |
canSelfRegister | 可以自行注册 |
canRegister | 可以注册其他用户 |
事件
| 事件 | 有效载荷 | 描述 |
connect | - - - - - - | 客户端连接成功 |
disconnect | { reason: string }? | 客户端已断开连接; 每个连接发出一次。 reason 是服务器的(例如,当踢)或 'connection closed' 当服务器断开连接时;之后没有有效载荷 disconnect() 或者重新连接 |
error | unknown | 后台错误,例如keepalive ping失败 |
channelCreate | Channel | 创建了一个频道 |
channelUpdate | Channel, ChannelChanges | 一个频道被更新 |
channelRemove | Channel | 一个通道已被删除 |
userCreate | User | 已连接的用户 |
userUpdate | User, UserChanges | 用户的状态已更改 |
userRemove | User | 用户已断开连接 |
speakingStateChange | { user: User, speaking: boolean } | 用户开始/停止说话 |
ClientOptions
扩展Node.js tls.ConnectionOptions.
| 选项 | 类型 | 默认的 | 描述 |
host | string | - - - - - - | 服务器主机名 |
port | number | 64738 | 服务器端口 |
username | string | - - - - - - | 用于身份验证的用户名 |
password | string? | - - - - - - | 服务器或用户密码 |
tokens | string[]? | [] | 服务器ACL组的访问令牌 |
clientName | string? | 'simple mumble bot' | 发送到服务器的客户端名称 |
pingInterval | number? | 10000 | 保持活动ping间隔 (毫秒) |
自 ClientOptions 扩展 tls.ConnectionOptions,您可以传递任何TLS选项,例如 rejectUnauthorized, cert, key, ca等。
许可证
麻省理工学院