Stop Logger being a singleton
This commit is contained in:
parent
d965265709
commit
3471a9c498
12 changed files with 147 additions and 138 deletions
|
|
@ -1,47 +1,45 @@
|
||||||
import type { Syncer } from "sync-client";
|
import type { SyncClient, Syncer } from "sync-client";
|
||||||
import { Logger } from "sync-client";
|
import { Logger } from "sync-client";
|
||||||
import type { TAbstractFile } from "obsidian";
|
import type { TAbstractFile } from "obsidian";
|
||||||
import { TFile } from "obsidian";
|
import { TFile } from "obsidian";
|
||||||
|
|
||||||
export class ObsidianFileEventHandler {
|
export class ObsidianFileEventHandler {
|
||||||
public constructor(private readonly syncer: Syncer) {}
|
public constructor(private readonly client: SyncClient) {}
|
||||||
|
|
||||||
public async onCreate(file: TAbstractFile): Promise<void> {
|
public async onCreate(file: TAbstractFile): Promise<void> {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
Logger.getInstance().info(`File created: ${file.path}`);
|
this.client.logger.info(`File created: ${file.path}`);
|
||||||
|
|
||||||
await this.syncer.syncLocallyCreatedFile(
|
await this.client.syncer.syncLocallyCreatedFile(
|
||||||
file.path,
|
file.path,
|
||||||
new Date(file.stat.ctime)
|
new Date(file.stat.ctime)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Logger.getInstance().debug(`Folder created: ${file.path}, ignored`);
|
this.client.logger.debug(`Folder created: ${file.path}, ignored`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDelete(file: TAbstractFile): Promise<void> {
|
public async onDelete(file: TAbstractFile): Promise<void> {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
Logger.getInstance().info(`File deleted: ${file.path}`);
|
this.client.logger.info(`File deleted: ${file.path}`);
|
||||||
|
|
||||||
await this.syncer.syncLocallyDeletedFile(file.path);
|
await this.client.syncer.syncLocallyDeletedFile(file.path);
|
||||||
} else {
|
} else {
|
||||||
Logger.getInstance().debug(`Folder deleted: ${file.path}, ignored`);
|
this.client.logger.debug(`Folder deleted: ${file.path}, ignored`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onRename(file: TAbstractFile, oldPath: string): Promise<void> {
|
public async onRename(file: TAbstractFile, oldPath: string): Promise<void> {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
Logger.getInstance().info(
|
this.client.logger.info(`File renamed: ${oldPath} -> ${file.path}`);
|
||||||
`File renamed: ${oldPath} -> ${file.path}`
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.syncer.syncLocallyUpdatedFile({
|
await this.client.syncer.syncLocallyUpdatedFile({
|
||||||
oldPath,
|
oldPath,
|
||||||
relativePath: file.path,
|
relativePath: file.path,
|
||||||
updateTime: new Date(file.stat.ctime)
|
updateTime: new Date(file.stat.ctime)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Logger.getInstance().debug(
|
this.client.logger.debug(
|
||||||
`Folder renamed: ${oldPath} -> ${file.path}, ignored`
|
`Folder renamed: ${oldPath} -> ${file.path}, ignored`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -53,16 +51,14 @@ export class ObsidianFileEventHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().info(`File modified: ${file.path}`);
|
this.client.logger.info(`File modified: ${file.path}`);
|
||||||
|
|
||||||
await this.syncer.syncLocallyUpdatedFile({
|
await this.client.syncer.syncLocallyUpdatedFile({
|
||||||
relativePath: file.path,
|
relativePath: file.path,
|
||||||
updateTime: new Date(file.stat.ctime)
|
updateTime: new Date(file.stat.ctime)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Logger.getInstance().debug(
|
this.client.logger.debug(`Folder modified: ${file.path}, ignored`);
|
||||||
`Folder modified: ${file.path}, ignored`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { StatusBar } from "./views/status-bar";
|
||||||
|
|
||||||
import { LogsView } from "./views/logs-view";
|
import { LogsView } from "./views/logs-view";
|
||||||
import { StatusDescription } from "./views/status-description";
|
import { StatusDescription } from "./views/status-description";
|
||||||
import { Logger, SyncClient } from "sync-client";
|
import { SyncClient } from "sync-client";
|
||||||
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
||||||
|
|
||||||
export default class VaultLinkPlugin extends Plugin {
|
export default class VaultLinkPlugin extends Plugin {
|
||||||
|
|
@ -18,8 +18,6 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
private client!: SyncClient;
|
private client!: SyncClient;
|
||||||
|
|
||||||
public async onload(): Promise<void> {
|
public async onload(): Promise<void> {
|
||||||
Logger.getInstance().info("Starting plugin");
|
|
||||||
|
|
||||||
this.client = await SyncClient.create(
|
this.client = await SyncClient.create(
|
||||||
new ObsidianFileSystemOperations(this.app.vault),
|
new ObsidianFileSystemOperations(this.app.vault),
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +26,8 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.client.logger.info("Starting plugin");
|
||||||
|
|
||||||
const statusDescription = new StatusDescription(this.client);
|
const statusDescription = new StatusDescription(this.client);
|
||||||
|
|
||||||
this.settingsTab = new SyncSettingsTab({
|
this.settingsTab = new SyncSettingsTab({
|
||||||
|
|
@ -42,12 +42,11 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
|
|
||||||
this.registerView(
|
this.registerView(
|
||||||
HistoryView.TYPE,
|
HistoryView.TYPE,
|
||||||
(leaf) =>
|
(leaf) => new HistoryView(leaf, this.client)
|
||||||
new HistoryView(leaf, this.client.settings, this.client.history)
|
|
||||||
);
|
);
|
||||||
this.registerView(
|
this.registerView(
|
||||||
LogsView.TYPE,
|
LogsView.TYPE,
|
||||||
(leaf) => new LogsView(this, this.client.settings, leaf)
|
(leaf) => new LogsView(this, this.client, leaf)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addRibbonIcon(
|
this.addRibbonIcon(
|
||||||
|
|
@ -61,11 +60,10 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventHandler = new ObsidianFileEventHandler(this.client.syncer);
|
const eventHandler = new ObsidianFileEventHandler(this.client);
|
||||||
|
|
||||||
this.app.workspace.onLayoutReady(async () => {
|
this.app.workspace.onLayoutReady(async () => {
|
||||||
Logger.getInstance().info("Initialising sync handlers");
|
this.client.logger.info("Initialising sync handlers");
|
||||||
|
|
||||||
[
|
[
|
||||||
this.app.vault.on(
|
this.app.vault.on(
|
||||||
"create",
|
"create",
|
||||||
|
|
@ -87,7 +85,7 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
this.registerEvent(event);
|
this.registerEvent(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.getInstance().info("Sync handlers initialised");
|
this.client.logger.info("Sync handlers initialised");
|
||||||
|
|
||||||
void this.client.syncer.scheduleSyncForOfflineChanges();
|
void this.client.syncer.scheduleSyncForOfflineChanges();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import type { IconName, WorkspaceLeaf } from "obsidian";
|
||||||
import { ItemView, setIcon } from "obsidian";
|
import { ItemView, setIcon } from "obsidian";
|
||||||
|
|
||||||
import { intlFormatDistance } from "date-fns";
|
import { intlFormatDistance } from "date-fns";
|
||||||
import type { SyncHistory, HistoryEntry, Settings } from "sync-client";
|
import type { HistoryEntry, SyncClient } from "sync-client";
|
||||||
import { SyncType, SyncSource, SyncStatus, Logger } from "sync-client";
|
import { SyncType, SyncSource, SyncStatus, Logger } from "sync-client";
|
||||||
|
|
||||||
export class HistoryView extends ItemView {
|
export class HistoryView extends ItemView {
|
||||||
|
|
@ -12,15 +12,14 @@ export class HistoryView extends ItemView {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
leaf: WorkspaceLeaf,
|
leaf: WorkspaceLeaf,
|
||||||
private readonly settings: Settings,
|
private readonly client: SyncClient
|
||||||
private readonly history: SyncHistory
|
|
||||||
) {
|
) {
|
||||||
super(leaf);
|
super(leaf);
|
||||||
this.icon = HistoryView.ICON;
|
this.icon = HistoryView.ICON;
|
||||||
|
|
||||||
history.addSyncHistoryUpdateListener(() => {
|
this.client.history.addSyncHistoryUpdateListener(() => {
|
||||||
this.updateView().catch((_error: unknown) => {
|
this.updateView().catch((_error: unknown) => {
|
||||||
Logger.getInstance().error("Failed to update history view");
|
this.client.logger.error("Failed to update history view");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -94,13 +93,13 @@ export class HistoryView extends ItemView {
|
||||||
container.empty();
|
container.empty();
|
||||||
container.createEl("h4", { text: "VaultLink History" });
|
container.createEl("h4", { text: "VaultLink History" });
|
||||||
|
|
||||||
const entries = this.history
|
const entries = this.client.history
|
||||||
.getEntries()
|
.getEntries()
|
||||||
.reverse()
|
.reverse()
|
||||||
.filter(
|
.filter(
|
||||||
(entry) =>
|
(entry) =>
|
||||||
entry.status !== SyncStatus.NO_OP ||
|
entry.status !== SyncStatus.NO_OP ||
|
||||||
this.settings.getSettings().displayNoopSyncEvents
|
this.client.settings.getSettings().displayNoopSyncEvents
|
||||||
);
|
);
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import type { WorkspaceLeaf } from "obsidian";
|
import type { WorkspaceLeaf } from "obsidian";
|
||||||
import { ItemView } from "obsidian";
|
import { ItemView } from "obsidian";
|
||||||
import type VaultLinkPlugin from "src/vault-link-plugin";
|
import type VaultLinkPlugin from "src/vault-link-plugin";
|
||||||
import type { Settings } from "sync-client";
|
import type { SyncClient } from "sync-client";
|
||||||
import { Logger } from "sync-client";
|
|
||||||
|
|
||||||
export class LogsView extends ItemView {
|
export class LogsView extends ItemView {
|
||||||
public static readonly TYPE = "logs-view";
|
public static readonly TYPE = "logs-view";
|
||||||
|
|
@ -10,20 +9,24 @@ export class LogsView extends ItemView {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly plugin: VaultLinkPlugin,
|
private readonly plugin: VaultLinkPlugin,
|
||||||
private readonly settings: Settings,
|
private readonly client: SyncClient,
|
||||||
leaf: WorkspaceLeaf
|
leaf: WorkspaceLeaf
|
||||||
) {
|
) {
|
||||||
super(leaf);
|
super(leaf);
|
||||||
this.icon = LogsView.ICON;
|
this.icon = LogsView.ICON;
|
||||||
Logger.getInstance().addOnMessageListener(() => {
|
this.client.logger.addOnMessageListener(() => {
|
||||||
this.updateView();
|
this.updateView();
|
||||||
});
|
});
|
||||||
|
|
||||||
settings.addOnSettingsChangeHandlers((newSettings, oldSettings) => {
|
this.client.settings.addOnSettingsChangeHandlers(
|
||||||
if (newSettings.minimumLogLevel !== oldSettings.minimumLogLevel) {
|
(newSettings, oldSettings) => {
|
||||||
this.updateView();
|
if (
|
||||||
|
newSettings.minimumLogLevel !== oldSettings.minimumLogLevel
|
||||||
|
) {
|
||||||
|
this.updateView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static formatTimestamp(timestamp: Date): string {
|
private static formatTimestamp(timestamp: Date): string {
|
||||||
|
|
@ -78,8 +81,8 @@ export class LogsView extends ItemView {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const logs = Logger.getInstance().getMessages(
|
const logs = this.client.logger.getMessages(
|
||||||
this.settings.getSettings().minimumLogLevel
|
this.client.settings.getSettings().minimumLogLevel
|
||||||
);
|
);
|
||||||
|
|
||||||
if (logs.length === 0) {
|
if (logs.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,19 @@ import { RelativePath } from "src/persistence/database";
|
||||||
import { isBinary, isFileTypeMergable, mergeText } from "sync_lib";
|
import { isBinary, isFileTypeMergable, mergeText } from "sync_lib";
|
||||||
|
|
||||||
export class FileOperations {
|
export class FileOperations {
|
||||||
public constructor(private readonly fs: FileSystemOperations) {}
|
public constructor(
|
||||||
|
private readonly logger: Logger,
|
||||||
|
private readonly fs: FileSystemOperations
|
||||||
|
) {}
|
||||||
|
|
||||||
public async listAllFiles(): Promise<RelativePath[]> {
|
public async listAllFiles(): Promise<RelativePath[]> {
|
||||||
const files = await this.fs.listAllFiles();
|
const files = await this.fs.listAllFiles();
|
||||||
Logger.getInstance().debug(`Listing all files, found ${files.length}`);
|
this.logger.debug(`Listing all files, found ${files.length}`);
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async read(path: RelativePath): Promise<Uint8Array> {
|
public async read(path: RelativePath): Promise<Uint8Array> {
|
||||||
Logger.getInstance().debug(`Reading file: ${path}`);
|
this.logger.debug(`Reading file: ${path}`);
|
||||||
const content = await this.fs.read(path);
|
const content = await this.fs.read(path);
|
||||||
|
|
||||||
if (isBinary(content)) {
|
if (isBinary(content)) {
|
||||||
|
|
@ -30,17 +33,17 @@ export class FileOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getFileSize(path: RelativePath): Promise<number> {
|
public async getFileSize(path: RelativePath): Promise<number> {
|
||||||
Logger.getInstance().debug(`Getting file size: ${path}`);
|
this.logger.debug(`Getting file size: ${path}`);
|
||||||
return this.fs.getFileSize(path);
|
return this.fs.getFileSize(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getModificationTime(path: RelativePath): Promise<Date> {
|
public async getModificationTime(path: RelativePath): Promise<Date> {
|
||||||
Logger.getInstance().debug(`Getting modification time: ${path}`);
|
this.logger.debug(`Getting modification time: ${path}`);
|
||||||
return this.fs.getModificationTime(path);
|
return this.fs.getModificationTime(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async exists(path: RelativePath): Promise<boolean> {
|
public async exists(path: RelativePath): Promise<boolean> {
|
||||||
Logger.getInstance().debug(`Checking existance of ${path}`);
|
this.logger.debug(`Checking existance of ${path}`);
|
||||||
return this.fs.exists(path);
|
return this.fs.exists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,9 +53,9 @@ export class FileOperations {
|
||||||
path: RelativePath,
|
path: RelativePath,
|
||||||
newContent: Uint8Array
|
newContent: Uint8Array
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
Logger.getInstance().debug(`Creating file: ${path}`);
|
this.logger.debug(`Creating file: ${path}`);
|
||||||
if (await this.fs.exists(path)) {
|
if (await this.fs.exists(path)) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Didn't expect ${path} to exist, when trying to create it, merging instead`
|
`Didn't expect ${path} to exist, when trying to create it, merging instead`
|
||||||
);
|
);
|
||||||
await this.write(path, new Uint8Array(0), newContent);
|
await this.write(path, new Uint8Array(0), newContent);
|
||||||
|
|
@ -71,9 +74,9 @@ export class FileOperations {
|
||||||
expectedContent: Uint8Array,
|
expectedContent: Uint8Array,
|
||||||
newContent: Uint8Array
|
newContent: Uint8Array
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
Logger.getInstance().debug(`Writing file: ${path}`);
|
this.logger.debug(`Writing file: ${path}`);
|
||||||
if (!(await this.fs.exists(path))) {
|
if (!(await this.fs.exists(path))) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`The caller assumed ${path} exists, but it no longer, so we wont recreate it`
|
`The caller assumed ${path} exists, but it no longer, so we wont recreate it`
|
||||||
);
|
);
|
||||||
return new Uint8Array(0);
|
return new Uint8Array(0);
|
||||||
|
|
@ -84,7 +87,7 @@ export class FileOperations {
|
||||||
isBinary(expectedContent) ||
|
isBinary(expectedContent) ||
|
||||||
isBinary(newContent)
|
isBinary(newContent)
|
||||||
) {
|
) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`The expected content is not mergable, so we won't perform a 3-way merge, just overwrite it`
|
`The expected content is not mergable, so we won't perform a 3-way merge, just overwrite it`
|
||||||
);
|
);
|
||||||
await this.fs.write(path, newContent);
|
await this.fs.write(path, newContent);
|
||||||
|
|
@ -99,14 +102,14 @@ export class FileOperations {
|
||||||
(currentText) => {
|
(currentText) => {
|
||||||
currentText = currentText.replace(/\r\n/g, "\n");
|
currentText = currentText.replace(/\r\n/g, "\n");
|
||||||
if (currentText !== expectedText) {
|
if (currentText !== expectedText) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Performing a 3-way merge for ${path} with the expected content`
|
`Performing a 3-way merge for ${path} with the expected content`
|
||||||
);
|
);
|
||||||
|
|
||||||
return mergeText(expectedText, currentText, newText);
|
return mergeText(expectedText, currentText, newText);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`The current content of ${path} is the same as the expected content, so we will just write the new content`
|
`The current content of ${path} is the same as the expected content, so we will just write the new content`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -117,7 +120,7 @@ export class FileOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async remove(path: RelativePath): Promise<void> {
|
public async remove(path: RelativePath): Promise<void> {
|
||||||
Logger.getInstance().debug(`Removing file: ${path}`);
|
this.logger.debug(`Removing file: ${path}`);
|
||||||
return this.fs.delete(path);
|
return this.fs.delete(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,7 +128,7 @@ export class FileOperations {
|
||||||
oldPath: RelativePath,
|
oldPath: RelativePath,
|
||||||
newPath: RelativePath
|
newPath: RelativePath
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
Logger.getInstance().debug(`Moving file: ${oldPath} -> ${newPath}`);
|
this.logger.debug(`Moving file: ${oldPath} -> ${newPath}`);
|
||||||
|
|
||||||
if (oldPath === newPath) {
|
if (oldPath === newPath) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ export class Database {
|
||||||
private lastSeenUpdateId: VaultUpdateId | undefined;
|
private lastSeenUpdateId: VaultUpdateId | undefined;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private readonly logger: Logger,
|
||||||
initialState: Partial<StoredDatabase> | undefined,
|
initialState: Partial<StoredDatabase> | undefined,
|
||||||
private readonly saveData: (data: unknown) => Promise<void>
|
private readonly saveData: (data: unknown) => Promise<void>
|
||||||
) {
|
) {
|
||||||
|
|
@ -32,10 +33,10 @@ export class Database {
|
||||||
this.documents.set(relativePath, metadata as DocumentMetadata);
|
this.documents.set(relativePath, metadata as DocumentMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.getInstance().debug(`Loaded ${this.documents.size} documents`);
|
this.logger.debug(`Loaded ${this.documents.size} documents`);
|
||||||
|
|
||||||
this.lastSeenUpdateId = initialState.lastSeenUpdateId;
|
this.lastSeenUpdateId = initialState.lastSeenUpdateId;
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Loaded last seen update id: ${this.lastSeenUpdateId}`
|
`Loaded last seen update id: ${this.lastSeenUpdateId}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export class Settings {
|
||||||
) => void)[] = [];
|
) => void)[] = [];
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private readonly logger: Logger,
|
||||||
initialState: Partial<SyncSettings> | undefined,
|
initialState: Partial<SyncSettings> | undefined,
|
||||||
private readonly saveData: (data: unknown) => Promise<void>
|
private readonly saveData: (data: unknown) => Promise<void>
|
||||||
) {
|
) {
|
||||||
|
|
@ -41,7 +42,7 @@ export class Settings {
|
||||||
...(initialState ?? {})
|
...(initialState ?? {})
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Loaded settings: ${JSON.stringify(this.settings, null, 2)}`
|
`Loaded settings: ${JSON.stringify(this.settings, null, 2)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +71,7 @@ export class Settings {
|
||||||
value: SyncSettings[T]
|
value: SyncSettings[T]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const newSettings = { ...this.settings, [key]: value };
|
const newSettings = { ...this.settings, [key]: value };
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Setting ${key} to ${value}, new settings: ${JSON.stringify(
|
`Setting ${key} to ${value}, new settings: ${JSON.stringify(
|
||||||
newSettings,
|
newSettings,
|
||||||
null,
|
null,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import type {
|
||||||
VaultUpdateId
|
VaultUpdateId
|
||||||
} from "../persistence/database";
|
} from "../persistence/database";
|
||||||
import { Logger } from "src/tracing/logger";
|
import { Logger } from "src/tracing/logger";
|
||||||
import { retriedFetch } from "src/utils/retried-fetch";
|
import { retriedFetchFactory } from "src/utils/retried-fetch";
|
||||||
import type { SyncSettings } from "dist/types";
|
import type { SyncSettings } from "dist/types";
|
||||||
import type { Settings } from "src/persistence/settings";
|
import type { Settings } from "src/persistence/settings";
|
||||||
|
|
||||||
|
|
@ -19,7 +19,10 @@ export class SyncService {
|
||||||
private client!: Client<paths>;
|
private client!: Client<paths>;
|
||||||
private clientWithoutRetries!: Client<paths>;
|
private clientWithoutRetries!: Client<paths>;
|
||||||
|
|
||||||
public constructor(private readonly settings: Settings) {
|
public constructor(
|
||||||
|
private readonly settings: Settings,
|
||||||
|
private readonly logger: Logger
|
||||||
|
) {
|
||||||
this.createClient(settings.getSettings());
|
this.createClient(settings.getSettings());
|
||||||
|
|
||||||
settings.addOnSettingsChangeHandlers(this.createClient.bind(this));
|
settings.addOnSettingsChangeHandlers(this.createClient.bind(this));
|
||||||
|
|
@ -73,7 +76,7 @@ export class SyncService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Created document ${JSON.stringify(response.data)} with id ${
|
`Created document ${JSON.stringify(response.data)} with id ${
|
||||||
response.data.documentId
|
response.data.documentId
|
||||||
}`
|
}`
|
||||||
|
|
@ -124,7 +127,7 @@ export class SyncService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Updated document ${JSON.stringify(response.data)} with id ${
|
`Updated document ${JSON.stringify(response.data)} with id ${
|
||||||
response.data.documentId
|
response.data.documentId
|
||||||
}`
|
}`
|
||||||
|
|
@ -165,7 +168,7 @@ export class SyncService {
|
||||||
throw new Error(`Failed to delete document`);
|
throw new Error(`Failed to delete document`);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Deleted document ${relativePath} with id ${documentId}`
|
`Deleted document ${relativePath} with id ${documentId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -198,7 +201,7 @@ export class SyncService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Get document ${response.data.relativePath} with id ${response.data.documentId}`
|
`Get document ${response.data.relativePath} with id ${response.data.documentId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -229,7 +232,7 @@ export class SyncService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Got ${response.data.latestDocuments.length} document metadata`
|
`Got ${response.data.latestDocuments.length} document metadata`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -267,9 +270,7 @@ export class SyncService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(`Ping response: ${JSON.stringify(response.data)}`);
|
||||||
`Ping response: ${JSON.stringify(response.data)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
@ -283,7 +284,7 @@ export class SyncService {
|
||||||
private createClient(settings: SyncSettings): void {
|
private createClient(settings: SyncSettings): void {
|
||||||
this.client = createClient<paths>({
|
this.client = createClient<paths>({
|
||||||
baseUrl: settings.remoteUri,
|
baseUrl: settings.remoteUri,
|
||||||
fetch: retriedFetch
|
fetch: retriedFetchFactory(this.logger)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.clientWithoutRetries = createClient<paths>({
|
this.clientWithoutRetries = createClient<paths>({
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,15 @@ import { FileSystemOperations } from "./file-operations/filesystem-operations";
|
||||||
import { FileOperations } from "./file-operations/file-operations";
|
import { FileOperations } from "./file-operations/file-operations";
|
||||||
|
|
||||||
export class SyncClient {
|
export class SyncClient {
|
||||||
private remoteListenerIntervalId: number | null = null;
|
private remoteListenerIntervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
private readonly _history: SyncHistory,
|
private readonly _history: SyncHistory,
|
||||||
private readonly _settings: Settings,
|
private readonly _settings: Settings,
|
||||||
private readonly _database: Database,
|
private readonly _database: Database,
|
||||||
private readonly _syncer: Syncer,
|
private readonly _syncer: Syncer,
|
||||||
private readonly _syncService: SyncService
|
private readonly _syncService: SyncService,
|
||||||
|
private readonly _logger: Logger
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public get history(): SyncHistory {
|
public get history(): SyncHistory {
|
||||||
|
|
@ -34,12 +35,17 @@ export class SyncClient {
|
||||||
return this._syncer;
|
return this._syncer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get logger(): Logger {
|
||||||
|
return this._logger;
|
||||||
|
}
|
||||||
|
|
||||||
public static async create(
|
public static async create(
|
||||||
fs: FileSystemOperations,
|
fs: FileSystemOperations,
|
||||||
persistence: PersistenceProvider
|
persistence: PersistenceProvider
|
||||||
): Promise<SyncClient> {
|
): Promise<SyncClient> {
|
||||||
const history = new SyncHistory();
|
const logger = new Logger();
|
||||||
Logger.getInstance().info("Starting SyncClient");
|
const history = new SyncHistory(logger);
|
||||||
|
logger.info("Starting SyncClient");
|
||||||
|
|
||||||
await init(
|
await init(
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|
@ -54,6 +60,7 @@ export class SyncClient {
|
||||||
database: undefined
|
database: undefined
|
||||||
};
|
};
|
||||||
const database = new Database(
|
const database = new Database(
|
||||||
|
logger,
|
||||||
state.database,
|
state.database,
|
||||||
async (data: unknown): Promise<void> => {
|
async (data: unknown): Promise<void> => {
|
||||||
state = { ...state, database: data };
|
state = { ...state, database: data };
|
||||||
|
|
@ -62,6 +69,7 @@ export class SyncClient {
|
||||||
);
|
);
|
||||||
|
|
||||||
const settings = new Settings(
|
const settings = new Settings(
|
||||||
|
logger,
|
||||||
state.settings,
|
state.settings,
|
||||||
async (data: unknown): Promise<void> => {
|
async (data: unknown): Promise<void> => {
|
||||||
state = { ...state, settings: data };
|
state = { ...state, settings: data };
|
||||||
|
|
@ -69,13 +77,14 @@ export class SyncClient {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const syncService = new SyncService(settings);
|
const syncService = new SyncService(settings, logger);
|
||||||
|
|
||||||
const syncer = new Syncer(
|
const syncer = new Syncer(
|
||||||
|
logger,
|
||||||
database,
|
database,
|
||||||
settings,
|
settings,
|
||||||
syncService,
|
syncService,
|
||||||
new FileOperations(fs),
|
new FileOperations(logger, fs),
|
||||||
history
|
history
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -84,7 +93,8 @@ export class SyncClient {
|
||||||
settings,
|
settings,
|
||||||
database,
|
database,
|
||||||
syncer,
|
syncer,
|
||||||
syncService
|
syncService,
|
||||||
|
logger
|
||||||
);
|
);
|
||||||
|
|
||||||
void syncer.scheduleSyncForOfflineChanges();
|
void syncer.scheduleSyncForOfflineChanges();
|
||||||
|
|
@ -102,14 +112,14 @@ export class SyncClient {
|
||||||
syncer
|
syncer
|
||||||
.scheduleSyncForOfflineChanges()
|
.scheduleSyncForOfflineChanges()
|
||||||
.catch((_error: unknown) => {
|
.catch((_error: unknown) => {
|
||||||
Logger.getInstance().error(
|
logger.error(
|
||||||
"Failed to schedule sync for offline changes"
|
"Failed to schedule sync for offline changes"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.getInstance().info("SyncClient loaded");
|
logger.info("SyncClient loaded");
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
@ -125,21 +135,21 @@ export class SyncClient {
|
||||||
public async reset(): Promise<void> {
|
public async reset(): Promise<void> {
|
||||||
await this._syncer.reset();
|
await this._syncer.reset();
|
||||||
this._history.reset();
|
this._history.reset();
|
||||||
Logger.getInstance().reset();
|
this.logger.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onunload(): void {
|
public onunload(): void {
|
||||||
if (this.remoteListenerIntervalId !== null) {
|
if (this.remoteListenerIntervalId !== null) {
|
||||||
window.clearInterval(this.remoteListenerIntervalId);
|
clearInterval(this.remoteListenerIntervalId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerRemoteEventListener(intervalMs: number): void {
|
private registerRemoteEventListener(intervalMs: number): void {
|
||||||
if (this.remoteListenerIntervalId !== null) {
|
if (this.remoteListenerIntervalId !== null) {
|
||||||
window.clearInterval(this.remoteListenerIntervalId);
|
clearInterval(this.remoteListenerIntervalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.remoteListenerIntervalId = window.setInterval(
|
this.remoteListenerIntervalId = setInterval(
|
||||||
() => void this._syncer.applyRemoteChangesLocally(),
|
() => void this._syncer.applyRemoteChangesLocally(),
|
||||||
intervalMs
|
intervalMs
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export class Syncer {
|
||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private readonly logger: Logger,
|
||||||
private readonly database: Database,
|
private readonly database: Database,
|
||||||
private readonly settings: Settings,
|
private readonly settings: Settings,
|
||||||
private readonly syncService: SyncService,
|
private readonly syncService: SyncService,
|
||||||
|
|
@ -91,16 +92,14 @@ export class Syncer {
|
||||||
|
|
||||||
public async scheduleSyncForOfflineChanges(): Promise<void> {
|
public async scheduleSyncForOfflineChanges(): Promise<void> {
|
||||||
if (!this.settings.getSettings().isSyncEnabled) {
|
if (!this.settings.getSettings().isSyncEnabled) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Syncing is disabled, not uploading local changes`
|
`Syncing is disabled, not uploading local changes`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.runningScheduleSyncForOfflineChanges != null) {
|
if (this.runningScheduleSyncForOfflineChanges != null) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug("Uploading local changes is already in progress");
|
||||||
"Uploading local changes is already in progress"
|
|
||||||
);
|
|
||||||
return this.runningScheduleSyncForOfflineChanges;
|
return this.runningScheduleSyncForOfflineChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,11 +107,9 @@ export class Syncer {
|
||||||
this.runningScheduleSyncForOfflineChanges =
|
this.runningScheduleSyncForOfflineChanges =
|
||||||
this.internalScheduleSyncForOfflineChanges();
|
this.internalScheduleSyncForOfflineChanges();
|
||||||
await this.runningScheduleSyncForOfflineChanges;
|
await this.runningScheduleSyncForOfflineChanges;
|
||||||
Logger.getInstance().info(
|
this.logger.info(`All local changes have been applied remotely`);
|
||||||
`All local changes have been applied remotely`
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.getInstance().error(
|
this.logger.error(
|
||||||
`Not all local changes have been applied remotely: ${e}`
|
`Not all local changes have been applied remotely: ${e}`
|
||||||
);
|
);
|
||||||
throw e;
|
throw e;
|
||||||
|
|
@ -150,7 +147,7 @@ export class Syncer {
|
||||||
(item) => item != originalFile
|
(item) => item != originalFile
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} was not found under its current path in the database but was found under a different path ${originalFile[0]}, scheduling sync to move it`
|
`Document ${relativePath} was not found under its current path in the database but was found under a different path ${originalFile[0]}, scheduling sync to move it`
|
||||||
);
|
);
|
||||||
return this.internalSyncLocallyUpdatedFile({
|
return this.internalSyncLocallyUpdatedFile({
|
||||||
|
|
@ -167,7 +164,7 @@ export class Syncer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} not found in database, scheduling sync to create it`
|
`Document ${relativePath} not found in database, scheduling sync to create it`
|
||||||
);
|
);
|
||||||
return this.internalSyncLocallyCreatedFile(
|
return this.internalSyncLocallyCreatedFile(
|
||||||
|
|
@ -178,7 +175,7 @@ export class Syncer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} has been updated locally, scheduling sync to update it`
|
`Document ${relativePath} has been updated locally, scheduling sync to update it`
|
||||||
);
|
);
|
||||||
return this.internalSyncLocallyUpdatedFile({
|
return this.internalSyncLocallyUpdatedFile({
|
||||||
|
|
@ -194,12 +191,12 @@ export class Syncer {
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
locallyDeletedFiles.map(async ([relativePath, _]) => {
|
locallyDeletedFiles.map(async ([relativePath, _]) => {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} has been deleted locally, scheduling sync to delete it`
|
`Document ${relativePath} has been deleted locally, scheduling sync to delete it`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (await this.operations.exists(relativePath)) {
|
if (await this.operations.exists(relativePath)) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} actually exists locally, skipping`
|
`Document ${relativePath} actually exists locally, skipping`
|
||||||
);
|
);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
@ -212,14 +209,14 @@ export class Syncer {
|
||||||
|
|
||||||
public async applyRemoteChangesLocally(): Promise<void> {
|
public async applyRemoteChangesLocally(): Promise<void> {
|
||||||
if (!this.settings.getSettings().isSyncEnabled) {
|
if (!this.settings.getSettings().isSyncEnabled) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Syncing is disabled, not fetching remote changes`
|
`Syncing is disabled, not fetching remote changes`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.runningApplyRemoteChangesLocally != null) {
|
if (this.runningApplyRemoteChangesLocally != null) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
"Applying remote changes locally is already in progress"
|
"Applying remote changes locally is already in progress"
|
||||||
);
|
);
|
||||||
return this.runningApplyRemoteChangesLocally;
|
return this.runningApplyRemoteChangesLocally;
|
||||||
|
|
@ -229,13 +226,9 @@ export class Syncer {
|
||||||
this.runningApplyRemoteChangesLocally =
|
this.runningApplyRemoteChangesLocally =
|
||||||
this.internalApplyRemoteChangesLocally();
|
this.internalApplyRemoteChangesLocally();
|
||||||
await this.runningApplyRemoteChangesLocally;
|
await this.runningApplyRemoteChangesLocally;
|
||||||
Logger.getInstance().info(
|
this.logger.info("All remote changes have been applied locally");
|
||||||
"All remote changes have been applied locally"
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.getInstance().error(
|
this.logger.error(`Failed to apply remote changes locally: ${e}`);
|
||||||
`Failed to apply remote changes locally: ${e}`
|
|
||||||
);
|
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
this.runningApplyRemoteChangesLocally = undefined;
|
this.runningApplyRemoteChangesLocally = undefined;
|
||||||
|
|
@ -248,11 +241,11 @@ export class Syncer {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (remote.latestDocuments.length === 0) {
|
if (remote.latestDocuments.length === 0) {
|
||||||
Logger.getInstance().debug("No remote changes to apply");
|
this.logger.debug("No remote changes to apply");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.getInstance().info("Applying remote changes locally");
|
this.logger.info("Applying remote changes locally");
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
remote.latestDocuments.map(async (remoteDocument) =>
|
remote.latestDocuments.map(async (remoteDocument) =>
|
||||||
|
|
@ -317,7 +310,7 @@ export class Syncer {
|
||||||
|
|
||||||
const localMetadata = this.database.getDocument(relativePath);
|
const localMetadata = this.database.getDocument(relativePath);
|
||||||
if (localMetadata) {
|
if (localMetadata) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document metadata already exists for ${relativePath}, it must have been downloaded from the server`
|
`Document metadata already exists for ${relativePath}, it must have been downloaded from the server`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -631,7 +624,7 @@ export class Syncer {
|
||||||
|
|
||||||
const [relativePath, metadata] = localMetadata;
|
const [relativePath, metadata] = localMetadata;
|
||||||
if (metadata.parentVersionId === remoteVersion.vaultUpdateId) {
|
if (metadata.parentVersionId === remoteVersion.vaultUpdateId) {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`Document ${relativePath} is already up to date`
|
`Document ${relativePath} is already up to date`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
@ -658,7 +651,7 @@ export class Syncer {
|
||||||
const currentHash = hash(currentContent);
|
const currentHash = hash(currentContent);
|
||||||
|
|
||||||
if (currentHash !== metadata.hash) {
|
if (currentHash !== metadata.hash) {
|
||||||
Logger.getInstance().info(
|
this.logger.info(
|
||||||
`Document ${relativePath} has been updated both remotely and locally, letting the local file update event handle it`
|
`Document ${relativePath} has been updated both remotely and locally, letting the local file update event handle it`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
@ -716,18 +709,18 @@ export class Syncer {
|
||||||
fn: () => Promise<void>
|
fn: () => Promise<void>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.settings.getSettings().isSyncEnabled) {
|
if (!this.settings.getSettings().isSyncEnabled) {
|
||||||
Logger.getInstance().info(
|
this.logger.info(
|
||||||
`Syncing is disabled, not syncing ${relativePath}`
|
`Syncing is disabled, not syncing ${relativePath}`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.operations.isFileEligibleForSync(relativePath)) {
|
if (!this.operations.isFileEligibleForSync(relativePath)) {
|
||||||
Logger.getInstance().info(
|
this.logger.info(
|
||||||
`File ${relativePath} is not eligible for syncing`
|
`File ${relativePath} is not eligible for syncing`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.getInstance().debug(`Syncing ${relativePath}`);
|
this.logger.debug(`Syncing ${relativePath}`);
|
||||||
|
|
||||||
await waitForDocumentLock(relativePath);
|
await waitForDocumentLock(relativePath);
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ export class SyncHistory {
|
||||||
error: 0
|
error: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public constructor(private logger: Logger) {}
|
||||||
|
|
||||||
public getEntries(): HistoryEntry[] {
|
public getEntries(): HistoryEntry[] {
|
||||||
return [...this.entries];
|
return [...this.entries];
|
||||||
}
|
}
|
||||||
|
|
@ -78,16 +80,16 @@ export class SyncHistory {
|
||||||
|
|
||||||
if (entry.status === SyncStatus.SUCCESS) {
|
if (entry.status === SyncStatus.SUCCESS) {
|
||||||
this.status.success++;
|
this.status.success++;
|
||||||
Logger.getInstance().info(
|
this.logger.info(
|
||||||
`History entry: ${entry.relativePath} - ${entry.message}`
|
`History entry: ${entry.relativePath} - ${entry.message}`
|
||||||
);
|
);
|
||||||
} else if (entry.status === SyncStatus.ERROR) {
|
} else if (entry.status === SyncStatus.ERROR) {
|
||||||
this.status.error++;
|
this.status.error++;
|
||||||
Logger.getInstance().error(
|
this.logger.error(
|
||||||
`Error syncing file: ${entry.relativePath} - ${entry.message}`
|
`Error syncing file: ${entry.relativePath} - ${entry.message}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Logger.getInstance().debug(
|
this.logger.debug(
|
||||||
`No-op syncing file: ${entry.relativePath} - ${entry.message}`
|
`No-op syncing file: ${entry.relativePath} - ${entry.message}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,23 +14,25 @@ function getUrlFromInput(input: RequestInfo | URL): string {
|
||||||
return input.url;
|
return input.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function retriedFetch(
|
export function retriedFetchFactory(logger: Logger) {
|
||||||
input: RequestInfo | URL,
|
return (
|
||||||
init: RequestInitRetryParams<typeof fetch> = {}
|
input: RequestInfo | URL,
|
||||||
): Promise<Response> {
|
init: RequestInitRetryParams<typeof fetch> = {}
|
||||||
return fetchWithRetry(input, {
|
): Promise<Response> => {
|
||||||
retryOn: function (attempt, error, response) {
|
return fetchWithRetry(input, {
|
||||||
if (error !== null || !response || response.status >= 500) {
|
retryOn: function (attempt, error, response) {
|
||||||
Logger.getInstance().warn(
|
if (error !== null || !response || response.status >= 500) {
|
||||||
`Retrying fetch for ${getUrlFromInput(input)}, attempt ${attempt}`
|
logger.warn(
|
||||||
);
|
`Retrying fetch for ${getUrlFromInput(input)}, attempt ${attempt}`
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
retries: 6,
|
retries: 6,
|
||||||
retryDelay: (attempt) => Math.pow(1.5, attempt) * 500,
|
retryDelay: (attempt) => Math.pow(1.5, attempt) * 500,
|
||||||
...init
|
...init
|
||||||
});
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue