mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
fix: write data directory compatibility gate on migration and import
Harden the startup migration path: fail fast and show an error dialog if schema migration cannot complete. Repair the gate retroactively for databases that were already migrated before the gate system existed. Raise the gate after every import path (full import, incremental import, stream import) and after opening any database that already carries a current-segment schema. Centralise gate-raising inside DatabaseManager so call sites cannot accidentally skip it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
1c7781d85b
commit
e7561e224e
25 files changed
+941
-124
No files matched your search
@@ -0,0 +1,102 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import type { PathProvider } from '@openchatlab/core'
|
||||
import { DatabaseManager, raiseDataDirMinRuntimeVersion, readDataDirCompatibilityMeta } from '@openchatlab/node-runtime'
|
||||
import { importData } from './importer'
|
||||
|
||||
const nativeBinding = path.resolve('apps/cli/native/better_sqlite3.node')
|
||||
|
||||
function makeTempDir(): string {
|
||||
const baseDir = fs.existsSync('/private/tmp') ? '/private/tmp' : os.tmpdir()
|
||||
return fs.mkdtempSync(path.join(baseDir, 'chatlab-cli-import-'))
|
||||
}
|
||||
|
||||
function createPathProvider(root: string): PathProvider {
|
||||
return {
|
||||
getSystemDir: () => root,
|
||||
getUserDataDir: () => path.join(root, 'data'),
|
||||
getDatabaseDir: () => path.join(root, 'data', 'databases'),
|
||||
getAiDataDir: () => path.join(root, 'ai'),
|
||||
getSettingsDir: () => path.join(root, 'settings'),
|
||||
getCacheDir: () => path.join(root, 'cache'),
|
||||
getTempDir: () => path.join(root, 'temp'),
|
||||
getLogsDir: () => path.join(root, 'logs'),
|
||||
getDownloadsDir: () => path.join(root, 'downloads'),
|
||||
}
|
||||
}
|
||||
|
||||
test('importData raises the data directory gate after creating a current-schema database', async () => {
|
||||
const root = makeTempDir()
|
||||
fs.mkdirSync(path.join(root, 'data', 'databases'), { recursive: true })
|
||||
const manager = new DatabaseManager(createPathProvider(root), {
|
||||
nativeBinding,
|
||||
runtime: { version: '0.25.1', kind: 'cli' },
|
||||
})
|
||||
|
||||
const result = await importData(
|
||||
manager,
|
||||
{
|
||||
meta: { name: 'Fresh Import', platform: 'qq', type: 'group' },
|
||||
members: [{ platformId: 'u1', accountName: 'Alice' }],
|
||||
messages: [
|
||||
{
|
||||
senderPlatformId: 'u1',
|
||||
senderAccountName: 'Alice',
|
||||
timestamp: 1000,
|
||||
type: 0,
|
||||
content: 'hello',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ nativeBinding }
|
||||
)
|
||||
|
||||
assert.equal(result.success, true)
|
||||
const meta = readDataDirCompatibilityMeta(path.join(root, 'data'))
|
||||
assert.equal(meta?.minRuntimeVersion, '0.25.1')
|
||||
assert.equal(meta?.dataCompatibilityVersion, 1)
|
||||
assert.deepEqual(meta?.reasons, ['segment-schema'])
|
||||
})
|
||||
|
||||
test('importData re-checks data directory compatibility before raw database writes', async () => {
|
||||
const root = makeTempDir()
|
||||
fs.mkdirSync(path.join(root, 'data', 'databases'), { recursive: true })
|
||||
const pathProvider = createPathProvider(root)
|
||||
raiseDataDirMinRuntimeVersion(pathProvider, {
|
||||
minRuntimeVersion: '0.26.0',
|
||||
dataCompatibilityVersion: 2,
|
||||
reason: 'future-schema',
|
||||
runtime: { version: '0.26.0', kind: 'desktop' },
|
||||
module: 'future-migration',
|
||||
now: () => 1780830000,
|
||||
})
|
||||
const manager = new DatabaseManager(pathProvider, {
|
||||
nativeBinding,
|
||||
runtime: { version: '0.25.1', kind: 'cli' },
|
||||
})
|
||||
|
||||
const result = await importData(
|
||||
manager,
|
||||
{
|
||||
meta: { name: 'Blocked Import', platform: 'qq', type: 'group' },
|
||||
members: [{ platformId: 'u1', accountName: 'Alice' }],
|
||||
messages: [
|
||||
{
|
||||
senderPlatformId: 'u1',
|
||||
senderAccountName: 'Alice',
|
||||
timestamp: 1000,
|
||||
type: 0,
|
||||
content: 'hello',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ nativeBinding }
|
||||
)
|
||||
|
||||
assert.equal(result.success, false)
|
||||
assert.match(result.error ?? '', /requires runtime version 0\.26\.0 or newer/)
|
||||
assert.equal(fs.readdirSync(path.join(root, 'data', 'databases')).filter((name) => name.endsWith('.db')).length, 0)
|
||||
})
|
||||
@@ -10,7 +10,7 @@ import * as crypto from 'crypto'
|
||||
import type { DatabaseAdapter } from '@openchatlab/core'
|
||||
import { CHAT_DB_SCHEMA, FTS_TABLE_SCHEMA, generateMessageKey, buildMemberIdMap } from '@openchatlab/core'
|
||||
import type { DatabaseManager } from '@openchatlab/node-runtime'
|
||||
import { openBetterSqliteDatabase, writeParseResultToDb } from '@openchatlab/node-runtime'
|
||||
import { writeParseResultToDb } from '@openchatlab/node-runtime'
|
||||
import type { ParsedData, ImportMessage } from './chatlab-reader'
|
||||
|
||||
export interface ImportResult {
|
||||
@@ -272,40 +272,30 @@ export async function importData(
|
||||
|
||||
try {
|
||||
if (exists) {
|
||||
dbManager.close(sessionId)
|
||||
const db = openBetterSqliteDatabase(dbPath, { readonly: false, nativeBinding: options?.nativeBinding })
|
||||
const db = dbManager.openRawSessionDatabase(sessionId, { readonly: false })
|
||||
let result: { messageCount: number; memberCount: number; duplicateCount: number }
|
||||
try {
|
||||
const result = incrementalImport(db, data, options?.onProgress)
|
||||
result = incrementalImport(db, data, options?.onProgress)
|
||||
} finally {
|
||||
db.close()
|
||||
return { success: true, sessionId, created: false, ...result }
|
||||
} catch (err) {
|
||||
db.close()
|
||||
throw err
|
||||
}
|
||||
dbManager.raiseCurrentChatDbCompatibilityGate()
|
||||
return { success: true, sessionId, created: false, ...result }
|
||||
}
|
||||
|
||||
const db = openBetterSqliteDatabase(dbPath, { nativeBinding: options?.nativeBinding })
|
||||
const result = fullImport(db, data, options?.onProgress)
|
||||
db.close()
|
||||
const db = dbManager.openRawSessionDatabase(sessionId, { create: true })
|
||||
let result: { messageCount: number; memberCount: number; duplicateCount: number }
|
||||
try {
|
||||
result = fullImport(db, data, options?.onProgress)
|
||||
} finally {
|
||||
db.close()
|
||||
}
|
||||
dbManager.raiseCurrentChatDbCompatibilityGate()
|
||||
return { success: true, sessionId, created: true, ...result }
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
if (!exists) {
|
||||
try {
|
||||
fs.unlinkSync(dbPath)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
fs.unlinkSync(dbPath + '-wal')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
fs.unlinkSync(dbPath + '-shm')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
dbManager.deleteSessionDatabaseFiles(sessionId)
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import type { PathProvider } from '@openchatlab/core'
|
||||
import { DatabaseManager, readDataDirCompatibilityMeta } from '@openchatlab/node-runtime'
|
||||
import { incrementalImport } from './stream-import'
|
||||
|
||||
const nativeBinding = path.resolve('apps/cli/native/better_sqlite3.node')
|
||||
|
||||
function makeTempDir(): string {
|
||||
const baseDir = fs.existsSync('/private/tmp') ? '/private/tmp' : os.tmpdir()
|
||||
return fs.mkdtempSync(path.join(baseDir, 'chatlab-cli-stream-import-'))
|
||||
}
|
||||
|
||||
function createPathProvider(root: string): PathProvider {
|
||||
return {
|
||||
getSystemDir: () => root,
|
||||
getUserDataDir: () => path.join(root, 'data'),
|
||||
getDatabaseDir: () => path.join(root, 'data', 'databases'),
|
||||
getAiDataDir: () => path.join(root, 'ai'),
|
||||
getSettingsDir: () => path.join(root, 'settings'),
|
||||
getCacheDir: () => path.join(root, 'cache'),
|
||||
getTempDir: () => path.join(root, 'temp'),
|
||||
getLogsDir: () => path.join(root, 'logs'),
|
||||
getDownloadsDir: () => path.join(root, 'downloads'),
|
||||
}
|
||||
}
|
||||
|
||||
function writeIncrementalJsonl(filePath: string): void {
|
||||
const rows = [
|
||||
{
|
||||
_type: 'header',
|
||||
chatlab: { version: '1.0.0', exportedAt: 1780830000 },
|
||||
meta: { name: 'Incremental Chat', platform: 'qq', type: 'group' },
|
||||
},
|
||||
{ _type: 'member', platformId: 'u1', accountName: 'Alice' },
|
||||
{
|
||||
_type: 'message',
|
||||
sender: 'u1',
|
||||
accountName: 'Alice',
|
||||
timestamp: 2000,
|
||||
type: 0,
|
||||
content: 'new incremental message',
|
||||
platformMessageId: 'm1',
|
||||
},
|
||||
]
|
||||
fs.writeFileSync(filePath, rows.map((row) => JSON.stringify(row)).join('\n'), 'utf-8')
|
||||
}
|
||||
|
||||
test('incrementalImport raises the data directory gate after successful writes', async () => {
|
||||
const root = makeTempDir()
|
||||
const pathProvider = createPathProvider(root)
|
||||
const manager = new DatabaseManager(pathProvider, {
|
||||
nativeBinding,
|
||||
runtime: { version: '0.25.1', kind: 'cli' },
|
||||
})
|
||||
|
||||
const db = manager.openRawSessionDatabase('existing', { create: true, initializeChatTables: true })
|
||||
db.prepare('INSERT INTO meta (name, platform, type, imported_at) VALUES (?, ?, ?, ?)').run(
|
||||
'Existing Chat',
|
||||
'qq',
|
||||
'group',
|
||||
1000
|
||||
)
|
||||
db.prepare('INSERT INTO member (platform_id, account_name) VALUES (?, ?)').run('u0', 'Existing User')
|
||||
db.close()
|
||||
|
||||
const filePath = path.join(root, 'incremental.jsonl')
|
||||
writeIncrementalJsonl(filePath)
|
||||
|
||||
const result = await incrementalImport(manager, 'existing', filePath)
|
||||
|
||||
assert.equal(result.success, true)
|
||||
assert.equal(result.newMessageCount, 1)
|
||||
const meta = readDataDirCompatibilityMeta(pathProvider.getUserDataDir())
|
||||
assert.equal(meta?.minRuntimeVersion, '0.25.1')
|
||||
assert.equal(meta?.dataCompatibilityVersion, 1)
|
||||
assert.deepEqual(meta?.reasons, ['segment-schema'])
|
||||
})
|
||||
@@ -6,12 +6,10 @@
|
||||
* nickname history, FTS, format fallback).
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import type { DatabaseManager } from '@openchatlab/node-runtime'
|
||||
import {
|
||||
DataDirCompatibilityError,
|
||||
streamingImport,
|
||||
openBetterSqliteDatabase,
|
||||
analyzeNewImport as sharedAnalyzeNewImport,
|
||||
analyzeIncrementalImport as sharedAnalyzeIncremental,
|
||||
incrementalImport as sharedIncrementalImport,
|
||||
@@ -27,7 +25,6 @@ import type {
|
||||
ImportOptions,
|
||||
AnalyzeNewImportResult,
|
||||
} from '@openchatlab/node-runtime'
|
||||
import { CHAT_DB_TABLES } from '@openchatlab/core'
|
||||
import {
|
||||
detectFormat as parserDetectFormat,
|
||||
detectAllFormats,
|
||||
@@ -65,31 +62,13 @@ function generateSessionId(): string {
|
||||
return `chat_${ts}_${rand}`
|
||||
}
|
||||
|
||||
function resolveNativeBinding(dbManager: DatabaseManager): string | undefined {
|
||||
return (dbManager as any).nativeBinding
|
||||
}
|
||||
|
||||
function buildStreamImportDeps(dbManager: DatabaseManager, onProgress?: ImportProgressCallback): StreamImportDeps {
|
||||
const nativeBinding = resolveNativeBinding(dbManager)
|
||||
return {
|
||||
openDatabase(sessionId: string) {
|
||||
const dbPath = dbManager.getDbPath(sessionId)
|
||||
const dir = path.dirname(dbPath)
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
|
||||
const db = openBetterSqliteDatabase(dbPath, { nativeBinding })
|
||||
db.exec(CHAT_DB_TABLES)
|
||||
return db
|
||||
return dbManager.openRawSessionDatabase(sessionId, { create: true, initializeChatTables: true })
|
||||
},
|
||||
deleteDatabase(sessionId: string) {
|
||||
const dbPath = dbManager.getDbPath(sessionId)
|
||||
for (const suffix of ['', '-wal', '-shm']) {
|
||||
try {
|
||||
const p = dbPath + suffix
|
||||
if (fs.existsSync(p)) fs.unlinkSync(p)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
dbManager.deleteSessionDatabaseFiles(sessionId)
|
||||
},
|
||||
onProgress: onProgress ?? (() => {}),
|
||||
postImportHook(db) {
|
||||
@@ -103,6 +82,10 @@ function buildStreamImportDeps(dbManager: DatabaseManager, onProgress?: ImportPr
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSessionDatabase(dbManager: DatabaseManager, sessionId: string): void {
|
||||
dbManager.deleteSessionDatabaseFiles(sessionId)
|
||||
}
|
||||
|
||||
/**
|
||||
* High-performance streaming import: parse a file and write to DB
|
||||
* with batched transactions, deferred indexes, and FTS.
|
||||
@@ -157,20 +140,38 @@ export async function streamImport(
|
||||
: () => {}
|
||||
|
||||
const deps = buildStreamImportDeps(dbManager, progressAdapter)
|
||||
return streamingImport(filePath, deps, formatOptions)
|
||||
const result = await streamingImport(filePath, deps, formatOptions)
|
||||
if (!result.success || !result.sessionId) return result
|
||||
|
||||
try {
|
||||
dbManager.raiseCurrentChatDbCompatibilityGate()
|
||||
} catch (error) {
|
||||
deleteSessionDatabase(dbManager, result.sessionId)
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
diagnostics: result.diagnostics,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ==================== Incremental import ====================
|
||||
|
||||
function buildIncrementalDeps(dbManager: DatabaseManager, onProgress?: ImportProgressCallback): IncrementalImportDeps {
|
||||
const nativeBinding = resolveNativeBinding(dbManager)
|
||||
function buildIncrementalDeps(
|
||||
dbManager: DatabaseManager,
|
||||
onProgress?: ImportProgressCallback,
|
||||
onCompatibilityError?: (error: DataDirCompatibilityError) => void
|
||||
): IncrementalImportDeps {
|
||||
return {
|
||||
openDatabase(sessionId: string, readonly?: boolean) {
|
||||
const dbPath = dbManager.getDbPath(sessionId)
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
throw new Error(`Session database not found: ${sessionId}`)
|
||||
try {
|
||||
return dbManager.openRawSessionDatabase(sessionId, { readonly: readonly ?? false })
|
||||
} catch (error) {
|
||||
if (error instanceof DataDirCompatibilityError) onCompatibilityError?.(error)
|
||||
throw error
|
||||
}
|
||||
return openBetterSqliteDatabase(dbPath, { readonly: readonly ?? false, nativeBinding })
|
||||
},
|
||||
onProgress: onProgress ?? (() => {}),
|
||||
postImportHook(db) {
|
||||
@@ -190,7 +191,30 @@ export async function incrementalImport(
|
||||
options?: ImportOptions & { onProgress?: ImportProgressCallback }
|
||||
): Promise<IncrementalImportResult> {
|
||||
const { onProgress, ...importOpts } = options || {}
|
||||
return sharedIncrementalImport(sessionId, filePath, buildIncrementalDeps(dbManager, onProgress), importOpts)
|
||||
let compatibilityError: DataDirCompatibilityError | null = null
|
||||
const result = await sharedIncrementalImport(
|
||||
sessionId,
|
||||
filePath,
|
||||
buildIncrementalDeps(dbManager, onProgress, (error) => {
|
||||
compatibilityError = error
|
||||
}),
|
||||
importOpts
|
||||
)
|
||||
if (compatibilityError) throw compatibilityError
|
||||
if (!result.success) return result
|
||||
|
||||
try {
|
||||
dbManager.raiseCurrentChatDbCompatibilityGate()
|
||||
} catch (error) {
|
||||
return {
|
||||
...result,
|
||||
success: false,
|
||||
newMessageCount: 0,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export async function analyzeIncrementalImport(
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import type { PathProvider } from '@openchatlab/core'
|
||||
import { DatabaseManager, DataDirCompatibilityError, raiseDataDirMinRuntimeVersion } from '@openchatlab/node-runtime'
|
||||
import { DirectImporter } from './adapters'
|
||||
|
||||
const nativeBinding = path.resolve('apps/cli/native/better_sqlite3.node')
|
||||
|
||||
function makeTempDir(): string {
|
||||
const baseDir = fs.existsSync('/private/tmp') ? '/private/tmp' : os.tmpdir()
|
||||
return fs.mkdtempSync(path.join(baseDir, 'chatlab-cli-sync-'))
|
||||
}
|
||||
|
||||
function createPathProvider(root: string): PathProvider {
|
||||
return {
|
||||
getSystemDir: () => root,
|
||||
getUserDataDir: () => path.join(root, 'data'),
|
||||
getDatabaseDir: () => path.join(root, 'data', 'databases'),
|
||||
getAiDataDir: () => path.join(root, 'ai'),
|
||||
getSettingsDir: () => path.join(root, 'settings'),
|
||||
getCacheDir: () => path.join(root, 'cache'),
|
||||
getTempDir: () => path.join(root, 'temp'),
|
||||
getLogsDir: () => path.join(root, 'logs'),
|
||||
getDownloadsDir: () => path.join(root, 'downloads'),
|
||||
}
|
||||
}
|
||||
|
||||
test('DirectImporter.sessionExists preserves session DBs when compatibility gate blocks access', () => {
|
||||
const root = makeTempDir()
|
||||
const pathProvider = createPathProvider(root)
|
||||
const dbDir = pathProvider.getDatabaseDir()
|
||||
fs.mkdirSync(dbDir, { recursive: true })
|
||||
const dbPath = path.join(dbDir, 'blocked.db')
|
||||
fs.writeFileSync(dbPath, 'sqlite content is not opened before the compatibility check', 'utf-8')
|
||||
raiseDataDirMinRuntimeVersion(pathProvider, {
|
||||
minRuntimeVersion: '0.26.0',
|
||||
dataCompatibilityVersion: 2,
|
||||
reason: 'future-schema',
|
||||
runtime: { version: '0.26.0', kind: 'desktop' },
|
||||
module: 'future-migration',
|
||||
now: () => 1780830000,
|
||||
})
|
||||
|
||||
const manager = new DatabaseManager(pathProvider, {
|
||||
nativeBinding,
|
||||
runtime: { version: '0.25.1', kind: 'cli' },
|
||||
})
|
||||
const importer = new DirectImporter(manager)
|
||||
|
||||
assert.throws(
|
||||
() => importer.sessionExists('blocked'),
|
||||
(error) => error instanceof DataDirCompatibilityError && error.code === 'DATA_DIR_REQUIRES_NEWER_RUNTIME'
|
||||
)
|
||||
assert.equal(fs.existsSync(dbPath), true)
|
||||
})
|
||||
@@ -14,10 +14,9 @@ import type { HttpFetcher, DataImporter, SyncNotifier, ImportResult, FetchParams
|
||||
import { NOOP_LOGGER } from '@openchatlab/sync'
|
||||
import { buildPullUrl } from '@openchatlab/sync'
|
||||
import type { DatabaseManager } from '@openchatlab/node-runtime'
|
||||
import { openBetterSqliteDatabase } from '@openchatlab/node-runtime'
|
||||
import { DataDirCompatibilityError } from '@openchatlab/node-runtime'
|
||||
import { parseFile } from '../import/chatlab-reader'
|
||||
import { importData } from '../import/importer'
|
||||
import { resolveCliPath } from '../paths'
|
||||
|
||||
function getTempFilePath(ext: string): string {
|
||||
const id = crypto.randomBytes(8).toString('hex')
|
||||
@@ -51,21 +50,12 @@ export class NodeFetcher implements HttpFetcher {
|
||||
|
||||
// ==================== DirectImporter ====================
|
||||
|
||||
function resolveNativeBinding(): string | undefined {
|
||||
if (process.versions.electron) return undefined
|
||||
const nativePath = resolveCliPath('native/better_sqlite3.node')
|
||||
if (fs.existsSync(nativePath)) return nativePath
|
||||
return undefined
|
||||
}
|
||||
|
||||
export class DirectImporter implements DataImporter {
|
||||
private dbManager: DatabaseManager
|
||||
private nativeBinding: string | undefined
|
||||
private logger: SyncLogger
|
||||
|
||||
constructor(dbManager: DatabaseManager, logger?: SyncLogger) {
|
||||
this.dbManager = dbManager
|
||||
this.nativeBinding = resolveNativeBinding()
|
||||
this.logger = logger ?? NOOP_LOGGER
|
||||
}
|
||||
|
||||
@@ -73,7 +63,7 @@ export class DirectImporter implements DataImporter {
|
||||
const dbPath = this.dbManager.getDbPath(sessionId)
|
||||
if (!fs.existsSync(dbPath)) return false
|
||||
try {
|
||||
const db = openBetterSqliteDatabase(dbPath, { readonly: true, nativeBinding: this.nativeBinding })
|
||||
const db = this.dbManager.openRawSessionDatabase(sessionId, { readonly: true })
|
||||
const row = db
|
||||
.prepare("SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='message'")
|
||||
.get() as { cnt: number }
|
||||
@@ -88,7 +78,9 @@ export class DirectImporter implements DataImporter {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} catch {
|
||||
} catch (error) {
|
||||
if (error instanceof DataDirCompatibilityError) throw error
|
||||
|
||||
this.logger.warn(`[DirectImporter] Cannot validate DB file: ${sessionId}, removing`)
|
||||
try {
|
||||
fs.unlinkSync(dbPath)
|
||||
@@ -119,7 +111,6 @@ export class DirectImporter implements DataImporter {
|
||||
this.dbManager.close(sessionId)
|
||||
const result = await importData(this.dbManager, data, {
|
||||
sessionId,
|
||||
nativeBinding: this.nativeBinding,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
@@ -154,7 +145,6 @@ export class DirectImporter implements DataImporter {
|
||||
|
||||
const result = await importData(this.dbManager, data, {
|
||||
sessionId: externalId,
|
||||
nativeBinding: this.nativeBinding,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
|
||||
Reference in new issue
Block a user