117 lines
3.3 KiB
Swift
117 lines
3.3 KiB
Swift
import Foundation
|
|
|
|
extension Content {
|
|
|
|
func needsSave() {
|
|
setModificationTimestamp()
|
|
|
|
if saveState == .isSaved {
|
|
update(saveState: saveState)
|
|
}
|
|
// 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() {
|
|
guard saveState != .isSaved else {
|
|
return
|
|
}
|
|
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 {
|
|
//print("Waiting while modifying")
|
|
return
|
|
}
|
|
print("Saving after 30 seconds of modifications")
|
|
}
|
|
saveUnconditionally()
|
|
}
|
|
|
|
func saveUnconditionally() {
|
|
guard saveToDisk() else {
|
|
update(saveState: .failedToSave)
|
|
// TODO: Try to save again
|
|
return
|
|
}
|
|
update(saveState: .isSaved)
|
|
setLastSaveTimestamp()
|
|
}
|
|
|
|
private func saveToDisk() -> Bool {
|
|
guard didLoadContent else { return false }
|
|
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)
|
|
}
|
|
}
|