第一次运行实验时自动建好预置的数据库
- 运行时带上当前实验;实验有 database.sql 而学生还没有其中的库时,先建好这些库 (已有的库不动,保留学生的数据);建库失败不影响运行 - 教材项目 8 要"附加"现成的 WisdomCampus 库,学生不用先去数据库页面恢复 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5ae07b851d
commit
10c50265b2
5 files changed
+27
-8
No files matched your search
+11
-3
@@ -27,16 +27,19 @@ export async function runScript(dir: string, script: string) {
|
||||
|
||||
/**
|
||||
* 把学生某个实验用到的库恢复成实验的初始数据:只替换脚本里建的库,学生的其他库不动。
|
||||
* onlyMissing 时只建学生还没有的库(第一次运行实验时自动建库,已有的库保留学生的数据)。
|
||||
* 返回恢复了哪些库。
|
||||
*/
|
||||
export async function restoreExperimentDatabases(userId: number, sampleId: string) {
|
||||
export async function restoreExperimentDatabases(userId: number, sampleId: string, onlyMissing = false) {
|
||||
const script = await experimentScript(sampleId)
|
||||
if (!script) return []
|
||||
const target = await userDatabaseDir(userId)
|
||||
const existing = new Set(await readdir(target))
|
||||
if (onlyMissing && scriptDatabases(script).every((name) => existing.has(`${name}.db`))) return []
|
||||
const temp = await mkdtemp(join(config.runsDir, 'db-'))
|
||||
try {
|
||||
await runScript(temp, script)
|
||||
const target = await userDatabaseDir(userId)
|
||||
const files = (await readdir(temp)).filter((f) => f.endsWith('.db') && f !== 'master.db')
|
||||
const files = (await readdir(temp)).filter((f) => f.endsWith('.db') && f !== 'master.db' && !(onlyMissing && existing.has(f)))
|
||||
for (const file of files) {
|
||||
for (const suffix of ['', '-wal', '-shm']) await rm(join(target, file + suffix), { force: true })
|
||||
await cp(join(temp, file), join(target, file))
|
||||
@@ -47,6 +50,11 @@ export async function restoreExperimentDatabases(userId: number, sampleId: strin
|
||||
}
|
||||
}
|
||||
|
||||
/** 脚本里 CREATE DATABASE 建的库名 */
|
||||
function scriptDatabases(script: string) {
|
||||
return [...script.matchAll(/^\s*CREATE\s+DATABASE\s+\[?([^\s\]]+)\]?/gim)].map((m) => m[1])
|
||||
}
|
||||
|
||||
/** 评分用:实验数据库的模板按实验缓存,每个检查项复制一份(互不影响) */
|
||||
const templates = new Map<string, Promise<string | undefined>>()
|
||||
|
||||
|
||||
+7
-1
@@ -7,7 +7,8 @@ import { languageService } from './language-service'
|
||||
import { config } from './config'
|
||||
import { openDatabase } from './db'
|
||||
import { createGradingQueue } from './grading/queue'
|
||||
import { userDatabaseDir } from './databases'
|
||||
import { restoreExperimentDatabases, userDatabaseDir } from './databases'
|
||||
import { listSamples } from './samples'
|
||||
import { cleanupStaleRuns, RunSession } from './run-session'
|
||||
import { sqlService } from './sql-service'
|
||||
import { checkSandbox, sandboxError } from './sandbox'
|
||||
@@ -56,6 +57,11 @@ const server = Bun.serve({
|
||||
if (!session) return
|
||||
if (message.type === 'run') {
|
||||
try {
|
||||
const { sampleId } = message
|
||||
if (typeof sampleId === 'string' && (await listSamples()).some((s) => s.id === sampleId)) {
|
||||
// 建库失败不影响运行(程序连不上库时会报出来)
|
||||
await restoreExperimentDatabases(ws.data.userId!, sampleId, true).catch((error) => console.error('自动建实验数据库失败', error))
|
||||
}
|
||||
await session.start(message.files)
|
||||
} catch (error) {
|
||||
ws.send(JSON.stringify({ type: 'serverError', message: String(error) } satisfies ServerMessage))
|
||||
|
||||
Reference in new issue
Block a user