95 lines
2.7 KiB
Swift
95 lines
2.7 KiB
Swift
import Foundation
|
|
import VelodyDomain
|
|
|
|
public protocol RemoteLibrarySyncCursorStore: Actor {
|
|
func loadCursor() async throws -> SyncCursor?
|
|
func saveCursor(_ cursor: SyncCursor) async throws
|
|
func clearCursor() async throws
|
|
}
|
|
|
|
private struct StoredRemoteLibrarySyncCursor: Codable {
|
|
var value: String
|
|
}
|
|
|
|
public actor FileRemoteLibrarySyncCursorStore: RemoteLibrarySyncCursorStore {
|
|
private let fileURL: URL
|
|
private let fileManager: FileManager
|
|
private let encoder = JSONEncoder()
|
|
private let decoder = JSONDecoder()
|
|
|
|
public init(
|
|
fileURL: URL? = nil,
|
|
fileManager: FileManager = .default
|
|
) throws {
|
|
self.fileManager = fileManager
|
|
if let fileURL {
|
|
self.fileURL = fileURL
|
|
} else {
|
|
self.fileURL = try Self.defaultFileURL(fileManager: fileManager)
|
|
}
|
|
}
|
|
|
|
public func loadCursor() async throws -> SyncCursor? {
|
|
guard fileManager.fileExists(atPath: fileURL.path) else {
|
|
return nil
|
|
}
|
|
|
|
let data = try Data(contentsOf: fileURL)
|
|
let storedCursor = try decoder.decode(StoredRemoteLibrarySyncCursor.self, from: data)
|
|
return SyncCursor(value: storedCursor.value)
|
|
}
|
|
|
|
public func saveCursor(_ cursor: SyncCursor) async throws {
|
|
try fileManager.createDirectory(
|
|
at: fileURL.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true
|
|
)
|
|
|
|
let data = try encoder.encode(
|
|
StoredRemoteLibrarySyncCursor(value: cursor.value)
|
|
)
|
|
try data.write(to: fileURL, options: .atomic)
|
|
}
|
|
|
|
public func clearCursor() async throws {
|
|
guard fileManager.fileExists(atPath: fileURL.path) else {
|
|
return
|
|
}
|
|
|
|
try fileManager.removeItem(at: fileURL)
|
|
}
|
|
|
|
private static func defaultFileURL(fileManager: FileManager) throws -> URL {
|
|
guard let applicationSupportURL = fileManager.urls(
|
|
for: .applicationSupportDirectory,
|
|
in: .userDomainMask
|
|
).first else {
|
|
throw CocoaError(.fileNoSuchFile)
|
|
}
|
|
|
|
return applicationSupportURL
|
|
.appendingPathComponent("Velody", isDirectory: true)
|
|
.appendingPathComponent("remote-library-sync-cursor.json")
|
|
}
|
|
}
|
|
|
|
public actor InMemoryRemoteLibrarySyncCursorStore: RemoteLibrarySyncCursorStore {
|
|
private var cursor: SyncCursor?
|
|
|
|
public init(cursor: SyncCursor? = nil) {
|
|
self.cursor = cursor
|
|
}
|
|
|
|
public func loadCursor() async throws -> SyncCursor? {
|
|
cursor
|
|
}
|
|
|
|
public func saveCursor(_ cursor: SyncCursor) async throws {
|
|
self.cursor = cursor
|
|
}
|
|
|
|
public func clearCursor() async throws {
|
|
cursor = nil
|
|
}
|
|
}
|