UNPKG

@geheimgang188/fmod-service-api

Version:
496 lines 40.6 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 __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; 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")); const events_1 = require("events"); const marker_data_1 = require("./marker-data"); 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 { static getEventIdFromResponse(response) { const spacePos = response.indexOf(' '); if (spacePos === -1) { return undefined; } return response.substring(spacePos + 1); } constructor(address, args) { var _a, _b; super(); this._events = new events_1.EventEmitter(); this._singleShotEventIds = new Map(); this._verboseLogging = false; this._subRunning = 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); if (args === null || args === void 0 ? void 0 : args.subscriberAddress) { this._subscriberAddress = args.subscriberAddress; } else { // Derive subscriber address from main address by incrementing the port const match = address.match(/^(.*:)(\d+)$/); this._subscriberAddress = match ? `${match[1]}${parseInt(match[2], 10) + 1}` : address.replace(/:\d+$/, ':3001'); } 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) .permit(Events.disconnect, ConnectionState.Disconnecting) .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.disconnect); } /** * Register a callback for marker events from FMOD. */ onMarker(cb) { this._events.on('marker', cb); } /** * Unregister a marker event callback. */ offMarker(cb) { this._events.off('marker', cb); } /** * Start an event; it can be stopped again */ start(event) { return __awaiter(this, void 0, void 0, function* () { const command = `start-event:${event}`; yield this.sendCommand(command); }); } /** * Stop a running event */ stop(event) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; const command = `stop-event:${event}`; let stoppedEvents = 0; stoppedEvents += yield this.stopSingleShotEvents(event); try { yield this.sendCommand(command); stoppedEvents++; } catch (err) { if (stoppedEvents === 0) { (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(`Failed stopping event ${event}: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`); } } return stoppedEvents; }); } 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}`; const result = yield this.sendCommand(command); this.addSingleShotId(event, command, result); }); } 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}`; const result = yield this.sendCommand(command); const mapId = FmodZeromqApi.toEventMapId(eventId, key); this.addSingleShotId(mapId, command, result); }); } stopVoice(eventId, key) { return __awaiter(this, void 0, void 0, function* () { const mapId = FmodZeromqApi.toEventMapId(eventId, key); return this.stopSingleShotEvents(mapId); }); } 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); }); } stopSingleShotEvents(eventIdentifier) { return __awaiter(this, void 0, void 0, function* () { const entries = this._singleShotEventIds.get(eventIdentifier); if (entries === undefined) { return 0; } let stoppedCount = 0; for (const entry of entries) { const command = `stop-event:${entry.uniqueEventId}`; const result = yield this.sendCommand(command); if (result.startsWith('OK')) { stoppedCount++; } } entries.length = 0; this.printSingleShotLength(); return stoppedCount; }); } addSingleShotId(eventIdentifier, fmodAction, fmodResponse) { var _a, _b, _c; const uniqueEventId = FmodZeromqApi.getEventIdFromResponse(fmodResponse); this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.trace(`Answer from ${fmodAction}: ${fmodResponse}; extracted ID: ${uniqueEventId}`)); if (uniqueEventId !== undefined) { this._verboseLogging && ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.trace(`Event ID received: ${uniqueEventId}`)); const eventList = (_c = this._singleShotEventIds.get(eventIdentifier)) !== null && _c !== void 0 ? _c : []; eventList.push({ tAdded: Date.now(), uniqueEventId, }); this._singleShotEventIds.set(eventIdentifier, eventList); } this.cleanupOldEventIds(); } cleanupOldEventIds() { var _a; const now = Date.now(); const minutes = 60 * 1000; for (const [key, val] of this._singleShotEventIds.entries()) { const cleaned = val.filter(el => (now - el.tAdded) < 10 * minutes); const delta = val.length - cleaned.length; if (delta > 0) { this._singleShotEventIds.set(key, cleaned); this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Old event IDs cleaned up: ${delta} removed`)); } } this.printSingleShotLength(); } printSingleShotLength() { var _a; const totalIds = Array.from(this._singleShotEventIds.values()) .map(el => el.length) .reduce((acc, cur) => acc + cur, 0); this._verboseLogging && ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Single-shot event list contains ${totalIds} unique IDs`)); } 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.connectSubscriber(); 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* () { var _a, _b; 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 // undefined (because disconnected) → no connection const writableStatus = (_b = (_a = this._socket) === null || _a === void 0 ? void 0 : _a.writable) !== null && _b !== void 0 ? _b : false; 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 …'); this.disconnectSubscriber(); 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; } const fireDisconnect = () => this._sm.fire(Events.disconnected); setImmediate(fireDisconnect); } 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')); } connectSubscriber() { var _a; if (this._subSocket !== undefined) return; this._subSocket = new zmq.Subscriber(); this._subSocket.connect(this._subscriberAddress); this._subSocket.subscribe(''); this._subRunning = true; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`ZMQ subscriber connecting to ${this._subscriberAddress}`); this.runSubscriberLoop() .catch((err) => { var _a, _b; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.error(`Error in subscriber loop: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`); }); } disconnectSubscriber() { this._subRunning = false; if (this._subSocket !== undefined) { this._subSocket.close(); this._subSocket = undefined; } } runSubscriberLoop() { return __awaiter(this, void 0, void 0, function* () { var _a, e_1, _b, _c; var _d, _e, _f; const socket = this._subSocket; if (!socket) return; try { try { for (var _g = true, socket_1 = __asyncValues(socket), socket_1_1; socket_1_1 = yield socket_1.next(), _a = socket_1_1.done, !_a; _g = true) { _c = socket_1_1.value; _g = false; const [msg] = _c; if (!this._subRunning) break; const message = msg.toString('utf-8'); this._verboseLogging && ((_d = this._logger) === null || _d === void 0 ? void 0 : _d.trace(`Sub received: ${message}`)); const parsed = (0, marker_data_1.parseMarkerMessage)(message); if (parsed) { this._events.emit('marker', parsed); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_g && !_a && (_b = socket_1.return)) yield _b.call(socket_1); } finally { if (e_1) throw e_1.error; } } } catch (err) { if (this._subRunning) { (_e = this._logger) === null || _e === void 0 ? void 0 : _e.warn(`Subscriber loop error: ${(_f = err === null || err === void 0 ? void 0 : err.message) !== null && _f !== void 0 ? _f : err}`); } } }); } } exports.FmodZeromqApi = FmodZeromqApi; FmodZeromqApi.toEventMapId = (eventId, key) => `${eventId};;${key}`; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm1vZC16ZXJvbXEtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9mbW9kLXplcm9tcS1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLDRDQUE4QjtBQUM5QiwyREFBa0Q7QUFDbEQsNkRBQXdEO0FBQ3hELDBFQUEwQztBQUMxQyxtQ0FBc0M7QUFJdEMsK0NBQStEO0FBRy9ELElBQVksZUFLWDtBQUxELFdBQVksZUFBZTtJQUN2QixnREFBNkIsQ0FBQTtJQUM3Qiw0Q0FBeUIsQ0FBQTtJQUN6QiwwQ0FBdUIsQ0FBQTtJQUN2QixrREFBK0IsQ0FBQTtBQUNuQyxDQUFDLEVBTFcsZUFBZSwrQkFBZixlQUFlLFFBSzFCO0FBRUQsSUFBSyxNQUtKO0FBTEQsV0FBSyxNQUFNO0lBQ1AsNkJBQW1CLENBQUE7SUFDbkIsaUNBQXVCLENBQUE7SUFDdkIsbUNBQXlCLENBQUE7SUFDekIsdUNBQTZCLENBQUE7QUFDakMsQ0FBQyxFQUxJLE1BQU0sS0FBTixNQUFNLFFBS1Y7QUFnQkQsTUFBYSxhQUFjLFNBQVEsaUNBQThCO0lBRTdELE1BQU0sQ0FBQyxzQkFBc0IsQ0FBRSxRQUFnQjtRQUMzQyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFFLEdBQUcsQ0FBRSxDQUFDO1FBQ3pDLElBQUssUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFHLENBQUM7WUFDcEIsT0FBTyxTQUFTLENBQUM7UUFDckIsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBRSxRQUFRLEdBQUcsQ0FBQyxDQUFFLENBQUM7SUFDOUMsQ0FBQztJQTJCRCxZQUFhLE9BQWUsRUFBRSxJQUF3Qjs7UUFDbEQsS0FBSyxFQUFFLENBQUM7UUFiSyxZQUFPLEdBQUcsSUFBSSxxQkFBWSxFQUFFLENBQUM7UUFJN0Isd0JBQW1CLEdBQUcs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