-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathts5-remote-apps-wrapper.min.js
138 lines (122 loc) · 19.1 KB
/
ts5-remote-apps-wrapper.min.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["TSRemoteAppWrapper"] = factory();
else
root["TSRemoteAppWrapper"] = factory();
})(self, () => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/TSApiWrapper.js":
/*!*****************************!*\
!*** ./src/TSApiWrapper.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ TSApiWrapper: () => (/* binding */ TSApiWrapper)\n/* harmony export */ });\n/* harmony import */ var _models_TSApiConfig_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./models/TSApiConfig.js */ \"./src/models/TSApiConfig.js\");\n/* harmony import */ var _models_TSApiConnection_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./models/TSApiConnection.js */ \"./src/models/TSApiConnection.js\");\n\n\n\nclass TSApiWrapper {\n // Public class variables\n\n #events = new Map(); // Used to create custom event handler: https://javascript.plainenglish.io/building-a-simple-event-emitter-in-javascript-f82f68c214ad\n #connection = null;\n #config = null;\n\n constructor(config) {\n this.#config = new _models_TSApiConfig_js__WEBPACK_IMPORTED_MODULE_0__.TSApiConfig(config);\n this.connect();\n }\n\n /**\n * Connect and subsequently authenticate to API\n * Also bind all the custom events\n *\n * @return {[void]}\n */\n connect() {\n // Avoid opening duplicate connections\n if (this.#connection?.isOpen || this.#connection?.isConnecting) {\n return;\n }\n\n this.#connection = new _models_TSApiConnection_js__WEBPACK_IMPORTED_MODULE_1__.TSApiConnection(this.#config);\n\n this.#connection.on('error', (params) => {\n this.#emit('apiError', params);\n });\n\n this.#connection.on('close', (params) => {\n this.#emit('apiConnectionClosed', params);\n });\n\n this.#connection.on('open', (params) => {\n this.#emit('apiConnectionOpen', params);\n });\n\n this.#connection.on('message', (params) => {\n this.#emit('apiIncomingMessage', params);\n\n var message = JSON.parse(params.data);\n\n // If message from TS API has a type we'll execute the type's message handler\n if (typeof message.type !== \"undefined\") {\n this.#messageHandler(message.type, message);\n }\n });\n\n this.#connection.on('ready', (message) => {\n this.#emit('apiReady', message);\n })\n }\n\n /**\n * Disconnect from API\n *\n * @return {[void]}\n */\n disconnect() {\n this.#connection.close();\n }\n\n /**\n * Send data to API\n *\n * @param {[Object]} data JSON Object to send to API\n */\n send(data = {}) {\n this.#connection.send(data);\n }\n\n #messageHandler(type, message) {\n var type = type.charAt(0).toUpperCase() + type.slice(1); // Capitalize first letter of type\n var eventName = 'tsOn' + type;\n\n\n if (this.#config.get('api').tsEventDebug) {\n console.log(\"Event received: \" + eventName);\n console.log(message);\n }\n\n this.#emit(eventName, message);\n }\n\n /**\n * Register callback to custom event handler\n *\n * @param {[string]} event Event name\n * @param {[function]} callback Callback to execute when event is emitted\n *\n * @return {[void]} \n */\n on(event, callback) {\n if (!this.#events.has(event)) {\n this.#events.set(event, []);\n }\n this.#events.get(event).push(callback);\n }\n\n /**\n * Remove callback from custom event handler\n *\n * @param {[string]} event Event name\n * @param {[function]} callback Callback to remove\n *\n * @return {[void]} \n */\n off(event, callback) {\n if (this.#events.has(event)) {\n const callbacks = this.#events.get(event).filter(cb => cb !== callback);\n this.#events.set(event, callbacks);\n }\n }\n\n /**\n * Emit event from custom event handler\n * \n * @param {[string]} event Event name\n * @param {[Object]} data JSON Object of data to forward to callback\n * \n * @return {[void]}\n */\n #emit(event, ...data) {\n if (this.#events.has(event)) {\n this.#events.get(event).forEach(callback => {\n setTimeout(() => callback(...data), 0);\n });\n }\n }\n}\n\n//# sourceURL=webpack://TSRemoteAppWrapper/./src/TSApiWrapper.js?");
/***/ }),
/***/ "./src/exceptions/TSApiAuthException.js":
/*!**********************************************!*\
!*** ./src/exceptions/TSApiAuthException.js ***!
\**********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ TSApiAuthException: () => (/* binding */ TSApiAuthException)\n/* harmony export */ });\nclass TSApiAuthException extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n//# sourceURL=webpack://TSRemoteAppWrapper/./src/exceptions/TSApiAuthException.js?");
/***/ }),
/***/ "./src/exceptions/TSApiConnectionException.js":
/*!****************************************************!*\
!*** ./src/exceptions/TSApiConnectionException.js ***!
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ TSApiConnectionException: () => (/* binding */ TSApiConnectionException)\n/* harmony export */ });\nclass TSApiConnectionException extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n//# sourceURL=webpack://TSRemoteAppWrapper/./src/exceptions/TSApiConnectionException.js?");
/***/ }),
/***/ "./src/models/TSApiConfig.js":
/*!***********************************!*\
!*** ./src/models/TSApiConfig.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ TSApiConfig: () => (/* binding */ TSApiConfig)\n/* harmony export */ });\nclass TSApiConfig {\n #config = {\n api: {\n host: 'localhost',\n port: 5899,\n key: '',\n tsEventDebug: false,\n },\n app: {\n name: \"TS Remote Apps Wrapper\",\n identifier: \"ts5-remote-apps-wrapper\",\n version: \"1.0.0\",\n description: \"An API wrapper written in JavaScript for TeamSpeak 5's remote apps WebSocket feature.\",\n }\n }\n\n constructor(config = {}) {\n this.#config = this.#mergeConfig(this.#config, config);\n }\n\n /**\n * Gets a config object according to it's key\n *\n * @param {[string]} key Key of config object to retreive\n *\n * @return {[Mixed]} Config JSON object. \"null\" if config object is not set.\n */\n get(key) {\n if (typeof key === \"undefined\") {\n return this.#config;\n }\n return this.#config[key];\n }\n\n /**\n * Merge existing config with new values\n *\n * @param {[Object]} config JSON Object with config\n *\n * @return {[void]}\n */\n set(config = {}) {\n this.#config = this.#mergeConfig(this.#config, config);\n }\n\n /**\n * Merge two json objects without loosing keys\n * \n * @param {[Object]} a JSON Object a\n * @param {[Object]} b JSON Object b\n * \n * @return {{Object}} Two JSON objects merged without loosing any subkeys\n */\n #mergeConfig(a, b) {\n for (var key in b) {\n if (key in a) {\n a[key] = typeof a[key] === 'object' && typeof b[key] === 'object' ? this.#mergeConfig(a[key], b[key]) : b[key];\n }\n }\n\n return a;\n }\n} \n\n//# sourceURL=webpack://TSRemoteAppWrapper/./src/models/TSApiConfig.js?");
/***/ }),
/***/ "./src/models/TSApiConnection.js":
/*!***************************************!*\
!*** ./src/models/TSApiConnection.js ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ TSApiConnection: () => (/* binding */ TSApiConnection)\n/* harmony export */ });\n/* harmony import */ var _exceptions_TSApiConnectionException_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../exceptions/TSApiConnectionException.js */ \"./src/exceptions/TSApiConnectionException.js\");\n/* harmony import */ var _exceptions_TSApiAuthException_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../exceptions/TSApiAuthException.js */ \"./src/exceptions/TSApiAuthException.js\");\n\n\n\nclass TSApiConnection {\n // Public class variables\n config = null;\n isConnecting = true;\n isOpen = false;\n isAuthenticated = false;\n authRequestSent = false;\n\n // Private class variables\n #events = new Map(); // Used to create custom event handler: https://javascript.plainenglish.io/building-a-simple-event-emitter-in-javascript-f82f68c214ad\n #socketUrl = null;\n #ws = null;\n\n /**\n * [constructor description]\n *\n * @param {[TSApiConfig]} config TSApiConfig object with config\n *\n * @return {[type]} [return description]\n */\n constructor(config) {\n this.config = config;\n\n this.#socketUrl = \"ws://\" + this.config.get('api').host + \":\" + parseInt(this.config.get('api').port) + \"/\";\n\n this.#ws = new WebSocket(this.#socketUrl);\n\n this.#ws.onopen = (event) => {\n this.isConnecting = false;\n this.isOpen = true;\n this.#auth();\n this.#emit('open', event);\n }\n\n this.#ws.onerror = (event) => {\n // No need to set isOpen to false here because event handler \"onclose\" is called parallel to \"onerror\" handler\n var data = {\n socketEvent: event,\n exception: new _exceptions_TSApiConnectionException_js__WEBPACK_IMPORTED_MODULE_0__.TSApiConnectionException(\"Error connecting to TeamSpeak remote apps API. Check connection parameters and try again.\"),\n }\n this.#emit('error', data);\n };\n\n this.#ws.onclose = (event) => {\n // If API connection closes after auth payload was sent and API is not authenticated then auth failed.\n // Send an exception via error event\n if (this.authRequestSent && this.isAuthenticated !== true) {\n var data = {\n socketEvent: event,\n exception: new _exceptions_TSApiAuthException_js__WEBPACK_IMPORTED_MODULE_1__.TSApiAuthException(\"Access to TS API has been denied in remote apps section of TS client or the API key is invalid.\"),\n }\n this.#emit('error', data);\n }\n\n this.isOpen = false;\n this.isConnecting = false;\n this.isAuthenticated = false;\n\n this.#emit('close', event);\n }\n\n this.#ws.onmessage = (event) => {\n var message = JSON.parse(event.data);\n if (message.type === \"auth\") {\n this.#handleAuthResponse(message);\n }\n\n this.#emit('message', event);\n }\n }\n\n #auth() {\n var authPayload = {\n \"type\": \"auth\",\n \"payload\": {\n \"identifier\": this.config.get('app').identifier,\n \"version\": this.config.get('app').version,\n \"name\": this.config.get('app').name,\n \"description\": this.config.get('app').description,\n \"content\": {\n \"apiKey\": this.config.get('api').key\n }\n }\n };\n\n // Use standard WebSocket send() because class0s send() method has auth check built in\n // We don't need to check if connection is open because \"#auth()\" is called immediately after WebSocket 'open' event in constructor \n this.#ws.send(JSON.stringify(authPayload));\n this.authRequestSent = true;\n }\n\n #handleAuthResponse(message) {\n // Save API key if API returns \"auth\" response\n this.config.set({\n api: {\n key: message.payload.apiKey\n }\n });\n this.isAuthenticated = true;\n\n // Emit ready event once authenticated\n this.#emit('ready', message);\n }\n\n /**\n * Send data to API\n *\n * @param {[Object]} data JSON Object to send to API\n *\n * @return {[void]}\n */\n send(data = {}) {\n if (this.isOpen !== true) {\n throw new _exceptions_TSApiConnectionException_js__WEBPACK_IMPORTED_MODULE_0__.TSApiConnectionException(\"Can't send data to API. Connection not open.\");\n }\n\n if (this.isAuthenticated !== true) {\n throw new _exceptions_TSApiAuthException_js__WEBPACK_IMPORTED_MODULE_1__.TSApiAuthException(\"Cant send data to API. Not authenticated.\");\n }\n\n this.#ws.send(JSON.stringify(data));\n }\n\n /**\n * Close WebSocket\n * \n * @return {[void]}\n */\n close() {\n // If WebSocket is still connecting and close is called\n if (this.isOpen !== true && this.isConnecting) {\n throw new _exceptions_TSApiConnectionException_js__WEBPACK_IMPORTED_MODULE_0__.TSApiConnectionException(\"Can not close connection that is still connecting\");\n } else if (this.isOpen) {\n this.isOpen = false;\n this.#ws.close();\n }\n }\n\n /**\n * Register callback to custom event handler\n *\n * @param {[string]} event Event name\n * @param {[function]} callback Callback to execute when event is emitted\n *\n * @return {[void]} \n */\n on(event, callback) {\n if (!this.#events.has(event)) {\n this.#events.set(event, []);\n }\n this.#events.get(event).push(callback);\n }\n\n /**\n * Remove callback from custom event handler\n *\n * @param {[string]} event Event name\n * @param {[function]} callback Callback to remove\n *\n * @return {[void]} \n */\n off(event, callback) {\n if (this.#events.has(event)) {\n const callbacks = this.#events.get(event).filter(cb => cb !== callback);\n this.#events.set(event, callbacks);\n }\n }\n\n /**\n * Emit event from custom event handler\n * \n * @param {[string]} event Event name\n * @param {[Object]} data JSON Object of data to forward to callback\n * \n * @return {[void]}\n */\n #emit(event, ...data) {\n if (this.#events.has(event)) {\n this.#events.get(event).forEach(callback => {\n setTimeout(() => callback(...data), 0);\n });\n }\n }\n}\n\n//# sourceURL=webpack://TSRemoteAppWrapper/./src/models/TSApiConnection.js?");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = __webpack_require__("./src/TSApiWrapper.js");
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});