Skip to main content

Server Configuration

Express Server Setup

Entry Point: general-socket/index.js

const express = require('express');
const app = express();

// Middleware Stack
app.use(cors()); // Cross-origin requests
app.use(bodyParser.json()); // JSON body parsing
app.use(helmet()); // Security headers
app.use(nocache()); // Disable caching

// Health Check
app.get('/status', (req, res) => {
res.json({ success: true, message: 'General socket is running' });
});

// REST API Routes
app.use('/', RestAPI);

// Server Initialization
const server = http.createServer(app);
const io = socketConfig(server); // Socket.IO configuration

Socket.IO Configuration

Configuration File: general-socket/Utils/socket.js

Key Features:

  • Singleton Pattern: Single Socket.IO instance across service
  • Redis Adapter: Horizontal scaling with pub/sub
  • WebSocket-Only: Disables long-polling fallback
  • CORS Enabled: Supports cross-origin connections
  • Custom Headers: Accepts x-token for authentication
const io = require('socket.io')(server, {
transports: ['websocket'], // WebSocket-only
cors: {
origin: '*',
methods: ['GET', 'POST'],
allowedHeaders: ['x-token'],
credentials: true,
},
});

// Redis Adapter for Scaling
const redisAdapter = require('@socket.io/redis-adapter');
const { createClient } = require('redis');
const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();
io.adapter(redisAdapter(pubClient, subClient));

Redis Adapter Configuration

Purpose: Enable horizontal scaling with multiple General Socket instances

Setup:

const redisAdapter = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

io.adapter(redisAdapter(pubClient, subClient));

Benefits:

  • Events broadcast across all instances
  • User can maintain single socket connection
  • Load balancing friendly
  • Session persistence

Environment Variable:

REDIS_URL=redis://localhost:6379

Counter Provider System

Location: general-socket/Integrations/Utils/counter.js

Purpose: Calculate and cache conversation counters per channel

Calculated Counters:

  • Open - Active conversations (not snoozed)
  • Unread - Conversations with unread messages
  • Closed - Closed conversations
  • Priority - Pinned conversations (show_on_top)
  • Snoozed - Temporarily hidden conversations

Special Channels:

  • You - Aggregated counters across all channels
  • Mentions - Conversations where user is @mentioned
  • Prospect - All prospect conversations

Cache Strategy: Counters are recalculated on each channel event and stored for performance.


Error Handling

Socket Event Errors

All socket event handlers follow this error pattern:

async onEventName(data, callback) {
try {
data = await isAuth(data); // Authenticate
await verifyScope(data, ['conversation']); // Check permissions

// Business logic...

sendResponse({ success: true, message: 'SUCCESS', data }, callback, false);
} catch (error) {
let errBody = {
success: false,
message: error.message,
additional_info: error
};
sendResponse(errBody, callback);
}
}

REST API Errors

router.use((error, req, res, next) => {
console.log('error--------------', error);
const status = error.statusCode || 400;
const message = error.message;
res.status(status).json({
success: false,
errno: status,
message: message,
});
});

Common Error Codes

CodeErrorCause
401INVALID_TOKENJWT verification failed
403NOT_ENOUGH_SCOPEUser lacks required permission scope
404NOT_FOUNDConversation/Message not found
400VALIDATION_ERRORMissing required parameters

Graceful Shutdown

Signal Handlers:

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);

async function shutdown() {
console.log('Shutting down gracefully...');

// Close Socket.IO connections
io.close(() => {
console.log('All sockets closed');
});

// Close database connection
await mongoose.connection.close();

// Exit process
process.exit(0);
}

Performance Considerations

  1. Connection Pooling: Mongoose maintains connection pool to MongoDB
  2. Redis Caching: Socket IDs cached in Redis for fast lookups
  3. Selective Population: Only populate required fields in database queries
  4. Event Batching: Multiple socket emissions batched when possible
  5. Async Processing: All socket handlers are async to prevent blocking
💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM