NodeServer - Real-Time Signaling & Communication Hub¶
Overview¶
The NodeServer is a critical Node.js-based WebSocket server that powers real-time communication for the Psyter telemedicine platform and multiple assessment/learning management systems. It handles:
- Presence Management - Online/offline status, user authentication
- WebRTC Signaling - Video/audio call setup via SDP/ICE candidate exchange
- Collaboration Sessions - Multi-party video consultations with time limits
- Real-time Messaging - Chat, file transfer, typing indicators
- Push Notifications - Firebase Cloud Messaging (FCM) and Apple Push Notifications (APN)
- Multi-Tenant Support - Serves multiple client systems (Psyter, QuranLMS, Assessment Systems)
Technology Stack:
- Runtime: Node.js
- WebSocket Library: ws (v7.2.1)
- Database: MS SQL Server via mssql (v6.0.1)
- Push Notifications: Firebase Admin SDK (v8.9.1), apn (v2.2.0)
- HTTPS Server: Native Node.js https module with SSL certificates
- Logging: Winston (v3.2.1) with daily log rotation
Prerequisites¶
Required Software¶
- Node.js: v12.x or v14.x (compatible with dependencies)
- npm: v6.x or higher
- SQL Server: Access to Psyter/QuranLMS/Assessment databases
- SSL Certificates: Per-tenant certificates for HTTPS/WSS
Required Access¶
- Database connection credentials for configured tenants
- Firebase service account JSON files
- Apple Push Notification certificates and keys
- SSL certificate files (
.pemformat)
Setup Instructions¶
1. Install Dependencies¶
cd NodeServer
npm install
Key Dependencies:
{
"ws": "7.2.1", // WebSocket server
"mssql": "6.0.1", // SQL Server driver
"firebase-admin": "8.9.1", // FCM notifications
"apn": "2.2.0", // Apple Push Notifications
"winston": "3.2.1", // Logging
"winston-daily-rotate-file": "4.4.1", // Log rotation
"yargs": "15.1.0", // Command-line args
"jsonfile": "5.0.0" // Config file reading
}
2. Configure SSL Certificates¶
Place SSL certificates in the ssl/ directory organized by client mode:
ssl/
├── PSYTER_DEV/
│ ├── key_live.pem
│ └── cert_live.pem
├── PSYTER_LIVE/
│ ├── key_live.pem
│ └── cert_live.pem
├── QURAN_DEV/
│ └── ...
└── [Other tenants]/
Certificate Passphrase: All certificates use passphrase 123456789 (⚠️ Change in production!)
3. Configure Database Connections¶
Database configurations are hardcoded in server.js within the setClientMode() function. Each tenant has its own database settings.
Example (PSYTER_DEV):
dbConfig = {
user: 'PsyterUser',
password: 'PsyterPa$$w0Rd',
server: 'db.innotech-sa.com',
database: 'Psyter_v1'
};
⚠️ Security Warning: Credentials should be externalized to environment variables or secure configuration management.
4. Configure Firebase Settings¶
Firebase configurations are also hardcoded per tenant in setClientMode():
fcmAPISettings = {
ProjectId: "psyterdev",
ClientEmail: "firebase-adminsdk-uh0r6@psyterdev.iam.gserviceaccount.com",
PrivateKey: "-----BEGIN PRIVATE KEY-----\n...",
DatabaseURL: "https://psyterdev.firebaseio.com"
};
5. Update config.json¶
Create/edit config.json in the root directory:
{
"enableLog": "true"
}
enableLog: Set to"true"to enable logging,"false"to disable
6. Set Client Mode and Start Server¶
The server requires a --clientmode argument to specify which tenant to serve:
# Development Mode
node server.js --clientmode=3 # PSYTER_DEV (port 3333)
# Production Mode
node server.js --clientmode=4 # PSYTER_LIVE (port 3223)
# QuranLMS
node server.js --clientmode=2 # QURAN_LMS (port 1443)
# Assessment Systems
node server.js --clientmode=6 # ASSESSMENTSYSTEM_DEV (port 5223)
Available Client Modes:
cClient = {
QURAN_DEV: 1, // Port 2333
QURAN_LMS: 2, // Port 1443
PSYTER_DEV: 3, // Port 3333
PSYTER_LIVE: 4, // Port 3223
ONE2ONE: 5, // Port 4223
ASSESSMENTSYSTEM_DEV: 6, // Port 5223
ASSESSMENTSYSTEM_AFU: 7, // Port 5224
ASSESSMENTSYSTEM_PSU: 8, // Port 5225
ASSESSMENTSYSTEM_KSU: 9, // Port 5226
ASSESSMENTSYSTEM_MBRU: 10, // Port 5227
ASSESSMENTSYSTEM_TAIF: 11, // Port 5228
NARAAKUM_DEV: 12 // Port 6223
};
7. Verify Server Startup¶
Look for these log messages:
Server is up and running
WebSocket server is up and running
APN is initialized
Sql connection is established
FCM is initialized
Running the Application¶
Development Mode¶
node server.js --clientmode=3
Production Mode (Using PM2)¶
# Install PM2
npm install -g pm2
# Start server
pm2 start server.js --name "psyter-nodeserver" -- --clientmode=4
# View logs
pm2 logs psyter-nodeserver
# Restart
pm2 restart psyter-nodeserver
# Stop
pm2 stop psyter-nodeserver
Using the Restart Script (Linux)¶
chmod +x restart.sh
./restart.sh
Note: The restart.sh script is hardcoded for QuranLive (clientmode=2). Modify it for other tenants.
Project Structure¶
NodeServer/
├── server.js # Main server file (~3000 lines)
├── package.json # Dependencies
├── package-lock.json # Dependency lock file
├── config.json # Runtime configuration
├── restart.sh # Linux restart script
├── ssl/ # SSL certificates per tenant
│ ├── PSYTER_DEV/
│ ├── PSYTER_LIVE/
│ ├── QURAN_DEV/
│ └── [other tenants]/
└── node_modules/ # Installed dependencies
server.js Architecture¶
The server.js file is monolithic (~3000 LOC) and contains:
1. Constants & Enums (Lines 1-150)
- cClient - Tenant identifiers
- cCommand - WebSocket command types (66 commands)
- cReason - Response reason codes
- cStatus - User presence states
- cConnectionMode - Presence vs Collaboration modes
- cCollaborationMode - Audio/video/both
- cClientPlatform - Web/Android/iOS identification
2. Configuration & Initialization (Lines 150-250)
- Database connection setup per tenant
- Firebase Admin SDK initialization
- SSL certificate loading
- WebSocket server creation
- APN provider setup
3. Connection Handling (Lines 250-400)
- WebSocket connection lifecycle
- Query parameter parsing (connectionMode, userId, collaborationKey, etc.)
- Client authentication routing
4. Presence Mode Functions (Lines 400-2200)
- PAuthenticate - User login via communication key/username
- PSignIn/PSignOut - Online/offline status
- PStatus - Status updates (online, away, DND)
- PChat - Chat message routing
- PCollaboration - Call invitation handling
- PReject/PNoAnswer - Call rejection flows
- PSendToUser - Direct user messaging
- PBroadCast - Status broadcasts to friend lists
5. Collaboration Mode Functions (Lines 2200-2800)
- CInitiate - WebRTC session initialization
- CCreateCollaboration - Multi-party call setup
- CSendCommand - SDP/ICE candidate exchange
- CLeaveCollaboration - User leaving call
- CEndCollaboration - Call termination
- CTimeLimit - Session time management
- CConsumptionInsert - Database logging of call duration
6. Messaging Functions (Lines 2800-2968)
- PSendMessage - Store and route chat messages
- PGetNewMessageCount - Unread message counts
- PGetUserConversationsList - Conversation list pagination
- PGetUserConversationMessageList - Message history
- PUpdateMessageStatus - Read receipts
7. Utility Functions
- logInfo - Winston logging with rotation
- SendFCMNotification - Firebase push notifications
- CleanSocketConnectionList - Connection cleanup
- UniqueToken - Collaboration key generation
Key Features¶
1. Presence Management¶
Authentication Methods:
- Communication Key: Mobile app-based verification code
- Username/Password: Direct credentials
- Client Key: Web portal authentication
- Re-authentication: Resume session after disconnect
User Status:
- OFFLINE (1), ONLINE (2), AWAY (3), DO_NOT_DISTURB (4), INVISIBLE (5)
- NETWORK_POOR (6), NETWORK_OK (7)
Connection Example:
wss://server:3333/?connectionMode=1&communicationKey=ABC123&deviceId=device1&clientPlatform=2
2. WebRTC Signaling¶
Call Flow:
1. Initiator: Sends C_CREATE_COLLABORATION with participant list
2. Server: Generates unique collaborationKey, broadcasts to participants
3. Participant: Receives P_ACCEPT_COLLABORATION via FCM/WebSocket
4. Both: Connect via connectionMode=2&collaborationKey=XYZ
5. Exchange: C_SDP (offers/answers) and C_ICECANDIDATE messages
6. Termination: C_END_COLLABORATION or C_LEAVE_COLLABORATION
Supported Commands:
- C_SDP - Session Description Protocol exchange
- C_ICECANDIDATE - ICE candidate exchange
- C_HOLD_COLLABORATION / C_UNHOLD_COLLABORATION - Call hold
- C_CAMERA_ON / C_CAMERA_OFF - Video toggle
- C_AUDIO_ON / C_AUDIO_OFF - Audio toggle
- C_TYPING_ON / C_TYPING_OFF - Typing indicators
3. Multi-Party Collaboration¶
Features:
- Initiator + Participants: One initiator, multiple participants
- Time Limits: Configurable session duration with automatic timeout
- Consumption Tracking: Call duration logged to database via Mobile_Package_ConsumptionDetail_Update
- Scheduled Sessions: Supports pre-booked appointments with bookingId
Time Limit Flow:
Client → C_TIME_LIMIT (60 seconds)
Server → Starts countdown timer
Server → [60s later] → C_TIMEOUT_COLLABORATION
Server → Calls CConsumptionInsert() to log duration
4. Push Notifications¶
Firebase Cloud Messaging (Android):
- Topic-based subscriptions: patient_{id}, doctor_{id}, student_{id}, staff_{id}
- Payload includes full command structure for offline users
Apple Push Notifications (iOS):
- VoIP notifications for incoming calls
- Topic: com.innotech-sa.Quran-University.voip
- Custom payload with collaboration data
Notification Triggers:
- Incoming collaboration requests
- Chat messages (when user offline)
- Call rejection/no answer
- Unreachable user
5. Real-Time Messaging¶
Database Integration:
Message_InsertMessage
Message_GetNewMessagesCount
Message_GetUserConversationsList
Message_GetUserConversationMessages
Message_UpdateMessageStatus
Features:
- Text and file attachments (images, documents)
- Read receipts (Sent, Delivered, Read)
- Pagination support for conversation lists and message history
- Offline message delivery via FCM
6. Multi-Tenant Support¶
Tenant Isolation:
- Separate database per tenant
- Separate Firebase project per tenant
- Separate SSL certificates
- Process title identifies running instance: NODE_PSYTER_DEV, PsyterLive, QuranLive
API Reference¶
WebSocket Connection URL¶
Format:
wss://<server>:<port>/?<queryParams>
Required Query Parameters:
| Parameter | Type | Description | Example |
|---|---|---|---|
connectionMode |
Int | 1=Presence, 2=Collaboration | 1 |
communicationKey |
String | Verification code (Presence auth) | ABC123 |
userName |
String | Username (alternative auth) | patient@example.com |
password |
String | Password (alternative auth) | password123 |
clientKey |
String | Client authentication key (Web) | KEY_ABC |
collaborationKey |
String | Session ID (Collaboration mode) | uuid-1234 |
fromUserId |
Int | User ID (Collaboration mode) | 42 |
deviceId |
String | Device identifier | device_android_123 |
clientPlatform |
Int | 1=Web, 2=Android, 3=iOS | 2 |
reConnect |
Int | 1=Re-authentication | 1 |
authenticateOnly |
Int | 1=Auth without presence | 1 |
WebSocket Message Structure¶
Client → Server:
{
"ConnectionMode": 1,
"Command": 5,
"Message": "Hello",
"FromUser": { "Id": 42, "Fullname": "John Doe" },
"ToUserList": [{ "Id": 43 }],
"CollaborationKey": "uuid-1234",
"ClientId": 123456789,
"ClientInitiationTime": "2025-11-10 12:00:00"
}
Server → Client:
{
"Message": "...",
"CollaborationKey": "uuid-1234",
"ConnectionMode": 1,
"Command": 5,
"Reason": 1,
"FromUser": { "Id": 42, "Fullname": "John Doe" },
"ToUserList": [{ "Id": 43 }],
"ClientInitiationTime": "2025-11-10 12:00:00",
"ServerIntimationTime": "2025-11-10 12:00:05"
}
Command Reference¶
Presence Commands (P_*):
| Command | ID | Description |
|---|---|---|
P_AUTHENTICATE |
1 | Initial authentication |
P_SIGNIN |
2 | User logged in |
P_SIGNOUT |
3 | User logged out |
P_CHAT |
5 | Chat message |
P_STATUS |
6 | Status change |
P_ACCEPT_COLLABORATION |
7 | Accept call |
P_REJECT_COLLABORATION |
8 | Reject call |
P_NO_ANSWER |
10 | Missed call |
P_CLOSE_CALL |
11 | Call ended |
P_NETWORK_POOR |
27 | Network degraded |
P_NETWORK_OK |
28 | Network restored |
P_SEND_MESSAGE |
55 | Send chat message |
P_RECIEVE_MESSAGE |
56 | Receive chat message |
P_GET_NEW_MESSAGE_COUNT |
57 | Unread count |
P_GET_MESSAGE_CONVERSATION_LIST |
58 | Conversation list |
P_GET_CONVERSATION_MESSAGE_LIST |
59 | Message history |
P_UPDATE_MESSAGE_STATUS |
60 | Read receipt |
P_OTHER_PARTY_JOINED |
66 | Participant joined |
Collaboration Commands (C_*):
| Command | ID | Description |
|---|---|---|
C_INITIATE |
12 | Join collaboration session |
C_CREATE_COLLABORATION |
13 | Start new call |
C_JOINED_COLLABORATION |
14 | Participant joined |
C_SDP |
16 | WebRTC SDP exchange |
C_ICECANDIDATE |
17 | WebRTC ICE candidate |
C_LEAVE_COLLABORATION |
18 | Leave call |
C_END_COLLABORATION |
19 | End call |
C_HOLD_COLLABORATION |
21 | Put call on hold |
C_UNHOLD_COLLABORATION |
22 | Resume call |
C_CAMERA_ON |
23 | Enable video |
C_CAMERA_OFF |
24 | Disable video |
C_AUDIO_ON |
32 | Unmute audio |
C_AUDIO_OFF |
33 | Mute audio |
C_NETWORK_POOR |
25 | Network issue |
C_TIME_LIMIT |
50 | Session time limit |
C_TIMEOUT_COLLABORATION |
54 | Session expired |
C_REINITIATE |
34 | Reconnect to session |
Reason Codes¶
| Reason | ID | Description |
|---|---|---|
SUCCESS |
1 | Operation successful |
ERROR |
2 | Generic error |
INVALID_REQUEST |
3 | Malformed request |
INVALID_USER |
4 | User not found/invalid credentials |
DATABASE_NOT_AVAILABLE |
5 | DB connection failure |
RECONNECT |
6 | Client should reconnect |
ALREADY_LOGGED_IN |
7 | Duplicate login (Assessment Systems) |
REJECT_COLLABORATION |
8 | Call rejected |
NO_ANSWER |
9 | Call not answered |
ALREADY_IN_COLLABORATION |
11 | User already in call |
CLOSE_COLLABORATION |
13 | Collaboration ended |
TIMEOUT |
16 | Session timeout |
Database Stored Procedures¶
The server calls these SQL Server stored procedures:
Authentication & User Management¶
COB_Authenticate- Client key authenticationCOB_Authenticate_Get_User_List- User authentication and friend listCOB_Get_User_List- All usersCOB_Get_Related_User_List- User’s friends/contactsCOB_Manage_User_Friend- Add/remove friendCOB_Update_Password- Change passwordCOB_Create_User- Register new user
Collaboration & Sessions¶
Mobile_Package_ConsumptionDetail_Update- Log call duration (Assessment Systems)SP_ManageCareProvidersServiceCount- Update provider service count (Psyter)SP_GetBookingDetailsById- Fetch booking details
Messaging¶
Message_InsertMessage- Save new messageMessage_GetNewMessagesCount- Unread countMessage_GetUserConversationsList- Conversation listMessage_GetUserConversationMessages- Message historyMessage_UpdateMessageStatus- Update read status
Logging¶
Log Configuration¶
Winston Logger Settings:
- Log Directory: /var/www/html/node/pro/log/{CLIENT_MODE}/
- File Pattern: {CLIENT_MODE}_YYYY-MM-DD.txt
- Rotation: Daily
- Levels: Info, Error
- Console Output: Enabled with colorization
Example Log Entry:
2025-11-10 14:32:15: -#----- Active Connections ( 42 ) -----#-
2025-11-10 14:32:15: INFO --> CLIENT --> cCommand.P_CHAT --> Sender = John Doe (42)
Log Types¶
INFO- Normal operations, command processingERROR- Exceptions, database errors, notification failures
Disabling Logs¶
Edit config.json:
{
"enableLog": "false"
}
The server polls this file every 10 seconds.
Common Issues & Troubleshooting¶
Issue 1: “Cannot read property ‘length’ of undefined”¶
Cause: Client disconnected abruptly, lists not cleaned up
Solution: Server has heartbeat mechanism (30-minute ping), should auto-clean. Check CleanSocketConnectionList() function.
Issue 2: Database Connection Errors¶
Symptoms: cReason.DATABASE_NOT_AVAILABLE errors
Solutions:
- Verify SQL Server is accessible from Node.js server
- Check firewall rules (SQL Server port 1433)
- Confirm credentials in setClientMode()
- Check database exists and user has permissions
Issue 3: Firebase Notifications Not Delivered¶
Symptoms: No push notifications when user offline
Solutions:
- Verify Firebase service account credentials
- Check topic naming: patient_{id}~, doctor_{id}~, etc.
- Ensure mobile apps subscribe to correct topics
- Check Firebase Console for delivery errors
Issue 4: SSL Certificate Errors¶
Symptoms: ENOENT: no such file or directory on startup
Solutions:
- Ensure SSL files exist in ssl/{CLIENT_MODE}/ directory
- Verify filenames: key_live.pem and cert_live.pem
- Check file permissions (readable by Node.js process)
Issue 5: Port Already in Use¶
Symptoms: EADDRINUSE: address already in use
Solutions:
# Find process using port
netstat -ano | findstr :3333 # Windows
lsof -i :3333 # Linux/Mac
# Kill process
taskkill /PID <PID> /F # Windows
kill -9 <PID> # Linux/Mac
Issue 6: Collaboration Not Starting¶
Symptoms: C_UNINITIATE or timeout
Solutions:
- Verify both users are authenticated (Presence mode)
- Check collaborationKey is generated and shared correctly
- Ensure users connect with connectionMode=2
- Review logs for INVALID_USER or ALREADY_IN_COLLABORATION
Issue 7: Messages Not Persisting¶
Symptoms: Chat works real-time but not saved
Solutions:
- Check Message_InsertMessage stored procedure exists
- Verify database user has EXECUTE permission
- Review SQL Server logs for errors
- Confirm CatMessageStatus values are valid
Security Considerations¶
⚠️ Critical Security Issues Identified:
-
Hardcoded Credentials - Database passwords and Firebase private keys are in source code
- Impact: Credential exposure in version control
- Recommendation: Use environment variables or Azure Key Vault -
SSL Certificate Passphrase - Hardcoded as
123456789
- Impact: Weak encryption protection
- Recommendation: Use strong passphrase, externalize to secure config -
No Input Validation - User input not sanitized before SQL queries
- Impact: Potential SQL injection via stored procedure parameters
- Recommendation: Validate all user inputs, use parameterized queries (already usingrequest.input(), good!) -
No Rate Limiting - WebSocket connections not throttled
- Impact: Vulnerable to DDoS attacks
- Recommendation: Implement connection limits per IP -
Unencrypted Database Connections - No SSL/TLS for SQL Server
- Impact: Credentials/data transmitted in plaintext internally
- Recommendation: Enable SQL Server encryption -
Global Error Handlers -
uncaughtExceptionandunhandledRejectioncatch-all
- Impact: Errors may be swallowed, process doesn’t crash
- Recommendation: Log and restart process on critical errors
Performance Considerations¶
Connection Limits¶
- Current: No hard limits configured
- WebSocket Library Default: ~10,000 concurrent connections (OS dependent)
- Database Pooling:
mssqldefault pool size is 10
Recommendations:
- Monitor active connection count (ccCount variable)
- Implement Redis pub/sub for horizontal scaling (multiple Node instances)
- Use database connection pooling configuration
Memory Management¶
- Heartbeat Interval: 30 minutes (ping/pong)
- Cleanup Functions:
CleanSocketConnectionList()runs on each disconnect - In-Memory Lists:
userList- All authenticated userspUserConnectionList- Presence connectionscUserConnectionList- Collaboration connectionscollaborationList- Active sessions
Risk: Memory leak if cleanup fails; monitor with process.memoryUsage()
Database Query Optimization¶
- Most queries use stored procedures (efficient)
- No connection pooling configuration (uses defaults)
- Consider caching user lists with Redis for high-traffic scenarios
Deployment Guide¶
Linux Server Deployment¶
1. Install Node.js:
curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
2. Clone/Copy Project:
cd /var/www/html/node/pro
git clone <repository> NodeServer
cd NodeServer
npm install --production
3. Create Log Directory:
sudo mkdir -p /var/www/html/node/pro/log/PSYTER_LIVE
sudo chown -R $USER:$USER /var/www/html/node/pro/log
4. Install PM2:
sudo npm install -g pm2
5. Start Server:
pm2 start server.js --name psyter-live -- --clientmode=4
pm2 save
pm2 startup
6. Configure Firewall:
sudo ufw allow 3223/tcp # PSYTER_LIVE port
Windows Server Deployment¶
1. Install Node.js:
- Download from https://nodejs.org/
- Run installer, select “Add to PATH”
2. Install Dependencies:
cd C:\NodeServer
npm install
3. Install PM2 (Windows Service):
npm install -g pm2
npm install -g pm2-windows-service
pm2-service-install
4. Start Server:
pm2 start server.js --name psyter-live -- --clientmode=4
pm2 save
Health Check Endpoint¶
⚠️ Missing: Server has no HTTP health check endpoint
Recommendation: Add Express.js for health checks:
const express = require('express');
const app = express();
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
connections: ccCount,
uptime: process.uptime()
});
});
app.listen(3334, () => console.log('Health check on port 3334'));
Monitoring & Maintenance¶
Key Metrics to Monitor¶
- Active Connections:
ccCountvariable - Process Memory:
process.memoryUsage().heapUsed - Database Connection State: SQL connection health
- Log File Size: Daily rotation in
/var/www/html/node/pro/log/
PM2 Monitoring¶
pm2 monit # Real-time monitoring
pm2 logs psyter-live # View logs
pm2 restart psyter-live # Restart process
pm2 stop psyter-live # Stop process
pm2 delete psyter-live # Remove from PM2
Log Analysis¶
# Search for errors
grep ERROR /var/www/html/node/pro/log/PSYTER_LIVE/*.txt
# Count connections over time
grep "Active Connections" /var/www/html/node/pro/log/PSYTER_LIVE/*.txt | wc -l
# Find authentication failures
grep "INVALID_USER" /var/www/html/node/pro/log/PSYTER_LIVE/*.txt
Development Workflow¶
Local Development¶
1. Mock Database (Optional):
If you don’t have access to the actual databases, comment out SQL calls and return mock data:
// In PAuthenticate function
// Comment out SQL query, return mock user
var mockUser = [{
Id: 1,
Fullname: "Test User",
Email: "test@example.com",
// ... other fields
}];
PAuthenticateSuccess(command, client, data, mockUser, []);
2. Run Server:
node server.js --clientmode=3
3. Test WebSocket Connection:
Use a WebSocket client like Smart WebSocket Client or:
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:3333/?connectionMode=1&communicationKey=TEST123&deviceId=dev1&clientPlatform=1', {
rejectUnauthorized: false // For self-signed certs
});
ws.on('open', () => {
console.log('Connected');
});
ws.on('message', (data) => {
console.log('Received:', data);
});
Code Formatting¶
ESLint Configuration (Not Present):
Recommend adding:
npm install --save-dev eslint
npx eslint --init
Recommended .eslintrc.json:
{
"env": {
"node": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
"indent": ["error", 4],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"]
}
}
Testing¶
⚠️ No automated tests present
Recommended Test Structure¶
1. Install Testing Framework:
npm install --save-dev mocha chai sinon
2. Create Test Directory:
NodeServer/
├── test/
│ ├── authentication.test.js
│ ├── collaboration.test.js
│ ├── messaging.test.js
│ └── utils.test.js
3. Example Test (authentication.test.js):
const { expect } = require('chai');
const WebSocket = require('ws');
describe('Authentication', () => {
let ws;
before((done) => {
// Start server
require('../server.js');
setTimeout(done, 1000);
});
it('should authenticate with valid communication key', (done) => {
ws = new WebSocket('wss://localhost:3333/?connectionMode=1&communicationKey=VALID_KEY');
ws.on('message', (data) => {
const msg = JSON.parse(data);
expect(msg.Command).to.equal(1); // P_AUTHENTICATE
expect(msg.Reason).to.equal(1); // SUCCESS
done();
});
});
after(() => {
if (ws) ws.close();
});
});
Manual Testing Checklist¶
Presence Mode:
- [ ] User authentication (communication key)
- [ ] User authentication (username/password)
- [ ] User sign out
- [ ] Status change broadcast
- [ ] Chat message delivery
- [ ] Friend list retrieval
- [ ] Network status updates
Collaboration Mode:
- [ ] Create collaboration (1-to-1)
- [ ] Create collaboration (multi-party)
- [ ] SDP/ICE candidate exchange
- [ ] Video/audio toggle
- [ ] Call hold/unhold
- [ ] Leave collaboration
- [ ] End collaboration
- [ ] Time limit enforcement
- [ ] Timeout handling
Messaging:
- [ ] Send text message
- [ ] Send file attachment
- [ ] Receive message (online user)
- [ ] Receive message (offline via FCM)
- [ ] Read receipts
- [ ] Conversation list pagination
- [ ] Message history pagination
Migration & Upgrade Path¶
Recommended Improvements¶
1. Externalize Configuration
- Move database credentials to .env file
- Use dotenv package
- Configure per environment (dev, staging, prod)
2. Add TypeScript
- Improve maintainability with type safety
- Better IDE support
- Catch errors at compile time
3. Modularize Code
- Split server.js into separate files:
src/
├── index.js
├── config/
│ ├── database.js
│ ├── firebase.js
│ └── ssl.js
├── handlers/
│ ├── presence.js
│ ├── collaboration.js
│ └── messaging.js
├── utils/
│ ├── logger.js
│ ├── notifications.js
│ └── helpers.js
└── models/
├── user.js
└── collaboration.js
4. Add Database ORM
- Consider using Sequelize or TypeORM
- Better query building and validation
- Migration management
5. Implement Horizontal Scaling
- Use Redis for pub/sub between multiple Node instances
- Share session state across instances
- Load balancer configuration (NGINX)
6. Add Monitoring
- Prometheus metrics export
- Grafana dashboards
- Error tracking (Sentry)
API Client Examples¶
JavaScript (Browser)¶
class PsyterWebSocket {
constructor(url, userId, communicationKey) {
this.ws = new WebSocket(
`${url}?connectionMode=1&communicationKey=${communicationKey}&deviceId=web_${Date.now()}&clientPlatform=1`
);
this.ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
this.handleMessage(msg);
};
}
handleMessage(msg) {
switch(msg.Command) {
case 1: // P_AUTHENTICATE
console.log('Authenticated:', msg.FromUser);
break;
case 2: // P_SIGNIN
console.log('User online:', msg.FromUser);
break;
case 5: // P_CHAT
console.log('Chat message:', msg.Message);
break;
}
}
sendChat(toUserId, message) {
this.ws.send(JSON.stringify({
ConnectionMode: 1,
Command: 5,
Message: message,
FromUser: this.currentUser,
ToUserList: [{ Id: toUserId }]
}));
}
}
// Usage
const client = new PsyterWebSocket('wss://server:3333', 42, 'ABC123');
Android (Java)¶
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("wss://server:3333/?connectionMode=1&communicationKey=ABC123&deviceId=android_1&clientPlatform=2")
.build();
WebSocket ws = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onMessage(WebSocket webSocket, String text) {
JSONObject msg = new JSONObject(text);
int command = msg.getInt("Command");
// Handle message
}
});
// Send chat
JSONObject chatMsg = new JSONObject();
chatMsg.put("ConnectionMode", 1);
chatMsg.put("Command", 5);
chatMsg.put("Message", "Hello");
ws.send(chatMsg.toString());
Contribution Guidelines¶
Code Style¶
- Indentation: 4 spaces
- Naming: camelCase for variables/functions, PascalCase for constants
- Comments: Explain complex logic, not obvious code
- Function Length: Keep under 50 lines when possible
Pull Request Process¶
- Create feature branch from
main - Implement changes with meaningful commit messages
- Add/update tests (when test framework added)
- Update README if adding features
- Submit PR with description of changes
Commit Message Format¶
type(scope): subject
- Detailed explanation if needed
- Can span multiple lines
Examples:
feat(messaging): add typing indicator support
fix(auth): resolve token expiration issue
docs(readme): update deployment guide
License & Credits¶
Author: Muhammad Mansoor Umer Chaudhry
Package Name: cn.signaling-server
Version: 0.0.0 (Should be updated!)
Support & Contact¶
For issues or questions:
1. Check logs in /var/www/html/node/pro/log/
2. Review this README’s troubleshooting section
3. Contact platform maintainers
Changelog¶
Current Version (0.0.0):
- Multi-tenant WebSocket signaling server
- Presence management
- WebRTC collaboration
- Firebase/APN push notifications
- Real-time messaging
- Database integration
Future Roadmap:
- [ ] Externalized configuration
- [ ] TypeScript migration
- [ ] Automated testing
- [ ] Health check endpoint
- [ ] Horizontal scaling with Redis
- [ ] Performance metrics
- [ ] Security hardening