unknownfriend00007 commited on
Commit
94093e6
·
verified ·
1 Parent(s): 21efc4c

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +106 -8
server.js CHANGED
@@ -76,7 +76,7 @@ app.use((err, req, res, next) => {
76
 
77
  // --- API KEY AUTHENTICATION MIDDLEWARE ---
78
  app.use((req, res, next) => {
79
- if (req.path === '/' || req.path === '/health') {
80
  return next();
81
  }
82
 
@@ -265,37 +265,80 @@ async function resolveChatflowId(instanceNum, botName) {
265
  return { id: match.id, instance };
266
  }
267
 
268
- // --- STREAMING HANDLER ---
269
  async function handleStreamingResponse(flowiseResponse, clientRes) {
270
  clientRes.setHeader('Content-Type', 'text/event-stream');
271
  clientRes.setHeader('Cache-Control', 'no-cache');
272
  clientRes.setHeader('Connection', 'keep-alive');
 
273
 
274
  console.log('[Streaming] Forwarding SSE stream...');
275
 
276
  let streamStarted = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
  flowiseResponse.body.on('data', (chunk) => {
 
279
  streamStarted = true;
 
 
 
 
 
280
  clientRes.write(chunk);
281
  });
282
 
283
  flowiseResponse.body.on('end', () => {
284
- console.log('[Streaming] Stream completed');
 
 
 
 
 
 
 
285
  clientRes.end();
286
  });
287
 
288
  flowiseResponse.body.on('error', (err) => {
 
289
  console.error('[Streaming Error]', err.message);
290
 
291
- if (streamStarted) {
292
  clientRes.write(`\n\nevent: error\ndata: {"error": "Stream interrupted"}\n\n`);
 
 
293
  }
294
  clientRes.end();
295
  });
296
  }
297
 
298
- // --- ROUTES ---
299
  app.post('/api/v1/prediction/:instanceNum/:botName', async (req, res) => {
300
  try {
301
  const instanceNum = parseInt(req.params.instanceNum);
@@ -322,6 +365,10 @@ app.post('/api/v1/prediction/:instanceNum/:botName', async (req, res) => {
322
  headers['Authorization'] = `Bearer ${instance.key}`;
323
  }
324
 
 
 
 
 
325
  const response = await fetchWithTimeout(
326
  `${instance.url}/api/v1/prediction/${id}`,
327
  {
@@ -329,9 +376,12 @@ app.post('/api/v1/prediction/:instanceNum/:botName', async (req, res) => {
329
  headers,
330
  body: JSON.stringify(req.body)
331
  },
332
- 30000
333
  );
334
 
 
 
 
335
  if (!response.ok) {
336
  const errorText = await response.text();
337
  console.error(`[Error] Instance returned ${response.status}: ${errorText.substring(0, 200)}`);
@@ -368,6 +418,7 @@ app.post('/api/v1/prediction/:instanceNum/:botName', async (req, res) => {
368
  }
369
  });
370
 
 
371
  app.get('/api/v1/public-chatbotConfig/:instanceNum/:botName', async (req, res) => {
372
  try {
373
  const instanceNum = parseInt(req.params.instanceNum);
@@ -399,6 +450,7 @@ app.get('/api/v1/public-chatbotConfig/:instanceNum/:botName', async (req, res) =
399
  }
400
  });
401
 
 
402
  app.get('/api/v1/chatflows-streaming/:instanceNum/:botName', async (req, res) => {
403
  try {
404
  const instanceNum = parseInt(req.params.instanceNum);
@@ -430,6 +482,43 @@ app.get('/api/v1/chatflows-streaming/:instanceNum/:botName', async (req, res) =>
430
  }
431
  });
432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  app.get('/', (req, res) => res.send('Federated Proxy Active'));
434
 
435
  app.get('/health', (req, res) => {
@@ -438,21 +527,30 @@ app.get('/health', (req, res) => {
438
  instances: INSTANCES.length,
439
  cached_bots: flowCache.size,
440
  daily_active_ips: dailyUsage.size,
441
- uptime: process.uptime()
 
442
  });
443
  });
444
 
 
445
  app.use((req, res) => {
446
  res.status(404).json({ error: 'Route not found' });
447
  });
448
 
 
449
  app.use((err, req, res, next) => {
450
  console.error('[Error] Unhandled error:', err);
451
  res.status(500).json({ error: 'Internal server error' });
452
  });
453
 
 
454
  const server = app.listen(7860, '0.0.0.0', () => {
455
- console.log('Federated Proxy running on port 7860');
 
 
 
 
 
456
  });
457
 
458
  process.on('SIGTERM', () => {
 
76
 
77
  // --- API KEY AUTHENTICATION MIDDLEWARE ---
78
  app.use((req, res, next) => {
79
+ if (req.path === '/' || req.path === '/health' || req.path.startsWith('/test-')) {
80
  return next();
81
  }
82
 
 
265
  return { id: match.id, instance };
266
  }
267
 
268
+ // --- IMPROVED STREAMING HANDLER WITH TIMEOUT ---
269
  async function handleStreamingResponse(flowiseResponse, clientRes) {
270
  clientRes.setHeader('Content-Type', 'text/event-stream');
271
  clientRes.setHeader('Cache-Control', 'no-cache');
272
  clientRes.setHeader('Connection', 'keep-alive');
273
+ clientRes.setHeader('X-Accel-Buffering', 'no');
274
 
275
  console.log('[Streaming] Forwarding SSE stream...');
276
 
277
  let streamStarted = false;
278
+ let dataReceived = false;
279
+ let lastDataTime = Date.now();
280
+ let totalBytes = 0;
281
+
282
+ // Check for stream timeout every 5 seconds
283
+ const timeoutCheck = setInterval(() => {
284
+ const timeSinceData = Date.now() - lastDataTime;
285
+
286
+ if (timeSinceData > 45000) { // 45 seconds without data
287
+ console.error(`[Streaming] Timeout - no data for ${(timeSinceData/1000).toFixed(1)}s`);
288
+ clearInterval(timeoutCheck);
289
+
290
+ if (!dataReceived) {
291
+ console.error('[Streaming] Stream completed with NO data received!');
292
+ if (!streamStarted) {
293
+ clientRes.status(504).json({
294
+ error: 'Gateway timeout',
295
+ message: 'No response from chatbot within 45 seconds'
296
+ });
297
+ } else {
298
+ clientRes.write('\n\nevent: error\ndata: {"error": "Response timeout - no data received"}\n\n');
299
+ }
300
+ }
301
+ clientRes.end();
302
+ }
303
+ }, 5000);
304
 
305
  flowiseResponse.body.on('data', (chunk) => {
306
+ clearTimeout(timeoutCheck);
307
  streamStarted = true;
308
+ dataReceived = true;
309
+ lastDataTime = Date.now();
310
+ totalBytes += chunk.length;
311
+
312
+ console.log(`[Streaming] Received chunk: ${chunk.length} bytes (total: ${totalBytes})`);
313
  clientRes.write(chunk);
314
  });
315
 
316
  flowiseResponse.body.on('end', () => {
317
+ clearInterval(timeoutCheck);
318
+
319
+ if (dataReceived) {
320
+ console.log(`[Streaming] Stream completed successfully - ${totalBytes} bytes total`);
321
+ } else {
322
+ console.warn('[Streaming] Stream completed but NO data was received!');
323
+ }
324
+
325
  clientRes.end();
326
  });
327
 
328
  flowiseResponse.body.on('error', (err) => {
329
+ clearInterval(timeoutCheck);
330
  console.error('[Streaming Error]', err.message);
331
 
332
+ if (streamStarted && dataReceived) {
333
  clientRes.write(`\n\nevent: error\ndata: {"error": "Stream interrupted"}\n\n`);
334
+ } else if (!streamStarted) {
335
+ clientRes.status(500).json({ error: 'Stream failed to start' });
336
  }
337
  clientRes.end();
338
  });
339
  }
340
 
341
+ // --- ROUTE 1: PREDICTION (WITH IMPROVED TIMEOUT) ---
342
  app.post('/api/v1/prediction/:instanceNum/:botName', async (req, res) => {
343
  try {
344
  const instanceNum = parseInt(req.params.instanceNum);
 
365
  headers['Authorization'] = `Bearer ${instance.key}`;
366
  }
367
 
368
+ // TIMING: Track how long Flowise takes
369
+ const startTime = Date.now();
370
+ console.log(`[Timing] Calling Flowise at ${new Date().toISOString()}`);
371
+
372
  const response = await fetchWithTimeout(
373
  `${instance.url}/api/v1/prediction/${id}`,
374
  {
 
376
  headers,
377
  body: JSON.stringify(req.body)
378
  },
379
+ 60000 // ← INCREASED TO 60 SECONDS
380
  );
381
 
382
+ const duration = Date.now() - startTime;
383
+ console.log(`[Timing] Flowise responded in ${duration}ms (${(duration/1000).toFixed(1)}s)`);
384
+
385
  if (!response.ok) {
386
  const errorText = await response.text();
387
  console.error(`[Error] Instance returned ${response.status}: ${errorText.substring(0, 200)}`);
 
418
  }
419
  });
420
 
421
+ // --- ROUTE 2: CHATBOT CONFIG ---
422
  app.get('/api/v1/public-chatbotConfig/:instanceNum/:botName', async (req, res) => {
423
  try {
424
  const instanceNum = parseInt(req.params.instanceNum);
 
450
  }
451
  });
452
 
453
+ // --- ROUTE 3: STREAMING CHECK ---
454
  app.get('/api/v1/chatflows-streaming/:instanceNum/:botName', async (req, res) => {
455
  try {
456
  const instanceNum = parseInt(req.params.instanceNum);
 
482
  }
483
  });
484
 
485
+ // --- TEST ENDPOINT: Stream Test ---
486
+ app.get('/test-stream', (req, res) => {
487
+ res.setHeader('Content-Type', 'text/event-stream');
488
+ res.setHeader('Cache-Control', 'no-cache');
489
+ res.setHeader('Connection', 'keep-alive');
490
+
491
+ let count = 0;
492
+ const interval = setInterval(() => {
493
+ count++;
494
+ res.write(`data: {"message": "Test chunk ${count}", "timestamp": "${new Date().toISOString()}"}\n\n`);
495
+
496
+ if (count >= 5) {
497
+ clearInterval(interval);
498
+ res.write('data: {"message": "Test complete"}\n\n');
499
+ res.end();
500
+ }
501
+ }, 500);
502
+ });
503
+
504
+ // --- TEST ENDPOINT: Delay Test ---
505
+ app.post('/test-delay', async (req, res) => {
506
+ const start = Date.now();
507
+ const delaySeconds = req.body.delay || 35;
508
+
509
+ console.log(`[Test] Starting ${delaySeconds}s delay test...`);
510
+ await new Promise(resolve => setTimeout(resolve, delaySeconds * 1000));
511
+
512
+ const duration = Date.now() - start;
513
+ res.json({
514
+ message: 'Test completed',
515
+ duration_ms: duration,
516
+ duration_sec: (duration/1000).toFixed(1),
517
+ requested_delay: delaySeconds
518
+ });
519
+ });
520
+
521
+ // --- HEALTH CHECK ---
522
  app.get('/', (req, res) => res.send('Federated Proxy Active'));
523
 
524
  app.get('/health', (req, res) => {
 
527
  instances: INSTANCES.length,
528
  cached_bots: flowCache.size,
529
  daily_active_ips: dailyUsage.size,
530
+ uptime: process.uptime(),
531
+ memory: process.memoryUsage()
532
  });
533
  });
534
 
535
+ // --- 404 HANDLER ---
536
  app.use((req, res) => {
537
  res.status(404).json({ error: 'Route not found' });
538
  });
539
 
540
+ // --- GLOBAL ERROR HANDLER ---
541
  app.use((err, req, res, next) => {
542
  console.error('[Error] Unhandled error:', err);
543
  res.status(500).json({ error: 'Internal server error' });
544
  });
545
 
546
+ // --- GRACEFUL SHUTDOWN ---
547
  const server = app.listen(7860, '0.0.0.0', () => {
548
+ console.log('===== Federated Proxy Started =====');
549
+ console.log('Port: 7860');
550
+ console.log(`Instances: ${INSTANCES.length}`);
551
+ console.log(`Allowed Origins: ${allowedOrigins.length || 'Open mode'}`);
552
+ console.log(`API Keys: ${API_KEYS.length || 'None'}`);
553
+ console.log('====================================');
554
  });
555
 
556
  process.on('SIGTERM', () => {