Refactor & lint
This commit is contained in:
parent
e47d8a8179
commit
6608804d34
16 changed files with 126 additions and 133 deletions
|
|
@ -136,10 +136,7 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
...(IS_DEBUG_BUILD
|
||||
? {
|
||||
fetch: debugging.slowFetchFactory(1),
|
||||
webSocket: debugging.slowWebSocketFactory(
|
||||
1,
|
||||
new Logger()
|
||||
)
|
||||
webSocket: debugging.slowWebSocketFactory(1, new Logger())
|
||||
}
|
||||
: {})
|
||||
});
|
||||
|
|
@ -174,7 +171,7 @@ export default class VaultLinkPlugin extends Plugin {
|
|||
|
||||
this.registerEditorExtension([remoteCursorsTheme, remoteCursorsPlugin]);
|
||||
|
||||
client.addRemoteCursorsUpdateListener((cursors) => {
|
||||
client.onRemoteCursorsUpdated.add((cursors) => {
|
||||
RemoteCursorsPluginValue.setCursors(cursors, this.app);
|
||||
renderCursorsInFileExplorer(cursors, this.app);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,30 +41,28 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
this.editedToken = this.syncClient.getSettings().token;
|
||||
this.editedVaultName = this.syncClient.getSettings().vaultName;
|
||||
|
||||
this.syncClient.onSettingsChanged.add(
|
||||
(newSettings, oldSettings) => {
|
||||
let hasChanged = false;
|
||||
this.syncClient.onSettingsChanged.add((newSettings, oldSettings) => {
|
||||
let hasChanged = false;
|
||||
|
||||
if (newSettings.remoteUri !== oldSettings.remoteUri) {
|
||||
this.editedServerUri = newSettings.remoteUri;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (newSettings.token !== oldSettings.token) {
|
||||
this.editedToken = newSettings.token;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (newSettings.vaultName !== oldSettings.vaultName) {
|
||||
this.editedVaultName = newSettings.vaultName;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
this.display();
|
||||
}
|
||||
if (newSettings.remoteUri !== oldSettings.remoteUri) {
|
||||
this.editedServerUri = newSettings.remoteUri;
|
||||
hasChanged = true;
|
||||
}
|
||||
);
|
||||
|
||||
if (newSettings.token !== oldSettings.token) {
|
||||
this.editedToken = newSettings.token;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (newSettings.vaultName !== oldSettings.vaultName) {
|
||||
this.editedVaultName = newSettings.vaultName;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
this.display();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private get isApplyingChanges(): boolean {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export class Database {
|
|||
i === 0
|
||||
? false
|
||||
: records[i - 1].parallelVersion ===
|
||||
current.parallelVersion
|
||||
current.parallelVersion
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ export const DEFAULT_SETTINGS: SyncSettings = {
|
|||
};
|
||||
|
||||
export class Settings {
|
||||
private settings: SyncSettings;
|
||||
private readonly lock: Lock = new Lock();
|
||||
|
||||
public readonly onSettingsChanged = new EventListeners<
|
||||
(newSettings: SyncSettings, oldSettings: SyncSettings) => unknown
|
||||
>();
|
||||
|
||||
private settings: SyncSettings;
|
||||
private readonly lock: Lock = new Lock();
|
||||
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
initialState: Partial<SyncSettings> | undefined,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { FixedSizeDocumentCache } from "./utils/data-structures/fix-sized-cache"
|
|||
import { setUpTelemetry } from "./utils/set-up-telemetry";
|
||||
import { DIFF_CACHE_SIZE_MB } from "./consts";
|
||||
import { ServerConfig } from "./services/server-config";
|
||||
import { EventListeners } from "./utils/data-structures/event-listeners";
|
||||
import type { EventListeners } from "./utils/data-structures/event-listeners";
|
||||
|
||||
export class SyncClient {
|
||||
private hasStartedOfflineSync = false;
|
||||
|
|
@ -54,7 +54,7 @@ export class SyncClient {
|
|||
database: Partial<StoredDatabase>;
|
||||
}>
|
||||
>
|
||||
) { }
|
||||
) {}
|
||||
|
||||
public get documentCount(): number {
|
||||
return this.database.length;
|
||||
|
|
@ -63,6 +63,42 @@ export class SyncClient {
|
|||
public get isWebSocketConnected(): boolean {
|
||||
return this.webSocketManager.isWebSocketConnected;
|
||||
}
|
||||
|
||||
public get onSyncHistoryUpdated(): EventListeners<
|
||||
(stats: HistoryStats) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onSyncHistoryUpdated getter");
|
||||
return this.history.onHistoryUpdated;
|
||||
}
|
||||
|
||||
public get onSettingsChanged(): EventListeners<
|
||||
(newSettings: SyncSettings, oldSettings: SyncSettings) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onSettingsChanged getter");
|
||||
return this.settings.onSettingsChanged;
|
||||
}
|
||||
|
||||
public get onRemainingOperationsCountChanged(): EventListeners<
|
||||
(remainingOperationsCount: number) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onRemainingOperationsCountChanged getter");
|
||||
return this.syncer.onRemainingOperationsCountChanged;
|
||||
}
|
||||
|
||||
public get onWebSocketStatusChanged(): EventListeners<
|
||||
(isConnected: boolean) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onWebSocketStatusChanged getter");
|
||||
return this.webSocketManager.onWebSocketStatusChanged;
|
||||
}
|
||||
|
||||
public get onRemoteCursorsUpdated(): EventListeners<
|
||||
(cursors: MaybeOutdatedClientCursors[]) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onRemoteCursorsUpdated getter");
|
||||
return this.cursorTracker.onRemoteCursorsUpdated;
|
||||
}
|
||||
|
||||
public static async create({
|
||||
fs,
|
||||
persistence,
|
||||
|
|
@ -228,9 +264,7 @@ export class SyncClient {
|
|||
}
|
||||
});
|
||||
|
||||
this.settings.onSettingsChanged.add(
|
||||
this.onSettingsChange.bind(this)
|
||||
);
|
||||
this.settings.onSettingsChanged.add(this.onSettingsChange.bind(this));
|
||||
|
||||
if (this.settings.getSettings().isSyncEnabled) {
|
||||
this.logger.info("Starting SyncClient");
|
||||
|
|
@ -318,37 +352,6 @@ export class SyncClient {
|
|||
await this.settings.setSettings(value);
|
||||
}
|
||||
|
||||
public get onSyncHistoryUpdated(): EventListeners<
|
||||
(stats: HistoryStats) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onSyncHistoryUpdated getter");
|
||||
return this.history.onHistoryUpdated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public get onSettingsChanged(): EventListeners<
|
||||
(newSettings: SyncSettings, oldSettings: SyncSettings) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onSettingsChanged getter");
|
||||
return this.settings.onSettingsChanged;
|
||||
}
|
||||
|
||||
public get onRemainingOperationsCountChanged(): EventListeners<
|
||||
(remainingOperationsCount: number) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onRemainingOperationsCountChanged getter");
|
||||
return this.syncer.onRemainingOperationsCountChanged;
|
||||
}
|
||||
|
||||
public get onWebSocketStatusChanged(): EventListeners<
|
||||
(isConnected: boolean) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onWebSocketStatusChanged getter");
|
||||
return this.webSocketManager.onWebSocketStatusChanged;
|
||||
}
|
||||
|
||||
public async syncLocallyCreatedFile(
|
||||
relativePath: RelativePath
|
||||
): Promise<void> {
|
||||
|
|
@ -414,14 +417,6 @@ export class SyncClient {
|
|||
await this.cursorTracker.sendLocalCursorsToServer(documentToCursors);
|
||||
}
|
||||
|
||||
|
||||
public get onRemoteCursorsUpdated(): EventListeners<
|
||||
(cursors: MaybeOutdatedClientCursors[]) => unknown
|
||||
> {
|
||||
this.checkIfDestroyed("onRemoteCursorsUpdated getter");
|
||||
return this.cursorTracker.onRemoteCursorsUpdated;
|
||||
}
|
||||
|
||||
public async waitUntilFinished(): Promise<void> {
|
||||
this.checkIfDestroyed("waitUntilIdle");
|
||||
await this.syncer.waitUntilFinished();
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ import { EventListeners } from "../utils/data-structures/event-listeners";
|
|||
// known remote cursor positions, and for each document, tries to return the latest cursor positions that are
|
||||
// not from the future.
|
||||
export class CursorTracker {
|
||||
private readonly updateLock = new Lock();
|
||||
|
||||
// The returned position may be accurate, if it matches the document version, or outdated, in which case
|
||||
// the client has to heuristically guess it's current position based on the local edits.
|
||||
public readonly onRemoteCursorsUpdated = new EventListeners<
|
||||
(cursors: MaybeOutdatedClientCursors[]) => unknown
|
||||
>();
|
||||
|
||||
private readonly updateLock = new Lock();
|
||||
|
||||
private knownRemoteCursors: (ClientCursors & {
|
||||
upToDateness: DocumentUpToDateness;
|
||||
})[] = [];
|
||||
|
|
@ -72,7 +72,6 @@ export class CursorTracker {
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
this.fileChangeNotifier.onFileChanged.add(async (relativePath) =>
|
||||
this.updateLock.withLock(async () => {
|
||||
for (const clientCursor of this.knownRemoteCursors) {
|
||||
|
|
@ -156,7 +155,6 @@ export class CursorTracker {
|
|||
this.webSocketManager.updateLocalCursors({ documentsWithCursors });
|
||||
}
|
||||
|
||||
|
||||
public reset(): void {
|
||||
this.knownRemoteCursors = [];
|
||||
this.lastLocalCursorState = [];
|
||||
|
|
|
|||
|
|
@ -24,16 +24,18 @@ import { awaitAll } from "../utils/await-all";
|
|||
import { EventListeners } from "../utils/data-structures/event-listeners";
|
||||
|
||||
export class Syncer {
|
||||
private readonly remoteDocumentsLock: Locks<DocumentId>;
|
||||
public readonly onRemainingOperationsCountChanged = new EventListeners<
|
||||
(remainingOperations: number) => unknown
|
||||
>();
|
||||
|
||||
private readonly remoteDocumentsLock: Locks<DocumentId>;
|
||||
|
||||
// FIFO to limit the number of concurrent sync operations
|
||||
private readonly syncQueue: PQueue;
|
||||
|
||||
private _isFirstSyncComplete = false;
|
||||
private runningScheduleSyncForOfflineChanges: Promise<void> | undefined;
|
||||
private previousRemainingOperationsCount = 0;
|
||||
|
||||
public constructor(
|
||||
private readonly deviceId: string,
|
||||
|
|
@ -58,17 +60,20 @@ export class Syncer {
|
|||
});
|
||||
|
||||
this.syncQueue.on("active", () => {
|
||||
this.onRemainingOperationsCountChanged.trigger(this.syncQueue.size);
|
||||
if (this.previousRemainingOperationsCount !== this.syncQueue.size) {
|
||||
this.previousRemainingOperationsCount = this.syncQueue.size;
|
||||
this.onRemainingOperationsCountChanged.trigger(
|
||||
this.syncQueue.size
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
this.webSocketManager.onWebSocketStatusChanged.add(
|
||||
(isConnected) => {
|
||||
if (isConnected) {
|
||||
// The JS WebSocket API doesn't support setting headers, so we have to send the token as a message
|
||||
this.sendHandshakeMessage();
|
||||
}
|
||||
this.webSocketManager.onWebSocketStatusChanged.add((isConnected) => {
|
||||
if (isConnected) {
|
||||
// The JS WebSocket API doesn't support setting headers, so we have to send the token as a message
|
||||
this.sendHandshakeMessage();
|
||||
}
|
||||
);
|
||||
});
|
||||
this.webSocketManager.onRemoteVaultUpdateReceived.add(
|
||||
this.syncRemotelyUpdatedFile.bind(this)
|
||||
);
|
||||
|
|
@ -166,7 +171,7 @@ export class Syncer {
|
|||
// in that case, we mustn't move it again.
|
||||
if (
|
||||
this.database.getLatestDocumentByRelativePath(relativePath) ===
|
||||
undefined ||
|
||||
undefined ||
|
||||
this.database.getLatestDocumentByRelativePath(relativePath)
|
||||
?.isDeleted === true
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ export class UnrestrictedSyncer {
|
|||
|
||||
const actualUpdateDetails: SyncUpdateDetails | SyncMovedDetails =
|
||||
oldPath !== undefined ||
|
||||
response.relativePath != originalRelativePath
|
||||
response.relativePath != originalRelativePath
|
||||
? {
|
||||
type: SyncType.MOVE,
|
||||
relativePath: response.relativePath,
|
||||
|
|
@ -540,8 +540,9 @@ export class UnrestrictedSyncer {
|
|||
type: SyncType.SKIPPED,
|
||||
relativePath
|
||||
},
|
||||
message: `File size of ${sizeInMB} MB exceeds the maximum file size limit of ${maxFileSizeMB
|
||||
} MB`
|
||||
message: `File size of ${sizeInMB} MB exceeds the maximum file size limit of ${
|
||||
maxFileSizeMB
|
||||
} MB`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,15 @@ export class LogLine {
|
|||
public constructor(
|
||||
public level: LogLevel,
|
||||
public message: string
|
||||
) { }
|
||||
) {}
|
||||
}
|
||||
|
||||
export class Logger {
|
||||
private readonly messages: LogLine[] = [];
|
||||
public readonly onLogEmitted = new EventListeners<
|
||||
(message: LogLine) => unknown
|
||||
>();
|
||||
|
||||
private readonly messages: LogLine[] = [];
|
||||
|
||||
public debug(message: string): void {
|
||||
this.pushMessage(message, LogLevel.DEBUG);
|
||||
|
|
|
|||
|
|
@ -70,18 +70,18 @@ export interface HistoryStats {
|
|||
}
|
||||
|
||||
export class SyncHistory {
|
||||
private readonly _entries: HistoryEntry[] = [];
|
||||
|
||||
public readonly onHistoryUpdated = new EventListeners<
|
||||
(status: HistoryStats) => unknown
|
||||
>();
|
||||
|
||||
private readonly _entries: HistoryEntry[] = [];
|
||||
|
||||
private status: HistoryStats = {
|
||||
success: 0,
|
||||
error: 0
|
||||
};
|
||||
|
||||
public constructor(private readonly logger: Logger) { }
|
||||
public constructor(private readonly logger: Logger) {}
|
||||
|
||||
public get entries(): readonly HistoryEntry[] {
|
||||
return this._entries;
|
||||
|
|
@ -114,8 +114,6 @@ export class SyncHistory {
|
|||
this.updateSuccessCount(historyEntry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public reset(): void {
|
||||
this._entries.length = 0;
|
||||
this.status = {
|
||||
|
|
@ -141,8 +139,8 @@ export class SyncHistory {
|
|||
candidate !== undefined &&
|
||||
(this._entries[0] === candidate ||
|
||||
candidate.timestamp.getTime() +
|
||||
TIMEOUT_FOR_MERGING_HISTORY_ENTRIES_IN_SECONDS * 1000 >
|
||||
entry.timestamp.getTime())
|
||||
TIMEOUT_FOR_MERGING_HISTORY_ENTRIES_IN_SECONDS * 1000 >
|
||||
entry.timestamp.getTime())
|
||||
) {
|
||||
return candidate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ export function createClientId(): string {
|
|||
typeof navigator !== "undefined"
|
||||
? navigator.platform // eslint-disable-line @typescript-eslint/no-deprecated
|
||||
: typeof process !== "undefined"
|
||||
? process.platform
|
||||
: "unknown";
|
||||
? process.platform
|
||||
: "unknown";
|
||||
|
||||
return `vault-link/${packageVersion} (${uuidv4()}; ${platform})`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import { EventListeners } from "./event-listeners";
|
|||
describe("EventListeners", () => {
|
||||
it("should add & remove listeners", () => {
|
||||
const listeners = new EventListeners<() => void>();
|
||||
const listener = () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener = (): void => {};
|
||||
|
||||
listeners.add(listener);
|
||||
|
||||
|
|
@ -16,10 +17,10 @@ describe("EventListeners", () => {
|
|||
assert.strictEqual(listeners.count, 0);
|
||||
});
|
||||
|
||||
|
||||
it("should remove listeners using unsubscribe function", () => {
|
||||
const listeners = new EventListeners<() => void>();
|
||||
const listener = () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener = (): void => {};
|
||||
|
||||
const unsubscribe = listeners.add(listener);
|
||||
unsubscribe();
|
||||
|
|
@ -29,7 +30,8 @@ describe("EventListeners", () => {
|
|||
|
||||
it("should return false when removing non-existent listener", () => {
|
||||
const listeners = new EventListeners<() => void>();
|
||||
const listener = () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener = (): void => {};
|
||||
|
||||
const removed = listeners.remove(listener);
|
||||
|
||||
|
|
@ -38,9 +40,12 @@ describe("EventListeners", () => {
|
|||
|
||||
it("should handle multiple listeners", () => {
|
||||
const listeners = new EventListeners<() => void>();
|
||||
const listener1 = () => { };
|
||||
const listener2 = () => { };
|
||||
const listener3 = () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener1 = (): void => {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener2 = (): void => {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const listener3 = (): void => {};
|
||||
|
||||
listeners.add(listener1);
|
||||
listeners.add(listener2);
|
||||
|
|
@ -82,10 +87,10 @@ describe("EventListeners", () => {
|
|||
let count1 = 0;
|
||||
let count2 = 0;
|
||||
|
||||
const listener1 = () => {
|
||||
const listener1 = (): void => {
|
||||
count1++;
|
||||
};
|
||||
const listener2 = () => {
|
||||
const listener2 = (): void => {
|
||||
count2++;
|
||||
};
|
||||
|
||||
|
|
@ -127,12 +132,10 @@ describe("EventListeners", () => {
|
|||
assert.strictEqual(results.length, 3);
|
||||
});
|
||||
|
||||
|
||||
|
||||
it("should not trigger cleared listeners", () => {
|
||||
const listeners = new EventListeners<() => void>();
|
||||
let called = false;
|
||||
const listener = () => {
|
||||
const listener = (): void => {
|
||||
called = true;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@ import { removeFromArray } from "../remove-from-array";
|
|||
import { awaitAll } from "../await-all";
|
||||
|
||||
/**
|
||||
* A utility class for managing event listeners with type-safe add/remove operations.
|
||||
*/
|
||||
* A utility class for managing event listeners with type-safe add/remove operations.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class EventListeners<TListener extends (...args: any[]) => any> {
|
||||
private readonly listeners: TListener[] = [];
|
||||
|
||||
public get count(): number {
|
||||
return this.listeners.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new listener to the collection.
|
||||
*
|
||||
|
|
@ -51,6 +56,7 @@ export class EventListeners<TListener extends (...args: any[]) => any> {
|
|||
await awaitAll(
|
||||
this.listeners
|
||||
.map((listener) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return listener(...args);
|
||||
})
|
||||
.filter((result): result is Promise<unknown> => {
|
||||
|
|
@ -62,10 +68,4 @@ export class EventListeners<TListener extends (...args: any[]) => any> {
|
|||
public clear(): void {
|
||||
this.listeners.length = 0;
|
||||
}
|
||||
|
||||
public get count(): number {
|
||||
return this.listeners.length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,14 +198,14 @@ export class MockAgent extends MockClient {
|
|||
);
|
||||
this.client.logger.info(
|
||||
"Local files: " +
|
||||
Array.from(otherAgent.localFiles.keys()).join(", ")
|
||||
Array.from(otherAgent.localFiles.keys()).join(", ")
|
||||
);
|
||||
otherAgent.client.logger.info(
|
||||
"Local data: " + JSON.stringify(otherAgent.data, null, 2)
|
||||
);
|
||||
otherAgent.client.logger.info(
|
||||
"Local files: " +
|
||||
Array.from(otherAgent.localFiles.keys()).join(", ")
|
||||
Array.from(otherAgent.localFiles.keys()).join(", ")
|
||||
);
|
||||
|
||||
throw e;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue