Trigger / server.js
Trigger82's picture
Update server.js
ddbaf47 verified
const express = require('express');
const { spawn } = require('child_process');
const { MongoClient } = require('mongodb');
const path = require('path');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
const crypto = require('crypto');
const fs = require('fs');
// MongoDB Connection
const MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017";
let db;
async function connectDB() {
try {
const client = new MongoClient(MONGO_URI);
await client.connect();
db = client.db('whatsapp-bots');
console.log("βœ… Connected to MongoDB");
// Initialize collections
const collections = ['users', 'bots', 'sessions'];
for (const colName of collections) {
if (!(await db.listCollections({ name: colName }).hasNext())) {
await db.createCollection(colName);
console.log(`Created collection: ${colName}`);
}
}
// Create admin user if not exists
const adminExists = await db.collection('users').findOne({ username: 'admin' });
if (!adminExists) {
await db.collection('users').insertOne({
username: 'admin',
password: hashPassword('admin123'),
isAdmin: true,
createdAt: new Date()
});
console.log("πŸ‘‘ Created admin user (password: admin123)");
}
} catch (err) {
console.error("❌ MongoDB connection error:", err);
process.exit(1);
}
}
function hashPassword(password) {
return crypto
.createHash('sha256')
.update(password + (process.env.PEPPER || 'defaultPepper'))
.digest('hex');
}
// Socket.IO
io.on('connection', (socket) => {
console.log(`New connection: ${socket.id}`);
// Force terminal initialization
socket.emit('terminal-init', {
status: 'ready',
timestamp: Date.now()
});
// Terminal command handler
socket.on('terminal-command', async (data) => {
try {
const { command, userId } = data;
console.log(`Command from ${userId}: ${command}`);
// Execute command in user's directory
const userDir = `/persistent/storage/${userId}`;
const child = spawn(command.split(' ')[0], command.split(' ').slice(1), {
cwd: userDir
});
child.stdout.on('data', (data) => {
socket.emit('terminal-output', data.toString());
});
child.stderr.on('data', (data) => {
socket.emit('terminal-output', `ERROR: ${data.toString()}`);
});
child.on('close', (code) => {
socket.emit('terminal-output', `Process exited with code ${code}\n`);
});
} catch (err) {
socket.emit('terminal-output', `ERROR: ${err.message}\n`);
}
});
// Authentication handlers
socket.on('login', async (data) => {
try {
const { username, password } = data;
const user = await db.collection('users').findOne({
username,
password: hashPassword(password)
});
if (user) {
currentUser = user._id.toString();
socket.emit('login-success', {
userId: currentUser,
isAdmin: user.isAdmin
});
// Ensure user directory exists
const userDir = `/persistent/storage/${currentUser}`;
if (!fs.existsSync(userDir)) {
fs.mkdirSync(userDir, { recursive: true });
}
} else {
socket.emit('login-error', 'Invalid credentials');
}
} catch (err) {
socket.emit('login-error', 'Authentication failed');
}
});
});
// Express middleware
app.use(express.static('public'));
app.use(express.json());
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
timestamp: Date.now()
});
});
// Error handling
app.use((err, req, res, next) => {
console.error('Global error:', err);
io.emit('terminal-output', `SYSTEM ERROR: ${err.message}\n`);
res.status(500).json({ error: err.message });
});
// Start server
const PORT = process.env.PORT || 7860;
connectDB().then(() => {
http.listen(PORT, () => {
console.log(`πŸš€ Server running on port ${PORT}`);
// Restart any previously running bots
db.collection('bots').find({ status: 'running' }).forEach(bot => {
console.log(`Restarting bot for user ${bot.userId}`);
startBotProcess(bot.userId, bot.repoUrl, bot.entryFile);
});
});
});
// Helper function to start bot processes
function startBotProcess(userId, repoUrl, entryFile) {
const botDir = `/persistent/storage/${userId}`;
// Clone repo if needed
if (!fs.existsSync(botDir)) {
const clone = spawn('git', ['clone', repoUrl, botDir]);
clone.on('close', (code) => {
if (code === 0) installDependencies(botDir, userId, repoUrl, entryFile);
});
} else {
installDependencies(botDir, userId, repoUrl, entryFile);
}
}
function installDependencies(botDir, userId, repoUrl, entryFile) {
const install = spawn('npm', ['install'], { cwd: botDir });
install.on('close', (code) => {
if (code === 0) runBot(botDir, userId, repoUrl, entryFile);
});
}
function runBot(botDir, userId, repoUrl, entryFile) {
const botProcess = spawn('node', [entryFile], { cwd: botDir });
// Save to database
db.collection('bots').updateOne(
{ userId },
{ $set: {
status: 'running',
repoUrl,
entryFile,
pid: botProcess.pid,
lastStarted: new Date()
}},
{ upsert: true }
);
// Handle process events
botProcess.on('exit', (code) => {
db.collection('bots').updateOne(
{ userId },
{ $set: { status: 'stopped', exitCode: code } }
);
});
}