Spaces:
Sleeping
Sleeping
| import express from 'express'; | |
| import { generateToken, authMiddleware } from '../auth/jwt.js'; | |
| import tokenManager from '../auth/token_manager.js'; | |
| import config, { getConfigJson, saveConfigJson } from '../config/config.js'; | |
| import logger from '../utils/logger.js'; | |
| import { generateProjectId } from '../utils/idGenerator.js'; | |
| import axios from 'axios'; | |
| import fs from 'fs'; | |
| import path from 'path'; | |
| import { fileURLToPath } from 'url'; | |
| import dotenv from 'dotenv'; | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const envPath = path.join(__dirname, '../../.env'); | |
| const configJsonPath = path.join(__dirname, '../../config.json'); | |
| const router = express.Router(); | |
| // 登录接口 | |
| router.post('/login', (req, res) => { | |
| const { username, password } = req.body; | |
| if (username === config.admin.username && password === config.admin.password) { | |
| const token = generateToken({ username, role: 'admin' }); | |
| res.json({ success: true, token }); | |
| } else { | |
| res.status(401).json({ success: false, message: '用户名或密码错误' }); | |
| } | |
| }); | |
| // Token管理API - 需要JWT认证 | |
| router.get('/tokens', authMiddleware, (req, res) => { | |
| const tokens = tokenManager.getTokenList(); | |
| res.json({ success: true, data: tokens }); | |
| }); | |
| router.post('/tokens', authMiddleware, (req, res) => { | |
| const { access_token, refresh_token, expires_in, timestamp, enable, projectId } = req.body; | |
| if (!access_token || !refresh_token) { | |
| return res.status(400).json({ success: false, message: 'access_token和refresh_token必填' }); | |
| } | |
| const tokenData = { access_token, refresh_token, expires_in }; | |
| if (timestamp) tokenData.timestamp = timestamp; | |
| if (enable !== undefined) tokenData.enable = enable; | |
| if (projectId) tokenData.projectId = projectId; | |
| const result = tokenManager.addToken(tokenData); | |
| res.json(result); | |
| }); | |
| router.put('/tokens/:refreshToken', authMiddleware, (req, res) => { | |
| const { refreshToken } = req.params; | |
| const updates = req.body; | |
| const result = tokenManager.updateToken(refreshToken, updates); | |
| res.json(result); | |
| }); | |
| router.delete('/tokens/:refreshToken', authMiddleware, (req, res) => { | |
| const { refreshToken } = req.params; | |
| const result = tokenManager.deleteToken(refreshToken); | |
| res.json(result); | |
| }); | |
| router.post('/tokens/reload', authMiddleware, async (req, res) => { | |
| try { | |
| await tokenManager.reload(); | |
| res.json({ success: true, message: 'Token已热重载' }); | |
| } catch (error) { | |
| logger.error('热重载失败:', error.message); | |
| res.status(500).json({ success: false, message: error.message }); | |
| } | |
| }); | |
| router.post('/oauth/exchange', authMiddleware, async (req, res) => { | |
| const { code, port } = req.body; | |
| if (!code || !port) { | |
| return res.status(400).json({ success: false, message: 'code和port必填' }); | |
| } | |
| const CLIENT_ID = '1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com'; | |
| const CLIENT_SECRET = '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'; | |
| try { | |
| const postData = new URLSearchParams({ | |
| code, | |
| client_id: CLIENT_ID, | |
| client_secret: CLIENT_SECRET, | |
| redirect_uri: `http://localhost:${port}/oauth-callback`, | |
| grant_type: 'authorization_code' | |
| }); | |
| const response = await fetch('https://oauth2.googleapis.com/token', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
| body: postData.toString() | |
| }); | |
| const tokenData = await response.json(); | |
| if (!tokenData.access_token) { | |
| return res.status(400).json({ success: false, message: 'Token交换失败' }); | |
| } | |
| const account = { | |
| access_token: tokenData.access_token, | |
| refresh_token: tokenData.refresh_token, | |
| expires_in: tokenData.expires_in, | |
| timestamp: Date.now(), | |
| enable: true | |
| }; | |
| if (config.skipProjectIdFetch) { | |
| account.projectId = generateProjectId(); | |
| logger.info('使用随机生成的projectId: ' + account.projectId); | |
| } else { | |
| try { | |
| const projectResponse = await axios({ | |
| method: 'POST', | |
| url: 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:loadCodeAssist', | |
| headers: { | |
| 'Host': 'daily-cloudcode-pa.sandbox.googleapis.com', | |
| 'User-Agent': 'antigravity/1.11.9 windows/amd64', | |
| 'Authorization': `Bearer ${account.access_token}`, | |
| 'Content-Type': 'application/json', | |
| 'Accept-Encoding': 'gzip' | |
| }, | |
| data: JSON.stringify({ metadata: { ideType: 'ANTIGRAVITY' } }), | |
| timeout: config.timeout, | |
| proxy: config.proxy ? (() => { | |
| const proxyUrl = new URL(config.proxy); | |
| return { protocol: proxyUrl.protocol.replace(':', ''), host: proxyUrl.hostname, port: parseInt(proxyUrl.port) }; | |
| })() : false | |
| }); | |
| const projectId = projectResponse.data?.cloudaicompanionProject; | |
| if (projectId === undefined) { | |
| return res.status(400).json({ success: false, message: '该账号无资格使用(无法获取projectId)' }); | |
| } | |
| account.projectId = projectId; | |
| logger.info('账号验证通过,projectId: ' + projectId); | |
| } catch (error) { | |
| logger.error('验证账号资格失败:', error.message); | |
| return res.status(500).json({ success: false, message: '验证账号资格失败: ' + error.message }); | |
| } | |
| } | |
| res.json({ success: true, data: account }); | |
| } catch (error) { | |
| logger.error('Token交换失败:', error.message); | |
| res.status(500).json({ success: false, message: error.message }); | |
| } | |
| }); | |
| // 获取配置 | |
| router.get('/config', authMiddleware, (req, res) => { | |
| try { | |
| const envData = {}; | |
| const envContent = fs.readFileSync(envPath, 'utf8'); | |
| envContent.split('\n').forEach(line => { | |
| line = line.trim(); | |
| if (line && !line.startsWith('#')) { | |
| const [key, ...valueParts] = line.split('='); | |
| if (key) envData[key.trim()] = valueParts.join('=').trim(); | |
| } | |
| }); | |
| const jsonData = getConfigJson(); | |
| res.json({ success: true, data: { env: envData, json: jsonData } }); | |
| } catch (error) { | |
| logger.error('读取配置失败:', error.message); | |
| res.status(500).json({ success: false, message: error.message }); | |
| } | |
| }); | |
| // 更新配置 | |
| router.put('/config', authMiddleware, (req, res) => { | |
| try { | |
| const { env: envUpdates, json: jsonUpdates } = req.body; | |
| // 更新 .env(只保留敏感信息) | |
| if (envUpdates) { | |
| let envContent = fs.readFileSync(envPath, 'utf8'); | |
| Object.entries(envUpdates).forEach(([key, value]) => { | |
| const regex = new RegExp(`^${key}=.*$`, 'm'); | |
| if (regex.test(envContent)) { | |
| envContent = envContent.replace(regex, `${key}=${value}`); | |
| } else { | |
| envContent += `\n${key}=${value}`; | |
| } | |
| }); | |
| fs.writeFileSync(envPath, envContent, 'utf8'); | |
| } | |
| // 更新 config.json | |
| if (jsonUpdates) { | |
| saveConfigJson(jsonUpdates); | |
| } | |
| // 重新加载环境变量 | |
| dotenv.config({ override: true }); | |
| // 更新config对象 | |
| const jsonConfig = getConfigJson(); | |
| config.server.port = jsonConfig.server?.port || 8045; | |
| config.server.host = jsonConfig.server?.host || '0.0.0.0'; | |
| config.defaults.temperature = jsonConfig.defaults?.temperature || 1; | |
| config.defaults.top_p = jsonConfig.defaults?.topP || 0.85; | |
| config.defaults.top_k = jsonConfig.defaults?.topK || 50; | |
| config.defaults.max_tokens = jsonConfig.defaults?.maxTokens || 8096; | |
| config.security.apiKey = process.env.API_KEY || null; | |
| config.timeout = jsonConfig.other?.timeout || 180000; | |
| config.proxy = process.env.PROXY || null; | |
| config.systemInstruction = process.env.SYSTEM_INSTRUCTION || ''; | |
| config.skipProjectIdFetch = jsonConfig.other?.skipProjectIdFetch === true; | |
| config.maxImages = jsonConfig.other?.maxImages || 10; | |
| config.useNativeAxios = jsonConfig.other?.useNativeAxios !== false; | |
| config.api.url = jsonConfig.api?.url || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse'; | |
| config.api.modelsUrl = jsonConfig.api?.modelsUrl || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels'; | |
| config.api.noStreamUrl = jsonConfig.api?.noStreamUrl || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent'; | |
| config.api.host = jsonConfig.api?.host || 'daily-cloudcode-pa.sandbox.googleapis.com'; | |
| config.api.userAgent = jsonConfig.api?.userAgent || 'antigravity/1.11.3 windows/amd64'; | |
| logger.info('配置已更新并热重载'); | |
| res.json({ success: true, message: '配置已保存并生效(端口/HOST修改需重启)' }); | |
| } catch (error) { | |
| logger.error('更新配置失败:', error.message); | |
| res.status(500).json({ success: false, message: error.message }); | |
| } | |
| }); | |
| export default router; |