@honeybbq/teamspeak 0.0.1 → 1.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +749 -2
- package/dist/client/abort.d.ts +5 -0
- package/dist/client/abort.d.ts.map +1 -0
- package/dist/client/abort.js +23 -0
- package/dist/client/abort.js.map +1 -0
- package/dist/client/address.d.ts +17 -0
- package/dist/client/address.d.ts.map +1 -0
- package/dist/client/address.js +66 -0
- package/dist/client/address.js.map +1 -0
- package/dist/client/api/avatars.d.ts +65 -0
- package/dist/client/api/avatars.d.ts.map +1 -0
- package/dist/client/api/avatars.js +118 -0
- package/dist/client/api/avatars.js.map +1 -0
- package/dist/client/api/voice.d.ts +59 -0
- package/dist/client/api/voice.d.ts.map +1 -0
- package/dist/client/api/voice.js +110 -0
- package/dist/client/api/voice.js.map +1 -0
- package/dist/client/capabilities.d.ts +68 -0
- package/dist/client/capabilities.d.ts.map +1 -0
- package/dist/client/capabilities.js +59 -0
- package/dist/client/capabilities.js.map +1 -0
- package/dist/client/client.d.ts +235 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +1666 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/commands.d.ts +66 -0
- package/dist/client/commands.d.ts.map +1 -0
- package/dist/client/commands.js +168 -0
- package/dist/client/commands.js.map +1 -0
- package/dist/client/connection-info.d.ts +14 -0
- package/dist/client/connection-info.d.ts.map +1 -0
- package/dist/client/connection-info.js +47 -0
- package/dist/client/connection-info.js.map +1 -0
- package/dist/client/crypto/crypt-ops.d.ts +7 -0
- package/dist/client/crypto/crypt-ops.d.ts.map +1 -0
- package/dist/client/crypto/crypt-ops.js +2 -0
- package/dist/client/crypto/crypt-ops.js.map +1 -0
- package/dist/client/crypto/crypt.d.ts +37 -0
- package/dist/client/crypto/crypt.d.ts.map +1 -0
- package/dist/client/crypto/crypt.js +203 -0
- package/dist/client/crypto/crypt.js.map +1 -0
- package/dist/client/crypto/eax.d.ts +12 -0
- package/dist/client/crypto/eax.d.ts.map +1 -0
- package/dist/client/crypto/eax.js +118 -0
- package/dist/client/crypto/eax.js.map +1 -0
- package/dist/client/crypto/identity.d.ts +97 -0
- package/dist/client/crypto/identity.d.ts.map +1 -0
- package/dist/client/crypto/identity.js +412 -0
- package/dist/client/crypto/identity.js.map +1 -0
- package/dist/client/crypto/index.d.ts +7 -0
- package/dist/client/crypto/index.d.ts.map +1 -0
- package/dist/client/crypto/index.js +5 -0
- package/dist/client/crypto/index.js.map +1 -0
- package/dist/client/crypto/primitives.d.ts +43 -0
- package/dist/client/crypto/primitives.d.ts.map +1 -0
- package/dist/client/crypto/primitives.js +116 -0
- package/dist/client/crypto/primitives.js.map +1 -0
- package/dist/client/diagnostics.d.ts +45 -0
- package/dist/client/diagnostics.d.ts.map +1 -0
- package/dist/client/diagnostics.js +30 -0
- package/dist/client/diagnostics.js.map +1 -0
- package/dist/client/discovery/index.d.ts +2 -0
- package/dist/client/discovery/index.d.ts.map +1 -0
- package/dist/client/discovery/index.js +2 -0
- package/dist/client/discovery/index.js.map +1 -0
- package/dist/client/discovery/resolver.d.ts +26 -0
- package/dist/client/discovery/resolver.d.ts.map +1 -0
- package/dist/client/discovery/resolver.js +275 -0
- package/dist/client/discovery/resolver.js.map +1 -0
- package/dist/client/errors.d.ts +82 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +201 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/events.d.ts +3 -0
- package/dist/client/events.d.ts.map +1 -0
- package/dist/client/events.js +8 -0
- package/dist/client/events.js.map +1 -0
- package/dist/client/handshake/crypt-handshake.d.ts +17 -0
- package/dist/client/handshake/crypt-handshake.d.ts.map +1 -0
- package/dist/client/handshake/crypt-handshake.js +128 -0
- package/dist/client/handshake/crypt-handshake.js.map +1 -0
- package/dist/client/handshake/crypt-init2.d.ts +7 -0
- package/dist/client/handshake/crypt-init2.d.ts.map +1 -0
- package/dist/client/handshake/crypt-init2.js +37 -0
- package/dist/client/handshake/crypt-init2.js.map +1 -0
- package/dist/client/handshake/index.d.ts +4 -0
- package/dist/client/handshake/index.d.ts.map +1 -0
- package/dist/client/handshake/index.js +4 -0
- package/dist/client/handshake/index.js.map +1 -0
- package/dist/client/handshake/license.d.ts +35 -0
- package/dist/client/handshake/license.d.ts.map +1 -0
- package/dist/client/handshake/license.js +169 -0
- package/dist/client/handshake/license.js.map +1 -0
- package/dist/client/handshake.d.ts +27 -0
- package/dist/client/handshake.d.ts.map +1 -0
- package/dist/client/handshake.js +126 -0
- package/dist/client/handshake.js.map +1 -0
- package/dist/client/helpers.d.ts +6 -0
- package/dist/client/helpers.d.ts.map +1 -0
- package/dist/client/helpers.js +13 -0
- package/dist/client/helpers.js.map +1 -0
- package/dist/client/hooks.d.ts +7 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/hooks.js +28 -0
- package/dist/client/hooks.js.map +1 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +29 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/reconnect.d.ts +12 -0
- package/dist/client/reconnect.d.ts.map +1 -0
- package/dist/client/reconnect.js +44 -0
- package/dist/client/reconnect.js.map +1 -0
- package/dist/client/throttle.d.ts +20 -0
- package/dist/client/throttle.d.ts.map +1 -0
- package/dist/client/throttle.js +83 -0
- package/dist/client/throttle.js.map +1 -0
- package/dist/client/trace.d.ts +223 -0
- package/dist/client/trace.d.ts.map +1 -0
- package/dist/client/trace.js +13 -0
- package/dist/client/trace.js.map +1 -0
- package/dist/client/transfer.d.ts +111 -0
- package/dist/client/transfer.d.ts.map +1 -0
- package/dist/client/transfer.js +243 -0
- package/dist/client/transfer.js.map +1 -0
- package/dist/client/transport/generation-window.d.ts +30 -0
- package/dist/client/transport/generation-window.d.ts.map +1 -0
- package/dist/client/transport/generation-window.js +97 -0
- package/dist/client/transport/generation-window.js.map +1 -0
- package/dist/client/transport/handler.d.ts +79 -0
- package/dist/client/transport/handler.d.ts.map +1 -0
- package/dist/client/transport/handler.js +868 -0
- package/dist/client/transport/handler.js.map +1 -0
- package/dist/client/transport/index.d.ts +6 -0
- package/dist/client/transport/index.d.ts.map +1 -0
- package/dist/client/transport/index.js +5 -0
- package/dist/client/transport/index.js.map +1 -0
- package/dist/client/transport/packet.d.ts +36 -0
- package/dist/client/transport/packet.d.ts.map +1 -0
- package/dist/client/transport/packet.js +55 -0
- package/dist/client/transport/packet.js.map +1 -0
- package/dist/client/transport/quicklz.d.ts +24 -0
- package/dist/client/transport/quicklz.d.ts.map +1 -0
- package/dist/client/transport/quicklz.js +179 -0
- package/dist/client/transport/quicklz.js.map +1 -0
- package/dist/client/transport/traffic.d.ts +43 -0
- package/dist/client/transport/traffic.d.ts.map +1 -0
- package/dist/client/transport/traffic.js +90 -0
- package/dist/client/transport/traffic.js.map +1 -0
- package/dist/client/types.d.ts +402 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +113 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/view.d.ts +162 -0
- package/dist/client/view.d.ts.map +1 -0
- package/dist/client/view.js +228 -0
- package/dist/client/view.js.map +1 -0
- package/dist/core/api/avatars.d.ts +26 -0
- package/dist/core/api/avatars.d.ts.map +1 -0
- package/dist/core/api/avatars.js +37 -0
- package/dist/core/api/avatars.js.map +1 -0
- package/dist/core/api/channels.d.ts +191 -0
- package/dist/core/api/channels.d.ts.map +1 -0
- package/dist/core/api/channels.js +174 -0
- package/dist/core/api/channels.js.map +1 -0
- package/dist/core/api/clients.d.ts +562 -0
- package/dist/core/api/clients.d.ts.map +1 -0
- package/dist/core/api/clients.js +435 -0
- package/dist/core/api/clients.js.map +1 -0
- package/dist/core/api/command.d.ts +400 -0
- package/dist/core/api/command.d.ts.map +1 -0
- package/dist/core/api/command.js +462 -0
- package/dist/core/api/command.js.map +1 -0
- package/dist/core/api/credentials.d.ts +186 -0
- package/dist/core/api/credentials.d.ts.map +1 -0
- package/dist/core/api/credentials.js +144 -0
- package/dist/core/api/credentials.js.map +1 -0
- package/dist/core/api/files.d.ts +153 -0
- package/dist/core/api/files.d.ts.map +1 -0
- package/dist/core/api/files.js +185 -0
- package/dist/core/api/files.js.map +1 -0
- package/dist/core/api/groups.d.ts +301 -0
- package/dist/core/api/groups.d.ts.map +1 -0
- package/dist/core/api/groups.js +339 -0
- package/dist/core/api/groups.js.map +1 -0
- package/dist/core/api/icons.d.ts +67 -0
- package/dist/core/api/icons.d.ts.map +1 -0
- package/dist/core/api/icons.js +125 -0
- package/dist/core/api/icons.js.map +1 -0
- package/dist/core/api/instance.d.ts +197 -0
- package/dist/core/api/instance.d.ts.map +1 -0
- package/dist/core/api/instance.js +160 -0
- package/dist/core/api/instance.js.map +1 -0
- package/dist/core/api/moderation.d.ts +266 -0
- package/dist/core/api/moderation.d.ts.map +1 -0
- package/dist/core/api/moderation.js +258 -0
- package/dist/core/api/moderation.js.map +1 -0
- package/dist/core/api/parse.d.ts +36 -0
- package/dist/core/api/parse.d.ts.map +1 -0
- package/dist/core/api/parse.js +109 -0
- package/dist/core/api/parse.js.map +1 -0
- package/dist/core/api/server.d.ts +334 -0
- package/dist/core/api/server.d.ts.map +1 -0
- package/dist/core/api/server.js +324 -0
- package/dist/core/api/server.js.map +1 -0
- package/dist/core/channel-tree.d.ts +87 -0
- package/dist/core/channel-tree.d.ts.map +1 -0
- package/dist/core/channel-tree.js +378 -0
- package/dist/core/channel-tree.js.map +1 -0
- package/dist/core/command/command.d.ts +20 -0
- package/dist/core/command/command.d.ts.map +1 -0
- package/dist/core/command/command.js +112 -0
- package/dist/core/command/command.js.map +1 -0
- package/dist/core/command/ids.d.ts +131 -0
- package/dist/core/command/ids.d.ts.map +1 -0
- package/dist/core/command/ids.js +87 -0
- package/dist/core/command/ids.js.map +1 -0
- package/dist/core/command/parser.d.ts +17 -0
- package/dist/core/command/parser.d.ts.map +1 -0
- package/dist/core/command/parser.js +65 -0
- package/dist/core/command/parser.js.map +1 -0
- package/dist/core/command/request.d.ts +61 -0
- package/dist/core/command/request.d.ts.map +1 -0
- package/dist/core/command/request.js +64 -0
- package/dist/core/command/request.js.map +1 -0
- package/dist/core/command/responses.d.ts +73 -0
- package/dist/core/command/responses.d.ts.map +1 -0
- package/dist/core/command/responses.js +97 -0
- package/dist/core/command/responses.js.map +1 -0
- package/dist/core/command-name.d.ts +349 -0
- package/dist/core/command-name.d.ts.map +1 -0
- package/dist/core/command-name.js +347 -0
- package/dist/core/command-name.js.map +1 -0
- package/dist/core/enums.d.ts +188 -0
- package/dist/core/enums.d.ts.map +1 -0
- package/dist/core/enums.js +172 -0
- package/dist/core/enums.js.map +1 -0
- package/dist/core/errorcode.d.ts +413 -0
- package/dist/core/errorcode.d.ts.map +1 -0
- package/dist/core/errorcode.js +410 -0
- package/dist/core/errorcode.js.map +1 -0
- package/dist/core/errors.d.ts +119 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +241 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/events.d.ts +404 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +6 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/helpers.d.ts +42 -0
- package/dist/core/helpers.d.ts.map +1 -0
- package/dist/core/helpers.js +156 -0
- package/dist/core/helpers.js.map +1 -0
- package/dist/core/index.d.ts +41 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/internal.d.ts +24 -0
- package/dist/core/internal.d.ts.map +1 -0
- package/dist/core/internal.js +21 -0
- package/dist/core/internal.js.map +1 -0
- package/dist/core/middleware.d.ts +14 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +18 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/notification-name.d.ts +160 -0
- package/dist/core/notification-name.d.ts.map +1 -0
- package/dist/core/notification-name.js +158 -0
- package/dist/core/notification-name.js.map +1 -0
- package/dist/core/notifications.d.ts +93 -0
- package/dist/core/notifications.d.ts.map +1 -0
- package/dist/core/notifications.js +301 -0
- package/dist/core/notifications.js.map +1 -0
- package/dist/core/permission-name.d.ts +1046 -0
- package/dist/core/permission-name.d.ts.map +1 -0
- package/dist/core/permission-name.js +1045 -0
- package/dist/core/permission-name.js.map +1 -0
- package/dist/core/permission.d.ts +31 -0
- package/dist/core/permission.d.ts.map +1 -0
- package/dist/core/permission.js +20 -0
- package/dist/core/permission.js.map +1 -0
- package/dist/core/property-name.d.ts +403 -0
- package/dist/core/property-name.d.ts.map +1 -0
- package/dist/core/property-name.js +405 -0
- package/dist/core/property-name.js.map +1 -0
- package/dist/core/reason.d.ts +39 -0
- package/dist/core/reason.d.ts.map +1 -0
- package/dist/core/reason.js +36 -0
- package/dist/core/reason.js.map +1 -0
- package/dist/core/reconnect.d.ts +59 -0
- package/dist/core/reconnect.d.ts.map +1 -0
- package/dist/core/reconnect.js +55 -0
- package/dist/core/reconnect.js.map +1 -0
- package/dist/core/types.d.ts +122 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +27 -0
- package/dist/core/types.js.map +1 -0
- package/dist/query/client.d.ts +244 -0
- package/dist/query/client.d.ts.map +1 -0
- package/dist/query/client.js +1122 -0
- package/dist/query/client.js.map +1 -0
- package/dist/query/errors.d.ts +61 -0
- package/dist/query/errors.d.ts.map +1 -0
- package/dist/query/errors.js +100 -0
- package/dist/query/errors.js.map +1 -0
- package/dist/query/index.d.ts +36 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +34 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/knownhosts.d.ts +61 -0
- package/dist/query/knownhosts.d.ts.map +1 -0
- package/dist/query/knownhosts.js +223 -0
- package/dist/query/knownhosts.js.map +1 -0
- package/dist/query/lines.d.ts +14 -0
- package/dist/query/lines.d.ts.map +1 -0
- package/dist/query/lines.js +29 -0
- package/dist/query/lines.js.map +1 -0
- package/dist/query/options.d.ts +206 -0
- package/dist/query/options.d.ts.map +1 -0
- package/dist/query/options.js +251 -0
- package/dist/query/options.js.map +1 -0
- package/dist/query/reconnect.d.ts +29 -0
- package/dist/query/reconnect.d.ts.map +1 -0
- package/dist/query/reconnect.js +87 -0
- package/dist/query/reconnect.js.map +1 -0
- package/dist/query/ssh.d.ts +385 -0
- package/dist/query/ssh.d.ts.map +1 -0
- package/dist/query/ssh.js +257 -0
- package/dist/query/ssh.js.map +1 -0
- package/dist/query/stream.d.ts +38 -0
- package/dist/query/stream.d.ts.map +1 -0
- package/dist/query/stream.js +70 -0
- package/dist/query/stream.js.map +1 -0
- package/dist/query/tcp.d.ts +38 -0
- package/dist/query/tcp.d.ts.map +1 -0
- package/dist/query/tcp.js +53 -0
- package/dist/query/tcp.js.map +1 -0
- package/dist/query/transport.d.ts +36 -0
- package/dist/query/transport.d.ts.map +1 -0
- package/dist/query/transport.js +2 -0
- package/dist/query/transport.js.map +1 -0
- package/dist/query/web.d.ts +78 -0
- package/dist/query/web.d.ts.map +1 -0
- package/dist/query/web.js +157 -0
- package/dist/query/web.js.map +1 -0
- package/dist/versions/index.d.ts +3094 -0
- package/dist/versions/index.d.ts.map +1 -0
- package/dist/versions/index.js +9237 -0
- package/dist/versions/index.js.map +1 -0
- package/package.json +119 -4
- package/src/client/abort.ts +24 -0
- package/src/client/address.ts +74 -0
- package/src/client/api/avatars.ts +164 -0
- package/src/client/api/voice.ts +177 -0
- package/src/client/capabilities.ts +106 -0
- package/src/client/client.ts +1976 -0
- package/src/client/commands.ts +201 -0
- package/src/client/connection-info.ts +52 -0
- package/src/client/crypto/crypt-ops.ts +6 -0
- package/src/client/crypto/crypt.ts +275 -0
- package/src/client/crypto/eax.ts +152 -0
- package/src/client/crypto/identity.ts +484 -0
- package/src/client/crypto/index.ts +21 -0
- package/src/client/crypto/primitives.ts +141 -0
- package/src/client/diagnostics.ts +58 -0
- package/src/client/discovery/index.ts +1 -0
- package/src/client/discovery/resolver.ts +325 -0
- package/src/client/errors.ts +217 -0
- package/src/client/events.ts +12 -0
- package/src/client/handshake/crypt-handshake.ts +157 -0
- package/src/client/handshake/crypt-init2.ts +48 -0
- package/src/client/handshake/index.ts +3 -0
- package/src/client/handshake/license.ts +208 -0
- package/src/client/handshake.ts +150 -0
- package/src/client/helpers.ts +10 -0
- package/src/client/hooks.ts +30 -0
- package/src/client/index.ts +97 -0
- package/src/client/reconnect.ts +43 -0
- package/src/client/throttle.ts +92 -0
- package/src/client/trace.ts +237 -0
- package/src/client/transfer.ts +436 -0
- package/src/client/transport/generation-window.ts +108 -0
- package/src/client/transport/handler.ts +1021 -0
- package/src/client/transport/index.ts +14 -0
- package/src/client/transport/packet.ts +69 -0
- package/src/client/transport/quicklz.ts +209 -0
- package/src/client/transport/traffic.ts +116 -0
- package/src/client/types.ts +478 -0
- package/src/client/view.ts +372 -0
- package/src/core/api/avatars.ts +40 -0
- package/src/core/api/channels.ts +420 -0
- package/src/core/api/clients.ts +1098 -0
- package/src/core/api/command.ts +737 -0
- package/src/core/api/credentials.ts +335 -0
- package/src/core/api/files.ts +411 -0
- package/src/core/api/groups.ts +730 -0
- package/src/core/api/icons.ts +175 -0
- package/src/core/api/instance.ts +369 -0
- package/src/core/api/moderation.ts +632 -0
- package/src/core/api/parse.ts +139 -0
- package/src/core/api/server.ts +769 -0
- package/src/core/channel-tree.ts +398 -0
- package/src/core/command/command.ts +125 -0
- package/src/core/command/ids.ts +153 -0
- package/src/core/command/parser.ts +68 -0
- package/src/core/command/request.ts +119 -0
- package/src/core/command/responses.ts +152 -0
- package/src/core/command-name.ts +350 -0
- package/src/core/enums.ts +215 -0
- package/src/core/errorcode.ts +412 -0
- package/src/core/errors.ts +266 -0
- package/src/core/events.ts +431 -0
- package/src/core/helpers.ts +161 -0
- package/src/core/index.ts +153 -0
- package/src/core/internal.ts +24 -0
- package/src/core/middleware.ts +24 -0
- package/src/core/notification-name.ts +161 -0
- package/src/core/notifications.ts +404 -0
- package/src/core/permission-name.ts +1162 -0
- package/src/core/permission.ts +34 -0
- package/src/core/property-name.ts +411 -0
- package/src/core/reason.ts +38 -0
- package/src/core/reconnect.ts +98 -0
- package/src/core/types.ts +150 -0
- package/src/query/client.ts +1303 -0
- package/src/query/errors.ts +108 -0
- package/src/query/index.ts +66 -0
- package/src/query/knownhosts.ts +257 -0
- package/src/query/lines.ts +28 -0
- package/src/query/options.ts +452 -0
- package/src/query/reconnect.ts +84 -0
- package/src/query/ssh.ts +674 -0
- package/src/query/stream.ts +91 -0
- package/src/query/tcp.ts +85 -0
- package/src/query/transport.ts +35 -0
- package/src/query/web.ts +234 -0
- package/src/versions/index.ts +10774 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icons: the file name and id of an icon, and the commands that point a
|
|
3
|
+
* channel, group, client or server at one.
|
|
4
|
+
*
|
|
5
|
+
* An icon is a file in channel 0's file area, uploaded as `/icon_<id>` and
|
|
6
|
+
* kept in its `icons` directory; `uploadIcon` in the client entry point sends
|
|
7
|
+
* it. Nothing references it until an id is set, and the id is not a property
|
|
8
|
+
* of `channeledit` or `channelcreate`: both servers answer 1538 to
|
|
9
|
+
* `channel_icon_id`, with the file present or not. A channel, a group or a
|
|
10
|
+
* client takes its icon from the `i_icon_id` permission, and the server from
|
|
11
|
+
* `virtualserver_icon_id`; the setters here send those.
|
|
12
|
+
*
|
|
13
|
+
* The server never checks that an id names an uploaded file: setting an id
|
|
14
|
+
* with no file is accepted, and the icon is then missing.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { exec } from "./command.js";
|
|
18
|
+
import { addChannelPermission, deleteChannelPermission } from "./channels.js";
|
|
19
|
+
import { addChannelGroupPermission, deleteChannelGroupPermission } from "./groups.js";
|
|
20
|
+
import { addClientPermission, deleteClientPermission } from "./clients.js";
|
|
21
|
+
import { addServerGroupPermission, deleteServerGroupPermission, editServer } from "./server.js";
|
|
22
|
+
import { asIconID } from "../command/ids.js";
|
|
23
|
+
import type {
|
|
24
|
+
ChannelGroupID,
|
|
25
|
+
ChannelID,
|
|
26
|
+
ClientDBID,
|
|
27
|
+
IconID,
|
|
28
|
+
ServerGroupID,
|
|
29
|
+
} from "../command/ids.js";
|
|
30
|
+
import type { CommandExecutor, CommandOptions } from "../command/request.js";
|
|
31
|
+
import { permissionByName } from "../permission.js";
|
|
32
|
+
|
|
33
|
+
/** The table of the standard CRC-32: polynomial 0xEDB88320, reflected. */
|
|
34
|
+
const CRC_TABLE: Uint32Array = (() => {
|
|
35
|
+
const table = new Uint32Array(256);
|
|
36
|
+
for (let n = 0; n < 256; n++) {
|
|
37
|
+
let c = n;
|
|
38
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
39
|
+
table[n] = c >>> 0;
|
|
40
|
+
}
|
|
41
|
+
return table;
|
|
42
|
+
})();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The id an icon is known by: the CRC-32 of its bytes, the standard one (zlib's
|
|
46
|
+
* `crc32`: polynomial 0xEDB88320, initial value and final XOR 0xFFFFFFFF), as
|
|
47
|
+
* an unsigned number.
|
|
48
|
+
*
|
|
49
|
+
* The SDK names an icon this way so that the same image always gets the same
|
|
50
|
+
* id, and uploading it twice reuses one file. The server accepts any number as
|
|
51
|
+
* the id in `/icon_<id>` and does not check it against the bytes. The id set
|
|
52
|
+
* on a channel, group, client or server (`i_icon_id`,
|
|
53
|
+
* `virtualserver_icon_id`) is stored exactly as given and names the file
|
|
54
|
+
* `/icon_<id>`, so an icon uploaded under another scheme works as long as the
|
|
55
|
+
* id set matches its file name. Whether other clients use this CRC-32 as well
|
|
56
|
+
* is not something the SDK can promise.
|
|
57
|
+
*/
|
|
58
|
+
export function iconIDOf(data: Uint8Array): IconID {
|
|
59
|
+
let crc = 0xffffffff;
|
|
60
|
+
for (const byte of data) crc = CRC_TABLE[(crc ^ byte) & 0xff]! ^ (crc >>> 8);
|
|
61
|
+
return asIconID((crc ^ 0xffffffff) >>> 0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The name an icon is uploaded and downloaded under in channel 0, with a
|
|
66
|
+
* leading slash: `/icon_<id>`. Listing channel 0's `/icons` directory shows it
|
|
67
|
+
* as `icon_<id>`.
|
|
68
|
+
*/
|
|
69
|
+
export function iconFileName(id: IconID): string {
|
|
70
|
+
return `/icon_${String(id)}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Delete an icon's file (`ftdeletefile cid=0 name=/icon_<id>`). Needs
|
|
75
|
+
* `b_icon_manage`. A channel, group or client that still names the icon keeps
|
|
76
|
+
* naming it.
|
|
77
|
+
*/
|
|
78
|
+
export async function removeIcon(
|
|
79
|
+
client: CommandExecutor,
|
|
80
|
+
id: IconID,
|
|
81
|
+
options?: CommandOptions,
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
await exec(
|
|
84
|
+
client,
|
|
85
|
+
"ftdeletefile",
|
|
86
|
+
[
|
|
87
|
+
["cid", 0],
|
|
88
|
+
["cpw", ""],
|
|
89
|
+
["name", iconFileName(id)],
|
|
90
|
+
],
|
|
91
|
+
options,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The permission value for an icon: the id as the signed 32-bit number the server stores. */
|
|
96
|
+
const permissionValue = (id: IconID): number => id | 0;
|
|
97
|
+
|
|
98
|
+
const iconPermission = permissionByName("i_icon_id");
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Give a channel an icon, or take it away with `undefined`
|
|
102
|
+
* (`channeladdperm` / `channeldelperm` with `i_icon_id`). Measured on
|
|
103
|
+
* TeamSpeak 3 and 6: `channeledit` cannot do this, and the new id shows in
|
|
104
|
+
* `channelinfo` and `channellist -icon` as `iconID`.
|
|
105
|
+
*/
|
|
106
|
+
export async function setChannelIcon(
|
|
107
|
+
client: CommandExecutor,
|
|
108
|
+
cid: ChannelID,
|
|
109
|
+
icon: IconID | undefined,
|
|
110
|
+
options?: CommandOptions,
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
if (icon === undefined) {
|
|
113
|
+
await deleteChannelPermission(client, cid, iconPermission, options);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
await addChannelPermission(client, cid, iconPermission, permissionValue(icon), options);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Give a server group an icon, or take it away with `undefined` (`i_icon_id`). */
|
|
120
|
+
export async function setServerGroupIcon(
|
|
121
|
+
client: CommandExecutor,
|
|
122
|
+
sgid: ServerGroupID,
|
|
123
|
+
icon: IconID | undefined,
|
|
124
|
+
options?: CommandOptions,
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
if (icon === undefined) {
|
|
127
|
+
await deleteServerGroupPermission(client, sgid, iconPermission, options);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
await addServerGroupPermission(client, sgid, iconPermission, permissionValue(icon), options);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Give a channel group an icon, or take it away with `undefined` (`i_icon_id`). */
|
|
134
|
+
export async function setChannelGroupIcon(
|
|
135
|
+
client: CommandExecutor,
|
|
136
|
+
cgid: ChannelGroupID,
|
|
137
|
+
icon: IconID | undefined,
|
|
138
|
+
options?: CommandOptions,
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
if (icon === undefined) {
|
|
141
|
+
await deleteChannelGroupPermission(client, cgid, iconPermission, options);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
await addChannelGroupPermission(client, cgid, iconPermission, permissionValue(icon), options);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Give a client an icon, or take it away with `undefined` (`i_icon_id` on the
|
|
149
|
+
* client's database record). `clientedit` has a `client_icon_id` in its
|
|
150
|
+
* documentation, but both servers answer it with 1538.
|
|
151
|
+
*/
|
|
152
|
+
export async function setClientIcon(
|
|
153
|
+
client: CommandExecutor,
|
|
154
|
+
cldbid: ClientDBID,
|
|
155
|
+
icon: IconID | undefined,
|
|
156
|
+
options?: CommandOptions,
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
if (icon === undefined) {
|
|
159
|
+
await deleteClientPermission(client, cldbid, iconPermission, options);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await addClientPermission(client, cldbid, iconPermission, permissionValue(icon), options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Give the virtual server an icon, or take it away with `undefined`
|
|
167
|
+
* (`serveredit virtualserver_icon_id`). Needs `b_virtualserver_modify_icon_id`.
|
|
168
|
+
*/
|
|
169
|
+
export async function setServerIcon(
|
|
170
|
+
client: CommandExecutor,
|
|
171
|
+
icon: IconID | undefined,
|
|
172
|
+
options?: CommandOptions,
|
|
173
|
+
): Promise<void> {
|
|
174
|
+
await editServer(client, { virtualserver_icon_id: String(icon ?? 0) }, options);
|
|
175
|
+
}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual servers, snapshots and the instance process.
|
|
3
|
+
*
|
|
4
|
+
* These address the instance rather than one virtual server, so they need the
|
|
5
|
+
* `b_serverinstance_*` and `b_virtualserver_*` permissions of an instance
|
|
6
|
+
* administrator, which not even a virtual server's Server Admin holds: over the
|
|
7
|
+
* voice protocol they answer error 2568. They are for a ServerQuery connection
|
|
8
|
+
* logged in as the instance's administrator; for most of them, one with no
|
|
9
|
+
* virtual server selected. Both TS3 and TS6 limit an unlicensed instance to one
|
|
10
|
+
* running virtual server, and refuse another with error 2816 (virtualserver
|
|
11
|
+
* limit reached).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
firstRow,
|
|
16
|
+
exec,
|
|
17
|
+
query,
|
|
18
|
+
list,
|
|
19
|
+
encodeFields,
|
|
20
|
+
rawProperties,
|
|
21
|
+
nonEmpty,
|
|
22
|
+
str,
|
|
23
|
+
big,
|
|
24
|
+
num,
|
|
25
|
+
bool,
|
|
26
|
+
durationMs,
|
|
27
|
+
SECOND,
|
|
28
|
+
} from "./command.js";
|
|
29
|
+
import type { WireNames } from "./command.js";
|
|
30
|
+
import type { CommandExecutor, CommandOptions } from "../command/request.js";
|
|
31
|
+
import type { ChannelID, ServerID } from "../command/ids.js";
|
|
32
|
+
import { asChannelID, asServerID } from "../command/ids.js";
|
|
33
|
+
|
|
34
|
+
// ---- Virtual servers --------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/** A virtual server, as `serverlist` reports it. */
|
|
37
|
+
export interface VirtualServer {
|
|
38
|
+
/** The server's id (`virtualserver_id`). */
|
|
39
|
+
readonly id: ServerID;
|
|
40
|
+
/** The voice port it listens on (`virtualserver_port`). */
|
|
41
|
+
readonly port: number;
|
|
42
|
+
/**
|
|
43
|
+
* Its state, as the server words it: "online", "offline", "booting up",
|
|
44
|
+
* "shutting down", "online virtual" (`virtualserver_status`).
|
|
45
|
+
*/
|
|
46
|
+
readonly status: string;
|
|
47
|
+
/** Its name (`virtualserver_name`); "" with `short`. */
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/** Voice clients connected (`virtualserver_clientsonline`); undefined with `short`, and for a server that is not running. */
|
|
50
|
+
readonly clientsOnline: number | undefined;
|
|
51
|
+
/** ServerQuery clients connected (`virtualserver_queryclientsonline`); undefined as `clientsOnline`. */
|
|
52
|
+
readonly queryClientsOnline: number | undefined;
|
|
53
|
+
/** How many clients it accepts (`virtualserver_maxclients`); undefined as `clientsOnline`. */
|
|
54
|
+
readonly maxClients: number | undefined;
|
|
55
|
+
/** How long it has been running, in milliseconds (`virtualserver_uptime`, sent in seconds); undefined as `clientsOnline`. */
|
|
56
|
+
readonly uptimeMs: number | undefined;
|
|
57
|
+
/** Whether it starts with the instance (`virtualserver_autostart`); undefined with `short`. */
|
|
58
|
+
readonly autoStart: boolean | undefined;
|
|
59
|
+
/** The machine id of the instance that runs it, "" for none (`virtualserver_machine_id`); undefined with `short`. */
|
|
60
|
+
readonly machineID: string | undefined;
|
|
61
|
+
/** Its unique identifier, with `uid`; "" otherwise (`virtualserver_unique_identifier`). */
|
|
62
|
+
readonly uid: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const optional = <T>(row: Record<string, string>, key: string, read: () => T): T | undefined =>
|
|
66
|
+
row[key] === undefined ? undefined : read();
|
|
67
|
+
|
|
68
|
+
const parseVirtualServer = (row: Record<string, string>): VirtualServer => ({
|
|
69
|
+
id: asServerID(big(row, "virtualserver_id")),
|
|
70
|
+
port: num(row, "virtualserver_port"),
|
|
71
|
+
status: str(row, "virtualserver_status"),
|
|
72
|
+
name: str(row, "virtualserver_name"),
|
|
73
|
+
clientsOnline: optional(row, "virtualserver_clientsonline", () =>
|
|
74
|
+
num(row, "virtualserver_clientsonline"),
|
|
75
|
+
),
|
|
76
|
+
queryClientsOnline: optional(row, "virtualserver_queryclientsonline", () =>
|
|
77
|
+
num(row, "virtualserver_queryclientsonline"),
|
|
78
|
+
),
|
|
79
|
+
maxClients: optional(row, "virtualserver_maxclients", () => num(row, "virtualserver_maxclients")),
|
|
80
|
+
uptimeMs: optional(row, "virtualserver_uptime", () =>
|
|
81
|
+
durationMs(row, "virtualserver_uptime", SECOND),
|
|
82
|
+
),
|
|
83
|
+
autoStart: optional(row, "virtualserver_autostart", () => bool(row, "virtualserver_autostart")),
|
|
84
|
+
machineID: row["virtualserver_machine_id"],
|
|
85
|
+
uid: str(row, "virtualserver_unique_identifier"),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/** Which servers {@link listServers} reports, and with what. */
|
|
89
|
+
export interface ServerListOptions extends CommandOptions {
|
|
90
|
+
/** Include each server's unique identifier (`-uid`). */
|
|
91
|
+
readonly uid?: boolean | undefined;
|
|
92
|
+
/** Leave out everything but the id, port and status (`-short`). */
|
|
93
|
+
readonly short?: boolean | undefined;
|
|
94
|
+
/** List every server in the database, whichever instance's machine id they carry (`-all`). */
|
|
95
|
+
readonly all?: boolean | undefined;
|
|
96
|
+
/** Only the servers that are offline (`-onlyoffline`). */
|
|
97
|
+
readonly onlyOffline?: boolean | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const serverListFlags: WireNames<ServerListOptions> = {
|
|
101
|
+
uid: "-uid",
|
|
102
|
+
short: "-short",
|
|
103
|
+
all: "-all",
|
|
104
|
+
onlyOffline: "-onlyoffline",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The instance's virtual servers. None is an empty list.
|
|
109
|
+
*
|
|
110
|
+
* Needs `b_serverinstance_virtualserver_list`, which a voice client's Server
|
|
111
|
+
* Admin lacks (error 2568). TS6 also reports `guest_can_create_channels`,
|
|
112
|
+
* `guest_can_create_homebase` and `virtualserver_weblist_enabled`, which are
|
|
113
|
+
* not read here.
|
|
114
|
+
*/
|
|
115
|
+
export async function listServers(
|
|
116
|
+
client: CommandExecutor,
|
|
117
|
+
options: ServerListOptions = {},
|
|
118
|
+
): Promise<VirtualServer[]> {
|
|
119
|
+
const rows = await list(client, "serverlist", encodeFields(options, serverListFlags), options);
|
|
120
|
+
return rows.map(parseVirtualServer);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** A server as {@link createServer} made it: its id and port, and the administrator's privilege key. */
|
|
124
|
+
export interface ServerCreated {
|
|
125
|
+
/** The new server's id (`sid`). */
|
|
126
|
+
readonly id: ServerID;
|
|
127
|
+
/** The voice port it was given (`virtualserver_port`). */
|
|
128
|
+
readonly port: number;
|
|
129
|
+
/**
|
|
130
|
+
* The privilege key that makes its holder the server's administrator
|
|
131
|
+
* (`token`). A secret the server shows only this once: store it, and do not
|
|
132
|
+
* log it.
|
|
133
|
+
*/
|
|
134
|
+
readonly token: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Create a virtual server and start it.
|
|
139
|
+
*
|
|
140
|
+
* `settings` are raw `virtualserver_*` properties, passed through as given for
|
|
141
|
+
* the reasons {@link editServer} gives; `virtualserver_port` picks the port,
|
|
142
|
+
* and the server takes the first free one from 9987 up when it is unset. Needs
|
|
143
|
+
* `b_virtualserver_create`. An instance without a license that already runs a
|
|
144
|
+
* server refuses with error 2816. The result's `token` is a secret shown only
|
|
145
|
+
* once: store it, and do not log it.
|
|
146
|
+
*/
|
|
147
|
+
export async function createServer(
|
|
148
|
+
client: CommandExecutor,
|
|
149
|
+
name: string,
|
|
150
|
+
settings: Readonly<Record<string, string>> = {},
|
|
151
|
+
options?: CommandOptions,
|
|
152
|
+
): Promise<ServerCreated> {
|
|
153
|
+
const rows = await query(
|
|
154
|
+
client,
|
|
155
|
+
"servercreate",
|
|
156
|
+
[["virtualserver_name", name], ...rawProperties(settings)],
|
|
157
|
+
options,
|
|
158
|
+
);
|
|
159
|
+
const row = firstRow(rows, "servercreate", "sid");
|
|
160
|
+
return {
|
|
161
|
+
id: asServerID(big(row, "sid")),
|
|
162
|
+
port: num(row, "virtualserver_port"),
|
|
163
|
+
token: str(row, "token"),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Start a virtual server. Needs `b_virtualserver_start_any`, or
|
|
169
|
+
* `b_virtualserver_start` for the server the connection is on.
|
|
170
|
+
*
|
|
171
|
+
* Starting a server that cannot start answers error 2816 when the license
|
|
172
|
+
* limit is reached.
|
|
173
|
+
*/
|
|
174
|
+
export async function startServer(
|
|
175
|
+
client: CommandExecutor,
|
|
176
|
+
sid: ServerID,
|
|
177
|
+
options?: CommandOptions,
|
|
178
|
+
): Promise<void> {
|
|
179
|
+
await exec(client, "serverstart", [["sid", sid]], options);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** What {@link stopServer} tells the clients. */
|
|
183
|
+
export interface ServerStopOptions extends CommandOptions {
|
|
184
|
+
/** A message sent to the clients before they are disconnected (`reasonmsg`); unset or "" sends none. */
|
|
185
|
+
readonly reason?: string | undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const stopNames: WireNames<ServerStopOptions> = { reason: ["reasonmsg", nonEmpty] };
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Stop a virtual server, disconnecting its clients. Needs
|
|
192
|
+
* `b_virtualserver_stop_any`, or `b_virtualserver_stop` for the server the
|
|
193
|
+
* connection is on. A server that is not running is refused with error 1033.
|
|
194
|
+
*/
|
|
195
|
+
export async function stopServer(
|
|
196
|
+
client: CommandExecutor,
|
|
197
|
+
sid: ServerID,
|
|
198
|
+
options: ServerStopOptions = {},
|
|
199
|
+
): Promise<void> {
|
|
200
|
+
await exec(client, "serverstop", [["sid", sid], ...encodeFields(options, stopNames)], options);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** How {@link deleteServer} reports the deletion. */
|
|
204
|
+
export interface ServerDeleteOptions extends CommandOptions {
|
|
205
|
+
/** Do not send the `virtualserver destroyed` event to other query clients (`-noevent`). */
|
|
206
|
+
readonly noEvent?: boolean | undefined;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const deleteFlags: WireNames<ServerDeleteOptions> = { noEvent: "-noevent" };
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Delete a virtual server for good: its channels, groups and client records
|
|
213
|
+
* go with it. Needs `b_virtualserver_delete`.
|
|
214
|
+
*
|
|
215
|
+
* The server must be stopped first, and one a query client has selected is
|
|
216
|
+
* refused with error 1035 even then. An id no server has is refused with 1024. `noEvent` is accepted by TS3 and TS6.
|
|
217
|
+
*/
|
|
218
|
+
export async function deleteServer(
|
|
219
|
+
client: CommandExecutor,
|
|
220
|
+
sid: ServerID,
|
|
221
|
+
options: ServerDeleteOptions = {},
|
|
222
|
+
): Promise<void> {
|
|
223
|
+
await exec(
|
|
224
|
+
client,
|
|
225
|
+
"serverdelete",
|
|
226
|
+
[["sid", sid], ...encodeFields(options, deleteFlags)],
|
|
227
|
+
options,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Stop the whole instance: the process exits, every virtual server with it,
|
|
233
|
+
* and nothing here can start it again. Needs `b_serverinstance_stop`.
|
|
234
|
+
*
|
|
235
|
+
* The answer comes before the process ends, and the connection drops after it.
|
|
236
|
+
*/
|
|
237
|
+
export async function stopInstance(
|
|
238
|
+
client: CommandExecutor,
|
|
239
|
+
options: ServerStopOptions = {},
|
|
240
|
+
): Promise<void> {
|
|
241
|
+
await exec(client, "serverprocessstop", encodeFields(options, stopNames), options);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Send a text message to every client on every virtual server of the
|
|
246
|
+
* instance. Needs `b_serverinstance_textmessage_send`.
|
|
247
|
+
*/
|
|
248
|
+
export async function sendGlobalMessage(
|
|
249
|
+
client: CommandExecutor,
|
|
250
|
+
message: string,
|
|
251
|
+
options?: CommandOptions,
|
|
252
|
+
): Promise<void> {
|
|
253
|
+
await exec(client, "gm", [["msg", message]], options);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ---- Snapshots --------------------------------------------------------------
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* A snapshot of a virtual server, as `serversnapshotcreate` returns it and
|
|
260
|
+
* `serversnapshotdeploy` takes it back.
|
|
261
|
+
*
|
|
262
|
+
* It holds the server's settings, groups, permissions, channels and the
|
|
263
|
+
* identities of every client it knows, so it is as sensitive as the server's
|
|
264
|
+
* database: store it as such, and do not log it. Without a `password` it is
|
|
265
|
+
* only compressed and encoded; with one it is encrypted.
|
|
266
|
+
*/
|
|
267
|
+
export interface ServerSnapshot {
|
|
268
|
+
/** The snapshot format's version (`version`); 3 on TS3 3.13 and TS6. */
|
|
269
|
+
readonly version: number;
|
|
270
|
+
/** The salt of the password the snapshot is encrypted with (`salt`); "" when it is not. */
|
|
271
|
+
readonly salt: string;
|
|
272
|
+
/** The snapshot itself (`data`), a base64 string, often several kilobytes. */
|
|
273
|
+
readonly data: string;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** How {@link createServerSnapshot} protects the snapshot. */
|
|
277
|
+
export interface ServerSnapshotOptions extends CommandOptions {
|
|
278
|
+
/** Encrypt the snapshot with this password; unset or "" leaves it unencrypted (`password`). */
|
|
279
|
+
readonly password?: string | undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const snapshotNames: WireNames<ServerSnapshotOptions> = { password: ["password", nonEmpty] };
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Take a snapshot of the selected virtual server.
|
|
286
|
+
*
|
|
287
|
+
* Needs `b_virtualserver_snapshot_create`, which a voice client's Server Admin
|
|
288
|
+
* lacks (error 2568). The same answer, `version`, `data` and with a password
|
|
289
|
+
* `salt`, comes over raw TCP, SSH and WebQuery on TS3 and TS6.
|
|
290
|
+
*/
|
|
291
|
+
export async function createServerSnapshot(
|
|
292
|
+
client: CommandExecutor,
|
|
293
|
+
options: ServerSnapshotOptions = {},
|
|
294
|
+
): Promise<ServerSnapshot> {
|
|
295
|
+
const rows = await query(
|
|
296
|
+
client,
|
|
297
|
+
"serversnapshotcreate",
|
|
298
|
+
encodeFields(options, snapshotNames),
|
|
299
|
+
options,
|
|
300
|
+
);
|
|
301
|
+
const row = firstRow(rows, "serversnapshotcreate", "data");
|
|
302
|
+
return { version: num(row, "version"), salt: str(row, "salt"), data: str(row, "data") };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** How {@link deployServerSnapshot} restores. */
|
|
306
|
+
export interface ServerSnapshotDeployOptions extends CommandOptions {
|
|
307
|
+
/** The password the snapshot was encrypted with; unset or "" for an unencrypted one (`password`). */
|
|
308
|
+
readonly password?: string | undefined;
|
|
309
|
+
/** Keep the files of the channels that exist both on the server and in the snapshot (`-keepfiles`). */
|
|
310
|
+
readonly keepFiles?: boolean | undefined;
|
|
311
|
+
/** Report which new channel each of the snapshot's channels became (`-mapping`). */
|
|
312
|
+
readonly mapping?: boolean | undefined;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const deployNames: WireNames<ServerSnapshotDeployOptions> = {
|
|
316
|
+
password: ["password", nonEmpty],
|
|
317
|
+
keepFiles: "-keepfiles",
|
|
318
|
+
mapping: "-mapping",
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/** Which channel of a snapshot became which channel on the server, as `-mapping` reports it. */
|
|
322
|
+
export interface ChannelMapping {
|
|
323
|
+
/** The channel's id in the snapshot (`ocid`). */
|
|
324
|
+
readonly oldID: ChannelID;
|
|
325
|
+
/** Its id on the server now (`ncid`). */
|
|
326
|
+
readonly newID: ChannelID;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Restore a virtual server from a snapshot.
|
|
331
|
+
*
|
|
332
|
+
* With a server selected, the snapshot replaces that server's settings,
|
|
333
|
+
* groups, channels and client records; the channels get new ids, which
|
|
334
|
+
* `mapping` reports as one entry per channel (the result is `[]` without it).
|
|
335
|
+
* With none selected, the server makes a new virtual server from it, which an
|
|
336
|
+
* unlicensed instance that is already running one refuses with error 2816. The
|
|
337
|
+
* server does not check permissions while deploying, so the right to do it is
|
|
338
|
+
* the right to give oneself any permission: needs
|
|
339
|
+
* `b_virtualserver_snapshot_deploy`, which a voice client's Server Admin lacks
|
|
340
|
+
* (error 2568).
|
|
341
|
+
*
|
|
342
|
+
* Over raw TCP and SSH the virtual server restarts, which ends the
|
|
343
|
+
* connection's selection of it: the next command is refused with error 1024
|
|
344
|
+
* until the connection selects it again with `use`. An encrypted snapshot
|
|
345
|
+
* with the wrong password is refused with error 1538; an unencrypted one
|
|
346
|
+
* ignores the password.
|
|
347
|
+
*/
|
|
348
|
+
export async function deployServerSnapshot(
|
|
349
|
+
client: CommandExecutor,
|
|
350
|
+
snapshot: ServerSnapshot,
|
|
351
|
+
options: ServerSnapshotDeployOptions = {},
|
|
352
|
+
): Promise<ChannelMapping[]> {
|
|
353
|
+
const rows = await query(
|
|
354
|
+
client,
|
|
355
|
+
"serversnapshotdeploy",
|
|
356
|
+
[
|
|
357
|
+
...encodeFields(options, deployNames),
|
|
358
|
+
["version", snapshot.version],
|
|
359
|
+
["salt", nonEmpty(snapshot.salt ?? "")],
|
|
360
|
+
["data", snapshot.data],
|
|
361
|
+
],
|
|
362
|
+
options,
|
|
363
|
+
);
|
|
364
|
+
return rows.flatMap((row) =>
|
|
365
|
+
row["ocid"] === undefined
|
|
366
|
+
? []
|
|
367
|
+
: [{ oldID: asChannelID(big(row, "ocid")), newID: asChannelID(big(row, "ncid")) }],
|
|
368
|
+
);
|
|
369
|
+
}
|