You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.5 KiB
105 lines
3.5 KiB
//
|
|
// CloudFileStorage.swift
|
|
// Notes
|
|
//
|
|
// Created by Laurent Morvillier on 16/09/2022.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
struct StorageRequest {
|
|
var filename: String
|
|
var content: String
|
|
}
|
|
|
|
let idleTimeBeforeSaving = 2.0
|
|
|
|
/// Should we have a way to go from local to iCloud?
|
|
/// https://stackoverflow.com/questions/33886846/best-way-to-use-icloud-documents-storage
|
|
/// Should we store the files locally whatever the iCloud choice is?
|
|
class FileStorage : FileOperator {
|
|
|
|
static var main: FileStorage = FileStorage()
|
|
|
|
fileprivate var _containerURL: URL?
|
|
|
|
fileprivate var _cloudStorageDetermined: Bool = false
|
|
|
|
fileprivate let containerIdentifier = "notes"
|
|
|
|
fileprivate var _timer: Timer? = nil
|
|
|
|
fileprivate var _storageRequests: [String : String] = [:]
|
|
|
|
init() {
|
|
DispatchQueue.global(qos: .userInteractive).async {
|
|
self._containerURL = FileManager.default.url(forUbiquityContainerIdentifier: self.containerIdentifier)
|
|
self._cloudStorageDetermined = true
|
|
print("Cloud container URL is : \(String(describing: self._containerURL?.absoluteString))")
|
|
}
|
|
}
|
|
|
|
fileprivate func _directoryURL() throws -> URL {
|
|
let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
|
return documentDirectory
|
|
}
|
|
|
|
// MARK: - FileOperator
|
|
|
|
func requestStorage(filename: String, content: String) {
|
|
|
|
self._storageRequests[filename] = content
|
|
|
|
self._timer?.invalidate()
|
|
self._timer = Timer.scheduledTimer(timeInterval: idleTimeBeforeSaving, target: self, selector: #selector(self._storageRequested), userInfo: nil, repeats: false)
|
|
|
|
}
|
|
|
|
@objc fileprivate func _storageRequested() {
|
|
|
|
for (filename, content) in self._storageRequests {
|
|
do {
|
|
try self._store(filename: filename, content: content)
|
|
} catch {
|
|
// TODO show errors to users, possibly by notifications
|
|
print("error: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
self._storageRequests.removeAll()
|
|
}
|
|
|
|
fileprivate func _store(filename: String, content: String) throws {
|
|
let fileURL = try self._directoryURL().appending(path: filename)
|
|
print("Store file to: \(fileURL.absoluteString)")
|
|
|
|
try content.write(to: fileURL, atomically: true, encoding: .utf8)
|
|
|
|
try self._copyToCloudContainerIfNecessary(fileURL: fileURL, filename: filename)
|
|
}
|
|
|
|
func getContent(filename: String) throws -> String? {
|
|
let fileURL = try self._directoryURL().appending(path: filename)
|
|
return try String(contentsOf: fileURL)
|
|
}
|
|
|
|
func lastEditDate(filename: String) throws -> Date? {
|
|
let fileURL = try self._directoryURL().appending(path: filename)
|
|
let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.absoluteString)
|
|
return attributes[FileAttributeKey.modificationDate] as? Date
|
|
}
|
|
|
|
fileprivate func _copyToCloudContainerIfNecessary(fileURL: URL, filename: String) throws {
|
|
guard let containerURL = self._containerURL else {
|
|
return
|
|
}
|
|
let cloudURL = containerURL.appending(path: filename)
|
|
try FileManager.default.copyItem(at: fileURL, to: cloudURL)
|
|
print("cloud copy to: \(cloudURL)")
|
|
}
|
|
|
|
deinit {
|
|
self._timer?.invalidate()
|
|
}
|
|
|
|
}
|
|
|