feat(remote): 添加 CORS 中间件支持文件跨域访问
This commit is contained in:
@@ -32,6 +32,110 @@ import { logger } from '../../utils/logger.js'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
router.get(
|
||||
'/drives',
|
||||
asyncHandler(async (_req: Request, res: Response) => {
|
||||
const drives: FileItemDTO[] = []
|
||||
const letters = 'CDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
|
||||
|
||||
for (const letter of letters) {
|
||||
const drivePath = `${letter}:\\`
|
||||
try {
|
||||
await fs.access(drivePath)
|
||||
drives.push({
|
||||
name: `${letter}:`,
|
||||
type: 'dir',
|
||||
size: 0,
|
||||
modified: new Date().toISOString(),
|
||||
path: drivePath,
|
||||
})
|
||||
} catch {
|
||||
// 驱动器不存在,跳过
|
||||
}
|
||||
}
|
||||
|
||||
successResponse(res, { items: drives })
|
||||
}),
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/system',
|
||||
validateQuery(listFilesQuerySchema),
|
||||
asyncHandler(async (req: Request, res: Response) => {
|
||||
const systemPath = req.query.path as string
|
||||
if (!systemPath) {
|
||||
throw new BadRequestError('路径不能为空')
|
||||
}
|
||||
|
||||
const fullPath = path.resolve(systemPath)
|
||||
|
||||
try {
|
||||
await fs.access(fullPath)
|
||||
} catch {
|
||||
throw new NotFoundError('路径不存在')
|
||||
}
|
||||
|
||||
const stats = await fs.stat(fullPath)
|
||||
if (!stats.isDirectory()) {
|
||||
throw new NotADirectoryError()
|
||||
}
|
||||
|
||||
const files = await fs.readdir(fullPath)
|
||||
const items = await Promise.all(
|
||||
files.map(async (name): Promise<FileItemDTO | null> => {
|
||||
const filePath = path.join(fullPath, name)
|
||||
try {
|
||||
const fileStats = await fs.stat(filePath)
|
||||
return {
|
||||
name,
|
||||
type: fileStats.isDirectory() ? 'dir' : 'file',
|
||||
size: fileStats.size,
|
||||
modified: fileStats.mtime.toISOString(),
|
||||
path: filePath,
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const visibleItems = items.filter((i): i is FileItemDTO => i !== null && !i.name.startsWith('.'))
|
||||
visibleItems.sort((a, b) => {
|
||||
if (a.type === b.type) return a.name.localeCompare(b.name)
|
||||
return a.type === 'dir' ? -1 : 1
|
||||
})
|
||||
|
||||
successResponse(res, { items: visibleItems })
|
||||
}),
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/system/content',
|
||||
validateQuery(contentQuerySchema),
|
||||
asyncHandler(async (req: Request, res: Response) => {
|
||||
const systemPath = req.query.path as string
|
||||
if (!systemPath) {
|
||||
throw new BadRequestError('路径不能为空')
|
||||
}
|
||||
|
||||
const fullPath = path.resolve(systemPath)
|
||||
const stats = await fs.stat(fullPath).catch(() => {
|
||||
throw new NotFoundError('文件不存在')
|
||||
})
|
||||
|
||||
if (!stats.isFile()) throw new BadRequestError('不是文件')
|
||||
|
||||
const content = await fs.readFile(fullPath, 'utf-8')
|
||||
successResponse(res, {
|
||||
content,
|
||||
metadata: {
|
||||
size: stats.size,
|
||||
modified: stats.mtime.toISOString(),
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
validateQuery(listFilesQuerySchema),
|
||||
|
||||
Reference in New Issue
Block a user