First commit merge
This commit is contained in:
164
routes/registration.js
Normal file
164
routes/registration.js
Normal file
@@ -0,0 +1,164 @@
|
||||
const logger = require('../utils/logger');
|
||||
const config = require('config');
|
||||
|
||||
/**
|
||||
* Registration Handler - Equivalent to Kamailio's REGISTRAR route
|
||||
* Handles SIP REGISTER requests and manages user location database
|
||||
*/
|
||||
class RegistrationHandler {
|
||||
constructor(srf) {
|
||||
this.srf = srf;
|
||||
this.registry = new Map(); // In-memory registry (equivalent to Kamailio usrloc)
|
||||
this.config = config.get('registry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate From header before processing (equivalent to kamailio.cfg:635-639)
|
||||
*/
|
||||
validateFromHeader(req, res) {
|
||||
const from = req.getParsedHeader('from');
|
||||
if (!from || !from.uri || !from.uri.user || !from.uri.host) {
|
||||
logger.error('[REGISTER] Cannot register user - From header is invalid | Call-ID: %s', req.get('Call-ID'));
|
||||
res.send(400, 'Bad Request - Invalid From header');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get registration expiry from Contact header (equivalent to kamailio.cfg:647-657)
|
||||
*/
|
||||
getRegistrationExpiry(req) {
|
||||
let expires = req.get('Expires');
|
||||
|
||||
if (!expires || expires === '') {
|
||||
expires = this.config.defaultExpires.toString();
|
||||
}
|
||||
|
||||
// Validate expires is a number
|
||||
if (expires !== '0' && !/^[0-9]+$/.test(expires)) {
|
||||
expires = this.config.defaultExpires.toString();
|
||||
}
|
||||
|
||||
const expiresNum = parseInt(expires);
|
||||
|
||||
// Validate expiry range
|
||||
if (expiresNum > this.config.maxExpires) {
|
||||
return this.config.maxExpires;
|
||||
}
|
||||
if (expiresNum < this.config.minExpires && expiresNum !== 0) {
|
||||
return this.config.minExpires;
|
||||
}
|
||||
|
||||
return expiresNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save registration to registry (equivalent to kamailio.cfg:644)
|
||||
*/
|
||||
saveToRegistry(from, contact, expires, sourceIp, sourcePort) {
|
||||
const key = `${from.uri.user}@${from.uri.host}`;
|
||||
const registration = {
|
||||
aor: key,
|
||||
contact: contact,
|
||||
expires: expires,
|
||||
registeredAt: Date.now(),
|
||||
sourceIp: sourceIp,
|
||||
sourcePort: sourcePort,
|
||||
callId: from.params.tag || 'unknown'
|
||||
};
|
||||
|
||||
if (expires === 0) {
|
||||
// Remove registration (unregister)
|
||||
this.registry.delete(key);
|
||||
logger.info('[REGISTER] User %s unregistered | From: %s:%s', key, sourceIp, sourcePort);
|
||||
} else {
|
||||
// Add/update registration
|
||||
this.registry.set(key, registration);
|
||||
logger.info('[REGISTER] User %s registered | Contact: %s | Expires: %ds | From: %s:%s',
|
||||
key, contact, expires, sourceIp, sourcePort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle REGISTER request (equivalent to kamailio.cfg:630-676)
|
||||
*/
|
||||
handleRegister(req, res) {
|
||||
const callId = req.get('Call-ID');
|
||||
const sourceIp = req.source_address;
|
||||
const sourcePort = req.source_port;
|
||||
|
||||
logger.info('[REGISTER] Registration request from %s:%s | Call-ID: %s', sourceIp, sourcePort, callId);
|
||||
|
||||
// Validate From header
|
||||
if (!this.validateFromHeader(req, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get registration details
|
||||
const from = req.getParsedHeader('from');
|
||||
const contact = req.get('Contact');
|
||||
const expires = this.getRegistrationExpiry(req);
|
||||
|
||||
// Save to registry
|
||||
this.saveToRegistry(from, contact, expires, sourceIp, sourcePort);
|
||||
|
||||
// Send response
|
||||
if (expires === 0) {
|
||||
res.send(200, 'OK - Unregistered from Cyanet VoIP system.');
|
||||
} else {
|
||||
res.send(200, 'OK - Welcome to Cyanet VoIP system.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup user in registry (equivalent to Kamailio's lookup() function)
|
||||
*/
|
||||
lookup(aor) {
|
||||
return this.registry.get(aor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered users
|
||||
*/
|
||||
getAllRegistrations() {
|
||||
return Array.from(this.registry.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean expired registrations
|
||||
*/
|
||||
cleanExpiredRegistrations() {
|
||||
const now = Date.now();
|
||||
const expiredKeys = [];
|
||||
|
||||
for (const [key, registration] of this.registry.entries()) {
|
||||
const expiryTime = registration.registeredAt + (registration.expires * 1000);
|
||||
if (registration.expires > 0 && expiryTime <= now) {
|
||||
expiredKeys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of expiredKeys) {
|
||||
this.registry.delete(key);
|
||||
logger.info('[REGISTER] Expired registration removed: %s', key);
|
||||
}
|
||||
|
||||
return expiredKeys.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start registration cleanup timer
|
||||
*/
|
||||
startCleanupTimer() {
|
||||
// Clean expired registrations every 60 seconds (equivalent to Kamailio timer_interval)
|
||||
setInterval(() => {
|
||||
const cleaned = this.cleanExpiredRegistrations();
|
||||
if (cleaned > 0) {
|
||||
logger.info('[REGISTER] Cleaned %d expired registrations', cleaned);
|
||||
}
|
||||
}, 60000);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegistrationHandler;
|
||||
Reference in New Issue
Block a user