UNPKG

@geheimgang188/fmod-service-api

Version:
317 lines 24.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FmodZeromqApi = exports.ConnectionState = void 0; const zmq = __importStar(require("zeromq")); const tiny_typed_emitter_1 = require("tiny-typed-emitter"); const small_state_machine_1 = require("small-state-machine"); const semaphore_promise_1 = __importDefault(require("semaphore-promise")); var ConnectionState; (function (ConnectionState) { ConnectionState["Disconnected"] = "Disconnected"; ConnectionState["Connecting"] = "Connecting"; ConnectionState["Connected"] = "Connected"; ConnectionState["Disconnecting"] = "Disconnecting"; })(ConnectionState || (exports.ConnectionState = ConnectionState = {})); var Events; (function (Events) { Events["connect"] = "connect"; Events["connected"] = "connected"; Events["disconnect"] = "disconnect"; Events["disconnected"] = "disconnected"; })(Events || (Events = {})); class FmodZeromqApi extends tiny_typed_emitter_1.TypedEmitter { constructor(address, args) { var _a, _b; super(); this._verboseLogging = false; this._logger = args === null || args === void 0 ? void 0 : args.logger; this._verboseLogging = (args === null || args === void 0 ? void 0 : args.logger) !== undefined; this._zmqAddress = address; this._heartbeatInterval = (_a = args === null || args === void 0 ? void 0 : args.heartbeatIntervalMillis) !== null && _a !== void 0 ? _a : 4000; this._socketStatusInterval = (_b = args === null || args === void 0 ? void 0 : args.socketStatusIntervalMillis) !== null && _b !== void 0 ? _b : 4000; this._socketSempahore = new semaphore_promise_1.default(1); this._sm = new small_state_machine_1.SmallStateMachine(ConnectionState.Disconnected); this._sm.configure(ConnectionState.Disconnected) .onEntry(() => this.onDisconnected()) .permit(Events.connect, ConnectionState.Connecting) // Manually calling connect() .permit(Events.connected, ConnectionState.Connected) // Socket became available again .ignore(Events.disconnected); this._sm.configure(ConnectionState.Connecting) .onEntry(() => this.onConnecting()) .permit(Events.connected, ConnectionState.Connected) .permit(Events.disconnected, ConnectionState.Disconnected) .ignore(Events.connect); this._sm.configure(ConnectionState.Connected) .onEntry(() => this.onConnected()) .permit(Events.disconnected, ConnectionState.Disconnected) .ignore(Events.connect) .ignore(Events.connected); this._sm.configure(ConnectionState.Disconnecting) .onEntry(() => this.onDisconnecting()) .permit(Events.disconnected, ConnectionState.Disconnected) .ignore(Events.disconnect); this._sm.onStateChange(newState => { var _a; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Now in state ${newState}`); }); } get connectionState() { return this._sm.currentState; } get verboseLogging() { return this._verboseLogging; } set verboseLogging(verbose) { this._verboseLogging = verbose; } connect() { this._sm.fire(Events.connect); } disconnect() { this._sm.fire(Events.disconnected); } /** * Start an event; it can be stopped again * @param event */ start(event) { return __awaiter(this, void 0, void 0, function* () { const command = `start-event:${event}`; yield this.sendCommand(command); }); } /** * Stop a running event * @param event */ stop(event) { return __awaiter(this, void 0, void 0, function* () { const command = `stop-event:${event}`; yield this.sendCommand(command); }); } stopStartedEvents() { return __awaiter(this, void 0, void 0, function* () { const command = 'stop-started-events'; yield this.sendCommand(command); }); } /** * Play an event (fire-and-forget) * @param event */ play(event) { return __awaiter(this, void 0, void 0, function* () { const command = `play-event:${event}`; yield this.sendCommand(command); }); } loadBank(bankName) { return __awaiter(this, void 0, void 0, function* () { const command = `load-bank:${bankName}`; yield this.sendCommand(command); }); } unloadBank(bankName) { return __awaiter(this, void 0, void 0, function* () { const command = `unload-bank:${bankName}`; yield this.sendCommand(command); }); } setParameter(eventId, name, value) { return __awaiter(this, void 0, void 0, function* () { const command = `set-parameter:${eventId};${name};${value}`; yield this.sendCommand(command); }); } playVoice(eventId, key) { return __awaiter(this, void 0, void 0, function* () { const command = `play-voice:${eventId};${key}`; yield this.sendCommand(command); }); } isPlaying(eventId) { throw new Error('Method not implemented.'); } listLoadedBankPaths() { return __awaiter(this, void 0, void 0, function* () { const command = 'list-bank-paths'; const list = yield this.sendCommand(command); return list .split(';') .map(el => el.replace(/^bank:\//, '')) .filter(el => el.length > 0); }); } doConnect() { var _a, _b; if (this._socket !== undefined) throw new Error('Socket already exists!'); this._socket = new zmq.Request(); /* // Connection timeouts may be helpful against calls piling up this._socket.connectTimeout = 2000; this._socket.sendTimeout = 200; this._socket.receiveTimeout = 2000; */ (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`ZMQ socket connecting to ${this._zmqAddress}`); this._socket.connect(this._zmqAddress); this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.debug(`Setting up heartbeat and status polling`)); // Regularly send message to the API to check if it is still online if (this._heartbeatPoll === undefined) { this._heartbeatPoll = setInterval(() => this.checkHeartbeat(), this._heartbeatInterval); } // Check if socket is writable; changes to false when it goes offline if (this._socketStatusPoll === undefined) { let lastWritableStatus = false; // TODO When the socket is not available, the calls pile up and are sent all at once when the socket becomes available. // Is there a better way? Not sending calls at all does not update socket.writable status … const checkConnection = () => __awaiter(this, void 0, void 0, function* () { if (this._socket === undefined) return; const release = yield this._socketSempahore.acquire(); try { // Socket can be … // closed → no connection // writable → all fine. This is how it should be after sending and receiving a message. // readable → only when we did not read the response, but the API should always read after writing const writableStatus = this._socket.writable; if (writableStatus !== lastWritableStatus) { lastWritableStatus = writableStatus; this._sm.fire(writableStatus ? Events.connected : Events.disconnected); } } finally { release(); } }); this._socketStatusPoll = setInterval(checkConnection, this._socketStatusInterval); setImmediate(checkConnection); } } doDisconnect() { var _a; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug('Disconnecting …'); if (this._socket !== undefined) { this._socket.disconnect(this._zmqAddress); this._socket = undefined; } if (this._heartbeatPoll !== undefined) { clearInterval(this._heartbeatPoll); this._heartbeatPoll = undefined; } if (this._socketStatusPoll !== undefined) { clearInterval(this._socketStatusPoll); this._socketStatusPoll = undefined; } this._sm.fire(Events.disconnected); } sendCommand(command) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; if (this._socket === undefined) throw new Error(`Socket not initialised; did you call init()?`); let msg = ''; const release = yield this._socketSempahore.acquire(); this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.trace(`Sending: ${command}`)); try { /* // Setting the sending timeout may be helpful. Needs further examination. this._logger?.info( `Send timeout is ${this._socket.sendTimeout}` ); this._socket.sendTimeout = 200; this._logger?.info( `Send timeout set to ${this._socket.sendTimeout}` ); */ // After sending a message to the socket, it is not writable anymore (and hopefully not closed) const sendPromise = this._socket.send(command); const [response] = yield this._socket.receive(); this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.trace(`Received: ${response}`)); msg = response.toString('utf-8'); if (msg.startsWith('Error:')) { throw new Error(msg); } } finally { release(); } this._verboseLogging && ((_c = this._logger) === null || _c === void 0 ? void 0 : _c.trace(`Done sending ${command}`)); return msg; }); } checkHeartbeat() { return __awaiter(this, void 0, void 0, function* () { var _a; try { const id = yield this.sendCommand('get:id'); if (this._lastId !== id) { if (this._lastId !== undefined) { process.nextTick(() => this.emit('reconnect')); } this._lastId = id; } this._sm.fire(Events.connected); } catch (err) { if (this._sm.currentState !== ConnectionState.Disconnected) { this._sm.fire(Events.disconnected); (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('FMOD has gone:', err); } } }); } onConnecting() { this.doConnect(); } onConnected() { process.nextTick(() => this.emit('connect')); } onDisconnecting() { this.doDisconnect(); } onDisconnected() { process.nextTick(() => this.emit('disconnect')); } } exports.FmodZeromqApi = FmodZeromqApi; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm1vZC16ZXJvbXEtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9mbW9kLXplcm9tcS1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQ0EsNENBQThCO0FBQzlCLDJEQUFrRDtBQUNsRCw2REFBd0Q7QUFDeEQsMEVBQTBDO0FBTTFDLElBQVksZUFLWDtBQUxELFdBQVksZUFBZTtJQUN2QixnREFBNkIsQ0FBQTtJQUM3Qiw0Q0FBeUIsQ0FBQTtJQUN6QiwwQ0FBdUIsQ0FBQTtJQUN2QixrREFBK0IsQ0FBQTtBQUNuQyxDQUFDLEVBTFcsZUFBZSwrQkFBZixlQUFlLFFBSzFCO0FBRUQsSUFBSyxNQUtKO0FBTEQsV0FBSyxNQUFNO0lBQ1AsNkJBQW1CLENBQUE7SUFDbkIsaUNBQXVCLENBQUE7SUFDdkIsbUNBQXlCLENBQUE7SUFDekIsdUNBQTZCLENBQUE7QUFDakMsQ0FBQyxFQUxJLE1BQU0sS0FBTixNQUFNLFFBS1Y7QUFRRCxNQUFhLGFBQWMsU0FBUSxpQ0FBOEI7SUFrQjdELFlBQWEsT0FBZSxFQUFFLElBQXdCOztRQUNsRCxLQUFLLEVBQUUsQ0FBQztRQUhKLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBSzVCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxhQUFKLElBQUksdUJBQUosSUFBSSxDQUFFLE1BQU0sQ0FBQztRQUM1QixJQUFJLENBQUMsZUFBZSxHQUFHLENBQUEsSUFBSSxhQUFKLElBQUksdUJBQUosSUFBSSxDQUFFLE1BQU0sTUFBSyxTQUFTLENBQUM7UUFFbEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUM7UUFDM0IsSUFBSSxDQUFDLGtCQUFrQixHQUFHLE1BQUEsSUFBSSxhQUFKLElBQUksdUJBQUosSUFBSSxDQUFFLHVCQUF1QixtQ0FBSSxJQUFJLENBQUM7UUFDaEUsSUFBSSxDQUFDLHFC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