Files
verdaccio-cache-manager/backend/server.js
T

83 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Verdaccio 缓存可视化管理面板 — 后端服务入口
* Express + better-sqlite3,§4.2 REST API
*
* 环境变量:
* VERDACCIO_STORAGE Verdaccio 缓存目录(优先于 UI 设置)
* PORT 监听端口(默认 3000)
* DATA_DIR SQLite 数据目录(默认 backend/data)
* VCM_USERNAME 面板登录账号(默认 admin)
* VCM_PASSWORD 面板登录密码(默认 666666,Docker 部署务必通过 compose 覆盖)
* UV_THREADPOOL_SIZE libuv IO 线程池大小(默认 4 → 8:扫描/stat/readFile 并发更高,NAS 四核安全)
*
* 模块划分:
* - scan-manager.js 扫描状态机与业务编排(缓存/进度/状态构建)
* - schedules.js 每日扫描 + 每周抓榜定时任务
* - routes/* REST 路由(按领域拆分)
*/
// 必须在 libuv 线程池首次使用前设置:扫描大量目录/文件时默认 4 线程是主要瓶颈
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || '8'
import express from 'express'
import path from 'node:path'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { resolveStorageDir } from './scanner.js'
import { isDemoMode } from './scan-manager.js'
import { scheduleDailyScan, scheduleWeeklyTopList } from './schedules.js'
import { authRouter, authMiddleware } from './routes/auth.js'
import { thresholdsRouter } from './routes/thresholds.js'
import { ignoredRouter } from './routes/ignored.js'
import { packagesRouter } from './routes/packages.js'
import { syncRouter } from './routes/sync.js'
import { toplistRouter } from './routes/toplist.js'
import { cleanRouter } from './routes/clean.js'
import { logsRouter } from './routes/logs.js'
import { apiNotFound, errorHandler } from './http.js'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const app = express()
app.use(express.json({ limit: '1mb' }))
const PORT = Number(process.env.PORT || 3000)
// —— 路由装配:登录/登出公开,其余 /api/* 需鉴权 ——
app.use('/api', authRouter)
app.use('/api', authMiddleware)
app.use('/api', thresholdsRouter)
app.use('/api', ignoredRouter)
app.use('/api', packagesRouter)
app.use('/api', syncRouter)
app.use('/api', toplistRouter)
app.use('/api', cleanRouter)
app.use('/api', logsRouter)
// —— /api 未匹配任何路由 → JSON 404(Express 默认对非 GET 返回 HTML) ——
app.use('/api', apiNotFound)
// —— 生产:托管前端 dist ——
const distDir = path.join(__dirname, '..', 'frontend', 'dist')
if (fs.existsSync(distDir)) {
app.use(express.static(distDir))
app.get('*', (req, res) => {
if (req.path.startsWith('/api/')) return res.status(404).json({ ok: false, message: 'not found' })
res.sendFile(path.join(distDir, 'index.html'))
})
}
// —— 统一错误处理:Express4 同步 throw 会跳到这里,返回 JSON 而非 HTML 500 ——
app.use(errorHandler)
app.listen(PORT, () => {
const storage = resolveStorageDir()
const mode = isDemoMode() ? 'demo' : 'storage'
if (!process.env.VCM_PASSWORD) {
console.warn(
'[auth] ⚠ 未设置 VCM_PASSWORD 环境变量,正在使用默认口令 666666。' +
'生产部署请务必通过 docker-compose 的环境变量覆盖,否则面板可被任意登录!',
)
}
console.log(`[verdaccio-manager] listening on :${PORT} (mode=${mode})`)
if (mode === 'storage') console.log(`[verdaccio-manager] storage: ${storage}`)
else console.log('[verdaccio-manager] 未配置 VERDACCIO_STORAGE,运行于演示模式(设置 VCM_DEMO=0 + 真实目录可关闭)')
scheduleDailyScan()
scheduleWeeklyTopList()
})