-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
200 lines (177 loc) · 7.27 KB
/
Copy pathserver.js
File metadata and controls
200 lines (177 loc) · 7.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
require('dotenv').config();
const express = require('express');
const http = require('http');
const session = require('express-session');
const cors = require('cors'); // Add CORS support
const passport = require('./config/passport');
const { GoogleGenerativeAI } = require('@google/generative-ai');
const { setupMultiplayer } = require('./multiplayer');
const { setupDebugMarathon } = require('./multiplayer/debugMarathon');
const { generateDSAValidationPrompt } = require('./utils/dsaProblemGenerator');
const app = express();
const server = http.createServer(app);
const connectDB = require('./config/database');
const path = require('path');
const authenticateToken = require('./middleware/auth');
const debugMarathonRoute = require('./routes/debugMarathon');
// Enable CORS for all routes - especially important for Render deployment
const allowedOrigins = process.env.NODE_ENV === 'production'
? [
'https://debug-arena.onrender.com', // Your Render domain
process.env.ALLOWED_ORIGIN || '', // Custom domain if applicable
...((process.env.ADDITIONAL_ALLOWED_ORIGINS || '').split(',').filter(Boolean))
].filter(Boolean) // Remove any empty strings
: [
'http://localhost:3000',
'http://localhost:3001',
'http://localhost:8080',
'http://127.0.0.1:3000',
'http://127.0.0.1:3001',
'http://127.0.0.1:8080'
];
const corsOptions = {
origin: allowedOrigins,
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
app.use(express.json()); // <-- Ensure this is at the very top
app.use(express.static('public'));
// Session and Passport setup
app.use(session({
secret: process.env.SESSION_SECRET || 'debugarena_session_secret',
resave: false,
saveUninitialized: false,
}));
app.use(passport.initialize());
app.use(passport.session());
// Connect to MongoDB
connectDB();
const authRoutes = require('./routes/auth');
const passwordResetRoutes = require('./routes/passwordReset');
const profileRoutes = require('./routes/profile');
const historyRoutes = require('./routes/history');
const contactRoutes = require('./routes/contact');
app.use('/api/auth', authRoutes);
app.use('/api/password', passwordResetRoutes);
app.use('/api/profile', profileRoutes);
app.use('/api/history', historyRoutes);
app.use('/api/contact', contactRoutes);
app.use('/debug-marathon', debugMarathonRoute);
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
// Test Gemini API connection
async function testGeminiConnection() {
try {
console.log('🧪 Testing Gemini API connection...');
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
const result = await model.generateContent("Say 'Hello' if you can read this.");
const response = await result.response;
console.log('✅ Gemini API connection successful:', response.text().trim());
} catch (error) {
console.error('❌ Gemini API connection failed:', error.message);
console.error('Make sure GEMINI_API_KEY is set correctly in your .env file');
}
}
// Test the connection on startup
testGeminiConnection();
// Serve home.html as the landing page, only if authenticated
app.get('/', (req, res) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
const jwt = require('jsonwebtoken');
if (!token) {
return res.redirect('/login.html');
}
jwt.verify(token, process.env.JWT_SECRET || 'debugarena_secret', (err, user) => {
if (err) return res.redirect('/login.html');
// Authenticated, serve home.html
res.sendFile(path.join(__dirname, 'public', 'home.html'));
});
});
// Redirect /index.html to /playground.html for backward compatibility
app.get('/index.html', (req, res) => {
res.redirect('/playground.html');
});
// Serve profile page
app.get('/profile', (req, res) => {
res.redirect('/profile.html');
});
// Serve playground.html only if authenticated
app.get('/playground.html', (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
const jwt = require('jsonwebtoken');
if (!token) {
return res.redirect('/login.html');
}
jwt.verify(token, process.env.JWT_SECRET || 'debugarena_secret', (err, user) => {
if (err) return res.redirect('/login.html');
// Authenticated, serve playground.html
res.sendFile(path.join(__dirname, 'public', 'playground.html'));
});
});
// Serve profile.html only if authenticated
app.get('/profile.html', (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
const jwt = require('jsonwebtoken');
if (!token) {
return res.redirect('/login.html');
}
jwt.verify(token, process.env.JWT_SECRET || 'debugarena_secret', (err, user) => {
if (err) return res.redirect('/login.html');
// Authenticated, serve profile.html
res.sendFile(path.join(__dirname, 'public', 'profile.html'));
});
});
// Serve developer.html (about page) - no authentication required
app.get('/developer.html', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'developer.html'));
});
// Generate Java buggy code
app.get('/generate-buggy', async (req, res) => {
try {
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
const prompt = `
Generate a buggy Java function (15-25 lines) focused on Data Structures and Algorithms.
Focus on basic DSA concepts: array manipulation, simple string operations, basic math operations, or elementary sorting/searching. Examples: finding max/min in array, counting elements, simple string reversal, basic arithmetic with arrays.
Make the bug simple and obvious - like off-by-one errors, wrong operators, or basic logic mistakes.
CRITICAL: DO NOT include ANY comments, explanations, bug descriptions, or hints. The code should contain bugs but NO comments whatsoever.
Return ONLY the pure Java code with no comments at all.
`;
const result = await model.generateContent(prompt);
const response = await result.response;
const buggyCode = response.text().replace(/```(?:java)?|```/g, "").trim();
res.json({ buggyCode });
} catch (err) {
console.error("Buggy code generation failed:", err);
res.status(500).json({ error: "Could not generate buggy code" });
}
});
// Validate user fix
app.post('/validate', async (req, res) => {
const { buggyCode, userCode, language = 'java' } = req.body;
try {
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
// Use the new DSA-focused validation prompt
const prompt = generateDSAValidationPrompt(buggyCode, userCode, language);
const result = await model.generateContent(prompt);
const response = await result.response;
const answer = response.text().trim().toUpperCase();
res.json({ correct: answer === "YES" });
} catch (err) {
console.error("Validation error:", err);
res.status(500).json({ error: "Validation failed" });
}
});
// Multiplayer logic
console.log("🎮 Setting up multiplayer...");
setupMultiplayer(server, genAI);
console.log("🏁 Setting up debug marathon...");
setupDebugMarathon(server, genAI);
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`🟢 Server running on port ${PORT}`);
console.log("🔌 Socket.IO server initialized");
console.log("🎮 Multiplayer setup complete");
});