Files
soul/app/api/sync/route.ts

231 lines
5.3 KiB
TypeScript

// app/api/sync/route.ts
// 实时同步API - 监听文件变化并同步到前端
import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
const BOOK_DIR = path.join(process.cwd(), 'book')
const SYNC_LOG_FILE = path.join(process.cwd(), 'SYNC_LOG.md')
// GET: 获取同步状态
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url)
const action = searchParams.get('action')
if (action === 'status') {
// 返回同步状态
const lastSync = getLastSyncTime()
const changedFiles = getChangedFiles(lastSync)
return NextResponse.json({
success: true,
lastSync,
changedFiles: changedFiles.length,
files: changedFiles,
needSync: changedFiles.length > 0
})
}
if (action === 'log') {
// 返回同步日志
const log = fs.existsSync(SYNC_LOG_FILE)
? fs.readFileSync(SYNC_LOG_FILE, 'utf-8')
: '暂无同步日志'
return NextResponse.json({
success: true,
log
})
}
return NextResponse.json(
{ error: '未知操作' },
{ status: 400 }
)
} catch (error) {
console.error('获取同步状态失败:', error)
return NextResponse.json(
{ error: '获取同步状态失败' },
{ status: 500 }
)
}
}
// POST: 执行同步
export async function POST(req: NextRequest) {
try {
const body = await req.json()
const { force } = body
const lastSync = force ? 0 : getLastSyncTime()
const changedFiles = getChangedFiles(lastSync)
if (changedFiles.length === 0 && !force) {
return NextResponse.json({
success: true,
message: '没有需要同步的文件',
synced: 0
})
}
// 执行同步(这里可以触发构建或缓存更新)
const syncResults = await syncFiles(changedFiles)
// 更新同步时间
updateSyncLog(changedFiles, syncResults)
return NextResponse.json({
success: true,
message: `成功同步 ${syncResults.success} 个文件`,
synced: syncResults.success,
failed: syncResults.failed,
files: changedFiles
})
} catch (error) {
console.error('同步失败:', error)
return NextResponse.json(
{ error: '同步失败' },
{ status: 500 }
)
}
}
// 获取最后同步时间
function getLastSyncTime(): number {
try {
if (!fs.existsSync(SYNC_LOG_FILE)) {
return 0
}
const log = fs.readFileSync(SYNC_LOG_FILE, 'utf-8')
const match = log.match(/最后同步时间: (\d+)/)
return match ? parseInt(match[1]) : 0
} catch (error) {
return 0
}
}
// 获取变化的文件
function getChangedFiles(since: number): string[] {
const changedFiles: string[] = []
function scanDirectory(dir: string) {
const items = fs.readdirSync(dir)
items.forEach(item => {
const fullPath = path.join(dir, item)
const stat = fs.statSync(fullPath)
if (stat.isDirectory()) {
scanDirectory(fullPath)
} else if (item.endsWith('.md')) {
// 检查文件修改时间
if (stat.mtimeMs > since) {
changedFiles.push(fullPath)
}
}
})
}
scanDirectory(BOOK_DIR)
return changedFiles
}
// 同步文件
async function syncFiles(files: string[]): Promise<{ success: number; failed: number }> {
let success = 0
let failed = 0
for (const file of files) {
try {
// 读取文件内容
const content = fs.readFileSync(file, 'utf-8')
const { data } = matter(content)
// 这里可以执行实际的同步操作:
// 1. 更新数据库
// 2. 清除缓存
// 3. 触发CDN刷新
// 4. 推送通知
console.log(`同步文件: ${file}`)
success++
} catch (error) {
console.error(`同步文件失败: ${file}`, error)
failed++
}
}
return { success, failed }
}
// 更新同步日志
function updateSyncLog(files: string[], results: { success: number; failed: number }) {
const timestamp = Date.now()
const date = new Date().toISOString()
let log = fs.existsSync(SYNC_LOG_FILE)
? fs.readFileSync(SYNC_LOG_FILE, 'utf-8')
: '# 同步日志\n\n'
const newEntry = `
## ${date}
- 同步文件数: ${files.length}
- 成功: ${results.success}
- 失败: ${results.failed}
- 文件列表:
${files.map(f => ` - ${path.relative(BOOK_DIR, f)}`).join('\n')}
最后同步时间: ${timestamp}
---
`
log = newEntry + log
fs.writeFileSync(SYNC_LOG_FILE, log, 'utf-8')
}
// PUT: 手动标记文件为已同步
export async function PUT(req: NextRequest) {
try {
const body = await req.json()
const { file } = body
if (!file) {
return NextResponse.json(
{ error: '文件路径不能为空' },
{ status: 400 }
)
}
const filePath = path.join(BOOK_DIR, file)
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: '文件不存在' },
{ status: 404 }
)
}
// 更新文件的访问时间和修改时间为当前时间
const now = new Date()
fs.utimesSync(filePath, now, now)
return NextResponse.json({
success: true,
message: '文件已标记为同步'
})
} catch (error) {
return NextResponse.json(
{ error: '操作失败' },
{ status: 500 }
)
}
}