mirror of
https://github.com/silvanocerza/github-gitless-sync.git
synced 2026-07-22 12:10:28 +00:00
Add some classes to handle file events
This commit is contained in:
parent
3fcd4ea56a
commit
6a73dd02e6
3 changed files with 148 additions and 0 deletions
97
src/events/handler.ts
Normal file
97
src/events/handler.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { Vault, TAbstractFile } from "obsidian";
|
||||
import { Event } from "./types";
|
||||
import MetadataStore from "../metadata-store";
|
||||
import EventsQueue from "./queue";
|
||||
|
||||
/**
|
||||
* Tracks changes to local sync directory and updates files metadata.
|
||||
*/
|
||||
export default class EventsHandler {
|
||||
private eventsQueue: EventsQueue = new EventsQueue();
|
||||
|
||||
constructor(
|
||||
private vault: Vault,
|
||||
private metadataStore: MetadataStore,
|
||||
private localContentDir: string,
|
||||
private repoContentDir: string,
|
||||
) {
|
||||
this.vault.on("create", this.onCreate.bind(this));
|
||||
this.vault.on("delete", this.onDelete.bind(this));
|
||||
this.vault.on("modify", this.onModify.bind(this));
|
||||
this.vault.on("rename", this.onRename.bind(this));
|
||||
}
|
||||
|
||||
private async onCreate(file: TAbstractFile) {
|
||||
if (!file.path.startsWith(this.localContentDir)) {
|
||||
// The file has not been created in directory that we're syncing with GitHub
|
||||
return;
|
||||
}
|
||||
this.metadataStore.data[file.path] = {
|
||||
localPath: file.path,
|
||||
remotePath: file.path.replace(this.localContentDir, this.repoContentDir),
|
||||
sha: null,
|
||||
dirty: true,
|
||||
};
|
||||
await this.metadataStore.save();
|
||||
this.eventsQueue.enqueue({
|
||||
type: "create",
|
||||
filePath: file.path,
|
||||
});
|
||||
}
|
||||
|
||||
private async onDelete(file: TAbstractFile) {
|
||||
if (!file.path.startsWith(this.localContentDir)) {
|
||||
// The file was not in directory that we're syncing with GitHub
|
||||
return;
|
||||
}
|
||||
delete this.metadataStore.data[file.path];
|
||||
await this.metadataStore.save();
|
||||
this.eventsQueue.enqueue({
|
||||
type: "delete",
|
||||
filePath: file.path,
|
||||
});
|
||||
}
|
||||
|
||||
private async onModify(file: TAbstractFile) {
|
||||
if (!file.path.startsWith(this.localContentDir)) {
|
||||
// The file has not been create in directory that we're syncing with GitHub
|
||||
return;
|
||||
}
|
||||
this.metadataStore.data[file.path].dirty = true;
|
||||
await this.metadataStore.save();
|
||||
this.eventsQueue.enqueue({
|
||||
type: "modify",
|
||||
filePath: file.path,
|
||||
});
|
||||
}
|
||||
|
||||
private async onRename(file: TAbstractFile, oldPath: string) {
|
||||
if (
|
||||
!file.path.startsWith(this.localContentDir) &&
|
||||
!oldPath.startsWith(this.localContentDir)
|
||||
) {
|
||||
// Both are not in directory that we're syncing with GitHub
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
file.path.startsWith(this.localContentDir) &&
|
||||
oldPath.startsWith(this.localContentDir)
|
||||
) {
|
||||
// Both files are in the synced directory
|
||||
// First create the new one
|
||||
await this.onCreate(file);
|
||||
// Then delete the old one
|
||||
await this.onDelete(file);
|
||||
return;
|
||||
} else if (file.path.startsWith(this.localContentDir)) {
|
||||
// Only the new file is in the local directory
|
||||
await this.onCreate(file);
|
||||
return;
|
||||
} else if (oldPath.startsWith(this.localContentDir)) {
|
||||
// Only the old file was in the local directory
|
||||
await this.onDelete(file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/events/queue.ts
Normal file
47
src/events/queue.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { Event } from "./types";
|
||||
|
||||
/**
|
||||
* A custom queue to better handle events.
|
||||
*/
|
||||
export default class EventsQueue {
|
||||
private eventsQueue: Map<string, Event> = new Map();
|
||||
|
||||
/**
|
||||
* Enqueues an event in the queue.
|
||||
* Handles special cases when the previous event and the new one
|
||||
* would cancel themselves out.
|
||||
*/
|
||||
enqueue(event: Event) {
|
||||
if (!this.eventsQueue.has(event.filePath)) {
|
||||
// No other event exist for this file, just enqueue it
|
||||
this.eventsQueue.set(event.filePath, event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.eventsQueue.get(event.filePath)?.type === "create" &&
|
||||
event.type === "delete"
|
||||
) {
|
||||
// The previous event was a create and the new one is a delete.
|
||||
// Just delete the previous one as they would amount to the same outcome.
|
||||
this.eventsQueue.delete(event.filePath);
|
||||
} else if (
|
||||
this.eventsQueue.get(event.filePath)?.type === "delete" &&
|
||||
event.type === "create"
|
||||
) {
|
||||
// The old event was a delete and the new one is a create.
|
||||
// Delete the old one and enqueue a modify event as it likely
|
||||
// that the content changed.
|
||||
this.eventsQueue.delete(event.filePath);
|
||||
this.eventsQueue.set(event.filePath, {
|
||||
type: "modify",
|
||||
filePath: event.filePath,
|
||||
});
|
||||
} else {
|
||||
// Delete and enqueue the event in all other cases.
|
||||
// We first delete the event to change the order of the queue
|
||||
this.eventsQueue.delete(event.filePath);
|
||||
this.eventsQueue.set(event.filePath, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/events/types.ts
Normal file
4
src/events/types.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export type Event = {
|
||||
type: "create" | "delete" | "modify";
|
||||
filePath: string;
|
||||
};
|
||||
Loading…
Reference in a new issue