Skip to content

Commit

Permalink
feat: requireConfirmationOnLargeDeletion
Browse files Browse the repository at this point in the history
  • Loading branch information
Dwynr committed Nov 28, 2024
1 parent 7e43495 commit dea2783
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 28 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@filen/sync",
"version": "0.1.84",
"version": "0.1.85",
"description": "Filen Sync",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -54,7 +54,7 @@
"wait-on": "^7.2.0"
},
"dependencies": {
"@filen/sdk": "^0.1.183",
"@filen/sdk": "^0.1.187",
"@parcel/watcher": "^2.5.0",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
Expand Down
8 changes: 1 addition & 7 deletions src/ignorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,9 @@ export class Ignorer {
return ""
}

const readContent = await fs.readFile(filePath, {
return await fs.readFile(filePath, {
encoding: "utf-8"
})

if (readContent.length === 0) {
return ""
}

return readContent
}

public async initialize(passedContent?: string): Promise<void> {
Expand Down
16 changes: 14 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,16 @@ export class SyncWorker {
tree: {},
inodes: {},
ignored: [],
errors: []
errors: [],
size: 0
}

sync.remoteFileSystem.getDirectoryTreeCache = {
timestamp: 0,
tree: {},
uuids: {},
ignored: []
ignored: [],
size: 0
}

sync.localFileSystem.ignoredCache.clear()
Expand Down Expand Up @@ -325,6 +327,16 @@ export class SyncWorker {
}
}

public confirmDeletion(uuid: string): void {
for (const syncUUID in this.syncs) {
if (syncUUID === uuid) {
this.syncs[syncUUID]!.needsDeletionConfirmation = false

break
}
}
}

/**
* Initialize the Sync worker.
* @date 2/23/2024 - 5:51:12 AM
Expand Down
16 changes: 13 additions & 3 deletions src/lib/filesystems/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type LocalDirectoryINodes = Record<number, LocalItem>
export type LocalTree = {
tree: LocalDirectoryTree
inodes: LocalDirectoryINodes
size: number
}

export type LocalTreeError = {
Expand Down Expand Up @@ -87,12 +88,14 @@ export class LocalFileSystem {
inodes: LocalDirectoryINodes
ignored: LocalTreeIgnored[]
errors: LocalTreeError[]
size: number
} = {
timestamp: 0,
tree: {},
inodes: {},
ignored: [],
errors: []
errors: [],
size: 0
}
public watcherRunning = false
private watcherInstanceParcel: watcher.AsyncSubscription | null = null
Expand Down Expand Up @@ -226,7 +229,8 @@ export class LocalFileSystem {
resolve({
result: {
tree: this.getDirectoryTreeCache.tree,
inodes: this.getDirectoryTreeCache.inodes
inodes: this.getDirectoryTreeCache.inodes,
size: this.getDirectoryTreeCache.size
},
errors: this.getDirectoryTreeCache.errors,
ignored: this.getDirectoryTreeCache.ignored,
Expand All @@ -240,8 +244,10 @@ export class LocalFileSystem {
this.getDirectoryTreeCache.inodes = {}
this.getDirectoryTreeCache.ignored = []
this.getDirectoryTreeCache.errors = []
this.getDirectoryTreeCache.size = 0

const pathsAdded: Record<string, boolean> = {}
let size = 0
let didError = false
let didErrorErr: Error = new Error("Could not read local directory.")
const stream = FastGlob.stream("**/*", {
Expand Down Expand Up @@ -386,6 +392,8 @@ export class LocalFileSystem {

this.getDirectoryTreeCache.tree[entryPath] = item
this.getDirectoryTreeCache.inodes[item.inode] = item

size += 1
}

if (didError) {
Expand All @@ -400,6 +408,7 @@ export class LocalFileSystem {
return
}

this.getDirectoryTreeCache.size = size
this.getDirectoryTreeCache.timestamp = Date.now()

// Clear old local file hashes that are not present anymore
Expand All @@ -412,7 +421,8 @@ export class LocalFileSystem {
resolve({
result: {
tree: this.getDirectoryTreeCache.tree,
inodes: this.getDirectoryTreeCache.inodes
inodes: this.getDirectoryTreeCache.inodes,
size: this.getDirectoryTreeCache.size
},
errors: this.getDirectoryTreeCache.errors,
ignored: this.getDirectoryTreeCache.ignored,
Expand Down
15 changes: 13 additions & 2 deletions src/lib/filesystems/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type RemoteDirectoryUUIDs = Record<string, RemoteItem>
export type RemoteTree = {
tree: RemoteDirectoryTree
uuids: RemoteDirectoryUUIDs
size: number
}

export type RemoteTreeIgnoredReason =
Expand Down Expand Up @@ -59,11 +60,13 @@ export class RemoteFileSystem {
tree: RemoteDirectoryTree
uuids: RemoteDirectoryUUIDs
ignored: RemoteTreeIgnored[]
size: number
} = {
timestamp: 0,
tree: {},
uuids: {},
ignored: []
ignored: [],
size: 0
}
private readonly mutex = new Semaphore(1)
private readonly mkdirMutex = new Semaphore(1)
Expand Down Expand Up @@ -256,10 +259,12 @@ export class RemoteFileSystem {

const folderNames: Record<string, string> = { base: "/" }
const pathsAdded: Record<string, boolean> = {}
let size = 0

this.getDirectoryTreeCache.ignored = []
this.getDirectoryTreeCache.tree = {}
this.getDirectoryTreeCache.uuids = {}
this.getDirectoryTreeCache.size = 0

for (const folder of dir.folders) {
try {
Expand Down Expand Up @@ -323,6 +328,8 @@ export class RemoteFileSystem {

this.getDirectoryTreeCache.tree[folderPath] = item
this.getDirectoryTreeCache.uuids[folder[0]] = item

size += 1
} catch (e) {
this.sync.worker.logger.log("error", e, "filesystems.remote.getDirectoryTree")
this.sync.worker.logger.log("error", e)
Expand Down Expand Up @@ -412,6 +419,8 @@ export class RemoteFileSystem {

this.getDirectoryTreeCache.tree[filePath] = item
this.getDirectoryTreeCache.uuids[item.uuid] = item

size += 1
} catch (e) {
this.sync.worker.logger.log("error", e, "filesystems.remote.getDirectoryTree")
this.sync.worker.logger.log("error", e)
Expand All @@ -421,12 +430,14 @@ export class RemoteFileSystem {
})
)

this.getDirectoryTreeCache.size = size
this.getDirectoryTreeCache.timestamp = now

return {
result: {
tree: this.getDirectoryTreeCache.tree,
uuids: this.getDirectoryTreeCache.uuids
uuids: this.getDirectoryTreeCache.uuids,
size: this.getDirectoryTreeCache.size
},
ignored: this.getDirectoryTreeCache.ignored,
changed: true
Expand Down
9 changes: 7 additions & 2 deletions src/lib/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,11 +480,16 @@ export class State {
return
}

const previousLocalTree = await this.readLargeRecordFromLineStream<LocalItem>(this.previousLocalTreePath)
const previousRemoteTree = await this.readLargeRecordFromLineStream<RemoteItem>(this.previousRemoteTreePath)

this.sync.isPreviousSavedTreeStateEmpty = false
this.sync.previousLocalTree.tree = await this.readLargeRecordFromLineStream<LocalItem>(this.previousLocalTreePath)
this.sync.previousLocalTree.tree = previousLocalTree
this.sync.previousLocalTree.inodes = await this.readLargeRecordFromLineStream<LocalItem>(this.previousLocalINodesPath)
this.sync.previousRemoteTree.tree = await this.readLargeRecordFromLineStream<RemoteItem>(this.previousRemoteTreePath)
this.sync.previousRemoteTree.tree = previousRemoteTree
this.sync.previousRemoteTree.uuids = await this.readLargeRecordFromLineStream<RemoteItem>(this.previousRemoteUUIDsPath)
this.sync.previousLocalTree.size = Object.keys(previousLocalTree).length
this.sync.previousRemoteTree.size = Object.keys(previousRemoteTree).length
}

public async savePreviousTrees(): Promise<void> {
Expand Down
63 changes: 59 additions & 4 deletions src/lib/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ export class Sync {
public readonly deltas: Deltas
public previousLocalTree: LocalTree = {
tree: {},
inodes: {}
inodes: {},
size: 0
}
public previousRemoteTree: RemoteTree = {
tree: {},
uuids: {}
uuids: {},
size: 0
}
public localFileHashes: Record<string, string> = {}
public readonly tasks: Tasks
Expand All @@ -56,6 +58,8 @@ export class Sync {
public localTreeErrors: LocalTreeError[] = []
public cleaningLocalTrash: boolean = false
public isPreviousSavedTreeStateEmpty: boolean = true
public requireConfirmationOnLargeDeletion: boolean
public needsDeletionConfirmation: boolean = false

/**
* Creates an instance of Sync.
Expand All @@ -75,6 +79,8 @@ export class Sync {
this.dbPath = worker.dbPath
this.sdk = worker.sdk
this.localTrashDisabled = syncPair.localTrashDisabled
this.requireConfirmationOnLargeDeletion =
typeof syncPair.requireConfirmationOnLargeDeletion === "boolean" ? syncPair.requireConfirmationOnLargeDeletion : false
this.localFileSystem = new LocalFileSystem(this)
this.remoteFileSystem = new RemoteFileSystem(this)
this.deltas = new Deltas(this)
Expand Down Expand Up @@ -412,6 +418,53 @@ export class Sync {
}
})

const confirmLocalDeletion = this.previousLocalTree.size > 0 && currentLocalTree.result.size === 0
const confirmRemoteDeletion = this.previousRemoteTree.size > 0 && currentRemoteTree.result.size === 0

// If the previous tree has nodes and the current one is empty, we should prompt the user to confirm deletion
if (
this.requireConfirmationOnLargeDeletion &&
((confirmLocalDeletion && (this.mode === "twoWay" || this.mode === "localToCloud")) ||
(confirmRemoteDeletion && (this.mode === "twoWay" || this.mode === "cloudToLocal")))
) {
this.needsDeletionConfirmation = true

await new Promise<void>(resolve => {
const interval = setInterval(() => {
if (!this.needsDeletionConfirmation) {
clearInterval(interval)

resolve()
} else {
postMessageToMain({
type: "confirmDeletion",
syncPair: this.syncPair,
data: {
where:
confirmLocalDeletion && confirmRemoteDeletion
? "both"
: confirmLocalDeletion
? "local"
: "remote",
previous:
confirmLocalDeletion && confirmRemoteDeletion
? this.previousLocalTree.size + this.previousRemoteTree.size
: confirmLocalDeletion
? this.previousLocalTree.size
: this.previousRemoteTree.size,
current:
confirmLocalDeletion && confirmRemoteDeletion
? currentLocalTree.result.size + currentRemoteTree.result.size
: confirmLocalDeletion
? currentLocalTree.result.size
: currentRemoteTree.result.size
}
})
}
}, 1000)
})
}

postMessageToMain({
type: "cycleProcessingDeltasStarted",
syncPair: this.syncPair
Expand Down Expand Up @@ -506,7 +559,8 @@ export class Sync {
tree: {},
inodes: {},
ignored: [],
errors: []
errors: [],
size: 0
}
}

Expand All @@ -515,7 +569,8 @@ export class Sync {
timestamp: 0,
tree: {},
uuids: {},
ignored: []
ignored: [],
size: 0
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type SyncPair = {
excludeDotFiles: boolean
paused: boolean
localTrashDisabled: boolean
requireConfirmationOnLargeDeletion?: boolean
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -290,6 +291,14 @@ export type SyncMessage =
size: number
}
}
| {
type: "confirmDeletion"
data: {
where: "local" | "remote" | "both"
previous: number
current: number
}
}
| {
type: "localTreeIgnored"
data: {
Expand Down

0 comments on commit dea2783

Please sign in to comment.