2025-02-16 18:03:53 +01:00

119 lines
3.4 KiB
Swift

import Foundation
extension Content {
func needsSave() {
setModificationTimestamp()
if saveState == .isSaved {
update(saveState: .needsSave)
}
// Wait a few seconds for a save, to allow additional changes
// Reduces the number of saves
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
self.saveIfNeeded()
}
}
func saveIfNeeded() {
switch saveState {
case .isSaved, .savingPausedDueToLoadErrors, .storageNotInitialized, .isSaving:
return
case .needsSave, .failedToSave:
break
}
if Date.now.timeIntervalSince(lastModification) < 5 {
// Additional modification made
// Wait for next scheduled invocation of saveIfNeeded()
// if the overall unsaved time is not too long
if Date.now.timeIntervalSince(lastSave) < 30 {
return
}
print("Saving after 30 seconds of modifications")
}
saveUnconditionally()
}
func saveUnconditionally() {
update(saveState: .isSaving)
guard saveToDisk() else {
update(saveState: .failedToSave)
// TODO: Try to save again
return
}
update(saveState: .isSaved)
setLastSaveTimestamp()
}
private func saveToDisk() -> Bool {
guard storage.contentScope != nil else {
print("Storage not initialized, not saving content")
return false
}
var failedSaves = 0
var saves = 0
let pageSaves = saveChanged(pages)
failedSaves += pageSaves.unsaved
saves += pageSaves.saved
let postSaves = saveChanged(posts)
failedSaves += postSaves.unsaved
saves += postSaves.saved
let tagSaves = saveChanged(tags)
failedSaves += tagSaves.unsaved
saves += tagSaves.saved
failedSaves.increment(!storage.save(settings: settings.data(tagOverview: tagOverview)))
let fileSaves = saveChanged(files)
failedSaves += fileSaves.unsaved
saves += fileSaves.saved
if saves > 0 {
print("Saved \(saves) changed items")
}
if failedSaves > 0 {
print("Save partially failed with \(failedSaves) errors")
return false
}
return true
}
func removeUnlinkedFiles() -> Bool {
var success = true
if !storage.deletePostFiles(notIn: posts.map { $0.id }) {
success = false
}
if !storage.deletePageFiles(notIn: pages.map { $0.id }) {
success = false
}
if !storage.deleteTagFiles(notIn: tags.map { $0.id }) {
success = false
}
if !storage.deleteFileResources(notIn: files.map { $0.id }) {
success = false
}
return success
}
private func saveChanged<S>(_ items: S) -> (saved: Int, unsaved: Int, unchanged: Int) where S: Sequence, S.Element: StorageItem {
var failed = 0
var saved = 0
var unchanged = 0
for item in items {
guard let wasSaved = item.saveIfNeeded() else {
unchanged += 1
continue
}
if wasSaved {
saved += 1
} else {
failed += 1
}
}
return (saved, failed, unchanged)
}
}