mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-09-07 11:46:03 +00:00
Compare commits
10 commits
c7f6001f76
...
0054a8778c
Author | SHA1 | Date | |
---|---|---|---|
|
0054a8778c | ||
|
5b1724d454 | ||
|
281d690ef3 | ||
|
a32d17705c | ||
|
df4c3a51b8 | ||
|
8e9b5fcc4a | ||
|
f3882997be | ||
|
bc67c06ef7 | ||
|
500e49edc3 | ||
|
ae34c59456 |
11 changed files with 73 additions and 52 deletions
|
@ -23,7 +23,7 @@ extension AppMessageError: LocalizedError {
|
|||
}
|
||||
}
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
|
||||
private var networkMonitor: NWPathMonitor?
|
||||
|
||||
private var site: Site?
|
||||
|
|
|
@ -6,7 +6,7 @@ import os.log
|
|||
let log = Logger(subsystem: "net.defined.mobileNebula", category: "Site")
|
||||
|
||||
enum SiteError: Error {
|
||||
case nonConforming(site: [String: Any]?)
|
||||
case nonConforming(site: String)
|
||||
case noCertificate
|
||||
case keyLoad
|
||||
case keySave
|
||||
|
@ -22,7 +22,7 @@ extension SiteError: CustomStringConvertible {
|
|||
public var description: String {
|
||||
switch self {
|
||||
case .nonConforming(let site):
|
||||
return String("Non-conforming site \(String(describing: site))")
|
||||
return String("Non-conforming site \(site)")
|
||||
case .noCertificate:
|
||||
return "No certificate found"
|
||||
case .keyLoad:
|
||||
|
@ -150,7 +150,7 @@ let statusString: [NEVPNStatus: String] = [
|
|||
]
|
||||
|
||||
// Represents a site that was pulled out of the system configuration
|
||||
class Site: Codable {
|
||||
class Site: Codable, @unchecked Sendable {
|
||||
// Stored in manager
|
||||
var name: String
|
||||
var id: String
|
||||
|
@ -208,7 +208,7 @@ class Site: Codable {
|
|||
|
||||
let id = dict?["id"] as? String ?? nil
|
||||
if id == nil {
|
||||
throw SiteError.nonConforming(site: dict)
|
||||
throw SiteError.nonConforming(site: String(describing: dict))
|
||||
}
|
||||
|
||||
try self.init(path: SiteList.getSiteConfigFile(id: id!, createDir: false))
|
||||
|
|
|
@ -10,11 +10,11 @@ PODS:
|
|||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (8.42.0)
|
||||
- sentry_flutter (8.12.0):
|
||||
- Sentry/HybridSDK (8.46.0)
|
||||
- sentry_flutter (8.14.2):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.42.0)
|
||||
- Sentry/HybridSDK (= 8.46.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- SwiftyJSON (5.0.2)
|
||||
|
@ -56,16 +56,16 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
file_picker: 8272ff2f2365937598e2407f4f2ff55c723f084a
|
||||
file_picker: c79185e70b9b45728cde2a8d8da454e0cb43f287
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
Sentry: 38ed8bf38eab5812787274bf591e528074c19e02
|
||||
sentry_flutter: a72ca0eb6e78335db7c4ddcddd1b9f6c8ed5b764
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
|
||||
sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
SwiftyJSON: f5b1bf1cd8dd53cd25887ac0eabcfd92301c6a5a
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
|
||||
PODFILE CHECKSUM: b44d9de9944d89118a4ff4bfffe1c2dab91de156
|
||||
|
||||
|
|
|
@ -563,6 +563,7 @@
|
|||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
|
@ -574,7 +575,7 @@
|
|||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
@ -784,6 +785,7 @@
|
|||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
|
@ -795,7 +797,7 @@
|
|||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -849,6 +851,7 @@
|
|||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
|
@ -860,7 +863,7 @@
|
|||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import MobileNebula
|
||||
@preconcurrency import MobileNebula
|
||||
|
||||
enum APIClientError: Error {
|
||||
case invalidCredentials
|
||||
}
|
||||
|
||||
class APIClient {
|
||||
struct APIClient: Sendable {
|
||||
let apiClient: MobileNebulaAPIClient
|
||||
let json = JSONDecoder()
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Flutter
|
||||
@preconcurrency import Flutter
|
||||
import MobileNebula
|
||||
import NetworkExtension
|
||||
import SwiftyJSON
|
||||
|
@ -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 {
|
||||
for await site in dnUpdater.siteUpdates {
|
||||
// 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 {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
|
||||
class DNUpdater {
|
||||
class DNUpdater: @unchecked Sendable {
|
||||
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, _) -> Void in
|
||||
// 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.
|
||||
|
@ -23,21 +23,33 @@ class DNUpdater {
|
|||
}
|
||||
}
|
||||
|
||||
func updateAllLoop(onUpdate: @escaping (Site) -> Void) {
|
||||
func updateAllLoop(onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||
timer.eventHandler = {
|
||||
self.updateAll(onUpdate: onUpdate)
|
||||
}
|
||||
timer.resume()
|
||||
}
|
||||
|
||||
func updateSingleLoop(site: Site, onUpdate: @escaping (Site) -> Void) {
|
||||
// Site updates provides an async/await alternative to `.updateAllLoop` that doesn't require a sendable closure.
|
||||
// https://developer.apple.com/documentation/swift/asyncstream
|
||||
var siteUpdates: AsyncStream<Site> {
|
||||
AsyncStream { continuation in
|
||||
self.updateAllLoop(onUpdate: { site in
|
||||
continuation.yield(site)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func updateSingleLoop(site: Site, onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||
timer.eventHandler = {
|
||||
self.updateSite(site: site, onUpdate: onUpdate)
|
||||
}
|
||||
timer.resume()
|
||||
}
|
||||
|
||||
func updateSite(site: Site, onUpdate: @escaping (Site) -> Void) {
|
||||
func updateSite(site: Site, onUpdate: @Sendable @escaping (Site) -> Void) {
|
||||
do {
|
||||
if !site.managed {
|
||||
return
|
||||
|
|
|
@ -78,14 +78,14 @@ class Sites {
|
|||
}
|
||||
}
|
||||
|
||||
class SiteUpdater: NSObject, FlutterStreamHandler {
|
||||
class SiteUpdater: NSObject, FlutterStreamHandler, @unchecked Sendable {
|
||||
private var eventSink: FlutterEventSink?
|
||||
private var eventChannel: FlutterEventChannel
|
||||
private var site: Site
|
||||
private var notification: Any?
|
||||
public var startFunc: (() -> Void)?
|
||||
private var configFd: Int32? = nil
|
||||
private var configObserver: (any DispatchSourceFileSystemObject)? = nil
|
||||
private var configFd: Int32?
|
||||
private var configObserver: (any DispatchSourceFileSystemObject)?
|
||||
|
||||
init(messenger: any FlutterBinaryMessenger, site: Site) {
|
||||
do {
|
||||
|
|
|
@ -152,6 +152,10 @@ class SwitchCameraButton extends StatelessWidget {
|
|||
icon = const Icon(Icons.camera_front);
|
||||
case CameraFacing.back:
|
||||
icon = const Icon(Icons.camera_rear);
|
||||
case CameraFacing.external:
|
||||
icon = const Icon(Icons.usb);
|
||||
case CameraFacing.unknown:
|
||||
icon = const Icon(Icons.device_unknown);
|
||||
}
|
||||
|
||||
return IconButton(
|
||||
|
|
18
pubspec.lock
18
pubspec.lock
|
@ -316,10 +316,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: mobile_scanner
|
||||
sha256: "1779bf862cfcf7a142117e707e2230624d42f153ddf51f4cc9f5ba455a2dd01e"
|
||||
sha256: "54005bdea7052d792d35b4fef0f84ec5ddc3a844b250ecd48dc192fb9b4ebc95"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0-beta.4"
|
||||
version: "7.0.1"
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -452,26 +452,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: sentry
|
||||
sha256: "576ad83415102ba2060142a6701611abc6e67a55af1d7ab339cedd3ba1b0f84c"
|
||||
sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.12.0"
|
||||
version: "8.14.2"
|
||||
sentry_dart_plugin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry_dart_plugin
|
||||
sha256: "14c298de1be3ba3a6a16d9ce0aad8662b14ca6ed85b8ade234f75b2f3c285edf"
|
||||
sha256: "84436958fa9231e2e716be117a3b31695e54458b9f27039f76d14515e24248a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.4.1"
|
||||
sentry_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry_flutter
|
||||
sha256: dc3761e8659839cc67a18432d9f12e5531affb7ff68e196dbb56846909b5dfdc
|
||||
sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.12.0"
|
||||
version: "8.14.2"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -719,4 +719,4 @@ packages:
|
|||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
flutter: ">=3.29.0"
|
||||
|
|
|
@ -36,9 +36,9 @@ dependencies:
|
|||
flutter_svg: ^2.0.10+1
|
||||
intl: ^0.19.0
|
||||
share_plus: ^10.0.2
|
||||
sentry_flutter: ^8.9.0
|
||||
sentry_dart_plugin: ^2.0.0
|
||||
mobile_scanner: ^7.0.0-beta.3
|
||||
sentry_flutter: ^8.14.2
|
||||
sentry_dart_plugin: ^2.4.1
|
||||
mobile_scanner: ^7.0.1
|
||||
path: ^1.9.1
|
||||
|
||||
dev_dependencies:
|
||||
|
|
Loading…
Add table
Reference in a new issue