Skip to content

Instantly share code, notes, and snippets.

@ntnmrndn
Last active July 10, 2020 07:28
Show Gist options
  • Save ntnmrndn/42cf2d32b1e42ecb27428e170d1c499a to your computer and use it in GitHub Desktop.
Save ntnmrndn/42cf2d32b1e42ecb27428e170d1c499a to your computer and use it in GitHub Desktop.
// MARK: - Caches
public protocol DirectoryCachable {
var directoryName: String { get }
}
extension Caches {
// MARK: - DataCacheStack
/// A synchronous, thread safe, directory cache.
public class DirectoryBased<E: DirectoryCachable> {
// MARK: Public
/// Multiple instances of the same generic type are NOT supported.
public init() throws {
self.baseURL = try Self.directoryURL.unwrap()
try FileManager.default.createDirectory(
at: self.baseURL,
withIntermediateDirectories: true
)
self.keys = try FileManager.default.contentsOfDirectory(at: self.baseURL, includingPropertiesForKeys: nil).map {
$0.lastPathComponent
}.asSet()
}
static var directoryURL: URL? {
guard let cacheURL = FileManager.default.urls(
for: .cachesDirectory,
in: .userDomainMask
).first else {
return nil
}
return cacheURL.appendingPathComponent(String(describing: E.self))
}
public func contains(_ element: E) -> Bool {
self.queue.sync {
keys.contains(element.directoryName)
}
}
public func get(_ element: E) -> URL? {
let key = element.directoryName
guard self.queue.sync(execute: {
keys.contains(key)
})
else {
return nil
}
return self.baseURL.appendingPathComponent(key, isDirectory: true)
}
public func add(_ element: E, fileURL: URL) throws {
try FileManager.default.moveItem(at: fileURL, to: self.baseURL.appendingPathComponent(element.directoryName, isDirectory: true))
_ = self.queue.async(flags: .barrier) {
self.keys.insert(element.directoryName)
}
}
// MARK: Private
private let baseURL: URL
private var keys: Set<String>
private let queue = DispatchQueue(
label: "Caches.DirectoryBased<\(String(describing: E.self))>",
attributes: .concurrent
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment