axiodb
Version:
The Pure JavaScript Alternative to SQLite. Embedded NoSQL database for Node.js with MongoDB-style queries, zero native dependencies, built-in InMemoryCache, and web GUI. Perfect for desktop apps, CLI tools, and embedded systems. No compilation, no platfor
173 lines • 5.59 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectionManager = void 0;
const events_1 = require("events");
const protocol_1 = require("../config/protocol");
const keys_1 = require("../config/keys");
/**
* Connection Manager - Manages all active TCP connections
*/
class ConnectionManager extends events_1.EventEmitter {
constructor() {
super();
this.connections = new Map();
this.connectionCounter = 0;
// Increase max listeners since we handle 1000+ concurrent connections
this.setMaxListeners(0); // 0 = unlimited
}
/**
* Add new connection
*/
addConnection(socket) {
if (this.connections.size >= keys_1.MAX_CONNECTIONS) {
return null; // Reject connection - server overload
}
const connectionId = this.generateConnectionId();
const info = {
socket,
buffer: new protocol_1.MessageBuffer(),
connectedAt: Date.now(),
lastActivity: Date.now(),
requestCount: 0,
};
this.connections.set(connectionId, info);
// Setup socket handlers
this.setupSocketHandlers(connectionId, socket, info);
this.emit('connection:added', connectionId, socket.remoteAddress);
return connectionId;
}
/**
* Remove connection
*/
removeConnection(connectionId) {
const info = this.connections.get(connectionId);
if (info) {
if (!info.socket.destroyed) {
info.socket.destroy();
}
this.connections.delete(connectionId);
this.emit('connection:removed', connectionId);
}
}
/**
* Send response to client
*/
sendResponse(connectionId, response) {
const info = this.connections.get(connectionId);
if (!info || info.socket.destroyed) {
return false;
}
try {
const buffer = protocol_1.MessageFramer.encode(response);
info.socket.write(buffer);
info.lastActivity = Date.now();
return true;
}
catch (error) {
this.emit('error', error, connectionId);
return false;
}
}
/**
* Get connection info
*/
getConnection(connectionId) {
return this.connections.get(connectionId);
}
/**
* Get total active connections
*/
get activeConnections() {
return this.connections.size;
}
/**
* Get all connection IDs
*/
getAllConnectionIds() {
return Array.from(this.connections.keys());
}
/**
* Close all connections gracefully
*/
closeAll() {
for (const [connectionId, info] of this.connections.entries()) {
if (!info.socket.destroyed) {
info.socket.end();
}
this.connections.delete(connectionId);
}
this.emit('all:closed');
}
/**
* Setup socket event handlers
*/
setupSocketHandlers(connectionId, socket, info) {
socket.on('data', (chunk) => {
try {
info.lastActivity = Date.now();
const messages = info.buffer.addChunk(chunk);
for (const message of messages) {
info.requestCount++;
this.emit('message', connectionId, message, socket);
}
}
catch (error) {
this.emit('error', error, connectionId);
// Send error response
const errorResponse = {
id: 'error',
statusCode: keys_1.StatusCode.BAD_REQUEST,
message: keys_1.ErrorMessage.INVALID_MESSAGE_FORMAT,
error: error instanceof Error ? error.message : String(error),
};
this.sendResponse(connectionId, errorResponse);
// Clear buffer for recovery
info.buffer.clear();
}
});
socket.on('error', (error) => {
this.emit('socket:error', error, connectionId);
this.removeConnection(connectionId);
});
socket.on('close', (hadError) => {
this.emit('socket:closed', connectionId, hadError);
this.removeConnection(connectionId);
});
socket.on('end', () => {
this.emit('socket:end', connectionId);
this.removeConnection(connectionId);
});
socket.on('timeout', () => {
this.emit('socket:timeout', connectionId);
this.removeConnection(connectionId);
});
}
/**
* Generate unique connection ID
*/
generateConnectionId() {
this.connectionCounter++;
return `conn_${this.connectionCounter}_${Date.now()}`;
}
/**
* Get connection statistics
*/
getStats() {
let totalRequests = 0;
let oldestConnection = Date.now();
for (const info of this.connections.values()) {
totalRequests += info.requestCount;
if (info.connectedAt < oldestConnection) {
oldestConnection = info.connectedAt;
}
}
return {
activeConnections: this.connections.size,
maxConnections: keys_1.MAX_CONNECTIONS,
totalRequests,
oldestConnectionAge: Date.now() - oldestConnection,
};
}
}
exports.ConnectionManager = ConnectionManager;
//# sourceMappingURL=ConnectionManager.js.map