Spaces:
Running
Running
const express = require('express'); | |
const path = require('node:path'); | |
const { WebSocketServer, WebSocket } = require('ws'); | |
const http = require('node:http'); | |
require('dotenv').config(); | |
const app = express(); | |
const server = http.createServer(app); | |
const ALLOWED_WEBSOCKET_ORIGIN = "https://www.aisada.ir"; // یا "http://www.aisada.ir"; // یا "https://aisada.ir"; // یا "http://aisada.ir" | |
const wss = new WebSocketServer({ | |
server, | |
verifyClient: (info, cb) => { | |
const origin = info.origin; | |
// --- 👇 لاگ Verify را نگه میداریم چون مهم است 👇 --- | |
console.log(`[WebSocket Verify] Verifying origin: ${origin}`); | |
if (origin === ALLOWED_WEBSOCKET_ORIGIN) { | |
console.log(`[WebSocket Verify] Origin allowed: ${origin}`); | |
cb(true); | |
} else { | |
console.warn(`[WebSocket Verify] Forbidden origin: ${origin}. Rejecting connection.`); | |
cb(false, 403, 'Forbidden Origin'); | |
} | |
} | |
}); | |
app.use(express.static(path.join(__dirname, '../build'))); | |
const GEMINI_API_KEY = process.env.GEMINI_API_KEY; | |
if (!GEMINI_API_KEY) { | |
console.error('FATAL ERROR: GEMINI_API_KEY environment variable is not set!'); | |
process.exit(1); | |
} | |
const createGeminiWebSocket = (clientWs) => { | |
const geminiWsUrl = `wss://generativelanguage.googleapis.com/v1beta/models/gemini-pro:streamGenerateContent?key=${GEMINI_API_KEY}&alt=sse`; | |
console.log(`[Gemini Connect] Attempting connection to Gemini...`); | |
const geminiWs = new WebSocket(geminiWsUrl); | |
geminiWs.on('open', () => { | |
console.log('[Gemini Connect] Connected to Gemini API'); | |
if (geminiWs.pendingSetup) { | |
// لاگ pendingSetup ممکن است حجیم باشد، خلاصهتر میکنیم | |
console.log('[Gemini Connect] Sending pending setup...'); | |
geminiWs.send(JSON.stringify(geminiWs.pendingSetup)); | |
geminiWs.pendingSetup = null; | |
} | |
}); | |
geminiWs.on('message', (data) => { | |
try { | |
// --- 👇 لاگ دریافت از Gemini حذف شد 👇 --- | |
// console.log('[Gemini Receive] Received from Gemini'); | |
if (clientWs.readyState === WebSocket.OPEN) { | |
if (Buffer.isBuffer(data)) { | |
clientWs.send(data, { binary: true }); | |
} else { | |
const blob = Buffer.from(data.toString()); | |
clientWs.send(blob, { binary: true }); | |
} | |
} | |
} catch (error) { | |
console.error('[Gemini Receive] Error handling Gemini message:', error); | |
} | |
}); | |
geminiWs.on('error', (error) => console.error('[Gemini Connect] Gemini WebSocket error:', error)); | |
geminiWs.on('close', (code, reason) => console.log('[Gemini Connect] Gemini WebSocket closed:', code, reason?.toString())); | |
return geminiWs; | |
}; | |
wss.on('connection', (ws, req) => { | |
const origin = req.headers.origin || 'N/A'; | |
console.log(`[WebSocket Event] Client connected (Origin: ${origin})`); | |
let geminiWs = null; | |
ws.on('message', async (message) => { | |
try { | |
const messageString = message.toString(); | |
const data = JSON.parse(messageString); | |
// --- 👇 لاگ دریافت از Client حذف شد 👇 --- | |
// console.log('[Client Receive] Received from client'); | |
if (data.setup) { | |
// لاگ setup را نگه میداریم چون مهم است | |
console.log('[Client Receive] Initializing Gemini connection...'); | |
geminiWs = createGeminiWebSocket(ws); | |
if (geminiWs.readyState !== WebSocket.OPEN) { | |
geminiWs.pendingSetup = data; | |
} else { | |
geminiWs.send(JSON.stringify(data)); | |
} | |
return; | |
} | |
if (geminiWs && geminiWs.readyState === WebSocket.OPEN) { | |
geminiWs.send(JSON.stringify(data)); | |
} else if (geminiWs) { | |
// لاگ انتظار را نگه میداریم | |
console.log('[Client Receive] Gemini connection not ready, waiting...'); | |
} else { | |
console.error('[Client Receive] No Gemini connection established. Closing client connection.'); | |
ws.close(1011, 'Backend connection not ready'); | |
} | |
} catch (error) { | |
console.error('[Client Receive] Error processing message:', error, message.toString().substring(0, 100) + '...'); | |
ws.close(1008, 'Message processing error'); | |
} | |
}); | |
ws.on('close', () => { | |
console.log('[WebSocket Event] Client disconnected'); | |
if (geminiWs && geminiWs.readyState !== WebSocket.CLOSED && geminiWs.readyState !== WebSocket.CLOSING) { | |
console.log('[WebSocket Event] Closing associated Gemini connection.'); | |
geminiWs.close(); | |
} | |
geminiWs = null; | |
}); | |
ws.on('error', (error) => { | |
console.error('[WebSocket Event] Client WebSocket error:', error); | |
if (geminiWs && geminiWs.readyState !== WebSocket.CLOSED && geminiWs.readyState !== WebSocket.CLOSING) { | |
console.log('[WebSocket Event] Closing associated Gemini connection due to client error.'); | |
geminiWs.close(); | |
} | |
geminiWs = null; | |
if (ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) { | |
ws.close(1011, 'Client error'); | |
} | |
}); | |
}); | |
app.get('*', (req, res) => { | |
res.sendFile(path.resolve(__dirname, '../build', 'index.html')); | |
}); | |
const PORT = process.env.PORT || 3001; | |
server.listen(PORT, () => { | |
console.log(`Server listening on port ${PORT}`); | |
console.log(`Allowed WebSocket Origin: ${ALLOWED_WEBSOCKET_ORIGIN}`); | |
}); |