mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-02-22 19:15:27 +00:00
Refactor DNUpdater to an actor and try to fix warnings
This commit is contained in:
parent
f59ab7c09d
commit
be56774197
4 changed files with 44 additions and 45 deletions
|
@ -23,7 +23,7 @@ extension AppMessageError: LocalizedError {
|
|||
}
|
||||
}
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
final class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
|
||||
private var networkMonitor: NWPathMonitor?
|
||||
|
||||
private var site: Site?
|
||||
|
@ -92,8 +92,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
throw err!
|
||||
}
|
||||
tunnelNetworkSettings.ipv4Settings = NEIPv4Settings(
|
||||
addresses: [ipNet!.ip], subnetMasks: [ipNet!.maskCIDR]
|
||||
)
|
||||
addresses: [ipNet!.ip], subnetMasks: [ipNet!.maskCIDR])
|
||||
var routes: [NEIPv4Route] = [
|
||||
NEIPv4Route(destinationAddress: ipNet!.network, subnetMask: ipNet!.maskCIDR)
|
||||
]
|
||||
|
@ -113,8 +112,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
try await setTunnelNetworkSettings(tunnelNetworkSettings)
|
||||
var nebulaErr: NSError?
|
||||
nebula = MobileNebulaNewNebula(
|
||||
String(data: config, encoding: .utf8), key, site!.logFile, tunFD, &nebulaErr
|
||||
)
|
||||
String(data: config, encoding: .utf8), key, site!.logFile, tunFD, &nebulaErr)
|
||||
startNetworkMonitor()
|
||||
|
||||
if nebulaErr != nil {
|
||||
|
@ -123,15 +121,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
}
|
||||
|
||||
nebula!.start()
|
||||
dnUpdater.updateSingleLoop(site: site!, onUpdate: handleDNUpdate)
|
||||
await dnUpdater.updateSingleLoop(site: site!, onUpdate: handleDNUpdate)
|
||||
}
|
||||
|
||||
private func handleDNUpdate(newSite: Site) {
|
||||
do {
|
||||
site = newSite
|
||||
try nebula?.reload(
|
||||
String(data: newSite.getConfig(), encoding: .utf8), key: newSite.getKey()
|
||||
)
|
||||
try nebula?.reload(String(data: newSite.getConfig(), encoding: .utf8), key: newSite.getKey())
|
||||
|
||||
} catch {
|
||||
log.error(
|
||||
|
@ -180,9 +176,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
networkMonitor = nil
|
||||
}
|
||||
|
||||
override func stopTunnel(
|
||||
with _: NEProviderStopReason, completionHandler: @escaping () -> Void
|
||||
) {
|
||||
override func stopTunnel(with _: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
nebula?.stop()
|
||||
stopNetworkMonitor()
|
||||
completionHandler()
|
||||
|
@ -259,9 +253,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
|
||||
if error != nil {
|
||||
return try? JSONEncoder().encode(
|
||||
IPCResponse(
|
||||
type: .error, message: JSON(error?.localizedDescription ?? "Unknown error")
|
||||
))
|
||||
IPCResponse(type: .error, message: JSON(error?.localizedDescription ?? "Unknown error")))
|
||||
} else {
|
||||
return try? JSONEncoder().encode(IPCResponse(type: .success, message: data))
|
||||
}
|
||||
|
@ -276,14 +268,16 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
private func getHostInfo(args: JSON) -> (JSON?, (any Error)?) {
|
||||
var err: NSError?
|
||||
let res = nebula!.getHostInfo(
|
||||
byVpnIp: args["vpnIp"].string, pending: args["pending"].boolValue, error: &err)
|
||||
byVpnIp: args["vpnIp"].string, pending: args["pending"].boolValue, error: &err
|
||||
)
|
||||
return (JSON(res), err)
|
||||
}
|
||||
|
||||
private func setRemoteForTunnel(args: JSON) -> (JSON?, (any Error)?) {
|
||||
var err: NSError?
|
||||
let res = nebula!.setRemoteForTunnel(
|
||||
args["vpnIp"].string, addr: args["addr"].string, error: &err)
|
||||
args["vpnIp"].string, addr: args["addr"].string, error: &err
|
||||
)
|
||||
return (JSON(res), err)
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ let statusString: [NEVPNStatus: String] = [
|
|||
]
|
||||
|
||||
// Represents a site that was pulled out of the system configuration
|
||||
class Site: Codable {
|
||||
final class Site: Codable, @unchecked Sendable {
|
||||
// Stored in manager
|
||||
var name: String
|
||||
var id: String
|
||||
|
@ -278,7 +278,10 @@ class Site: Codable {
|
|||
}
|
||||
}
|
||||
|
||||
if hasErrors && !managed {
|
||||
if hasErrors, !managed {
|
||||
errors.append("There are issues with 1 or more ca certificates")
|
||||
}
|
||||
if hasErrors, !managed {
|
||||
errors.append("There are issues with 1 or more ca certificates")
|
||||
}
|
||||
|
||||
|
@ -294,7 +297,7 @@ class Site: Codable {
|
|||
errors.append("Unable to create the site directory: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
if managed && (try? getDNCredentials())?.invalid != false {
|
||||
if managed, (try? getDNCredentials())?.invalid != false {
|
||||
errors.append("Unable to fetch managed updates - please re-enroll the device")
|
||||
}
|
||||
|
||||
|
@ -426,7 +429,7 @@ class DNCredentials: Codable {
|
|||
}
|
||||
|
||||
// This class represents a site coming in from flutter, meant only to be saved and re-loaded as a proper Site
|
||||
struct IncomingSite: Codable {
|
||||
struct IncomingSite: Codable, @unchecked Sendable {
|
||||
var name: String
|
||||
var id: String
|
||||
var staticHostmap: [String: StaticHosts]
|
||||
|
|
|
@ -25,17 +25,19 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
|
|||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
|
||||
dnUpdater.updateAllLoop { site in
|
||||
// Signal the site has changed in case the current site details screen is active
|
||||
let container = self.sites?.getContainer(id: site.id)
|
||||
if container != nil {
|
||||
// Update references to the site with the new site config
|
||||
container!.site = site
|
||||
container!.updater.update(connected: site.connected ?? false, replaceSite: site)
|
||||
}
|
||||
Task {
|
||||
await dnUpdater.updateAllLoop { @MainActor site in
|
||||
// Signal the site has changed in case the current site details screen is active
|
||||
let container = self.sites?.getContainer(id: site.id)
|
||||
if container != nil {
|
||||
// Update references to the site with the new site config
|
||||
container!.site = site
|
||||
container!.updater.update(connected: site.connected ?? false, replaceSite: site)
|
||||
}
|
||||
|
||||
// Signal to the main screen to reload
|
||||
self.ui?.invokeMethod("refreshSites", arguments: nil)
|
||||
// Signal to the main screen to reload
|
||||
self.ui?.invokeMethod("refreshSites", arguments: nil)
|
||||
}
|
||||
}
|
||||
|
||||
guard let controller = window?.rootViewController as? FlutterViewController else {
|
||||
|
@ -86,8 +88,7 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
|
|||
if err != nil {
|
||||
return result(
|
||||
CallFailedError(
|
||||
message: "Error while parsing certificate(s)", details: err!.localizedDescription
|
||||
))
|
||||
message: "Error while parsing certificate(s)", details: err!.localizedDescription))
|
||||
}
|
||||
|
||||
return result(json)
|
||||
|
@ -109,8 +110,7 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
|
|||
return result(
|
||||
CallFailedError(
|
||||
message: "Error while verifying certificate and private key",
|
||||
details: err!.localizedDescription
|
||||
))
|
||||
details: err!.localizedDescription))
|
||||
}
|
||||
|
||||
return result(valid)
|
||||
|
@ -122,8 +122,7 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
|
|||
if err != nil {
|
||||
return result(
|
||||
CallFailedError(
|
||||
message: "Error while generating key pairs", details: err!.localizedDescription
|
||||
))
|
||||
message: "Error while generating key pairs", details: err!.localizedDescription))
|
||||
}
|
||||
|
||||
return result(kp)
|
||||
|
@ -241,8 +240,7 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
|
|||
} catch {
|
||||
return result(
|
||||
CallFailedError(
|
||||
message: "Could not start site", details: error.localizedDescription
|
||||
))
|
||||
message: "Could not start site", details: error.localizedDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
|
||||
class DNUpdater {
|
||||
actor DNUpdater {
|
||||
private let apiClient = APIClient()
|
||||
private let timer = RepeatingTimer(timeInterval: 15 * 60) // 15 * 60 is 15 minutes
|
||||
private let log = Logger(subsystem: "net.defined.mobileNebula", category: "DNUpdater")
|
||||
|
||||
func updateAll(onUpdate: @escaping (Site) -> Void) {
|
||||
func updateAll(onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||
_ = SiteList { sites, _ in
|
||||
guard let unwrappedSites = sites else {
|
||||
// There was an error, let's bail.
|
||||
return
|
||||
}
|
||||
// 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.
|
||||
Task.detached(priority: .userInitiated) {
|
||||
sites?.values.forEach { site in
|
||||
for site in unwrappedSites.values {
|
||||
if site.connected == true {
|
||||
// The vpn service is in charge of updating the currently connected site
|
||||
return
|
||||
}
|
||||
|
||||
self.updateSite(site: site, onUpdate: onUpdate)
|
||||
await self.updateSite(site: site, onUpdate: onUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateAllLoop(onUpdate: @escaping (Site) -> Void) {
|
||||
func updateAllLoop(onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||
timer.eventHandler = {
|
||||
self.updateAll(onUpdate: onUpdate)
|
||||
}
|
||||
|
@ -37,7 +41,7 @@ class DNUpdater {
|
|||
timer.resume()
|
||||
}
|
||||
|
||||
func updateSite(site: Site, onUpdate: @escaping (Site) -> Void) {
|
||||
func updateSite(site: Site, onUpdate: sending @escaping (Site) -> Void) {
|
||||
do {
|
||||
if !site.managed {
|
||||
return
|
||||
|
|
Loading…
Reference in a new issue