diff --git a/plugin/src/database/database.ts b/plugin/src/database/database.ts new file mode 100644 index 00000000..f0d99f65 --- /dev/null +++ b/plugin/src/database/database.ts @@ -0,0 +1,153 @@ +import { Logger } from "src/logger"; + +export type DocumentId = string; +export type DocumentVersionId = number; +export type RelativePath = string; + +export interface SyncSettings { + remoteUri: string; + token: string; + fullScanIntervalInSeconds: number; + fullScanEnabled: boolean; +} + +export const DEFAULT_SETTINGS: SyncSettings = { + remoteUri: "", + token: "", + fullScanIntervalInSeconds: 60, + fullScanEnabled: true, +}; + +export interface DocumentMetadata { + documentId: DocumentId; + parentVersionId: DocumentVersionId; +} + +interface StoredDatabase { + documents: Map; + settings: SyncSettings; +} + +export class Database { + private _documents: Map = new Map(); + private _settings: SyncSettings; + private onSettingsChangeHandlers: Array<(settings: SyncSettings) => void> = + []; + + public constructor( + initialState: Partial | undefined, + private saveData: (data: any) => Promise + ) { + initialState = initialState || {}; + if ( + Object.prototype.hasOwnProperty.call(initialState, "documents") && + initialState.documents + ) { + for (const [relativePath, metadata] of Object.entries( + initialState.documents + )) { + this._documents.set(relativePath, metadata as DocumentMetadata); + } + } + + Logger.getInstance().debug( + `Loaded documents ${JSON.stringify( + Object.fromEntries(this._documents.entries()), + null, + 2 + )}` + ); + + this._settings = Object.assign( + {}, + DEFAULT_SETTINGS, + initialState.settings || {} + ); + + Logger.getInstance().debug( + `Loaded settings ${JSON.stringify(this._settings, null, 2)}` + ); + } + + public getSettings(): SyncSettings { + return this._settings; + } + + public async setSettings(value: SyncSettings): Promise { + this._settings = value; + this.onSettingsChangeHandlers.forEach((handler) => handler(value)); + await this.save(); + } + + public addOnSettingsChangeHandlers( + handler: (settings: SyncSettings) => void + ) { + this.onSettingsChangeHandlers.push(handler); + } + + public async setSetting( + key: T, + value: SyncSettings[T] + ): Promise { + this._settings[key] = value; + Logger.getInstance().debug( + `Setting ${key} to ${value}, new settings: ${JSON.stringify( + this._settings + )}` + ); + await this.setSettings(this._settings); + } + + public async setDocument({ + relativePath, + documentId, + parentVersionId, + }: { + relativePath: RelativePath; + documentId: DocumentId; + parentVersionId: DocumentVersionId; + }): Promise { + this._documents.set(relativePath, { + documentId, + parentVersionId, + }); + await this.save(); + } + + public async moveDocument({ + oldRelativePath, + relativePath, + documentId, + parentVersionId, + }: { + oldRelativePath: RelativePath; + relativePath: RelativePath; + documentId: DocumentId; + parentVersionId: DocumentVersionId; + }): Promise { + this._documents.delete(oldRelativePath); + this._documents.set(relativePath, { + documentId, + parentVersionId, + }); + await this.save(); + } + + public async removeDocument(relativePath: RelativePath): Promise { + this._documents.delete(relativePath); + await this.save(); + } + + public getDocument( + relativePath: RelativePath + ): DocumentMetadata | undefined { + return this._documents.get(relativePath); + } + + private async save(): Promise { + await this.saveData({ + documents: Object.fromEntries(this._documents.entries()), + settings: this._settings, + }); + } +} diff --git a/plugin/src/settings/settings.ts b/plugin/src/settings/settings.ts deleted file mode 100644 index 0364e892..00000000 --- a/plugin/src/settings/settings.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Logger } from "src/logger"; -import SyncPlugin from "src/plugin"; - -export interface SyncSettings { - remoteUri: string; - token: string; - fullScanIntervalInSeconds: number; - fullScanEnabled: boolean; -} - -export const DEFAULT_SETTINGS: SyncSettings = { - remoteUri: "", - token: "", - fullScanIntervalInSeconds: 60, - fullScanEnabled: true, -}; - -export class SettingsContainer { - private _settings: SyncSettings; - - private onChangeHandlers: Array<(settings: SyncSettings) => void> = []; - - public constructor(private plugin: SyncPlugin, loadedSettings: any) { - Logger.getInstance().debug( - "Loaded settings " + JSON.stringify(loadedSettings, null, 2) - ); - this._settings = Object.assign({}, DEFAULT_SETTINGS, loadedSettings); - } - - public onChange(handler: (settings: SyncSettings) => void) { - this.onChangeHandlers.push(handler); - } - - public getSettings(): SyncSettings { - return this._settings; - } - - public async setSettings(value: SyncSettings): Promise { - this._settings = value; - await this.plugin.saveData(value); - this.onChangeHandlers.forEach((handler) => handler(value)); - } - - public async setSetting( - key: T, - value: SyncSettings[T] - ): Promise { - this._settings[key] = value; - Logger.getInstance().debug( - `Setting ${key} to ${value}, new settings: ${JSON.stringify( - this._settings - )}` - ); - await this.plugin.saveData(this._settings); - this.onChangeHandlers.forEach((handler) => handler(this._settings)); - } -} diff --git a/plugin/src/settings/settings-tab.ts b/plugin/src/views/settings-tab.ts similarity index 59% rename from plugin/src/settings/settings-tab.ts rename to plugin/src/views/settings-tab.ts index cf60f31c..f03b4a8c 100644 --- a/plugin/src/settings/settings-tab.ts +++ b/plugin/src/views/settings-tab.ts @@ -10,18 +10,17 @@ import { } from "obsidian"; import SyncPlugin from "src/plugin.js"; -import { SettingsContainer } from "./settings"; +import { Database } from "src/database/database"; +import { SyncServer } from "src/services/sync_service"; export class SyncSettingsTab extends PluginSettingTab { - plugin: SyncPlugin; - constructor( app: App, plugin: SyncPlugin, - private settingsContainer: SettingsContainer + private database: Database, + private syncServer: SyncServer ) { super(app, plugin); - this.plugin = plugin; } display(): void { @@ -38,25 +37,36 @@ export class SyncSettingsTab extends PluginSettingTab { .addText((text) => text .setPlaceholder("https://example.com:8080/obsidian") - .setValue(this.settingsContainer.getSettings().remoteUri) + .setValue(this.database.getSettings().remoteUri) .onChange((value) => - this.settingsContainer.setSetting("remoteUri", value) + this.database.setSetting("remoteUri", value) ) ) - .addButton((button) => button.setButtonText("Test Connection")); + .addButton((button) => + button.setButtonText("Test Connection").onClick(async () => { + try { + const result = await this.syncServer.ping(); + new Notice( + `Successfully connected to server! (server version: ${result.serverVersion})` + ); + } catch (e) { + new Notice("Failed to connect to server: " + e); + } + }) + ); new Setting(containerEl) .setName("Access token") .setDesc( "Set the access token for the server that you can get from the server" ) - .setTooltip("todo, links to docs") + .setTooltip("todo, links to dcocs") .addTextArea((text) => text .setPlaceholder("ey...") - .setValue(this.settingsContainer.getSettings().token) + .setValue(this.database.getSettings().token) .onChange((value) => - this.settingsContainer.setSetting("token", value) + this.database.setSetting("token", value) ) ); @@ -68,14 +78,9 @@ export class SyncSettingsTab extends PluginSettingTab { .setTooltip("todo, links to docs") .addToggle((toggle) => toggle - .setValue( - this.settingsContainer.getSettings().fullScanEnabled - ) + .setValue(this.database.getSettings().fullScanEnabled) .onChange((value) => - this.settingsContainer.setSetting( - "fullScanEnabled", - value - ) + this.database.setSetting("fullScanEnabled", value) ) ) .addSlider((text) => @@ -83,11 +88,10 @@ export class SyncSettingsTab extends PluginSettingTab { .setLimits(1, 3600, 1) .setDynamicTooltip() .setValue( - this.settingsContainer.getSettings() - .fullScanIntervalInSeconds + this.database.getSettings().fullScanIntervalInSeconds ) .onChange((value) => - this.settingsContainer.setSetting( + this.database.setSetting( "fullScanIntervalInSeconds", value )