mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-02-14 16:05:25 +00:00
Make SiteList.loadAll
a static method
This commit is contained in:
parent
8ff1da215c
commit
6564a18d3d
3 changed files with 106 additions and 113 deletions
|
@ -1,108 +1,103 @@
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
class SiteList {
|
class SiteList {
|
||||||
private var sites = [String: Site]()
|
|
||||||
|
|
||||||
/// Gets the root directory that can be used to share files between the UI and VPN process. Does ensure the directory exists
|
/// Gets the root directory that can be used to share files between the UI and VPN process. Does ensure the directory exists
|
||||||
static func getRootDir() throws -> URL {
|
static func getRootDir() throws -> URL {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let rootDir = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.net.defined.mobileNebula")!
|
let rootDir = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.net.defined.mobileNebula")!
|
||||||
|
|
||||||
if (!fileManager.fileExists(atPath: rootDir.absoluteString)) {
|
if !fileManager.fileExists(atPath: rootDir.absoluteString) {
|
||||||
try fileManager.createDirectory(at: rootDir, withIntermediateDirectories: true)
|
try fileManager.createDirectory(at: rootDir, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootDir
|
return rootDir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the directory where all sites live, $rootDir/sites. Does ensure the directory exists
|
/// Gets the directory where all sites live, $rootDir/sites. Does ensure the directory exists
|
||||||
static func getSitesDir() throws -> URL {
|
static func getSitesDir() throws -> URL {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let sitesDir = try getRootDir().appendingPathComponent("sites", isDirectory: true)
|
let sitesDir = try getRootDir().appendingPathComponent("sites", isDirectory: true)
|
||||||
if (!fileManager.fileExists(atPath: sitesDir.absoluteString)) {
|
if !fileManager.fileExists(atPath: sitesDir.absoluteString) {
|
||||||
try fileManager.createDirectory(at: sitesDir, withIntermediateDirectories: true)
|
try fileManager.createDirectory(at: sitesDir, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
return sitesDir
|
return sitesDir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the directory where a single site would live, $rootDir/sites/$siteID
|
/// Gets the directory where a single site would live, $rootDir/sites/$siteID
|
||||||
static func getSiteDir(id: String, create: Bool = false) throws -> URL {
|
static func getSiteDir(id: String, create: Bool = false) throws -> URL {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let siteDir = try getSitesDir().appendingPathComponent(id, isDirectory: true)
|
let siteDir = try getSitesDir().appendingPathComponent(id, isDirectory: true)
|
||||||
if (create && !fileManager.fileExists(atPath: siteDir.absoluteString)) {
|
if create && !fileManager.fileExists(atPath: siteDir.absoluteString) {
|
||||||
try fileManager.createDirectory(at: siteDir, withIntermediateDirectories: true)
|
try fileManager.createDirectory(at: siteDir, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
return siteDir
|
return siteDir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the file that represents the site configuration, $rootDir/sites/$siteID/config.json
|
/// Gets the file that represents the site configuration, $rootDir/sites/$siteID/config.json
|
||||||
static func getSiteConfigFile(id: String, createDir: Bool) throws -> URL {
|
static func getSiteConfigFile(id: String, createDir: Bool) throws -> URL {
|
||||||
return try getSiteDir(id: id, create: createDir).appendingPathComponent("config", isDirectory: false).appendingPathExtension("json")
|
return try getSiteDir(id: id, create: createDir).appendingPathComponent("config", isDirectory: false)
|
||||||
|
.appendingPathExtension("json")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the file that represents the site log output, $rootDir/sites/$siteID/log
|
/// Gets the file that represents the site log output, $rootDir/sites/$siteID/log
|
||||||
static func getSiteLogFile(id: String, createDir: Bool) throws -> URL {
|
static func getSiteLogFile(id: String, createDir: Bool) throws -> URL {
|
||||||
return try getSiteDir(id: id, create: createDir).appendingPathComponent("logs", isDirectory: false)
|
return try getSiteDir(id: id, create: createDir).appendingPathComponent("logs", isDirectory: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(completion: @escaping ([String: Site]?, (any Error)?) -> ()) {
|
static func loadAll(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
||||||
#if targetEnvironment(simulator)
|
#if targetEnvironment(simulator)
|
||||||
SiteList.loadAllFromFS { sites, err in
|
SiteList.loadAllFromFS { sites, err in
|
||||||
if sites != nil {
|
|
||||||
self.sites = sites!
|
completion(sites, err)
|
||||||
}
|
}
|
||||||
completion(sites, err)
|
#else
|
||||||
}
|
SiteList.loadAllFromNETPM { sites, err in
|
||||||
#else
|
|
||||||
SiteList.loadAllFromNETPM { sites, err in
|
completion(sites, err)
|
||||||
if sites != nil {
|
|
||||||
self.sites = sites!
|
|
||||||
}
|
}
|
||||||
completion(sites, err)
|
#endif
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func loadAllFromFS(completion: @escaping ([String: Site]?, (any Error)?) -> ()) {
|
private static func loadAllFromFS(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
var siteDirs: [URL]
|
var siteDirs: [URL]
|
||||||
var sites = [String: Site]()
|
var sites = [String: Site]()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
siteDirs = try fileManager.contentsOfDirectory(at: getSitesDir(), includingPropertiesForKeys: nil)
|
siteDirs = try fileManager.contentsOfDirectory(at: getSitesDir(), includingPropertiesForKeys: nil)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
completion(nil, error)
|
completion(nil, error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
siteDirs.forEach { path in
|
siteDirs.forEach { path in
|
||||||
do {
|
do {
|
||||||
let site = try Site(path: path.appendingPathComponent("config").appendingPathExtension("json"))
|
let site = try Site(path: path.appendingPathComponent("config").appendingPathExtension("json"))
|
||||||
sites[site.id] = site
|
sites[site.id] = site
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
try? fileManager.removeItem(at: path)
|
try? fileManager.removeItem(at: path)
|
||||||
print("Deleted non conforming site \(path)")
|
print("Deleted non conforming site \(path)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completion(sites, nil)
|
completion(sites, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func loadAllFromNETPM(completion: @escaping ([String: Site]?, (any Error)?) -> ()) {
|
private static func loadAllFromNETPM(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
||||||
var sites = [String: Site]()
|
var sites = [String: Site]()
|
||||||
|
|
||||||
// dispatchGroup is used to ensure we have migrated all sites before returning them
|
// dispatchGroup is used to ensure we have migrated all sites before returning them
|
||||||
// If there are no sites to migrate, there are never any entrants
|
// If there are no sites to migrate, there are never any entrants
|
||||||
let dispatchGroup = DispatchGroup()
|
let dispatchGroup = DispatchGroup()
|
||||||
|
|
||||||
NETunnelProviderManager.loadAllFromPreferences() { newManagers, err in
|
NETunnelProviderManager.loadAllFromPreferences { newManagers, err in
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
return completion(nil, err)
|
return completion(nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newManagers?.forEach { manager in
|
newManagers?.forEach { manager in
|
||||||
do {
|
do {
|
||||||
let site = try Site(manager: manager)
|
let site = try Site(manager: manager)
|
||||||
|
@ -112,14 +107,14 @@ class SiteList {
|
||||||
if error != nil {
|
if error != nil {
|
||||||
print("Error while migrating site to fs: \(error!.localizedDescription)")
|
print("Error while migrating site to fs: \(error!.localizedDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Migrated site to fs: \(site.name)")
|
print("Migrated site to fs: \(site.name)")
|
||||||
site.needsToMigrateToFS = false
|
site.needsToMigrateToFS = false
|
||||||
dispatchGroup.leave()
|
dispatchGroup.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sites[site.id] = site
|
sites[site.id] = site
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
//TODO: notify the user about this
|
//TODO: notify the user about this
|
||||||
print("Deleted non conforming site \(manager) \(error)")
|
print("Deleted non conforming site \(manager) \(error)")
|
||||||
|
@ -127,14 +122,10 @@ class SiteList {
|
||||||
//TODO: delete from disk, we need to try and discover the site id though
|
//TODO: delete from disk, we need to try and discover the site id though
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchGroup.notify(queue: .main) {
|
dispatchGroup.notify(queue: .main) {
|
||||||
completion(sites, nil)
|
completion(sites, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSites() -> [String: Site] {
|
|
||||||
return sites
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ actor DNUpdater {
|
||||||
private let timer = RepeatingTimer(timeInterval: 15 * 60) // 15 * 60 is 15 minutes
|
private let timer = RepeatingTimer(timeInterval: 15 * 60) // 15 * 60 is 15 minutes
|
||||||
private let log = Logger(subsystem: "net.defined.mobileNebula", category: "DNUpdater")
|
private let log = Logger(subsystem: "net.defined.mobileNebula", category: "DNUpdater")
|
||||||
|
|
||||||
func updateAll(onUpdate: @escaping (Site) -> Void) {
|
private func updateAll(onUpdate: @escaping (Site) -> Void) {
|
||||||
_ = SiteList { (sites, _) -> Void in
|
SiteList.loadAll(completion: { (sites, _) -> Void in
|
||||||
if let unwrappedSites = sites?.values {
|
if let unwrappedSites = sites?.values {
|
||||||
// NEVPN seems to force us onto the main thread and we are about to make network calls that
|
// NEVPN seems to force us onto the main thread and we are about to make network calls that
|
||||||
// could block for a while. Push ourselves onto another thread to avoid blocking the UI.
|
// could block for a while. Push ourselves onto another thread to avoid blocking the UI.
|
||||||
|
@ -25,7 +25,7 @@ actor DNUpdater {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAllLoop(onUpdate: @escaping (Site) -> Void) {
|
func updateAllLoop(onUpdate: @escaping (Site) -> Void) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import NetworkExtension
|
|
||||||
import MobileNebula
|
import MobileNebula
|
||||||
|
import NetworkExtension
|
||||||
|
|
||||||
class SiteContainer {
|
class SiteContainer {
|
||||||
var site: Site
|
var site: Site
|
||||||
var updater: SiteUpdater
|
var updater: SiteUpdater
|
||||||
|
|
||||||
init(site: Site, updater: SiteUpdater) {
|
init(site: Site, updater: SiteUpdater) {
|
||||||
self.site = site
|
self.site = site
|
||||||
self.updater = updater
|
self.updater = updater
|
||||||
|
@ -14,39 +14,39 @@ class SiteContainer {
|
||||||
class Sites {
|
class Sites {
|
||||||
private var containers = [String: SiteContainer]()
|
private var containers = [String: SiteContainer]()
|
||||||
private var messenger: (any FlutterBinaryMessenger)?
|
private var messenger: (any FlutterBinaryMessenger)?
|
||||||
|
|
||||||
init(messenger: (any FlutterBinaryMessenger)?) {
|
init(messenger: (any FlutterBinaryMessenger)?) {
|
||||||
self.messenger = messenger
|
self.messenger = messenger
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSites(completion: @escaping ([String: Site]?, (any Error)?) -> ()) {
|
func loadSites(completion: @escaping ([String: Site]?, (any Error)?) -> Void) {
|
||||||
_ = SiteList { (sites, err) in
|
SiteList.loadAll(completion: { (sites, err) in
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
return completion(nil, err)
|
return completion(nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sites?.values.forEach{ site in
|
sites?.values.forEach { site in
|
||||||
var updater = self.containers[site.id]?.updater
|
var updater = self.containers[site.id]?.updater
|
||||||
if (updater != nil) {
|
if updater != nil {
|
||||||
updater!.setSite(site: site)
|
updater!.setSite(site: site)
|
||||||
} else {
|
} else {
|
||||||
updater = SiteUpdater(messenger: self.messenger!, site: site)
|
updater = SiteUpdater(messenger: self.messenger!, site: site)
|
||||||
}
|
}
|
||||||
self.containers[site.id] = SiteContainer(site: site, updater: updater!)
|
self.containers[site.id] = SiteContainer(site: site, updater: updater!)
|
||||||
}
|
}
|
||||||
|
|
||||||
let justSites = self.containers.mapValues {
|
let justSites = self.containers.mapValues {
|
||||||
return $0.site
|
return $0.site
|
||||||
}
|
}
|
||||||
completion(justSites, nil)
|
completion(justSites, nil)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteSite(id: String, callback: @escaping ((any Error)?) -> ()) {
|
func deleteSite(id: String, callback: @escaping ((any Error)?) -> Void) {
|
||||||
if let site = self.containers.removeValue(forKey: id) {
|
if let site = self.containers.removeValue(forKey: id) {
|
||||||
_ = KeyChain.delete(key: "\(site.site.id).dnCredentials")
|
_ = KeyChain.delete(key: "\(site.site.id).dnCredentials")
|
||||||
_ = KeyChain.delete(key: "\(site.site.id).key")
|
_ = KeyChain.delete(key: "\(site.site.id).key")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let siteDir = try SiteList.getSiteDir(id: site.site.id)
|
let siteDir = try SiteList.getSiteDir(id: site.site.id)
|
||||||
|
@ -54,39 +54,39 @@ class Sites {
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to delete site from fs: \(error.localizedDescription)")
|
print("Failed to delete site from fs: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !targetEnvironment(simulator)
|
#if !targetEnvironment(simulator)
|
||||||
site.site.manager!.removeFromPreferences(completionHandler: callback)
|
site.site.manager!.removeFromPreferences(completionHandler: callback)
|
||||||
return
|
return
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to remove
|
// Nothing to remove
|
||||||
callback(nil)
|
callback(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSite(id: String) -> Site? {
|
func getSite(id: String) -> Site? {
|
||||||
return self.containers[id]?.site
|
return self.containers[id]?.site
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUpdater(id: String) -> SiteUpdater? {
|
func getUpdater(id: String) -> SiteUpdater? {
|
||||||
return self.containers[id]?.updater
|
return self.containers[id]?.updater
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainer(id: String) -> SiteContainer? {
|
func getContainer(id: String) -> SiteContainer? {
|
||||||
return self.containers[id]
|
return self.containers[id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SiteUpdater: NSObject, FlutterStreamHandler {
|
class SiteUpdater: NSObject, FlutterStreamHandler {
|
||||||
private var eventSink: FlutterEventSink?;
|
private var eventSink: FlutterEventSink?
|
||||||
private var eventChannel: FlutterEventChannel;
|
private var eventChannel: FlutterEventChannel
|
||||||
private var site: Site
|
private var site: Site
|
||||||
private var notification: Any?
|
private var notification: Any?
|
||||||
public var startFunc: (() -> Void)?
|
public var startFunc: (() -> Void)?
|
||||||
private var configFd: Int32? = nil
|
private var configFd: Int32? = nil
|
||||||
private var configObserver: (any DispatchSourceFileSystemObject)? = nil
|
private var configObserver: (any DispatchSourceFileSystemObject)? = nil
|
||||||
|
|
||||||
init(messenger: any FlutterBinaryMessenger, site: Site) {
|
init(messenger: any FlutterBinaryMessenger, site: Site) {
|
||||||
do {
|
do {
|
||||||
let configPath = try SiteList.getSiteConfigFile(id: site.id, createDir: false)
|
let configPath = try SiteList.getSiteConfigFile(id: site.id, createDir: false)
|
||||||
|
@ -95,18 +95,18 @@ class SiteUpdater: NSObject, FlutterStreamHandler {
|
||||||
fileDescriptor: self.configFd!,
|
fileDescriptor: self.configFd!,
|
||||||
eventMask: .write
|
eventMask: .write
|
||||||
)
|
)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
// SiteList.getSiteConfigFile should never throw because we are not creating it here
|
// SiteList.getSiteConfigFile should never throw because we are not creating it here
|
||||||
self.configObserver = nil
|
self.configObserver = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
eventChannel = FlutterEventChannel(name: "net.defined.nebula/\(site.id)", binaryMessenger: messenger)
|
eventChannel = FlutterEventChannel(name: "net.defined.nebula/\(site.id)", binaryMessenger: messenger)
|
||||||
self.site = site
|
self.site = site
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
eventChannel.setStreamHandler(self)
|
eventChannel.setStreamHandler(self)
|
||||||
|
|
||||||
self.configObserver?.setEventHandler(handler: self.configUpdated)
|
self.configObserver?.setEventHandler(handler: self.configUpdated)
|
||||||
self.configObserver?.setCancelHandler {
|
self.configObserver?.setCancelHandler {
|
||||||
if self.configFd != nil {
|
if self.configFd != nil {
|
||||||
|
@ -114,72 +114,74 @@ class SiteUpdater: NSObject, FlutterStreamHandler {
|
||||||
}
|
}
|
||||||
self.configObserver = nil
|
self.configObserver = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.configObserver?.resume()
|
self.configObserver?.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
func setSite(site: Site) {
|
func setSite(site: Site) {
|
||||||
self.site = site
|
self.site = site
|
||||||
}
|
}
|
||||||
|
|
||||||
/// onListen is called when flutter code attaches an event listener
|
/// onListen is called when flutter code attaches an event listener
|
||||||
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
||||||
eventSink = events;
|
eventSink = events
|
||||||
|
|
||||||
#if !targetEnvironment(simulator)
|
#if !targetEnvironment(simulator)
|
||||||
if site.manager == nil {
|
if site.manager == nil {
|
||||||
//TODO: The dn updater path seems to race to build a site that lacks a manager. The UI does not display this error
|
//TODO: The dn updater path seems to race to build a site that lacks a manager. The UI does not display this error
|
||||||
// and a another listen should occur and succeed.
|
// and a another listen should occur and succeed.
|
||||||
return FlutterError(code: "Internal Error", message: "Flutter manager was not present", details: nil)
|
return FlutterError(code: "Internal Error", message: "Flutter manager was not present", details: nil)
|
||||||
}
|
|
||||||
|
|
||||||
self.notification = NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: site.manager!.connection , queue: nil) { n in
|
|
||||||
let oldConnected = self.site.connected
|
|
||||||
self.site.status = statusString[self.site.manager!.connection.status]
|
|
||||||
self.site.connected = statusMap[self.site.manager!.connection.status]
|
|
||||||
|
|
||||||
// Check to see if we just moved to connected and if we have a start function to call when that happens
|
|
||||||
if self.site.connected! && oldConnected != self.site.connected && self.startFunc != nil {
|
|
||||||
self.startFunc!()
|
|
||||||
self.startFunc = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update(connected: self.site.connected!)
|
self.notification = NotificationCenter.default.addObserver(
|
||||||
}
|
forName: NSNotification.Name.NEVPNStatusDidChange, object: site.manager!.connection, queue: nil
|
||||||
#endif
|
) { n in
|
||||||
|
let oldConnected = self.site.connected
|
||||||
|
self.site.status = statusString[self.site.manager!.connection.status]
|
||||||
|
self.site.connected = statusMap[self.site.manager!.connection.status]
|
||||||
|
|
||||||
|
// Check to see if we just moved to connected and if we have a start function to call when that happens
|
||||||
|
if self.site.connected! && oldConnected != self.site.connected && self.startFunc != nil {
|
||||||
|
self.startFunc!()
|
||||||
|
self.startFunc = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update(connected: self.site.connected!)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// onCancel is called when the flutter listener stops listening
|
/// onCancel is called when the flutter listener stops listening
|
||||||
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
||||||
if (self.notification != nil) {
|
if self.notification != nil {
|
||||||
NotificationCenter.default.removeObserver(self.notification!)
|
NotificationCenter.default.removeObserver(self.notification!)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// update is a way to send information to the flutter listener and generally should not be used directly
|
/// update is a way to send information to the flutter listener and generally should not be used directly
|
||||||
func update(connected: Bool, replaceSite: Site? = nil) {
|
func update(connected: Bool, replaceSite: Site? = nil) {
|
||||||
if (replaceSite != nil) {
|
if replaceSite != nil {
|
||||||
site = replaceSite!
|
site = replaceSite!
|
||||||
}
|
}
|
||||||
site.connected = connected
|
site.connected = connected
|
||||||
site.status = connected ? "Connected" : "Disconnected"
|
site.status = connected ? "Connected" : "Disconnected"
|
||||||
|
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
let data = try! encoder.encode(site)
|
let data = try! encoder.encode(site)
|
||||||
self.eventSink?(String(data: data, encoding: .utf8))
|
self.eventSink?(String(data: data, encoding: .utf8))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func configUpdated() {
|
private func configUpdated() {
|
||||||
if self.site.connected != true {
|
if self.site.connected != true {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let newSite = try? Site(manager: self.site.manager!) else {
|
guard let newSite = try? Site(manager: self.site.manager!) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update(connected: newSite.connected ?? false, replaceSite: newSite)
|
self.update(connected: newSite.connected ?? false, replaceSite: newSite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue