Spaces:
Paused
Paused
Update server.js
Browse files
server.js
CHANGED
|
@@ -19,7 +19,7 @@ let currentTunnelUrl = ''; // Будет обновляться при запу
|
|
| 19 |
|
| 20 |
const app = express();
|
| 21 |
|
| 22 |
-
//
|
| 23 |
function formatBytes(bytes, decimals = 2) {
|
| 24 |
if (bytes === 0) return '0 Bytes';
|
| 25 |
const k = 1024;
|
|
@@ -64,14 +64,12 @@ async function cleanupOldFiles(dirPath, ttlHours) {
|
|
| 64 |
let errors = 0;
|
| 65 |
|
| 66 |
try {
|
| 67 |
-
const files = await glob(`${dirPath}/**/*`, { nodir: true, dot: true, stat: true, withFileTypes: false });
|
| 68 |
|
| 69 |
for (const file of files) {
|
| 70 |
processed++;
|
| 71 |
try {
|
| 72 |
-
|
| 73 |
-
// поэтому перепроверяем stat для каждого файла
|
| 74 |
-
const stats = await fs.stat(file); // file здесь это строка пути
|
| 75 |
if (stats.isFile()) {
|
| 76 |
const fileAge = now - stats.mtimeMs;
|
| 77 |
if (fileAge > ttlMs) {
|
|
@@ -85,8 +83,6 @@ async function cleanupOldFiles(dirPath, ttlHours) {
|
|
| 85 |
errors++;
|
| 86 |
}
|
| 87 |
}
|
| 88 |
-
// Попытка удалить пустые директории (опционально, может быть сложно и рискованно)
|
| 89 |
-
// Для простоты пока не реализуем удаление пустых директорий после очистки файлов.
|
| 90 |
} catch (globError) {
|
| 91 |
console.error(`[TTL] Error during glob search:`, globError);
|
| 92 |
return { processed, deleted, errors: errors + 1, message: `Glob error: ${globError.message}` };
|
|
@@ -97,6 +93,7 @@ async function cleanupOldFiles(dirPath, ttlHours) {
|
|
| 97 |
return result;
|
| 98 |
}
|
| 99 |
|
|
|
|
| 100 |
// --- Обновление Gist ---
|
| 101 |
async function updateEnvGistInGithub(tunnelUrlToSave) {
|
| 102 |
if (!GITHUB_USERNAME || !GITHUB_TOKEN || !ENV_GIST_ID) {
|
|
@@ -106,6 +103,10 @@ async function updateEnvGistInGithub(tunnelUrlToSave) {
|
|
| 106 |
try {
|
| 107 |
const spaceId = process.env.SPACE_ID || 'N/A';
|
| 108 |
const spaceHost = process.env.SPACE_HOST || 'N/A';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
const content = {
|
| 110 |
last_updated: new Date().toISOString(),
|
| 111 |
space_id: spaceId,
|
|
@@ -115,14 +116,17 @@ async function updateEnvGistInGithub(tunnelUrlToSave) {
|
|
| 115 |
tools_app_internal_port: EXPRESS_PORT,
|
| 116 |
files_ttl_hours: FILES_TTL_HOURS > 0 ? FILES_TTL_HOURS : 'disabled',
|
| 117 |
};
|
|
|
|
| 118 |
const gistData = {
|
| 119 |
-
description: `Hugging Face Space Info - ${spaceId}`,
|
| 120 |
files: {
|
| 121 |
-
[
|
| 122 |
content: JSON.stringify(content, null, 2),
|
| 123 |
},
|
| 124 |
},
|
| 125 |
};
|
|
|
|
|
|
|
| 126 |
const response = await fetch(`https://api.github.com/gists/${ENV_GIST_ID}`, {
|
| 127 |
method: 'PATCH',
|
| 128 |
headers: {
|
|
@@ -133,17 +137,22 @@ async function updateEnvGistInGithub(tunnelUrlToSave) {
|
|
| 133 |
},
|
| 134 |
body: JSON.stringify(gistData),
|
| 135 |
});
|
|
|
|
| 136 |
if (!response.ok) {
|
| 137 |
-
|
|
|
|
|
|
|
|
|
|
| 138 |
}
|
| 139 |
console.log(`Gist ${ENV_GIST_ID} updated successfully with tunnel URL: ${tunnelUrlToSave}`);
|
| 140 |
} catch (error) {
|
| 141 |
-
console.error('Error updating Gist:', error);
|
| 142 |
}
|
| 143 |
}
|
| 144 |
|
| 145 |
|
| 146 |
// --- Маршруты Express ---
|
|
|
|
| 147 |
app.get('/', (req, res) => {
|
| 148 |
res.send(`Telegram API Tools. Tunnel: ${currentTunnelUrl || 'pending...'}. Stats: ${currentTunnelUrl}/stats. File base: ${currentTunnelUrl}/file/`);
|
| 149 |
});
|
|
@@ -164,11 +173,10 @@ app.get('/stats', async (req, res) => {
|
|
| 164 |
|
| 165 |
app.get('/file/:filepath(*)', (req, res) => {
|
| 166 |
const relativePath = req.params.filepath;
|
| 167 |
-
if (!relativePath || relativePath.includes('..')) {
|
| 168 |
return res.status(400).send('Invalid file path.');
|
| 169 |
}
|
| 170 |
|
| 171 |
-
// Нормализуем путь и убеждаемся, что он внутри TELEGRAM_DATA_DIR
|
| 172 |
const absoluteRequestedPath = path.normalize(path.join(TELEGRAM_DATA_DIR, relativePath));
|
| 173 |
|
| 174 |
if (!absoluteRequestedPath.startsWith(path.resolve(TELEGRAM_DATA_DIR))) {
|
|
@@ -195,6 +203,7 @@ app.get('/file/:filepath(*)', (req, res) => {
|
|
| 195 |
});
|
| 196 |
|
| 197 |
// --- Запуск сервера и туннеля ---
|
|
|
|
| 198 |
app.listen(EXPRESS_PORT, () => {
|
| 199 |
console.log(`Express server (for tools) listening on port ${EXPRESS_PORT}`);
|
| 200 |
console.log(`Attempting to start localhost.run tunnel for port ${EXPRESS_PORT}...`);
|
|
@@ -205,20 +214,18 @@ app.listen(EXPRESS_PORT, () => {
|
|
| 205 |
'-o', 'UserKnownHostsFile=/dev/null',
|
| 206 |
'-o', 'ServerAliveInterval=60',
|
| 207 |
'-o', 'ExitOnForwardFailure=yes',
|
| 208 |
-
'-o', 'LogLevel=ERROR',
|
| 209 |
'nokey@localhost.run'
|
| 210 |
]);
|
| 211 |
|
| 212 |
tunnelProcess.stdout.on('data', (data) => {
|
| 213 |
const output = data.toString();
|
| 214 |
-
// Ищем URL в формате https://*.lhr.life или https://*.lhr.run
|
| 215 |
const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.(lhr\.life|lhr\.run)/);
|
| 216 |
if (urlMatch && urlMatch[0] !== currentTunnelUrl) {
|
| 217 |
currentTunnelUrl = urlMatch[0];
|
| 218 |
console.log(`>>> Tools Tunnel active: ${currentTunnelUrl}`);
|
| 219 |
updateEnvGistInGithub(currentTunnelUrl).catch(console.error);
|
| 220 |
}
|
| 221 |
-
// Выводим весь stdout для отладки, если URL не найден сразу
|
| 222 |
if (!urlMatch) {
|
| 223 |
console.log(`localhost.run stdout: ${output}`);
|
| 224 |
}
|
|
@@ -230,7 +237,7 @@ app.listen(EXPRESS_PORT, () => {
|
|
| 230 |
|
| 231 |
tunnelProcess.on('close', (code) => {
|
| 232 |
console.log(`localhost.run tunnel process exited with code ${code}`);
|
| 233 |
-
currentTunnelUrl = '';
|
| 234 |
updateEnvGistInGithub('Tunnel closed or failed.').catch(console.error);
|
| 235 |
});
|
| 236 |
|
|
@@ -240,28 +247,22 @@ app.listen(EXPRESS_PORT, () => {
|
|
| 240 |
updateEnvGistInGithub('Tunnel failed to start.').catch(console.error);
|
| 241 |
});
|
| 242 |
|
| 243 |
-
// Первоначальное обновление Gist
|
| 244 |
updateEnvGistInGithub('Tunnel URL pending...').catch(console.error);
|
| 245 |
|
| 246 |
-
// Периодическая очистка файлов, если TTL настроен
|
| 247 |
if (FILES_TTL_HOURS > 0) {
|
| 248 |
const ttlIntervalMs = FILES_TTL_HOURS * 60 * 60 * 1000;
|
| 249 |
-
// const ttlIntervalMs = 60 * 1000; // Для теста - каждую минуту
|
| 250 |
console.log(`[TTL] Scheduling cleanup every ${FILES_TTL_HOURS} hours.`);
|
| 251 |
-
// Запуск первой очистки через некоторое время после старта, чтобы дать системе "успокоиться"
|
| 252 |
setTimeout(() => {
|
| 253 |
cleanupOldFiles(TELEGRAM_DATA_DIR, FILES_TTL_HOURS).catch(console.error);
|
| 254 |
setInterval(() => {
|
| 255 |
cleanupOldFiles(TELEGRAM_DATA_DIR, FILES_TTL_HOURS).catch(console.error);
|
| 256 |
}, ttlIntervalMs);
|
| 257 |
-
}, 5 * 60 * 1000);
|
| 258 |
}
|
| 259 |
});
|
| 260 |
|
| 261 |
-
// Обработка сигналов для корректного завершения
|
| 262 |
function gracefulShutdown() {
|
| 263 |
console.log('Received shutdown signal. Closing server...');
|
| 264 |
-
// Здесь можно добавить закрытие сервера Express, если нужно дождаться завершения запросов
|
| 265 |
process.exit(0);
|
| 266 |
}
|
| 267 |
process.on('SIGINT', gracefulShutdown);
|
|
|
|
| 19 |
|
| 20 |
const app = express();
|
| 21 |
|
| 22 |
+
// ... (остальные вспомогательные функции без изменений) ...
|
| 23 |
function formatBytes(bytes, decimals = 2) {
|
| 24 |
if (bytes === 0) return '0 Bytes';
|
| 25 |
const k = 1024;
|
|
|
|
| 64 |
let errors = 0;
|
| 65 |
|
| 66 |
try {
|
| 67 |
+
const files = await glob(`${dirPath}/**/*`, { nodir: true, dot: true, stat: true, withFileTypes: false });
|
| 68 |
|
| 69 |
for (const file of files) {
|
| 70 |
processed++;
|
| 71 |
try {
|
| 72 |
+
const stats = await fs.stat(file);
|
|
|
|
|
|
|
| 73 |
if (stats.isFile()) {
|
| 74 |
const fileAge = now - stats.mtimeMs;
|
| 75 |
if (fileAge > ttlMs) {
|
|
|
|
| 83 |
errors++;
|
| 84 |
}
|
| 85 |
}
|
|
|
|
|
|
|
| 86 |
} catch (globError) {
|
| 87 |
console.error(`[TTL] Error during glob search:`, globError);
|
| 88 |
return { processed, deleted, errors: errors + 1, message: `Glob error: ${globError.message}` };
|
|
|
|
| 93 |
return result;
|
| 94 |
}
|
| 95 |
|
| 96 |
+
|
| 97 |
// --- Обновление Gist ---
|
| 98 |
async function updateEnvGistInGithub(tunnelUrlToSave) {
|
| 99 |
if (!GITHUB_USERNAME || !GITHUB_TOKEN || !ENV_GIST_ID) {
|
|
|
|
| 103 |
try {
|
| 104 |
const spaceId = process.env.SPACE_ID || 'N/A';
|
| 105 |
const spaceHost = process.env.SPACE_HOST || 'N/A';
|
| 106 |
+
|
| 107 |
+
// Используем более простое и статичное имя файла для Gist
|
| 108 |
+
const gistFilename = `hf_space_info.json`;
|
| 109 |
+
|
| 110 |
const content = {
|
| 111 |
last_updated: new Date().toISOString(),
|
| 112 |
space_id: spaceId,
|
|
|
|
| 116 |
tools_app_internal_port: EXPRESS_PORT,
|
| 117 |
files_ttl_hours: FILES_TTL_HOURS > 0 ? FILES_TTL_HOURS : 'disabled',
|
| 118 |
};
|
| 119 |
+
|
| 120 |
const gistData = {
|
| 121 |
+
description: `Hugging Face Space Info - ${spaceId}`, // Описание можно оставить динамическим
|
| 122 |
files: {
|
| 123 |
+
[gistFilename]: { // Используем новое имя файла
|
| 124 |
content: JSON.stringify(content, null, 2),
|
| 125 |
},
|
| 126 |
},
|
| 127 |
};
|
| 128 |
+
|
| 129 |
+
console.log(`Attempting to update Gist ${ENV_GIST_ID} with filename ${gistFilename}`);
|
| 130 |
const response = await fetch(`https://api.github.com/gists/${ENV_GIST_ID}`, {
|
| 131 |
method: 'PATCH',
|
| 132 |
headers: {
|
|
|
|
| 137 |
},
|
| 138 |
body: JSON.stringify(gistData),
|
| 139 |
});
|
| 140 |
+
|
| 141 |
if (!response.ok) {
|
| 142 |
+
const errorBody = await response.text();
|
| 143 |
+
console.error(`GitHub API Response Status: ${response.status}`);
|
| 144 |
+
console.error(`GitHub API Response Body: ${errorBody}`);
|
| 145 |
+
throw new Error(`GitHub API error: ${response.status} - ${errorBody}`);
|
| 146 |
}
|
| 147 |
console.log(`Gist ${ENV_GIST_ID} updated successfully with tunnel URL: ${tunnelUrlToSave}`);
|
| 148 |
} catch (error) {
|
| 149 |
+
console.error('Error updating Gist:', error.message); // Выводим только сообщение об ошибке для краткости
|
| 150 |
}
|
| 151 |
}
|
| 152 |
|
| 153 |
|
| 154 |
// --- Маршруты Express ---
|
| 155 |
+
// ... (маршруты без изменений) ...
|
| 156 |
app.get('/', (req, res) => {
|
| 157 |
res.send(`Telegram API Tools. Tunnel: ${currentTunnelUrl || 'pending...'}. Stats: ${currentTunnelUrl}/stats. File base: ${currentTunnelUrl}/file/`);
|
| 158 |
});
|
|
|
|
| 173 |
|
| 174 |
app.get('/file/:filepath(*)', (req, res) => {
|
| 175 |
const relativePath = req.params.filepath;
|
| 176 |
+
if (!relativePath || relativePath.includes('..')) {
|
| 177 |
return res.status(400).send('Invalid file path.');
|
| 178 |
}
|
| 179 |
|
|
|
|
| 180 |
const absoluteRequestedPath = path.normalize(path.join(TELEGRAM_DATA_DIR, relativePath));
|
| 181 |
|
| 182 |
if (!absoluteRequestedPath.startsWith(path.resolve(TELEGRAM_DATA_DIR))) {
|
|
|
|
| 203 |
});
|
| 204 |
|
| 205 |
// --- Запуск сервера и туннеля ---
|
| 206 |
+
// ... (логика запуска сервера и туннеля без изменений) ...
|
| 207 |
app.listen(EXPRESS_PORT, () => {
|
| 208 |
console.log(`Express server (for tools) listening on port ${EXPRESS_PORT}`);
|
| 209 |
console.log(`Attempting to start localhost.run tunnel for port ${EXPRESS_PORT}...`);
|
|
|
|
| 214 |
'-o', 'UserKnownHostsFile=/dev/null',
|
| 215 |
'-o', 'ServerAliveInterval=60',
|
| 216 |
'-o', 'ExitOnForwardFailure=yes',
|
| 217 |
+
'-o', 'LogLevel=ERROR',
|
| 218 |
'nokey@localhost.run'
|
| 219 |
]);
|
| 220 |
|
| 221 |
tunnelProcess.stdout.on('data', (data) => {
|
| 222 |
const output = data.toString();
|
|
|
|
| 223 |
const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.(lhr\.life|lhr\.run)/);
|
| 224 |
if (urlMatch && urlMatch[0] !== currentTunnelUrl) {
|
| 225 |
currentTunnelUrl = urlMatch[0];
|
| 226 |
console.log(`>>> Tools Tunnel active: ${currentTunnelUrl}`);
|
| 227 |
updateEnvGistInGithub(currentTunnelUrl).catch(console.error);
|
| 228 |
}
|
|
|
|
| 229 |
if (!urlMatch) {
|
| 230 |
console.log(`localhost.run stdout: ${output}`);
|
| 231 |
}
|
|
|
|
| 237 |
|
| 238 |
tunnelProcess.on('close', (code) => {
|
| 239 |
console.log(`localhost.run tunnel process exited with code ${code}`);
|
| 240 |
+
currentTunnelUrl = '';
|
| 241 |
updateEnvGistInGithub('Tunnel closed or failed.').catch(console.error);
|
| 242 |
});
|
| 243 |
|
|
|
|
| 247 |
updateEnvGistInGithub('Tunnel failed to start.').catch(console.error);
|
| 248 |
});
|
| 249 |
|
|
|
|
| 250 |
updateEnvGistInGithub('Tunnel URL pending...').catch(console.error);
|
| 251 |
|
|
|
|
| 252 |
if (FILES_TTL_HOURS > 0) {
|
| 253 |
const ttlIntervalMs = FILES_TTL_HOURS * 60 * 60 * 1000;
|
|
|
|
| 254 |
console.log(`[TTL] Scheduling cleanup every ${FILES_TTL_HOURS} hours.`);
|
|
|
|
| 255 |
setTimeout(() => {
|
| 256 |
cleanupOldFiles(TELEGRAM_DATA_DIR, FILES_TTL_HOURS).catch(console.error);
|
| 257 |
setInterval(() => {
|
| 258 |
cleanupOldFiles(TELEGRAM_DATA_DIR, FILES_TTL_HOURS).catch(console.error);
|
| 259 |
}, ttlIntervalMs);
|
| 260 |
+
}, 5 * 60 * 1000);
|
| 261 |
}
|
| 262 |
});
|
| 263 |
|
|
|
|
| 264 |
function gracefulShutdown() {
|
| 265 |
console.log('Received shutdown signal. Closing server...');
|
|
|
|
| 266 |
process.exit(0);
|
| 267 |
}
|
| 268 |
process.on('SIGINT', gracefulShutdown);
|