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(_ 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) } }