Trigger82 commited on
Commit
60f5fc7
Β·
verified Β·
1 Parent(s): 8d2ebba

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +167 -190
server.js CHANGED
@@ -5,225 +5,202 @@ const path = require('path');
5
  const app = express();
6
  const http = require('http').createServer(app);
7
  const io = require('socket.io')(http, {
8
- cors: {
9
- origin: "*",
10
- methods: ["GET", "POST"]
11
- }
12
  });
13
  const crypto = require('crypto');
14
- const fetch = require('node-fetch');
15
 
16
- // Connect to MongoDB
17
  const MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017";
18
  let db;
19
 
20
  async function connectDB() {
21
- try {
22
- const client = new MongoClient(MONGO_URI);
23
- await client.connect();
24
- db = client.db('whatsapp-bots');
25
- console.log("βœ… Connected to MongoDB");
26
-
27
- // Create collections if they don't exist
28
- const collections = ['users', 'bots', 'settings'];
29
- for (const colName of collections) {
30
- if (!(await db.listCollections({name: colName}).hasNext())) {
31
- await db.createCollection(colName);
32
- console.log(`Created collection: ${colName}`);
33
- }
34
- }
35
-
36
- // Create admin user if not exists
37
- const adminExists = await db.collection('users').findOne({username: 'admin'});
38
- if (!adminExists) {
39
- await db.collection('users').insertOne({
40
- username: 'admin',
41
- password: crypto.createHash('sha256').update('admin2008').digest('hex'),
42
- isAdmin: true,
43
- createdAt: new Date()
44
- });
45
- console.log("πŸ‘‘ Created admin user (password: admin123)");
46
- }
47
-
48
- // Restart all bots that were running
49
- const runningBots = await db.collection('bots').find({status: 'running'}).toArray();
50
- runningBots.forEach(bot => {
51
- startBotProcess(bot.userId, bot.repoUrl, bot.entryFile);
52
- });
53
- } catch (err) {
54
- console.error("❌ MongoDB connection error:", err);
55
- }
56
- }
57
-
58
- // Start a bot process
59
- function startBotProcess(userId, repoUrl, entryFile) {
60
- const botDir = `/persistent/storage/${userId}`;
61
-
62
- // Clone repo if not exists
63
- if (!require('fs').existsSync(botDir)) {
64
- const clone = spawn('git', ['clone', repoUrl, botDir]);
65
- clone.on('close', (code) => {
66
- if (code === 0) {
67
- console.log(`βœ… Cloned ${repoUrl} for user ${userId}`);
68
- installDependencies(botDir, userId, repoUrl, entryFile);
69
- } else {
70
- console.error(`❌ Failed to clone ${repoUrl} for user ${userId}`);
71
- }
72
- });
73
- } else {
74
- installDependencies(botDir, userId, repoUrl, entryFile);
75
- }
76
- }
77
-
78
- function installDependencies(botDir, userId, repoUrl, entryFile) {
79
- const install = spawn('npm', ['install'], { cwd: botDir });
80
- install.on('close', (code) => {
81
- if (code === 0) {
82
- console.log(`βœ… Installed dependencies for ${userId}`);
83
- runBot(botDir, userId, repoUrl, entryFile);
84
- } else {
85
- console.error(`❌ Failed to install dependencies for ${userId}`);
86
  }
87
- });
88
  }
89
 
90
- function runBot(botDir, userId, repoUrl, entryFile) {
91
- const botProcess = spawn('node', [entryFile], {
92
- cwd: botDir,
93
- stdio: ['pipe', 'pipe', 'pipe', 'ipc']
94
- });
95
-
96
- // Save to database
97
- db.collection('bots').updateOne(
98
- { userId },
99
- { $set: {
100
- status: 'running',
101
- repoUrl,
102
- entryFile,
103
- startedAt: new Date(),
104
- pid: botProcess.pid
105
- }},
106
- { upsert: true }
107
- );
108
-
109
- botProcess.stdout.on('data', (data) => {
110
- io.to(userId).emit('bot-output', data.toString());
111
- });
112
-
113
- botProcess.stderr.on('data', (data) => {
114
- io.to(userId).emit('bot-error', data.toString());
115
- });
116
-
117
- botProcess.on('close', (code) => {
118
- console.log(`Bot ${userId} exited with code ${code}`);
119
- db.collection('bots').updateOne(
120
- { userId },
121
- { $set: { status: 'stopped', exitCode: code } }
122
- );
123
- });
124
  }
125
 
126
- // Web server setup
127
- app.use(express.static('public'));
128
- app.use(express.json());
129
-
130
- // API endpoints
131
- app.post('/api/deploy', async (req, res) => {
132
- const { userId, repoUrl, entryFile } = req.body;
133
-
134
- if (!userId || !repoUrl || !entryFile) {
135
- return res.status(400).json({ error: "Missing parameters" });
136
- }
137
-
138
- try {
139
- startBotProcess(userId, repoUrl, entryFile);
140
- res.json({ success: true, message: "Bot deployment started" });
141
- } catch (err) {
142
- res.status(500).json({ error: err.message });
143
- }
144
- });
145
-
146
  // Socket.IO
147
  io.on('connection', (socket) => {
148
- console.log(`User connected: ${socket.id}`);
149
-
150
- socket.on('register', async (data) => {
151
- const { username, password } = data;
152
- const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
153
 
154
- try {
155
- await db.collection('users').insertOne({
156
- username,
157
- password: hashedPassword,
158
- createdAt: new Date()
159
- });
160
- socket.emit('register-success');
161
- } catch (err) {
162
- socket.emit('register-error', 'Username already exists');
163
- }
164
- });
165
-
166
- socket.on('login', async (data) => {
167
- const { username, password } = data;
168
- const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
169
 
170
- const user = await db.collection('users').findOne({
171
- username,
172
- password: hashedPassword
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  });
174
 
175
- if (user) {
176
- socket.emit('login-success', { userId: user._id.toString(), isAdmin: user.isAdmin });
177
- socket.join(user._id.toString());
178
- } else {
179
- socket.emit('login-error', 'Invalid credentials');
180
- }
181
- });
182
-
183
- socket.on('deploy-bot', (data) => {
184
- const { userId, repoUrl, entryFile } = data;
185
- startBotProcess(userId, repoUrl, entryFile);
186
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  });
188
 
189
- // Add this to your Socket.IO setup
190
- io.on('connection', (socket) => {
191
- console.log(`New connection: ${socket.id}`);
192
-
193
- // Force terminal to be visible
194
- socket.emit('terminal-init', {
195
- ready: true,
196
- timestamp: Date.now()
197
- });
198
 
199
- // New event to force terminal visibility
200
- socket.on('force-terminal-visible', () => {
201
- socket.emit('terminal-output', 'Terminal session activated\n');
202
- socket.emit('terminal-output', 'Ready for commands\n');
 
203
  });
 
204
 
205
-
206
- // Add this error handling middleware
207
  app.use((err, req, res, next) => {
208
  console.error('Global error:', err);
209
- io.emit('terminal-output', `ERROR: ${err.message}\n`);
210
- next();
211
- });
212
  });
 
213
  // Start server
214
  const PORT = process.env.PORT || 7860;
215
  connectDB().then(() => {
216
- http.listen(PORT, () => {
217
- console.log(`πŸš€ Server running on port ${PORT}`);
218
- console.log(`🌐 Open: http://localhost:${PORT}`);
219
- });
 
 
 
 
 
220
  });
221
 
222
- // Error handling
223
- process.on('uncaughtException', (err) => {
224
- console.error('Uncaught Exception:', err);
225
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
- process.on('unhandledRejection', (reason, promise) => {
228
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
229
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  const app = express();
6
  const http = require('http').createServer(app);
7
  const io = require('socket.io')(http, {
8
+ cors: {
9
+ origin: "*",
10
+ methods: ["GET", "POST"]
11
+ }
12
  });
13
  const crypto = require('crypto');
14
+ const fs = require('fs');
15
 
16
+ // MongoDB Connection
17
  const MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017";
18
  let db;
19
 
20
  async function connectDB() {
21
+ try {
22
+ const client = new MongoClient(MONGO_URI);
23
+ await client.connect();
24
+ db = client.db('whatsapp-bots');
25
+ console.log("βœ… Connected to MongoDB");
26
+
27
+ // Initialize collections
28
+ const collections = ['users', 'bots', 'sessions'];
29
+ for (const colName of collections) {
30
+ if (!(await db.listCollections({ name: colName }).hasNext()) {
31
+ await db.createCollection(colName);
32
+ console.log(`Created collection: ${colName}`);
33
+ }
34
+ }
35
+
36
+ // Create admin user if not exists
37
+ const adminExists = await db.collection('users').findOne({ username: 'admin' });
38
+ if (!adminExists) {
39
+ await db.collection('users').insertOne({
40
+ username: 'admin',
41
+ password: hashPassword('admin123'),
42
+ isAdmin: true,
43
+ createdAt: new Date()
44
+ });
45
+ console.log("πŸ‘‘ Created admin user (password: admin123)");
46
+ }
47
+ } catch (err) {
48
+ console.error("❌ MongoDB connection error:", err);
49
+ process.exit(1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
 
51
  }
52
 
53
+ function hashPassword(password) {
54
+ return crypto
55
+ .createHash('sha256')
56
+ .update(password + (process.env.PEPPER || 'defaultPepper'))
57
+ .digest('hex');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  // Socket.IO
61
  io.on('connection', (socket) => {
62
+ console.log(`New connection: ${socket.id}`);
 
 
 
 
63
 
64
+ // Force terminal initialization
65
+ socket.emit('terminal-init', {
66
+ status: 'ready',
67
+ timestamp: Date.now()
68
+ });
 
 
 
 
 
 
 
 
 
 
69
 
70
+ // Terminal command handler
71
+ socket.on('terminal-command', async (data) => {
72
+ try {
73
+ const { command, userId } = data;
74
+ console.log(`Command from ${userId}: ${command}`);
75
+
76
+ // Execute command in user's directory
77
+ const userDir = `/persistent/storage/${userId}`;
78
+ const child = spawn(command.split(' ')[0], command.split(' ').slice(1), {
79
+ cwd: userDir
80
+ });
81
+
82
+ child.stdout.on('data', (data) => {
83
+ socket.emit('terminal-output', data.toString());
84
+ });
85
+
86
+ child.stderr.on('data', (data) => {
87
+ socket.emit('terminal-output', `ERROR: ${data.toString()}`);
88
+ });
89
+
90
+ child.on('close', (code) => {
91
+ socket.emit('terminal-output', `Process exited with code ${code}\n`);
92
+ });
93
+ } catch (err) {
94
+ socket.emit('terminal-output', `ERROR: ${err.message}\n`);
95
+ }
96
  });
97
 
98
+ // Authentication handlers
99
+ socket.on('login', async (data) => {
100
+ try {
101
+ const { username, password } = data;
102
+ const user = await db.collection('users').findOne({
103
+ username,
104
+ password: hashPassword(password)
105
+ });
106
+
107
+ if (user) {
108
+ currentUser = user._id.toString();
109
+ socket.emit('login-success', {
110
+ userId: currentUser,
111
+ isAdmin: user.isAdmin
112
+ });
113
+
114
+ // Ensure user directory exists
115
+ const userDir = `/persistent/storage/${currentUser}`;
116
+ if (!fs.existsSync(userDir)) {
117
+ fs.mkdirSync(userDir, { recursive: true });
118
+ }
119
+ } else {
120
+ socket.emit('login-error', 'Invalid credentials');
121
+ }
122
+ } catch (err) {
123
+ socket.emit('login-error', 'Authentication failed');
124
+ }
125
+ });
126
  });
127
 
128
+ // Express middleware
129
+ app.use(express.static('public'));
130
+ app.use(express.json());
 
 
 
 
 
 
131
 
132
+ // Health check endpoint
133
+ app.get('/health', (req, res) => {
134
+ res.status(200).json({
135
+ status: 'healthy',
136
+ timestamp: Date.now()
137
  });
138
+ });
139
 
140
+ // Error handling
 
141
  app.use((err, req, res, next) => {
142
  console.error('Global error:', err);
143
+ io.emit('terminal-output', `SYSTEM ERROR: ${err.message}\n`);
144
+ res.status(500).json({ error: err.message });
 
145
  });
146
+
147
  // Start server
148
  const PORT = process.env.PORT || 7860;
149
  connectDB().then(() => {
150
+ http.listen(PORT, () => {
151
+ console.log(`πŸš€ Server running on port ${PORT}`);
152
+
153
+ // Restart any previously running bots
154
+ db.collection('bots').find({ status: 'running' }).forEach(bot => {
155
+ console.log(`Restarting bot for user ${bot.userId}`);
156
+ startBotProcess(bot.userId, bot.repoUrl, bot.entryFile);
157
+ });
158
+ });
159
  });
160
 
161
+ // Helper function to start bot processes
162
+ function startBotProcess(userId, repoUrl, entryFile) {
163
+ const botDir = `/persistent/storage/${userId}`;
164
+
165
+ // Clone repo if needed
166
+ if (!fs.existsSync(botDir)) {
167
+ const clone = spawn('git', ['clone', repoUrl, botDir]);
168
+ clone.on('close', (code) => {
169
+ if (code === 0) installDependencies(botDir, userId, repoUrl, entryFile);
170
+ });
171
+ } else {
172
+ installDependencies(botDir, userId, repoUrl, entryFile);
173
+ }
174
+ }
175
+
176
+ function installDependencies(botDir, userId, repoUrl, entryFile) {
177
+ const install = spawn('npm', ['install'], { cwd: botDir });
178
+ install.on('close', (code) => {
179
+ if (code === 0) runBot(botDir, userId, repoUrl, entryFile);
180
+ });
181
+ }
182
 
183
+ function runBot(botDir, userId, repoUrl, entryFile) {
184
+ const botProcess = spawn('node', [entryFile], { cwd: botDir });
185
+
186
+ // Save to database
187
+ db.collection('bots').updateOne(
188
+ { userId },
189
+ { $set: {
190
+ status: 'running',
191
+ repoUrl,
192
+ entryFile,
193
+ pid: botProcess.pid,
194
+ lastStarted: new Date()
195
+ }},
196
+ { upsert: true }
197
+ );
198
+
199
+ // Handle process events
200
+ botProcess.on('exit', (code) => {
201
+ db.collection('bots').updateOne(
202
+ { userId },
203
+ { $set: { status: 'stopped', exitCode: code } }
204
+ );
205
+ });
206
+ }