@nodedaemon/core
Version:
Production-ready Node.js process manager with zero external dependencies
173 lines • 5.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IPCClient = void 0;
const net_1 = require("net");
const helpers_1 = require("../utils/helpers");
const constants_1 = require("../utils/constants");
class IPCClient {
socket = null;
pendingRequests = new Map();
connected = false;
connectionTimeout = 5000;
requestTimeout = 30000;
async connect() {
if (this.connected) {
return;
}
return new Promise((resolve, reject) => {
this.socket = new net_1.Socket();
const connectionTimer = setTimeout(() => {
this.socket?.destroy();
reject(new Error('Connection timeout'));
}, this.connectionTimeout);
this.socket.connect(constants_1.IPC_SOCKET_PATH, () => {
clearTimeout(connectionTimer);
this.connected = true;
this.setupSocketHandlers();
resolve();
});
this.socket.on('error', (error) => {
clearTimeout(connectionTimer);
if (error.message.includes('ENOENT') || error.message.includes('ECONNREFUSED')) {
reject(new Error('NodeDaemon is not running. Start it with: nodedaemon daemon'));
}
else {
reject(new Error(`Connection failed: ${error.message}`));
}
});
});
}
setupSocketHandlers() {
if (!this.socket)
return;
let buffer = '';
this.socket.on('data', (data) => {
buffer += data.toString();
// Process complete JSON messages (separated by newlines)
const messages = buffer.split('\n');
buffer = messages.pop() || ''; // Keep incomplete message in buffer
messages.forEach(messageStr => {
if (messageStr.trim()) {
try {
const response = JSON.parse(messageStr);
this.handleResponse(response);
}
catch (error) {
console.error('Failed to parse response:', error);
}
}
});
});
this.socket.on('error', (error) => {
console.error('Socket error:', error.message);
this.handleDisconnection();
});
this.socket.on('close', () => {
this.handleDisconnection();
});
this.socket.on('end', () => {
this.handleDisconnection();
});
}
handleResponse(response) {
const request = this.pendingRequests.get(response.id);
if (request) {
clearTimeout(request.timeout);
this.pendingRequests.delete(response.id);
if (response.success) {
request.resolve(response);
}
else {
const error = response.data?.error || 'Unknown error';
request.reject(new Error(error));
}
}
}
handleDisconnection() {
this.connected = false;
this.socket = null;
// Reject all pending requests
this.pendingRequests.forEach((request) => {
clearTimeout(request.timeout);
request.reject(new Error('Connection lost'));
});
this.pendingRequests.clear();
}
async sendMessage(type, data) {
if (!this.connected || !this.socket) {
await this.connect();
}
return new Promise((resolve, reject) => {
const id = (0, helpers_1.generateId)();
const message = {
id,
type,
data,
timestamp: Date.now()
};
const timeout = setTimeout(() => {
this.pendingRequests.delete(id);
reject(new Error(`Request timeout for ${type}`));
}, this.requestTimeout);
this.pendingRequests.set(id, {
resolve: (response) => resolve(response.data),
reject,
timeout
});
const messageData = JSON.stringify(message) + '\n';
this.socket.write(messageData, (error) => {
if (error) {
clearTimeout(timeout);
this.pendingRequests.delete(id);
reject(new Error(`Failed to send message: ${error.message}`));
}
});
});
}
async ping() {
return this.sendMessage('ping');
}
async start(config) {
return this.sendMessage('start', config);
}
async stop(options) {
return this.sendMessage('stop', options);
}
async restart(options) {
return this.sendMessage('restart', options);
}
async list() {
return this.sendMessage('list');
}
async status(options) {
return this.sendMessage('status', options);
}
async logs(options) {
return this.sendMessage('logs', options);
}
async shutdown() {
return this.sendMessage('shutdown');
}
disconnect() {
if (this.socket) {
this.socket.end();
this.socket = null;
}
this.connected = false;
// Clear pending requests
this.pendingRequests.forEach((request) => {
clearTimeout(request.timeout);
request.reject(new Error('Client disconnected'));
});
this.pendingRequests.clear();
}
isConnected() {
return this.connected;
}
setTimeout(connectionTimeout, requestTimeout) {
this.connectionTimeout = Math.max(1000, connectionTimeout);
this.requestTimeout = Math.max(5000, requestTimeout);
}
}
exports.IPCClient = IPCClient;
//# sourceMappingURL=IPCClient.js.map