329 lines
12 KiB
Swift
329 lines
12 KiB
Swift
//
|
|
// SBUCacheManager.Template.swift
|
|
// QuickStart
|
|
//
|
|
// Created by Tez Park on 2023/02/26.
|
|
// Copyright © 2023 SendBird, Inc. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
extension SBUCacheManager {
|
|
class Template {
|
|
static let memoryCache = MemoryCacheForTemplate()
|
|
static let diskCache = DiskCacheForTemplate(cacheType: "templates")
|
|
static let cachePath = diskCache.cachePathURL()
|
|
static let cacheKey = "templates"
|
|
|
|
// MARK: - TemplateList token (updated time)
|
|
static var lastToken: String {
|
|
get { self.loadLastTokenKey() }
|
|
set { self.saveLastTokenKey(newValue) }
|
|
}
|
|
|
|
// MARK: - Template list
|
|
static func save(templates: [SBUNotificationChannelManager.TemplateList.Template]) {
|
|
self.memoryCache.set(templates: templates)
|
|
self.diskCache.set(templates: templates)
|
|
}
|
|
|
|
@discardableResult
|
|
static func loadAllTemplates() -> [String: SBUNotificationChannelManager.TemplateList.Template]? {
|
|
if let templateList = memoryCache.getAllTemplates() {
|
|
// SBULog.info("Loaded templates from memory cache")
|
|
return templateList
|
|
} else if let templateList = diskCache.getAllTemplates() {
|
|
// SBULog.info("Loaded templates from disk cache")
|
|
self.memoryCache.set(templates: Array(templateList.values))
|
|
return templateList
|
|
}
|
|
|
|
SBULog.info("No have templates in cache")
|
|
return nil
|
|
}
|
|
|
|
static func upsert(templates: [SBUNotificationChannelManager.TemplateList.Template]) {
|
|
self.save(templates: templates)
|
|
}
|
|
|
|
// MARK: - Single template
|
|
static func save(template: SBUNotificationChannelManager.TemplateList.Template) {
|
|
self.save(templates: [template])
|
|
}
|
|
|
|
static func getTemplate(forKey key: String) -> SBUNotificationChannelManager.TemplateList.Template? {
|
|
if let memoryTemplate = self.memoryCache.get(key: key) {
|
|
return memoryTemplate
|
|
} else if let templates = loadAllTemplates(),
|
|
let memoryTemplate = templates[key] {
|
|
return memoryTemplate
|
|
} else if let diskTemplate = self.diskCache.get(key: key) {
|
|
self.memoryCache.set(templates: [diskTemplate])
|
|
return diskTemplate
|
|
}
|
|
return nil
|
|
}
|
|
|
|
static func removeTemplate(forKey key: String) {
|
|
self.memoryCache.remove(key: key)
|
|
self.diskCache.remove(key: key)
|
|
}
|
|
|
|
// MARK: lastTokenKey
|
|
static func loadLastTokenKey() -> String {
|
|
if let memoryCache = self.memoryCache.lastToken {
|
|
return memoryCache
|
|
} else {
|
|
return self.diskCache.loadLastTokenKey()
|
|
}
|
|
}
|
|
|
|
static func saveLastTokenKey(_ value: String) {
|
|
self.memoryCache.lastToken = value
|
|
self.diskCache.saveLastTokenKey(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension SBUCacheManager {
|
|
struct DiskCacheForTemplate {
|
|
// MARK: - Properties
|
|
let fileManager = FileManager.default
|
|
let cacheType: String
|
|
let diskQueue = DispatchQueue(label: "\(SBUConstant.bundleIdentifier).queue.diskcache.template", qos: .background)
|
|
var fileSemaphore = DispatchSemaphore(value: 1)
|
|
|
|
let lastTokenKey = "sbu_template_list_updated_at"
|
|
|
|
// MARK: - Initializers
|
|
init(cacheType: String) {
|
|
self.cacheType = cacheType
|
|
|
|
let cachePath = self.cachePathURL().path
|
|
|
|
if self.fileManager.fileExists(atPath: cachePath) {
|
|
return
|
|
}
|
|
|
|
do {
|
|
try self.fileManager.createDirectory(
|
|
atPath: cachePath,
|
|
withIntermediateDirectories: true,
|
|
attributes: nil
|
|
)
|
|
} catch {
|
|
SBULog.error(error.localizedDescription)
|
|
}
|
|
}
|
|
|
|
func cacheExists(key: String) -> Bool {
|
|
return fileManager.fileExists(atPath: self.pathForKey(key))
|
|
}
|
|
|
|
func get(fullPath: URL, needToSync: Bool = true) -> SBUNotificationChannelManager.TemplateList.Template? {
|
|
let template: SBUNotificationChannelManager.TemplateList.Template? = {
|
|
do {
|
|
let data = try Data(contentsOf: fullPath)
|
|
let template = try JSONDecoder().decode(SBUNotificationChannelManager.TemplateList.Template.self, from: data)
|
|
return template as SBUNotificationChannelManager.TemplateList.Template
|
|
} catch {
|
|
SBULog.info(error.localizedDescription)
|
|
}
|
|
return nil
|
|
}()
|
|
|
|
if needToSync {
|
|
return self.diskQueue.sync {
|
|
self.fileSemaphore.wait()
|
|
defer { self.fileSemaphore.signal() }
|
|
|
|
return template
|
|
}
|
|
} else {
|
|
return template
|
|
}
|
|
}
|
|
|
|
func get(key: String) -> SBUNotificationChannelManager.TemplateList.Template? {
|
|
guard cacheExists(key: key) else { return nil }
|
|
|
|
let filePath = URL(fileURLWithPath: self.pathForKey(key))
|
|
return self.get(fullPath: filePath)
|
|
}
|
|
|
|
func getAllTemplates() -> [String: SBUNotificationChannelManager.TemplateList.Template]? {
|
|
return self.diskQueue.sync {
|
|
self.fileSemaphore.wait()
|
|
defer { self.fileSemaphore.signal() }
|
|
|
|
var templateList: [String: SBUNotificationChannelManager.TemplateList.Template]?
|
|
|
|
do {
|
|
let items = try fileManager.contentsOfDirectory(at: cachePathURL(), includingPropertiesForKeys: nil)
|
|
if items.count > 0 {
|
|
templateList = [:]
|
|
}
|
|
for item in items {
|
|
if let template = get(fullPath: item, needToSync: false) {
|
|
templateList?[template.key] = template
|
|
}
|
|
}
|
|
} catch {
|
|
SBULog.info(error.localizedDescription)
|
|
}
|
|
|
|
return templateList
|
|
}
|
|
}
|
|
|
|
func set(templates: [SBUNotificationChannelManager.TemplateList.Template]) {
|
|
for template in templates {
|
|
let encoder = JSONEncoder()
|
|
do {
|
|
let data = try encoder.encode(template)
|
|
self.set(key: template.key, data: data as NSData)
|
|
} catch {
|
|
SBULog.error("Failed to save template to disk cache: \(error)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func set(key: String, data: NSData, completionHandler: SBUCacheCompletionHandler? = nil) {
|
|
diskQueue.sync {
|
|
self.fileSemaphore.wait()
|
|
defer { self.fileSemaphore.signal() }
|
|
|
|
let filePath = URL(fileURLWithPath: self.pathForKey(key))
|
|
|
|
do {
|
|
let subPath = filePath.deletingLastPathComponent()
|
|
try self.fileManager.createDirectory(
|
|
atPath: subPath.path,
|
|
withIntermediateDirectories: true,
|
|
attributes: nil
|
|
)
|
|
} catch {
|
|
SBULog.error(error.localizedDescription)
|
|
DispatchQueue.main.async {
|
|
completionHandler?(nil, nil)
|
|
}
|
|
return
|
|
}
|
|
|
|
data.write(to: filePath, atomically: true)
|
|
DispatchQueue.main.async {
|
|
completionHandler?(filePath, data)
|
|
}
|
|
}
|
|
}
|
|
|
|
func remove(key: String) {
|
|
diskQueue.sync {
|
|
self.fileSemaphore.wait()
|
|
defer { self.fileSemaphore.signal() }
|
|
|
|
do {
|
|
let path = self.pathForKey(key)
|
|
let fileManager = self.fileManager
|
|
try fileManager.removeItem(atPath: path)
|
|
} catch {
|
|
SBULog.error("Could not remove file: \(error)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func removePath() {
|
|
diskQueue.sync {
|
|
self.fileSemaphore.wait()
|
|
defer { self.fileSemaphore.signal() }
|
|
|
|
do {
|
|
let path = self.cachePathURL()
|
|
let fileManager = self.fileManager
|
|
try fileManager.removeItem(at: path)
|
|
} catch {
|
|
SBULog.error("Could not remove path: \(error)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func cachePathURL() -> URL {
|
|
guard let cacheDirectoryURL = try? FileManager.default.url(
|
|
for: .cachesDirectory,
|
|
in: .userDomainMask,
|
|
appropriateFor: nil,
|
|
create: true) else { return URL(fileURLWithPath: "") }
|
|
|
|
let cachePathURL = cacheDirectoryURL.appendingPathComponent("\(self.cacheType)/")
|
|
return cachePathURL
|
|
}
|
|
|
|
func pathForKey(_ key: String) -> String {
|
|
let cachePathURL = cachePathURL()
|
|
let fullPath = cachePathURL.appendingPathComponent(key)
|
|
return fullPath.path
|
|
}
|
|
|
|
// MARK: lastTokenKey
|
|
func loadLastTokenKey() -> String {
|
|
let cachePathURL = cachePathURL()
|
|
let filePath = cachePathURL.appendingPathComponent(lastTokenKey)
|
|
guard let retrievedString = try? String(contentsOf: filePath, encoding: .utf8) else {
|
|
if let storedValue = UserDefaults.standard.string(forKey: lastTokenKey) {
|
|
// for backward
|
|
UserDefaults.standard.removeObject(forKey: lastTokenKey)
|
|
self.saveLastTokenKey(storedValue)
|
|
return storedValue
|
|
}
|
|
return ""
|
|
}
|
|
return retrievedString
|
|
}
|
|
|
|
func saveLastTokenKey(_ value: String) {
|
|
do {
|
|
let cachePathURL = cachePathURL()
|
|
let filePath = cachePathURL.appendingPathComponent(lastTokenKey)
|
|
try value.write(to: filePath, atomically: true, encoding: .utf8)
|
|
} catch {
|
|
SBULog.error("Error writing to file: lastTokenKey value")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - MemoryCache
|
|
class MemoryCacheForTemplate {
|
|
var lastToken: String?
|
|
var templateList: [String: SBUNotificationChannelManager.TemplateList.Template]?
|
|
|
|
// MARK: - Memory Cache
|
|
func set(templates: [SBUNotificationChannelManager.TemplateList.Template]) {
|
|
for template in templates {
|
|
set(key: template.key, template: template)
|
|
}
|
|
}
|
|
|
|
func set(key: String, template: SBUNotificationChannelManager.TemplateList.Template) {
|
|
if self.templateList == nil { self.templateList = [:] }
|
|
self.templateList?[key] = template
|
|
}
|
|
|
|
func get(key: String) -> SBUNotificationChannelManager.TemplateList.Template? {
|
|
guard let template = self.templateList?[key] else { return nil }
|
|
return template as SBUNotificationChannelManager.TemplateList.Template
|
|
}
|
|
|
|
func getAllTemplates() -> [String: SBUNotificationChannelManager.TemplateList.Template]? {
|
|
return templateList
|
|
}
|
|
|
|
func remove(key: String) {
|
|
self.templateList?.removeValue(forKey: key)
|
|
}
|
|
|
|
// func cacheExists(key: String) -> Bool {
|
|
// return self.templateList?[key] != nil
|
|
// }
|
|
}
|
|
}
|