homebridge-pioneer-avr-2025
Version:
A Pioneer AVR plugin for homebridge. This plugin is designed for Pioneer models that use Telnet Commands (e.g., VSX-922). It may not be compatible with newer models (e.g., VSX-LX304).
157 lines • 6.77 kB
JavaScript
"use strict";
// src/telnet-avr/messageQueue.ts
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageQueue = void 0;
class MessageQueue {
constructor(connection) {
this.connection = connection;
this.queue = []; // Array storing message and its callback character string
this.queueCallbackChars = {}; // Maps callback character strings to an array of associated callbacks
this.callbackLocks = {}; // Locks specific to callback characters
// Start periodic queue checking
this.startQueueCheck();
this.conn = connection;
this.log = connection.log;
}
/**
* Starts periodic checking and processing of the queue.
* Releases locks and processes messages as needed.
*/
startQueueCheck() {
setInterval(() => {
var _a;
// Process the next item in the queue if it is not locked
if (this.queue.length > 0 && ((_a = this.conn) === null || _a === void 0 ? void 0 : _a.socket) && this.conn.socket.readyState === 'open') {
// Unlock callbackLocks if they are active for more than 5 seconds
for (const key of Object.keys(this.callbackLocks)) {
const lock = this.callbackLocks[key];
if (lock.message &&
key !== '!none' &&
lock.queueLock &&
lock.queueLockDate &&
Date.now() - lock.queueLockDate > 13000) {
this.connection.directSend(lock.message);
lock.message = undefined;
}
else if (lock.queueLock &&
lock.queueLockDate &&
Date.now() - lock.queueLockDate > 25000) {
delete this.callbackLocks[key];
}
}
this.processQueue();
}
}, 7); // Check every 7ms
}
/**
* Processes the first item in the queue, sending the message if not locked.
*/
processQueue() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (this.queue.length === 0) {
return;
}
const [message, callbackKey] = this.queue[0];
// Skip processing if the lock for the callback key is active
const lock = this.callbackLocks[callbackKey];
// this.log.debug('in processQueue', message, lock?.queueLock);
if (lock === null || lock === void 0 ? void 0 : lock.queueLock) {
return;
}
// Lock the callback key before sending the message
if (!this.callbackLocks[callbackKey]) {
this.callbackLocks[callbackKey] = {
queueLock: true,
queueLockDate: Date.now(),
message: message,
};
}
else {
this.callbackLocks[callbackKey].queueLock = true;
this.callbackLocks[callbackKey].queueLockDate = Date.now();
}
// Enforce a delay between messages if necessary
if (Date.now() - ((_a = this.connection.lastWrite) !== null && _a !== void 0 ? _a : 0) < 17) {
yield new Promise((resolve) => setTimeout(resolve, 7));
}
// Send the message via the connection
this.connection.directSend(message);
});
}
/**
* Adds a message to the queue with optional callback characters and a callback function.
* @param message - The message to send
* @param callbackChars - The callback character string to track
* @param callback - The function to execute when the response is received
*/
enqueue(message, callbackChars, callback) {
if (!callbackChars) {
callbackChars = '!none';
}
// Add the message to the queue if not already present
if (message === '?P') {
this.queue.unshift([message, callbackChars]);
}
else {
this.queue.push([message, callbackChars]);
}
if (callback) {
// Add the callback to the list of callbacks for the callback character string
if (!this.queueCallbackChars[callbackChars]) {
this.queueCallbackChars[callbackChars] = [];
}
this.queueCallbackChars[callbackChars].push(callback);
}
}
/**
* Clears the entire queue and resets all locks and callbacks.
*/
clearQueue() {
// this.log.debug('clearQueue called', this.queue, this.queueCallbackChars, this.callbackLocks);
this.queue = [];
this.queueCallbackChars = {};
this.callbackLocks = {};
}
/**
* Removes all callbacks associated with a specific callback character key.
* @param callbackKey - The callback key to clear
* @param callback - The specific callback to remove
*/
removeCallbackForKey(callbackKey) {
if (this.queueCallbackChars[callbackKey]) {
// If no more callbacks exist for the key, delete the key
delete this.queueCallbackChars[callbackKey];
}
if (this.callbackLocks[callbackKey]) {
this.callbackLocks[callbackKey].queueLock = false;
this.callbackLocks[callbackKey].queueLockDate = null;
}
}
/**
* Retrieves all callback keys currently in the queueCallbackChars map.
* @returns {string[]} - An array of callback keys
*/
getCallbackKeys() {
return Object.keys(this.queueCallbackChars);
}
/**
* Retrieves all callbacks associated with a specific callback key.
* @param callbackKey - The key to retrieve callbacks for
* @returns {Function[]} - An array of callbacks
*/
getCallbacksForKey(callbackKey) {
return this.queueCallbackChars[callbackKey] || [];
}
}
exports.MessageQueue = MessageQueue;
//# sourceMappingURL=messageQueue.js.map