fix: remove better-sqlite3 that is not working anymore

This commit is contained in:
linonetwo 2024-03-20 19:23:06 +08:00
parent 4e3985040f
commit c79143fd32
15 changed files with 10 additions and 416 deletions

View file

@ -82,8 +82,6 @@ Some library doesn't fit electron usage, we move their code to this repo and mod
- [app-path](https://github.com/sindresorhus/app-path): Need to be installed, so we can copy its binary to the resource folder. This lib is used by `externalApp` below.
- When not installed in package.json, when make release, forge will throw error `An unhandled rejection has occurred inside Forge: Error: ENOENT: no such file or directory, stat '/Users/linonetwo/Desktop/repo/TiddlyGit-Desktop/node_modules/app-path/main'`
- [externalApp](https://github.com/desktop/desktop/blob/742b4c44c39d64d01048f1e85364d395432e3413/app/src/lib/editors/lookup.ts): This was used by [Github Desktop](https://github.com/desktop/desktop) to lookup the location of editors like VSCode, we use it in context menu to "open in default text editor"
- [sqlite-vss](https://github.com/asg017/sqlite-vss): The path from its method `loadablePathResolver` maybe incorrect after electron app packaged. (It will be in `.webpack/main/index.js` in the dist folder instead of in `node_modules/sqlite-vss` folder.)
- Still need to install its `optionalDependencies` like `sqlite-vss-darwin-x64` in package.json
## Code Tour

View file

@ -88,7 +88,6 @@ exports.default = async (
}),
);
const packagePathsToCopyDereferenced = [
[`sqlite-vss-${process.platform}-${process.arch}`],
['@tiddlygit', 'tiddlywiki', 'package.json'],
['@tiddlygit', 'tiddlywiki', 'boot'],
['@tiddlygit', 'tiddlywiki', 'core'],
@ -106,7 +105,6 @@ exports.default = async (
['@llama-node', 'rwkv-cpp', 'package.json'],
['@llama-node', 'llama-cpp', 'index.js'],
['@llama-node', 'llama-cpp', 'package.json'],
['better-sqlite3', 'build', 'Release', 'better_sqlite3.node'],
// we only need its `main` binary, no need its dependency and code, because we already copy it to src/services/native/externalApp
['app-path', 'main'],
];

View file

@ -2,7 +2,7 @@ import { app } from 'electron';
import path from 'path';
import { __TEST__ as v8CompileCacheLibrary } from 'v8-compile-cache-lib';
import { isDevelopmentOrTest } from './environment';
import { cacheDatabaseFolderName, httpsCertKeyFolderName, languageModelFolderName, settingFolderName } from './fileNames';
import { httpsCertKeyFolderName, languageModelFolderName, settingFolderName } from './fileNames';
import { sourcePath } from './paths';
// in dev mode, set userData to a different folder, so gotTheLock will be true, we can run dev instance and normal instance.
@ -12,7 +12,6 @@ if (isDevelopmentOrTest) {
export const USER_DATA_FOLDER = app.getPath('userData');
export const SETTINGS_FOLDER = path.resolve(USER_DATA_FOLDER, settingFolderName);
export const HTTPS_CERT_KEY_FOLDER = path.resolve(USER_DATA_FOLDER, httpsCertKeyFolderName);
export const CACHE_DATABASE_FOLDER = path.resolve(USER_DATA_FOLDER, cacheDatabaseFolderName);
/** During dev, we don't want to clean up the language model folder */
export const LANGUAGE_MODEL_FOLDER = isDevelopmentOrTest
? path.resolve(sourcePath, '..', `${languageModelFolderName}-dev`)

View file

@ -26,7 +26,6 @@ export const PACKAGE_PATH_BASE = isDevelopmentOrTest
: path.resolve(process.resourcesPath, 'node_modules');
export const ZX_FOLDER = path.resolve(PACKAGE_PATH_BASE, 'zx', 'build', 'cli.js');
export const TIDDLYWIKI_PACKAGE_FOLDER = path.resolve(PACKAGE_PATH_BASE, '@tiddlygit', 'tiddlywiki', 'boot');
export const SQLITE_BINARY_PATH = path.resolve(PACKAGE_PATH_BASE, 'better-sqlite3', 'build', 'Release', 'better_sqlite3.node');
export const RWKV_CPP_TOKENIZER_PATH = path.resolve(PACKAGE_PATH_BASE, 'llama-node', '20B_tokenizer.json');
export const LOCALIZATION_FOLDER = isDevelopmentOrTest

View file

@ -1,9 +1,5 @@
# Database Service
We have workspace level db, work as cache for tiddlers, and change logs (to record deletion, for sync deletion with mobile clients).
We used to have workspace level db, work as cache for tiddlers, and change logs (to record deletion, for sync deletion with mobile clients).
And we have app level db, to store things for pages like workflow pages. They are also regarded as temporary cache, and user can toggle a switch to store something inside cache to a wiki.
## App level DB
`src/services/database/entity` and `src/services/database/migration` are for app level db.
But better-sqlite build failed for latest electron, and sqlite-vss is always not useable, so we drop support for sqlite.

View file

@ -1,111 +1,19 @@
/* eslint-disable @typescript-eslint/require-await */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
import Sqlite3Database from 'better-sqlite3';
import settings from 'electron-settings';
import fs from 'fs-extra';
import { injectable } from 'inversify';
import { debounce } from 'lodash';
import path from 'path';
import * as rotateFs from 'rotating-file-stream';
import { DataSource } from 'typeorm';
import { CACHE_DATABASE_FOLDER } from '@/constants/appPaths';
import { DEBOUNCE_SAVE_SETTING_BACKUP_FILE, DEBOUNCE_SAVE_SETTING_FILE } from '@/constants/parameters';
import { PACKAGE_PATH_BASE, SQLITE_BINARY_PATH } from '@/constants/paths';
import { logger } from '@services/libs/log';
import { fixSettingFileWhenError } from './configSetting';
import { IDatabaseService, ISettingFile } from './interface';
import { loadSqliteVss } from './sqlite-vss';
@injectable()
export class DatabaseService implements IDatabaseService {
// tiddlywiki require methods to be sync, so direct run them in the main process. But later we can use worker_thread to run heavier search queries, as a readonly slave db, and do some data sync between them.
// many operations has to be done in wikiWorker, so can be accessed by nodejs wiki in a sync way.
// private readonly dbWorker?: ModuleThread<GitWorker>;
async initializeForWorkspace(workspaceID: string): Promise<void> {
const destinationFilePath = this.getWorkspaceDataBasePath(workspaceID);
// only create db file for this workspace's wiki if it doesn't exist
if (await fs.exists(this.getWorkspaceDataBasePath(workspaceID))) {
logger.debug(`DatabaseService.initializeForWorkspace skip, there already has sqlite database for workspace ${workspaceID} in ${destinationFilePath}`);
return;
}
await fs.ensureDir(CACHE_DATABASE_FOLDER);
try {
// create a database and table that adapts tiddlywiki usage
logger.debug(`DatabaseService.initializeForWorkspace create a sqlite database for workspace`, { SQLITE_BINARY_PATH, workspaceID });
let database: Sqlite3Database.Database;
try {
database = new Sqlite3Database(':memory:', { verbose: logger.debug, nativeBinding: SQLITE_BINARY_PATH });
} catch (error) {
logger.error(`error when loading sqlite3 for workspace ${workspaceID}, skip because of error to prevent crash: ${(error as Error).message}`);
return;
}
try {
logger.debug(`DatabaseService.initializeForWorkspace load vss for sqlite database`, { PACKAGE_PATH_BASE, workspaceID });
loadSqliteVss(database, PACKAGE_PATH_BASE);
const vssVersion = database.prepare('select vss_version()').pluck().get() as string;
logger.debug(`DatabaseService.initializeForWorkspace successfully using sqlite-vss version: ${vssVersion} for workspace ${workspaceID}`);
} catch (error) {
logger.error(`error when loading sqlite-vss for workspace ${workspaceID}: ${(error as Error).message}`);
}
logger.debug(`DatabaseService.initializeForWorkspace create a table that adapts tiddlywiki usage for workspace`, { workspaceID });
/**
* Create table storing most commonly used tiddler fields, other fields are stored in `fields` column as a JSON string.
*/
const createTiddlywikiTable = database.prepare(`
CREATE TABLE IF NOT EXISTS tiddlers (
title TEXT PRIMARY KEY,
text TEXT,
type TEXT,
created INTEGER,
modified INTEGER,
tags TEXT,
fields TEXT,
creator TEXT,
modifier TEXT
);
`);
logger.debug(`DatabaseService.initializeForWorkspace table is created, start backup and close`, { workspaceID });
createTiddlywikiTable.run();
await database.backup(destinationFilePath);
database.close();
} catch (error) {
logger.error(`DatabaseService.initializeForWorkspace error when creating sqlite cache database for workspace: ${(error as Error).message}`, { workspaceID });
}
}
async initializeForApp(): Promise<void> {
const destinationFilePath = this.getAppDataBasePath();
// only create db file for app if it doesn't exist
if (await fs.exists(destinationFilePath)) {
logger.debug(`DatabaseService.initializeForApp skip, there already has sqlite database for app in ${destinationFilePath}`);
return;
}
await fs.ensureDir(CACHE_DATABASE_FOLDER);
try {
logger.debug(`DatabaseService.initializeForApp create a sqlite database for app`, { SQLITE_BINARY_PATH });
// Initialize TypeORM Connection using DataSource
const appDataSource = new DataSource({
type: 'better-sqlite3',
nativeBinding: SQLITE_BINARY_PATH,
database: destinationFilePath,
// entities,
synchronize: false,
migrationsRun: true,
logging: true,
// migrations,
});
await appDataSource.initialize();
await appDataSource.runMigrations();
await appDataSource.destroy();
logger.info(`DatabaseService.initializeForApp TypeORM connection initialized and migrations ran for app`);
} catch (error) {
logger.error(`DatabaseService.initializeForApp error when initializing TypeORM connection and running migrations for app: ${(error as Error).message}`);
}
// init config
try {
this.settingBackupStream = rotateFs.createStream(`${settings.file()}.bak`, {
@ -118,100 +26,6 @@ export class DatabaseService implements IDatabaseService {
}
}
private readonly dataSources = new Map<string, DataSource>();
async getAppDatabase(isRetry = false): Promise<DataSource> {
const name = 'app-tidgi';
if (!this.dataSources.has(name)) {
try {
const dataSource = new DataSource({
type: 'sqlite',
database: this.getAppDataBasePath(),
// entities,
synchronize: false,
migrationsRun: false,
logging: true,
// migrations,
});
/**
* Error `TypeError: Cannot read property 'transaction' of undefined` will show if run any query without initialize.
*/
await dataSource.initialize();
this.dataSources.set(name, dataSource);
return dataSource;
} catch (error) {
console.error(`Failed to getDatabase ${name}: ${(error as Error).message} ${(error as Error).stack ?? ''}`);
if (!isRetry) {
try {
await this.#fixAppDbLock();
return await this.getAppDatabase(true);
} catch (error) {
console.error(`Failed to retry getDatabase ${name}: ${(error as Error).message} ${(error as Error).stack ?? ''}`);
}
}
try {
await this.dataSources.get(name)?.destroy();
} catch (error) {
console.error(`Failed to destroy in getDatabase ${name}: ${(error as Error).message} ${(error as Error).stack ?? ''}`);
}
throw error;
}
}
return this.dataSources.get(name)!;
}
async closeAppDatabase(drop?: boolean) {
const name = 'app-tidgi';
if (this.dataSources.has(name)) {
try {
const dataSource = this.dataSources.get(name)!;
this.dataSources.delete(name);
if (drop === true) {
await dataSource.dropDatabase();
// need to delete the file. May encounter SQLITE_BUSY error if not deleted.
await fs.unlink(this.getAppDataBasePath());
} else {
await dataSource.destroy();
console.log(`closeDatabase ${name}`);
}
} catch (error) {
console.error(`Failed to closeDatabase ${name}: ${(error as Error).message} ${(error as Error).stack ?? ''}`);
throw error;
}
}
}
/**
* Fix SQLite busy by move the file.
* @url https://stackoverflow.com/a/1226850
*
* Fixes this:
*
* ```error
* [Error: Error getting skinny tiddlers list from SQLite: Call to function 'ExpoSQLite.exec' has been rejected.
* Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY): , while compiling: PRAGMA journal_mode] Error: Error getting skinny tiddlers list from SQLite: Call to function 'ExpoSQLite.exec' has been rejected.
* Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY): , while compiling: PRAGMA journal_mode
* ```
*/
async #fixAppDbLock() {
const oldSqlitePath = this.getAppDataBasePath();
const temporarySqlitePath = `${oldSqlitePath}.temp`;
await fs.copy(oldSqlitePath, temporarySqlitePath);
await fs.unlink(oldSqlitePath);
await fs.copy(temporarySqlitePath, oldSqlitePath);
await fs.unlink(temporarySqlitePath);
}
getWorkspaceDataBasePath(workspaceID: string): string {
return path.resolve(CACHE_DATABASE_FOLDER, `${workspaceID}-sqlite3-cache.db`);
}
getAppDataBasePath(): string {
return path.resolve(CACHE_DATABASE_FOLDER, `app-tidgi-sqlite3-cache.db`);
}
private settingFileContent: ISettingFile = settings.getSync() as unknown as ISettingFile || {};
private settingBackupStream: rotateFs.RotatingFileStream | undefined;

View file

@ -4,7 +4,6 @@ import { IPage } from '@services/pages/interface';
import { IPreferences } from '@services/preferences/interface';
import { IWorkspace } from '@services/workspaces/interface';
import { ProxyPropertyType } from 'electron-ipc-cat/common';
import { DataSource } from 'typeorm';
export interface ISettingFile {
pages: Record<string, IPage>;
@ -14,31 +13,19 @@ export interface ISettingFile {
}
/**
* Allow wiki or external app to save/search tiddlers cache from database like sqlite+sqlite-vss (vector storage)
* Allow wiki or external app to save/search external non-tiddlywiki store like sqlite (removed) or config file.
*/
export interface IDatabaseService {
closeAppDatabase(drop?: boolean): void;
getAppDataBasePath(): string;
/**
* Get a database connection for the app db, which is a sqlite manages by TypeORM for all app level data
*/
getAppDatabase(isRetry?: boolean): Promise<DataSource>;
/**
* Get setting that used by services
* @param key setting file top level key like `userInfos`
*/
getSetting<K extends keyof ISettingFile>(key: K): ISettingFile[K] | undefined;
getWorkspaceDataBasePath(workspaceID: string): string;
/**
* Save settings to FS. Due to bugs of electron-settings, you should mostly use `setSetting` instead.
*/
immediatelyStoreSettingsToFile(): Promise<void>;
initializeForApp(): Promise<void>;
/**
* Create a database file for a workspace, store it in the appData folder, and load it in a worker_thread to execute SQL. *
* (not store `.db` file in the workspace wiki's folder, because this cache file shouldn't not by Database committed)
*/
initializeForWorkspace(workspaceID: string): Promise<void>;
/**
* Save setting that used by services to same file, will handle data race.
* Normally you should use methods on other services instead of this, and they will can this method instead.
@ -50,9 +37,7 @@ export interface IDatabaseService {
export const DatabaseServiceIPCDescriptor = {
channel: DatabaseChannel.name,
properties: {
getAppDataBasePath: ProxyPropertyType.Function,
getDataBasePath: ProxyPropertyType.Function,
initializeForApp: ProxyPropertyType.Function,
initializeForWorkspace: ProxyPropertyType.Function,
},
};

View file

@ -1,72 +0,0 @@
import type Sqlite3Database from 'better-sqlite3';
import fs from 'fs-extra';
import path from 'path';
import { arch, platform } from 'process';
const supportedPlatforms: Array<[string, string]> = [
['darwin', 'x64'],
['darwin', 'arm64'],
['linux', 'x64'],
];
function validPlatform(platform: string, arch: string): boolean {
return supportedPlatforms.find(([p, a]) => platform === p && arch === a) !== null;
}
function extensionSuffix(platform: string): string {
if (platform === 'win32') return 'dll';
if (platform === 'darwin') return 'dylib';
return 'so';
}
function platformPackageName(platform: string, arch: string): string {
const os = platform === 'win32' ? 'windows' : platform;
return `sqlite-vss-${os}-${arch}`;
}
function loadablePathResolver(name: string, PACKAGE_PATH_BASE: string): string {
if (!validPlatform(platform, arch)) {
throw new Error(
`Unsupported platform for sqlite-vss, on a ${platform}-${arch} machine, but not in supported platforms (${
supportedPlatforms
.map(([p, a]) => `${p}-${a}`)
.join(',')
}). Consult the sqlite-vss NPM package README for details. `,
);
}
const packageName = platformPackageName(platform, arch);
const loadablePath = path.join(
PACKAGE_PATH_BASE,
packageName,
'lib',
`${name}.${extensionSuffix(platform)}`,
);
if (fs.statSync(loadablePath, { throwIfNoEntry: false }) === undefined) {
throw new Error(
`Loadble extension for sqlite-vss not found in ${loadablePath}. Was the ${packageName} package installed? Avoid using the --no-optional flag, as the optional dependencies for sqlite-vss are required.`,
);
}
return loadablePath;
}
export function getVectorLoadablePath(PACKAGE_PATH_BASE: string): string {
return loadablePathResolver('vector0', PACKAGE_PATH_BASE);
}
export function getVssLoadablePath(PACKAGE_PATH_BASE: string): string {
return loadablePathResolver('vss0', PACKAGE_PATH_BASE);
}
export function loadVector(database: Sqlite3Database.Database, PACKAGE_PATH_BASE: string): void {
database.loadExtension(getVectorLoadablePath(PACKAGE_PATH_BASE));
}
export function loadVss(database: Sqlite3Database.Database, PACKAGE_PATH_BASE: string): void {
database.loadExtension(getVssLoadablePath(PACKAGE_PATH_BASE));
}
export function loadSqliteVss(database: Sqlite3Database.Database, PACKAGE_PATH_BASE: string): void {
loadVector(database, PACKAGE_PATH_BASE);
loadVss(database, PACKAGE_PATH_BASE);
}

View file

@ -1,63 +0,0 @@
import type { ITiddlerFields } from '@tiddlygit/tiddlywiki';
import Sqlite3Database from 'better-sqlite3';
import fs from 'fs-extra';
import { loadSqliteVss } from './sqlite-vss';
export interface ISqliteDatabasePaths {
databaseFile: string;
packagePathBase: string;
sqliteBinary: string;
}
export class WikiWorkerDatabaseOperations {
public database: Sqlite3Database.Database;
constructor(paths: ISqliteDatabasePaths) {
if (!fs.existsSync(paths.databaseFile)) {
throw new SqliteDatabaseNotInitializedError(paths.databaseFile);
}
const database = new Sqlite3Database(paths.databaseFile, { verbose: console.log, fileMustExist: true, nativeBinding: paths.sqliteBinary });
this.database = database;
this.prepareMethods();
this.loadVSS(database, paths);
}
loadVSS(database: Sqlite3Database.Database, paths: ISqliteDatabasePaths) {
try {
loadSqliteVss(database, paths.packagePathBase);
} catch {
// ignore, error already logged in src/services/database/index.ts 's `initializeForWorkspace`
}
}
insertTiddlers!: Sqlite3Database.Transaction<(tiddlers: ITiddlerFields[]) => void>;
putTiddlers(tiddlers: ITiddlerFields[]) {
this.insertTiddlers(tiddlers);
}
private prepareMethods() {
const insertTiddler = this.database.prepare(`
INSERT INTO tiddlers (title, text, type, created, modified, tags, fields, creator, modifier)
VALUES (@title, @text, @type, @created, @modified, @tags, @fields, @creator, @modifier)
ON CONFLICT(title) DO UPDATE SET
text = excluded.text,
type = excluded.type,
created = excluded.created,
modified = excluded.modified,
tags = excluded.tags,
fields = excluded.fields,
creator = excluded.creator,
modifier = excluded.modifier
`);
this.insertTiddlers = this.database.transaction((tiddlers: ITiddlerFields[]) => {
for (const tiddler of tiddlers) {
insertTiddler.run(tiddler);
}
});
}
}
export class SqliteDatabaseNotInitializedError extends Error {
constructor(databaseFile: string) {
super();
this.message = `database file not found (This is OK for first init of workspace, until initializeWorkspaceView call initializeForWorkspace): ${databaseFile}`;
}
}

View file

@ -19,7 +19,6 @@ const logger = (
close: () => {},
})
: winston.createLogger({
levels,
transports: [
new winston.transports.Console(),
new winston.transports.DailyRotateFile({

View file

@ -11,7 +11,7 @@ import { ModuleThread, spawn, Thread, Worker } from 'threads';
import type { WorkerEvent } from 'threads/dist/types/master';
import { WikiChannel } from '@/constants/channels';
import { PACKAGE_PATH_BASE, SQLITE_BINARY_PATH, TIDDLERS_PATH, TIDDLYWIKI_PACKAGE_FOLDER, TIDDLYWIKI_TEMPLATE_FOLDER_PATH } from '@/constants/paths';
import { TIDDLERS_PATH, TIDDLYWIKI_PACKAGE_FOLDER, TIDDLYWIKI_TEMPLATE_FOLDER_PATH } from '@/constants/paths';
import type { IAuthenticationService } from '@services/auth/interface';
import { lazyInject } from '@services/container';
import type { IGitService, IGitUserInfos } from '@services/git/interface';
@ -179,17 +179,6 @@ export class Wiki implements IWikiService {
}
});
logger.debug('startWiki calling initCacheDatabase in the main process', { function: 'wikiWorker.initCacheDatabase' });
worker.initCacheDatabase({
databaseFile: this.databaseService.getWorkspaceDataBasePath(workspaceID),
sqliteBinary: SQLITE_BINARY_PATH,
packagePathBase: PACKAGE_PATH_BASE,
}).subscribe(async (message) => {
if (message.type === 'stderr' || message.type === 'stdout') {
logger.info(message.message, { function: 'wikiWorker.initCacheDatabase' });
}
});
// subscribe to the Observable that startNodeJSWiki returns, handle messages send by our code
logger.debug('startWiki calling startNodeJSWiki in the main process', { function: 'wikiWorker.startNodeJSWiki' });
worker.startNodeJSWiki(workerData).subscribe(async (message) => {

View file

@ -1,14 +1,8 @@
import { WikiWorkerDatabaseOperations } from '@services/database/wikiWorkerOperations';
import type { ITiddlyWiki } from 'tiddlywiki';
let wikiInstance: ITiddlyWiki | undefined;
let cacheDatabase: WikiWorkerDatabaseOperations | undefined;
export const getWikiInstance = () => wikiInstance;
export const getCacheDatabase = () => cacheDatabase;
export const setWikiInstance = (instance: ITiddlyWiki) => {
wikiInstance = instance;
};
export const setCacheDatabase = (database: WikiWorkerDatabaseOperations) => {
cacheDatabase = database;
};

View file

@ -9,19 +9,16 @@
import { uninstall } from '@/helpers/installV8Cache';
import './preload';
import 'source-map-support/register';
import { type IUtils } from '@tiddlygit/tiddlywiki';
import Sqlite3Database from 'better-sqlite3';
import { mkdtemp } from 'fs-extra';
import { tmpdir } from 'os';
import path from 'path';
import { Observable } from 'rxjs';
import { expose } from 'threads/worker';
import { ISqliteDatabasePaths, SqliteDatabaseNotInitializedError, WikiWorkerDatabaseOperations } from '@services/database/wikiWorkerOperations';
import { IWikiLogMessage, IZxWorkerMessage, ZxWorkerControlActions } from '../interface';
import { IZxWorkerMessage, ZxWorkerControlActions } from '../interface';
import { executeScriptInTWContext, executeScriptInZxScriptContext, extractTWContextScripts, type IVariableContextList } from '../plugin/zxPlugin';
import { wikiOperationsInWikiWorker } from '../wikiOperations/executor/wikiOperationInServer';
import { getWikiInstance, setCacheDatabase } from './globals';
import { getWikiInstance } from './globals';
import { extractWikiHTML, packetHTMLFromWikiFolder } from './htmlWiki';
import { ipcServerRoutesMethods } from './ipcServerRoutes';
import { startNodeJSWiki } from './startNodeJSWiki';
@ -47,30 +44,6 @@ export interface IStartNodeJSWikiConfigs {
userName: string;
}
export interface IUtilsWithSqlite extends IUtils {
Sqlite: Sqlite3Database.Database;
TidgiCacheDB: WikiWorkerDatabaseOperations;
}
function initCacheDatabase(cacheDatabaseConfig: ISqliteDatabasePaths) {
return new Observable<IWikiLogMessage>((observer) => {
try {
observer.next({ type: 'stdout', message: 'Will new WikiWorkerDatabaseOperations' });
const cacheDatabase = new WikiWorkerDatabaseOperations(cacheDatabaseConfig);
observer.next({ type: 'stdout', message: 'WikiWorkerDatabaseOperations instance created.' });
setCacheDatabase(cacheDatabase);
} catch (error) {
if (error instanceof SqliteDatabaseNotInitializedError) {
// this is usual for first time
observer.next({ type: 'stdout', message: error.message });
} else {
// unexpected error
observer.next({ type: 'stderr', message: (error as Error)?.message });
}
}
});
}
export type IZxFileInput = { fileContent: string; fileName: string } | { filePath: string };
function executeZxScript(file: IZxFileInput, zxPath: string): Observable<IZxWorkerMessage> {
/** this will be observed in src/services/native/index.ts */
@ -131,7 +104,6 @@ const wikiWorker = {
extractWikiHTML,
packetHTMLFromWikiFolder,
beforeExit,
initCacheDatabase,
wikiOperation: wikiOperationsInWikiWorker.wikiOperation.bind(wikiOperationsInWikiWorker),
...ipcServerRoutesMethods,
};

View file

@ -8,8 +8,8 @@ import path from 'path';
import { Observable } from 'rxjs';
import { IWikiMessage, WikiControlActions } from '../interface';
import { wikiOperationsInWikiWorker } from '../wikiOperations/executor/wikiOperationInServer';
import { IStartNodeJSWikiConfigs, IUtilsWithSqlite } from '.';
import { getCacheDatabase, setWikiInstance } from './globals';
import { IStartNodeJSWikiConfigs } from '.';
import { setWikiInstance } from './globals';
import { ipcServerRoutes } from './ipcServerRoutes';
import { authTokenIsProvided } from './wikiWorkerUtils';
@ -50,12 +50,6 @@ export function startNodeJSWiki({
try {
const wikiInstance = TiddlyWiki();
setWikiInstance(wikiInstance);
const cacheDatabase = getCacheDatabase();
// mount database to $tw
if (wikiInstance !== undefined && cacheDatabase !== undefined) {
(wikiInstance.utils as IUtilsWithSqlite).TidgiCacheDB = cacheDatabase;
(wikiInstance.utils as IUtilsWithSqlite).Sqlite = cacheDatabase.database;
}
process.env.TIDDLYWIKI_PLUGIN_PATH = path.resolve(homePath, 'plugins');
process.env.TIDDLYWIKI_THEME_PATH = path.resolve(homePath, 'themes');
// don't add `+` prefix to plugin name here. `+` only used in args[0], but we are not prepend this list to the args list.

View file

@ -183,19 +183,11 @@ export class WorkspaceView implements IWorkspaceViewService {
}
}
};
const initDatabaseWhenInitializeWorkspaceView = async (): Promise<void> => {
if (workspace.isSubWiki) {
return;
}
// after all init finished, create cache database if there is no one
await this.databaseService.initializeForWorkspace(workspace.id);
};
logger.debug(`initializeWorkspaceView() calling wikiStartup()`);
await Promise.all([
this.wikiService.wikiStartup(workspace),
addViewWhenInitializeWorkspaceView(),
initDatabaseWhenInitializeWorkspaceView(),
]);
void syncGitWhenInitializeWorkspaceView();
}