Add/remove profile to/from filesystem immediately

Save unnecessary serialization of unaffected profiles.
This commit is contained in:
Davide De Rosa 2018-11-04 14:51:01 +01:00
parent bc0568cc38
commit e7d2dde972
2 changed files with 49 additions and 39 deletions

View File

@ -421,7 +421,7 @@ extension OrganizerViewController {
extension OrganizerViewController: ConnectionServiceDelegate { extension OrganizerViewController: ConnectionServiceDelegate {
func connectionService(didAdd profile: ConnectionProfile) { func connectionService(didAdd profile: ConnectionProfile) {
TransientStore.shared.serialize(withProfiles: true) // add TransientStore.shared.serialize(withProfiles: false) // add
reloadModel() reloadModel()
tableView.reloadData() tableView.reloadData()
@ -444,14 +444,14 @@ extension OrganizerViewController: ConnectionServiceDelegate {
} }
func connectionService(didRename oldProfile: ConnectionProfile, to newProfile: ConnectionProfile) { func connectionService(didRename oldProfile: ConnectionProfile, to newProfile: ConnectionProfile) {
TransientStore.shared.serialize(withProfiles: true) // rename TransientStore.shared.serialize(withProfiles: false) // rename
reloadModel() reloadModel()
tableView.reloadData() tableView.reloadData()
} }
func connectionService(didRemoveProfileWithKey key: ConnectionService.ProfileKey) { func connectionService(didRemoveProfileWithKey key: ConnectionService.ProfileKey) {
TransientStore.shared.serialize(withProfiles: true) // delete TransientStore.shared.serialize(withProfiles: false) // delete
splitViewController?.serviceViewController?.hideProfileIfDeleted() splitViewController?.serviceViewController?.hideProfileIfDeleted()
} }

View File

@ -115,8 +115,6 @@ class ConnectionService: Codable {
private var cache: [ProfileKey: ConnectionProfile] private var cache: [ProfileKey: ConnectionProfile]
private var pendingRemoval: Set<ProfileKey>
private(set) var activeProfileKey: ProfileKey? { private(set) var activeProfileKey: ProfileKey? {
willSet { willSet {
if let oldProfile = activeProfile { if let oldProfile = activeProfile {
@ -160,7 +158,6 @@ class ConnectionService: Codable {
preferences = EditablePreferences() preferences = EditablePreferences()
cache = [:] cache = [:]
pendingRemoval = []
} }
// MARK: Codable // MARK: Codable
@ -181,7 +178,6 @@ class ConnectionService: Codable {
preferences = try container.decode(EditablePreferences.self, forKey: .preferences) preferences = try container.decode(EditablePreferences.self, forKey: .preferences)
cache = [:] cache = [:]
pendingRemoval = []
} }
func encode(to encoder: Encoder) throws { func encode(to encoder: Encoder) throws {
@ -232,42 +228,42 @@ class ConnectionService: Codable {
func saveProfiles() { func saveProfiles() {
let encoder = JSONEncoder() let encoder = JSONEncoder()
ensureDirectoriesExistence()
for profile in cache.values {
saveProfile(profile, withEncoder: encoder, checkDirectories: false)
}
}
private func ensureDirectoriesExistence() {
let fm = FileManager.default let fm = FileManager.default
try? fm.createDirectory(at: providersURL, withIntermediateDirectories: false, attributes: nil) try? fm.createDirectory(at: providersURL, withIntermediateDirectories: false, attributes: nil)
try? fm.createDirectory(at: hostsURL, withIntermediateDirectories: false, attributes: nil) try? fm.createDirectory(at: hostsURL, withIntermediateDirectories: false, attributes: nil)
}
for key in pendingRemoval { private func saveProfile(_ profile: ConnectionProfile, withEncoder encoder: JSONEncoder, checkDirectories: Bool) {
let url = profileURL(key) if checkDirectories {
try? fm.removeItem(at: url) ensureDirectoriesExistence()
if let cfg = configurationURL(for: key) {
try? fm.removeItem(at: cfg)
}
} }
for entry in cache.values { do {
if let profile = entry as? ProviderConnectionProfile { let url = profileURL(ProfileKey(profile))
do { var optData: Data?
let url = profileURL(ProfileKey(.provider, entry.id)) if let providerProfile = profile as? ProviderConnectionProfile {
let data = try encoder.encode(profile) optData = try encoder.encode(providerProfile)
try data.write(to: url) } else if let hostProfile = profile as? HostConnectionProfile {
log.debug("Saved provider '\(profile.id)'") optData = try encoder.encode(hostProfile)
} catch let e { } else if let placeholder = profile as? PlaceholderConnectionProfile {
log.error("Could not save provider '\(profile.id)': \(e)")
continue
}
} else if let profile = entry as? HostConnectionProfile {
do {
let url = profileURL(ProfileKey(.host, entry.id))
let data = try encoder.encode(profile)
try data.write(to: url)
log.debug("Saved host '\(profile.id)'")
} catch let e {
log.error("Could not save host '\(profile.id)': \(e)")
continue
}
} else if let placeholder = entry as? PlaceholderConnectionProfile {
log.debug("Skipped \(placeholder.context) '\(placeholder.id)'") log.debug("Skipped \(placeholder.context) '\(placeholder.id)'")
} else {
fatalError("Attempting to add an unhandled profile type: \(type(of: profile))")
} }
guard let data = optData else {
return
}
try data.write(to: url)
log.debug("Serialized \(profile.context) profile '\(profile.id)'")
} catch let e {
log.warning("Could not serialize \(profile.context) profile '\(profile.id)': \(e)")
} }
} }
@ -336,13 +332,14 @@ class ConnectionService: Codable {
func addOrReplaceProfile(_ profile: ConnectionProfile, credentials: Credentials?) { func addOrReplaceProfile(_ profile: ConnectionProfile, credentials: Credentials?) {
let key = ProfileKey(profile) let key = ProfileKey(profile)
cache[key] = profile cache[key] = profile
pendingRemoval.remove(key)
try? setCredentials(credentials, for: profile) try? setCredentials(credentials, for: profile)
if cache.count == 1 { if cache.count == 1 {
activeProfileKey = key activeProfileKey = key
} }
delegate?.connectionService(didAdd: profile) delegate?.connectionService(didAdd: profile)
// serialization (can fail)
saveProfile(profile, withEncoder: JSONEncoder(), checkDirectories: true)
} }
@discardableResult func renameProfile(_ key: ProfileKey, to newId: String) -> ConnectionProfile? { @discardableResult func renameProfile(_ key: ProfileKey, to newId: String) -> ConnectionProfile? {
@ -392,14 +389,27 @@ class ConnectionService: Codable {
guard let profile = cache[key] else { guard let profile = cache[key] else {
return return
} }
cache.removeValue(forKey: key) cache.removeValue(forKey: key)
removeCredentials(for: profile) removeCredentials(for: profile)
pendingRemoval.insert(key)
if cache.isEmpty { if cache.isEmpty {
activeProfileKey = nil activeProfileKey = nil
} }
delegate?.connectionService(didRemoveProfileWithKey: key) delegate?.connectionService(didRemoveProfileWithKey: key)
// serialization (can fail)
do {
let fm = FileManager.default
if let cfg = configurationURL(for: key) {
try? fm.removeItem(at: cfg)
}
let url = profileURL(key)
try fm.removeItem(at: url)
log.debug("Deleted removed profile '\(profile.id)'")
} catch let e {
log.warning("Could not delete profile '\(profile.id)': \(e)")
}
} }
func containsProfile(_ key: ProfileKey) -> Bool { func containsProfile(_ key: ProfileKey) -> Bool {