mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
fix(storage): require legacy data before showing migrate hint
This commit is contained in:
1 parent
42837278fa
commit
f234a25ff6
4 files changed
+66
-1
No files matched your search
@@ -1,11 +1,14 @@
|
||||
import { describe, it } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import Fastify from 'fastify'
|
||||
import type { PathProvider } from '@openchatlab/core'
|
||||
import type { HttpRouteContext } from '../../context'
|
||||
import { registerCacheRoutes } from './cache'
|
||||
|
||||
function createPathProvider(): PathProvider {
|
||||
function createPathProvider(overrides: Partial<PathProvider> = {}): PathProvider {
|
||||
return {
|
||||
getSystemDir: () => '/tmp/chatlab-test',
|
||||
getUserDataDir: () => '/tmp/chatlab-test/data',
|
||||
@@ -16,9 +19,15 @@ function createPathProvider(): PathProvider {
|
||||
getTempDir: () => '/tmp/chatlab-test/temp',
|
||||
getLogsDir: () => '/tmp/chatlab-test/logs',
|
||||
getDownloadsDir: () => '/tmp/chatlab-test/downloads',
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
function makeTempDir(): string {
|
||||
const baseDir = fs.existsSync('/private/tmp') ? '/private/tmp' : os.tmpdir()
|
||||
return fs.mkdtempSync(path.join(baseDir, 'chatlab-cache-routes-'))
|
||||
}
|
||||
|
||||
describe('registerCacheRoutes data directory routes', () => {
|
||||
it('returns data directory capability and pending migration', async () => {
|
||||
const app = Fastify()
|
||||
@@ -45,6 +54,7 @@ describe('registerCacheRoutes data directory routes', () => {
|
||||
defaultPath: '/tmp/chatlab-test/default-data',
|
||||
isCustom: true,
|
||||
canSetDataDir: true,
|
||||
hasLegacyDataAtDefaultDir: false,
|
||||
pendingMigration: {
|
||||
from: '/tmp/chatlab-test/data',
|
||||
to: '/tmp/chatlab-test/new-data',
|
||||
@@ -55,6 +65,42 @@ describe('registerCacheRoutes data directory routes', () => {
|
||||
await app.close()
|
||||
})
|
||||
|
||||
it('reports legacy data at default directory only when default databases contain db files', async () => {
|
||||
const root = makeTempDir()
|
||||
const currentDir = path.join(root, 'custom-data')
|
||||
const defaultDir = path.join(root, 'default-data')
|
||||
fs.mkdirSync(path.join(defaultDir, 'databases'), { recursive: true })
|
||||
fs.writeFileSync(path.join(defaultDir, '.chatlab'), 'ChatLab Data Directory')
|
||||
|
||||
const appWithoutDb = Fastify()
|
||||
registerCacheRoutes(appWithoutDb, {
|
||||
pathProvider: createPathProvider({ getUserDataDir: () => currentDir }),
|
||||
defaultUserDataDir: defaultDir,
|
||||
isCustomDataDir: true,
|
||||
} as unknown as HttpRouteContext)
|
||||
await appWithoutDb.ready()
|
||||
|
||||
const emptyResponse = await appWithoutDb.inject({ method: 'GET', url: '/_web/cache/data-dir' })
|
||||
assert.equal(emptyResponse.statusCode, 200)
|
||||
assert.equal(emptyResponse.json().hasLegacyDataAtDefaultDir, false)
|
||||
await appWithoutDb.close()
|
||||
|
||||
fs.writeFileSync(path.join(defaultDir, 'databases', 'legacy.db'), 'sqlite')
|
||||
|
||||
const appWithDb = Fastify()
|
||||
registerCacheRoutes(appWithDb, {
|
||||
pathProvider: createPathProvider({ getUserDataDir: () => currentDir }),
|
||||
defaultUserDataDir: defaultDir,
|
||||
isCustomDataDir: true,
|
||||
} as unknown as HttpRouteContext)
|
||||
await appWithDb.ready()
|
||||
|
||||
const response = await appWithDb.inject({ method: 'GET', url: '/_web/cache/data-dir' })
|
||||
assert.equal(response.statusCode, 200)
|
||||
assert.equal(response.json().hasLegacyDataAtDefaultDir, true)
|
||||
await appWithDb.close()
|
||||
})
|
||||
|
||||
it('delegates data directory changes to context callback', async () => {
|
||||
const app = Fastify()
|
||||
const calls: Array<{ path: string | null; migrate?: boolean }> = []
|
||||
|
||||
@@ -43,6 +43,17 @@ async function getFileCount(dirPath: string): Promise<number> {
|
||||
return count
|
||||
}
|
||||
|
||||
function hasChatLabDatabases(dirPath: string): boolean {
|
||||
try {
|
||||
const markerPath = path.join(dirPath, '.chatlab')
|
||||
const dbDir = path.join(dirPath, 'databases')
|
||||
if (!fs.existsSync(markerPath) || !fs.existsSync(dbDir)) return false
|
||||
return fs.readdirSync(dbDir).some((file) => file.endsWith('.db'))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function registerCacheRoutes(server: FastifyInstance, ctx: HttpRouteContext): void {
|
||||
const pp = ctx.pathProvider
|
||||
const downloadsDir = ctx.downloadsDir ?? pp.getDownloadsDir()
|
||||
@@ -128,6 +139,10 @@ export function registerCacheRoutes(server: FastifyInstance, ctx: HttpRouteConte
|
||||
defaultPath: ctx.defaultUserDataDir,
|
||||
isCustom: ctx.isCustomDataDir ?? false,
|
||||
canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),
|
||||
hasLegacyDataAtDefaultDir:
|
||||
Boolean(ctx.defaultUserDataDir) &&
|
||||
path.resolve(pp.getUserDataDir()) !== path.resolve(ctx.defaultUserDataDir ?? '') &&
|
||||
hasChatLabDatabases(ctx.defaultUserDataDir ?? ''),
|
||||
pendingMigration: pending
|
||||
? {
|
||||
from: pending.from,
|
||||
|
||||
@@ -20,6 +20,7 @@ const clearingId = ref<string | null>(null)
|
||||
const dataDir = ref('')
|
||||
const dataDirInput = ref('')
|
||||
const defaultDataDir = ref('')
|
||||
const hasLegacyDataAtDefaultDir = ref(false)
|
||||
const isCustomDataDir = ref(false)
|
||||
const canSetDataDir = ref(false)
|
||||
const isUpdatingDataDir = ref(false)
|
||||
@@ -72,6 +73,7 @@ const canMigrateToDefault = computed(() => {
|
||||
dataDir.value &&
|
||||
defaultDataDir.value &&
|
||||
dataDir.value !== defaultDataDir.value &&
|
||||
hasLegacyDataAtDefaultDir.value &&
|
||||
!isMigrateHintIgnored.value
|
||||
)
|
||||
})
|
||||
@@ -95,6 +97,7 @@ async function loadDataDir() {
|
||||
dataDir.value = info.path
|
||||
dataDirInput.value = info.pendingMigration?.to || info.path
|
||||
defaultDataDir.value = info.defaultPath || ''
|
||||
hasLegacyDataAtDefaultDir.value = Boolean(info.hasLegacyDataAtDefaultDir)
|
||||
isCustomDataDir.value = info.isCustom
|
||||
canSetDataDir.value = IS_ELECTRON || Boolean(info.canSetDataDir)
|
||||
updateMigrateHintIgnored()
|
||||
|
||||
Vendored
+1
@@ -21,6 +21,7 @@ export interface DataDirInfo {
|
||||
defaultPath?: string
|
||||
isCustom: boolean
|
||||
canSetDataDir?: boolean
|
||||
hasLegacyDataAtDefaultDir?: boolean
|
||||
pendingMigration?: {
|
||||
from: string
|
||||
to: string
|
||||
|
||||
Reference in new issue
Block a user