Spaces:
Running
Running
Update server.js
Browse files
server.js
CHANGED
@@ -13,51 +13,89 @@ const openaiKey = process.env.OPENAI_KEY;
|
|
13 |
const port = 7860;
|
14 |
const baseUrl = getExternalUrl(process.env.SPACE_ID);
|
15 |
|
16 |
-
let requestDetails = [];
|
17 |
-
let
|
18 |
|
19 |
io.on('connection', (socket) => {
|
20 |
console.log('A user connected to the websocket for live logs.');
|
21 |
});
|
22 |
|
23 |
-
function logAndEmit(message) {
|
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 |
}, proxy(targetUrl, {
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
}));
|
56 |
|
57 |
app.get("/", (req, res) => {
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
});
|
62 |
|
63 |
app.get('/logs', (req, res) => {
|
@@ -74,5 +112,6 @@ function getExternalUrl(spaceId) {
|
|
74 |
}
|
75 |
|
76 |
server.listen(port, () => {
|
77 |
-
|
|
|
78 |
});
|
|
|
13 |
const port = 7860;
|
14 |
const baseUrl = getExternalUrl(process.env.SPACE_ID);
|
15 |
|
16 |
+
let requestDetails = [];
|
17 |
+
let apiKeyDetails = {}; // Track API key usage and first use timestamp
|
18 |
|
19 |
io.on('connection', (socket) => {
|
20 |
console.log('A user connected to the websocket for live logs.');
|
21 |
});
|
22 |
|
23 |
+
function logAndEmit(message, includeTotal = false) {
|
24 |
+
if (includeTotal) {
|
25 |
+
const totalRequests = getTotalRequests();
|
26 |
+
message += ` Total requests so far: ${totalRequests}`;
|
27 |
+
}
|
28 |
+
console.log(message);
|
29 |
+
io.emit('log', message);
|
30 |
}
|
31 |
|
32 |
+
function getTotalRequests() {
|
33 |
+
return Object.values(apiKeyDetails).reduce((acc, details) => acc + details.count, 0);
|
34 |
+
}
|
35 |
+
|
36 |
+
function authenticateApiKey(req, res, next) {
|
37 |
+
const receivedApiKey = req.headers['authorization'];
|
38 |
+
if (!receivedApiKey) {
|
39 |
+
return res.status(401).send('Unauthorized: No API key provided');
|
40 |
+
}
|
41 |
+
|
42 |
+
const validApiKeys = (process.env.SECRET_API_KEYS || '').split(',');
|
43 |
+
const apiKeyMatch = validApiKeys.find(key => `Bearer ${key.trim()}` === receivedApiKey);
|
44 |
|
45 |
+
if (!apiKeyMatch) {
|
46 |
+
return res.status(401).send('Unauthorized: API key is invalid');
|
47 |
+
}
|
48 |
+
|
49 |
+
const displayKey = apiKeyMatch.trim().substring(0, 7); // Only use the first four characters for display
|
50 |
+
|
51 |
+
if (!apiKeyDetails[apiKeyMatch]) {
|
52 |
+
apiKeyDetails[apiKeyMatch] = {
|
53 |
+
count: 0,
|
54 |
+
firstUse: moment() // Set the first use to now if it's not already set
|
55 |
+
};
|
56 |
+
}
|
57 |
+
|
58 |
+
// Check if more than a week has passed since the first use
|
59 |
+
if (moment().diff(apiKeyDetails[apiKeyMatch].firstUse, 'weeks') >= 1) {
|
60 |
+
return res.status(429).send(`API Key ${displayKey}... is blocked after one week of use.`);
|
61 |
+
}
|
62 |
|
63 |
+
// Increment the request count
|
64 |
+
apiKeyDetails[apiKeyMatch].count++;
|
65 |
+
|
66 |
+
const logMessage = `API Key ${displayKey}... used ${apiKeyDetails[apiKeyMatch].count} times so far.`;
|
67 |
+
logAndEmit(logMessage, true);
|
68 |
+
|
69 |
+
req.apiKey = apiKeyMatch; // Store the API key for the request
|
70 |
+
next();
|
71 |
+
}
|
72 |
+
|
73 |
+
app.use('/api', authenticateApiKey, (req, res, next) => {
|
74 |
+
const timestamp = moment().tz("Asia/Tbilisi").format("DD-MMM-YYYY HH:mm");
|
75 |
+
const displayKey = req.apiKey.substring(0, 4);
|
76 |
+
const requestData = {
|
77 |
+
requestNumber: apiKeyDetails[req.apiKey].count,
|
78 |
+
apiKey: displayKey,
|
79 |
+
timestamp: timestamp,
|
80 |
+
text: req.method + ' ' + req.url
|
81 |
+
};
|
82 |
+
requestDetails.push(requestData);
|
83 |
+
|
84 |
+
const detailedLog = `Request ${requestData.requestNumber} on ${requestData.timestamp} from API Key ${displayKey}... with method "${req.method}" and text "${requestData.text}"`;
|
85 |
+
logAndEmit(detailedLog, true);
|
86 |
+
|
87 |
+
next();
|
88 |
}, proxy(targetUrl, {
|
89 |
+
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
|
90 |
+
proxyReqOpts.headers['Authorization'] = 'Bearer ' + openaiKey;
|
91 |
+
return proxyReqOpts;
|
92 |
+
}
|
93 |
}));
|
94 |
|
95 |
app.get("/", (req, res) => {
|
96 |
+
let requestsInfo = requestDetails.map(detail =>
|
97 |
+
`Request ${detail.requestNumber} on ${detail.timestamp} from API Key ${detail.apiKey}... with text "${detail.text}"`).join('<br>');
|
98 |
+
res.send(`This is your OpenAI Reverse Proxy URL: ${baseUrl}.<br><br>Requests Overview:<br>${requestsInfo}`);
|
99 |
});
|
100 |
|
101 |
app.get('/logs', (req, res) => {
|
|
|
112 |
}
|
113 |
|
114 |
server.listen(port, () => {
|
115 |
+
const message = `Reverse proxy server and WebSocket running on port ${port}`;
|
116 |
+
logAndEmit(message, true); // true to include total requests in the log
|
117 |
});
|