219 lines
7.0 KiB
Swift
219 lines
7.0 KiB
Swift
//
|
|
// SyncManager.swift
|
|
// Delta
|
|
//
|
|
// Created by Riley Testut on 11/12/18.
|
|
// Copyright © 2018 Riley Testut. All rights reserved.
|
|
//
|
|
|
|
import Harmony
|
|
import Harmony_Drive
|
|
import Harmony_Dropbox
|
|
|
|
extension SyncManager
|
|
{
|
|
enum RecordType: String, Hashable
|
|
{
|
|
case game = "Game"
|
|
case gameCollection = "GameCollection"
|
|
case cheat = "Cheat"
|
|
case saveState = "SaveState"
|
|
case controllerSkin = "ControllerSkin"
|
|
case gameControllerInputMapping = "GameControllerInputMapping"
|
|
case gameSave = "GameSave"
|
|
|
|
var localizedName: String {
|
|
switch self
|
|
{
|
|
case .game: return NSLocalizedString("Game", comment: "")
|
|
case .gameCollection: return NSLocalizedString("Game Collection", comment: "")
|
|
case .cheat: return NSLocalizedString("Cheat", comment: "")
|
|
case .saveState: return NSLocalizedString("Save State", comment: "")
|
|
case .controllerSkin: return NSLocalizedString("Controller Skin", comment: "")
|
|
case .gameControllerInputMapping: return NSLocalizedString("Game Controller Input Mapping", comment: "")
|
|
case .gameSave: return NSLocalizedString("Game Save", comment: "")
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Service: String, CaseIterable
|
|
{
|
|
case googleDrive = "com.rileytestut.Harmony.Drive"
|
|
case dropbox = "com.rileytestut.Harmony.Dropbox"
|
|
|
|
var localizedName: String {
|
|
switch self
|
|
{
|
|
case .googleDrive: return NSLocalizedString("Google Drive", comment: "")
|
|
case .dropbox: return NSLocalizedString("Dropbox", comment: "")
|
|
}
|
|
}
|
|
|
|
var service: Harmony.Service {
|
|
switch self
|
|
{
|
|
case .googleDrive: return DriveService.shared
|
|
case .dropbox: return DropboxService.shared
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Error: LocalizedError
|
|
{
|
|
case nilService
|
|
|
|
var errorDescription: String? {
|
|
switch self
|
|
{
|
|
case .nilService: return NSLocalizedString("There is no chosen service for syncing.", comment: "")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Syncable where Self: NSManagedObject
|
|
{
|
|
var recordType: SyncManager.RecordType {
|
|
let recordType = SyncManager.RecordType(rawValue: self.syncableType)!
|
|
return recordType
|
|
}
|
|
}
|
|
|
|
final class SyncManager
|
|
{
|
|
static let shared = SyncManager()
|
|
|
|
var service: Service? {
|
|
guard let service = self.coordinator?.service else { return nil }
|
|
return Service(rawValue: service.identifier)
|
|
}
|
|
|
|
var recordController: RecordController? {
|
|
return self.coordinator?.recordController
|
|
}
|
|
|
|
private(set) var syncProgress: Progress?
|
|
|
|
private(set) var previousSyncResult: SyncResult?
|
|
|
|
private(set) var coordinator: SyncCoordinator?
|
|
|
|
private init()
|
|
{
|
|
DriveService.shared.clientID = "457607414709-7oc45nq59frd7rre6okq22fafftd55g1.apps.googleusercontent.com"
|
|
|
|
DropboxService.shared.clientID = "f5btgysf9ma9bb6"
|
|
DropboxService.shared.preferredDirectoryName = "Delta Emulator"
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.syncingDidFinish(_:)), name: SyncCoordinator.didFinishSyncingNotification, object: nil)
|
|
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
|
NotificationCenter.default.addObserver(self, selector: #selector(SyncManager.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
|
}
|
|
}
|
|
|
|
extension SyncManager
|
|
{
|
|
func start(service: Service?, completionHandler: @escaping (Result<Void, Swift.Error>) -> Void)
|
|
{
|
|
guard let service = service else { return completionHandler(.success) }
|
|
|
|
let coordinator = SyncCoordinator(service: service.service, persistentContainer: DatabaseManager.shared)
|
|
coordinator.start { (result) in
|
|
do
|
|
{
|
|
_ = try result.get()
|
|
|
|
self.coordinator = coordinator
|
|
|
|
completionHandler(.success)
|
|
}
|
|
catch
|
|
{
|
|
completionHandler(.failure(error))
|
|
}
|
|
}
|
|
}
|
|
|
|
func reset(for service: Service?, completionHandler: @escaping (Result<Void, Swift.Error>) -> Void)
|
|
{
|
|
if let coordinator = self.coordinator
|
|
{
|
|
coordinator.deauthenticate { (result) in
|
|
self.coordinator = nil
|
|
self.start(service: service, completionHandler: completionHandler)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.start(service: service, completionHandler: completionHandler)
|
|
}
|
|
}
|
|
|
|
func authenticate(presentingViewController: UIViewController? = nil, completionHandler: @escaping (Result<Account, AuthenticationError>) -> Void)
|
|
{
|
|
guard let coordinator = self.coordinator else { return completionHandler(.failure(AuthenticationError(Error.nilService))) }
|
|
|
|
coordinator.authenticate(presentingViewController: presentingViewController) { (result) in
|
|
do
|
|
{
|
|
let account = try result.get()
|
|
|
|
if !coordinator.recordController.isSeeded
|
|
{
|
|
coordinator.recordController.seedFromPersistentContainer { (result) in
|
|
switch result
|
|
{
|
|
case .success: completionHandler(.success(account))
|
|
case .failure(let error): completionHandler(.failure(AuthenticationError(error)))
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
completionHandler(.success(account))
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
completionHandler(.failure(AuthenticationError(error)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func deauthenticate(completionHandler: @escaping (Result<Void, DeauthenticationError>) -> Void)
|
|
{
|
|
guard let coordinator = self.coordinator else { return completionHandler(.success) }
|
|
|
|
coordinator.deauthenticate(completionHandler: completionHandler)
|
|
}
|
|
|
|
func sync()
|
|
{
|
|
let progress = self.coordinator?.sync()
|
|
self.syncProgress = progress
|
|
}
|
|
}
|
|
|
|
private extension SyncManager
|
|
{
|
|
@objc func syncingDidFinish(_ notification: Notification)
|
|
{
|
|
guard let result = notification.userInfo?[SyncCoordinator.syncResultKey] as? SyncResult else { return }
|
|
self.previousSyncResult = result
|
|
|
|
self.syncProgress = nil
|
|
|
|
print("Finished syncing!")
|
|
}
|
|
|
|
@objc func didEnterBackground(_ notification: Notification)
|
|
{
|
|
self.sync()
|
|
}
|
|
|
|
@objc func willEnterForeground(_ notification: Notification)
|
|
{
|
|
self.sync()
|
|
}
|
|
}
|