Spaces:
Paused
Paused
| import express from 'express'; | |
| import http from 'http'; | |
| import { spawn } from 'child_process'; | |
| import url from 'url'; | |
| const EXPRESS_PORT = 3000; // Внутренний порт для Express-приложения (для туннеля) | |
| const HF_PORT = 7860; // Порт для Hugging Face | |
| // Функция для форматирования информации о запросе | |
| function formatRequestInfo(req, isExpress = true) { | |
| let info = 'ИНФОРМАЦИЯ О ЗАПРОСЕ:\n\n'; | |
| // Основная информация | |
| info += `Метод запроса: ${req.method}\n`; | |
| info += `URL: ${isExpress ? req.originalUrl : req.url}\n`; | |
| info += `IP клиента: ${isExpress ? req.ip : req.socket.remoteAddress}\n\n`; | |
| // Query параметры | |
| const queryParams = isExpress ? req.query : url.parse(req.url, true).query; | |
| info += 'QUERY ПАРАМЕТРЫ:\n'; | |
| if (Object.keys(queryParams).length === 0) { | |
| info += '(нет параметров)\n'; | |
| } else { | |
| for (const [key, value] of Object.entries(queryParams)) { | |
| info += `${key}: ${value}\n`; | |
| } | |
| } | |
| info += '\n'; | |
| // Заголовки запроса | |
| info += 'ЗАГОЛОВКИ ЗАПРОСА:\n'; | |
| const headers = req.headers; | |
| for (const [key, value] of Object.entries(headers)) { | |
| info += `${key}: ${value}\n`; | |
| } | |
| // User-Agent (информация о браузере) | |
| info += '\nИНФОРМАЦИЯ О БРАУЗЕРЕ:\n'; | |
| info += headers['user-agent'] || 'Информация недоступна'; | |
| return info; | |
| } | |
| // --- Сервер 1: Express-приложение для localhost.run --- | |
| const app = express(); | |
| app.get('*', (req, res) => { | |
| const requestInfo = formatRequestInfo(req); | |
| res.setHeader('Content-Type', 'text/plain; charset=utf-8'); | |
| res.send(requestInfo); | |
| }); | |
| app.listen(EXPRESS_PORT, () => { | |
| console.log(`Express server (для туннеля) слушает порт ${EXPRESS_PORT}`); | |
| // Запускаем туннель localhost.run ПОСЛЕ того, как Express-сервер стартовал | |
| console.log(`Попытка запустить туннель localhost.run для порта ${EXPRESS_PORT}...`); | |
| const tunnel = spawn('ssh', [ | |
| '-R', `80:localhost:${EXPRESS_PORT}`, // Туннелируем порт 80 публичного URL на наш localhost:EXPRESS_PORT | |
| '-o', 'StrictHostKeyChecking=no', // Отключаем проверку ключа хоста для автоматизации | |
| '-o', 'UserKnownHostsFile=/dev/null', // Не сохраняем ключи хостов | |
| '-o', 'ServerAliveInterval=60', // Поддерживать соединение активным | |
| '-o', 'ExitOnForwardFailure=yes', // Выйти, если форвардинг не удался | |
| 'nokey@localhost.run' | |
| ]); | |
| tunnel.stdout.on('data', (data) => { | |
| const output = data.toString(); | |
| console.log(`localhost.run stdout: ${output}`); | |
| // Попытка извлечь URL из вывода | |
| const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.lhr\.life/); | |
| if (urlMatch) { | |
| console.log(`>>> Туннель активен: ${urlMatch[0]}`); | |
| } | |
| }); | |
| tunnel.stderr.on('data', (data) => { | |
| console.error(`localhost.run stderr: ${data}`); | |
| }); | |
| tunnel.on('close', (code) => { | |
| console.log(`Процесс localhost.run завершился с кодом ${code}`); | |
| }); | |
| tunnel.on('error', (err) => { | |
| console.error('Не удалось запустить процесс localhost.run:', err); | |
| }); | |
| }); | |
| // --- Сервер 2: Простой HTTP-сервер для Hugging Face на порту 7860 --- | |
| const server2 = http.createServer((req, res) => { | |
| const requestInfo = formatRequestInfo(req, false); | |
| res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); | |
| res.end(requestInfo); | |
| }); | |
| server2.listen(HF_PORT, () => { | |
| console.log(`Второй HTTP-сервер (для Hugging Face) слушает порт ${HF_PORT}`); | |
| }); | |
| // Обработка сигналов для корректного завершения | |
| process.on('SIGINT', () => { | |
| console.log('Получен SIGINT. Завершение...'); | |
| process.exit(0); | |
| }); | |
| process.on('SIGTERM', () => { | |
| console.log('Получен SIGTERM. Завершение...'); | |
| process.exit(0); | |
| }); |