169 lines
5.0 KiB
Swift
169 lines
5.0 KiB
Swift
//
|
||
// PrivadoUninstallerClient.swift
|
||
// PrivadoVPN
|
||
//
|
||
// Created by Juraldinio on 12/24/20.
|
||
// Copyright © 2020 Privado LLC. All rights reserved.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
final class PrivadoUninstallerClient: NSObject {
|
||
|
||
// MARK: - Properties
|
||
|
||
private var connection: NSXPCConnection?
|
||
|
||
private var installed = false
|
||
|
||
private(set) var state: XPCClientState = .undefined
|
||
|
||
func install(installer: @escaping (String) -> Bool) -> Future<PrivadoUninstallerClient> {
|
||
|
||
self.state = .installing
|
||
|
||
return Future<PrivadoUninstallerClient> { completion in
|
||
|
||
let success = installer(PrivadoConstants.Uninstaller.bundle)
|
||
self.installed = success
|
||
|
||
let result: Result<PrivadoUninstallerClient, Error> = success ? .success(self) : .failure(FutureError.none)
|
||
completion(result)
|
||
}
|
||
}
|
||
|
||
func resume() {
|
||
|
||
guard let connection = self.connection else {
|
||
self.createConnection()
|
||
return
|
||
}
|
||
|
||
connection.resume()
|
||
}
|
||
|
||
func uninstall() -> Future<Void> {
|
||
|
||
return self
|
||
.checkCallAllowed()
|
||
.flatMap { intercomm -> Future<Void> in
|
||
|
||
return Future<Void> { completion in
|
||
|
||
intercomm.uninstall { completion(.success(())) }
|
||
}
|
||
}.onSuccess { [weak self] in self?.reset() }
|
||
}
|
||
|
||
// MARK: - Private
|
||
|
||
private func reset() {
|
||
guard self.state == .undefined else { return }
|
||
self.connection?.invalidate()
|
||
self.connection = nil
|
||
}
|
||
|
||
private func createConnection() {
|
||
|
||
guard !self.connection.isExist else { return }
|
||
|
||
let connection = NSXPCConnection(machServiceName: PrivadoConstants.Uninstaller.bundle, options: .privileged)
|
||
|
||
connection.exportedInterface = NSXPCInterface(with: IntercommConsoleClientType.self)
|
||
connection.exportedObject = self
|
||
connection.remoteObjectInterface = NSXPCInterface(with: IntercommUninstallerType.self)
|
||
|
||
connection.invalidationHandler = self.connectionInvalidationHandler
|
||
connection.interruptionHandler = self.connetionInterruptionHandler
|
||
|
||
self.connection = connection
|
||
|
||
connection.resume()
|
||
}
|
||
|
||
private func intercomm() -> Future<IntercommUninstallerType> {
|
||
|
||
return Future<IntercommUninstallerType> { [weak self] completion in
|
||
|
||
guard let self = self else {
|
||
completion(.failure(XPCСommonClientError.unowned))
|
||
return
|
||
}
|
||
|
||
guard let connection = self.connection
|
||
, let intercomm = connection.remoteObjectProxyWithErrorHandler({ error in
|
||
completion(.failure(XPCСommonClientError.proxy(error)))
|
||
}) as? IntercommUninstallerType else {
|
||
completion(.failure(XPCСommonClientError.incorrectType))
|
||
return
|
||
}
|
||
|
||
completion(.success(intercomm))
|
||
}.onResult { result in
|
||
|
||
switch result {
|
||
case let .failure(hiveError):
|
||
switch hiveError {
|
||
case XPCСommonClientError.unowned:
|
||
break
|
||
case let XPCСommonClientError.proxy(error):
|
||
CometLogger.shared.record(error: error)
|
||
if self.state == .initializing {
|
||
self.state = .invalid
|
||
}
|
||
case XPCСommonClientError.incorrectType:
|
||
if self.state == .initializing {
|
||
self.state = .invalid
|
||
}
|
||
default:
|
||
break
|
||
}
|
||
default:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
private func checkCallAllowed() -> Future<IntercommUninstallerType> {
|
||
|
||
return self.intercomm().onFailure { [weak self] _ in
|
||
|
||
self?.state = .undefined
|
||
/*throw NSError(domain: PrivadoConstants.Hive.error,
|
||
code: PrivadoConstants.Hive.ErrorCode.xpcEmptyRemoteObject,
|
||
userInfo: nil)*/
|
||
}
|
||
}
|
||
|
||
private func connetionInterruptionHandler() {
|
||
guard self.state != .requireUpdate else { return }
|
||
|
||
if self.state == .initializing
|
||
, !self.installed {
|
||
self.state = .invalid
|
||
return
|
||
}
|
||
self.state = .interrupted
|
||
// NSLog("[SMJBS]: \(#function)")
|
||
}
|
||
|
||
private func connectionInvalidationHandler() {
|
||
|
||
if self.installed {
|
||
// Think what I must todo here
|
||
return
|
||
}
|
||
|
||
guard self.state != .invalid else { return }
|
||
|
||
if self.state == .initializing {
|
||
self.state = .invalid
|
||
return
|
||
}
|
||
|
||
self.state = .invalid
|
||
// NSLog("[SMJBS]: \(#function)")
|
||
}
|
||
|
||
}
|