Simplify API
This commit is contained in:
parent
010b3d61e9
commit
eb1ad9921a
5 changed files with 203 additions and 53 deletions
|
|
@ -1,19 +1,6 @@
|
|||
export { applyRemoteChangesLocally } from "./sync-operations/apply-remote-changes-locally";
|
||||
|
||||
export {
|
||||
Database,
|
||||
type RelativePath,
|
||||
type DocumentId,
|
||||
type VaultUpdateId,
|
||||
type DocumentMetadata
|
||||
} from "./persistence/database";
|
||||
|
||||
export { Settings, type SyncSettings } from "./persistence/settings";
|
||||
|
||||
export {
|
||||
SyncService,
|
||||
type CheckConnectionResult
|
||||
} from "./services/sync-service";
|
||||
export { type CheckConnectionResult } from "./services/sync-service";
|
||||
|
||||
export { Syncer } from "./sync-operations/syncer";
|
||||
|
||||
|
|
@ -25,26 +12,17 @@ export {
|
|||
type HistoryStats,
|
||||
type HistoryEntry
|
||||
} from "./tracing/sync-history";
|
||||
|
||||
export { Logger, LogLevel } from "./tracing/logger";
|
||||
|
||||
export { SyncClient } from "./sync-client";
|
||||
export { type FileOperations } from "./file-operations";
|
||||
|
||||
import init from "sync_lib";
|
||||
import wasmBin from "sync_lib/sync_lib_bg.wasm";
|
||||
export { type RelativePath } from "./persistence/database";
|
||||
export type { PersistenceProvider } from "./persistence/persistence";
|
||||
|
||||
export {
|
||||
isFileTypeMergable,
|
||||
mergeText,
|
||||
bytesToBase64,
|
||||
base64ToBytes,
|
||||
merge,
|
||||
isBinary
|
||||
merge
|
||||
} from "sync_lib";
|
||||
|
||||
export const initialize = async (): Promise<void> => {
|
||||
await init(
|
||||
// eslint-disable-next-line
|
||||
(wasmBin as any).default // it is loaded as a base64 string by webpack
|
||||
);
|
||||
};
|
||||
|
|
|
|||
4
frontend/sync-client/src/persistence/persistence.ts
Normal file
4
frontend/sync-client/src/persistence/persistence.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export interface PersistenceProvider {
|
||||
load: () => Promise<unknown>;
|
||||
save: (data: unknown) => Promise<void>;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Client } from "openapi-fetch";
|
||||
import createClient from "openapi-fetch";
|
||||
import type { components, paths } from "./types"; // Generated by openapi-typescript
|
||||
import type { components, paths } from "./types"; // generated by openapi-typescript
|
||||
import type {
|
||||
DocumentId,
|
||||
RelativePath,
|
||||
|
|
@ -16,8 +16,8 @@ export interface CheckConnectionResult {
|
|||
message: string;
|
||||
}
|
||||
export class SyncService {
|
||||
private client: Client<paths>;
|
||||
private clientWithoutRetries: Client<paths>;
|
||||
private client!: Client<paths>;
|
||||
private clientWithoutRetries!: Client<paths>;
|
||||
|
||||
public constructor(private readonly settings: Settings) {
|
||||
this.createClient(settings.getSettings());
|
||||
|
|
@ -39,28 +39,6 @@ export class SyncService {
|
|||
return result;
|
||||
}
|
||||
|
||||
public async ping(): Promise<components["schemas"]["PingResponse"]> {
|
||||
const response = await this.clientWithoutRetries.GET("/ping", {
|
||||
params: {
|
||||
header: {
|
||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Logger.getInstance().debug(
|
||||
`Ping response: ${JSON.stringify(response.data)}`
|
||||
);
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error(
|
||||
`Failed to ping server: ${SyncService.formatError(response.error)}`
|
||||
);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async create({
|
||||
relativePath,
|
||||
contentBytes,
|
||||
|
|
@ -282,6 +260,28 @@ export class SyncService {
|
|||
}
|
||||
}
|
||||
|
||||
private async ping(): Promise<components["schemas"]["PingResponse"]> {
|
||||
const response = await this.clientWithoutRetries.GET("/ping", {
|
||||
params: {
|
||||
header: {
|
||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Logger.getInstance().debug(
|
||||
`Ping response: ${JSON.stringify(response.data)}`
|
||||
);
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error(
|
||||
`Failed to ping server: ${SyncService.formatError(response.error)}`
|
||||
);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
private createClient(settings: SyncSettings): void {
|
||||
this.client = createClient<paths>({
|
||||
baseUrl: settings.remoteUri,
|
||||
|
|
|
|||
168
frontend/sync-client/src/sync-client.ts
Normal file
168
frontend/sync-client/src/sync-client.ts
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import init from "sync_lib";
|
||||
import wasmBin from "sync_lib/sync_lib_bg.wasm";
|
||||
import type { PersistenceProvider } from "./persistence/persistence";
|
||||
import { SyncHistory } from "./tracing/sync-history";
|
||||
import type { FileOperations } from "./file-operations";
|
||||
import { Logger } from "./tracing/logger";
|
||||
import { Database } from "./persistence/database";
|
||||
import { Settings } from "./persistence/settings";
|
||||
import type { CheckConnectionResult } from "./services/sync-service";
|
||||
import { SyncService } from "./services/sync-service";
|
||||
import { Syncer } from "./sync-operations/syncer";
|
||||
import { applyRemoteChangesLocally } from "./sync-operations/apply-remote-changes-locally";
|
||||
|
||||
export class SyncClient {
|
||||
private remoteListenerIntervalId: number | null = null;
|
||||
|
||||
private constructor(
|
||||
private readonly _history: SyncHistory,
|
||||
private readonly _settings: Settings,
|
||||
private readonly _database: Database,
|
||||
private readonly _syncer: Syncer,
|
||||
private readonly _syncService: SyncService
|
||||
) {}
|
||||
|
||||
public get history(): SyncHistory {
|
||||
return this._history;
|
||||
}
|
||||
|
||||
public get settings(): Settings {
|
||||
return this._settings;
|
||||
}
|
||||
|
||||
public get syncer(): Syncer {
|
||||
return this._syncer;
|
||||
}
|
||||
|
||||
public static async create(
|
||||
operations: FileOperations,
|
||||
persistence: PersistenceProvider
|
||||
): Promise<SyncClient> {
|
||||
const history = new SyncHistory();
|
||||
Logger.getInstance().info("Starting SyncClient");
|
||||
|
||||
await init(
|
||||
// eslint-disable-next-line
|
||||
(wasmBin as any).default // it is loaded as a base64 string by webpack
|
||||
);
|
||||
|
||||
let state: Partial<{
|
||||
settings: any;
|
||||
database: any;
|
||||
}> = (await persistence.load()) ?? {
|
||||
settings: undefined,
|
||||
database: undefined
|
||||
};
|
||||
const database = new Database(
|
||||
state.database,
|
||||
async (data: unknown): Promise<void> => {
|
||||
state = { ...state, database: data };
|
||||
return persistence.save(state);
|
||||
}
|
||||
);
|
||||
|
||||
const settings = new Settings(
|
||||
state.settings,
|
||||
async (data: unknown): Promise<void> => {
|
||||
state = { ...state, settings: data };
|
||||
return persistence.save(state);
|
||||
}
|
||||
);
|
||||
|
||||
const syncService = new SyncService(settings);
|
||||
|
||||
const syncer = new Syncer(
|
||||
database,
|
||||
settings,
|
||||
syncService,
|
||||
operations,
|
||||
history
|
||||
);
|
||||
|
||||
const client = new SyncClient(
|
||||
history,
|
||||
settings,
|
||||
database,
|
||||
syncer,
|
||||
syncService
|
||||
);
|
||||
|
||||
void syncer.scheduleSyncForOfflineChanges();
|
||||
|
||||
client.registerRemoteEventListener(
|
||||
settings,
|
||||
database,
|
||||
syncService,
|
||||
syncer,
|
||||
settings.getSettings().fetchChangesUpdateIntervalMs
|
||||
);
|
||||
|
||||
settings.addOnSettingsChangeHandlers((newSettings, oldSettings) => {
|
||||
client.registerRemoteEventListener(
|
||||
settings,
|
||||
database,
|
||||
syncService,
|
||||
syncer,
|
||||
newSettings.fetchChangesUpdateIntervalMs
|
||||
);
|
||||
|
||||
if (!oldSettings.isSyncEnabled && newSettings.isSyncEnabled) {
|
||||
syncer
|
||||
.scheduleSyncForOfflineChanges()
|
||||
.catch((_error: unknown) => {
|
||||
Logger.getInstance().error(
|
||||
"Failed to schedule sync for offline changes"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Logger.getInstance().info("SyncClient loaded");
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
public get documentCount(): number {
|
||||
return this._database.getDocuments().size;
|
||||
}
|
||||
|
||||
public async checkConnection(): Promise<CheckConnectionResult> {
|
||||
return this._syncService.checkConnection();
|
||||
}
|
||||
|
||||
public async reset(): Promise<void> {
|
||||
await this._syncer.reset();
|
||||
this._history.reset();
|
||||
Logger.getInstance().reset();
|
||||
}
|
||||
|
||||
public onunload(): void {
|
||||
if (this.remoteListenerIntervalId !== null) {
|
||||
window.clearInterval(this.remoteListenerIntervalId);
|
||||
}
|
||||
}
|
||||
|
||||
private registerRemoteEventListener(
|
||||
settings: Settings,
|
||||
database: Database,
|
||||
syncService: SyncService,
|
||||
syncer: Syncer,
|
||||
intervalMs: number
|
||||
): void {
|
||||
if (this.remoteListenerIntervalId !== null) {
|
||||
window.clearInterval(this.remoteListenerIntervalId);
|
||||
}
|
||||
|
||||
this.remoteListenerIntervalId = window.setInterval(
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
async () =>
|
||||
applyRemoteChangesLocally({
|
||||
settings,
|
||||
database,
|
||||
syncService,
|
||||
syncer
|
||||
}),
|
||||
intervalMs
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { RelativePath } from "src/persistence/database";
|
||||
import type { RelativePath } from "src/persistence/database";
|
||||
import { Logger } from "./logger";
|
||||
|
||||
export interface CommonHistoryEntry {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue