mirror of
https://github.com/hiddify/hiddify-app.git
synced 2026-06-03 11:27:32 +00:00
new: update the ios interface
This commit is contained in:
@@ -197,7 +197,7 @@ macos-libs:
|
||||
|
||||
ios-libs: #not tested
|
||||
mkdir -p $(IOS_OUT)
|
||||
rm -rf $(IOS_OUT)/Libcore.xcframework
|
||||
rm -rf $(IOS_OUT)/HiddifyCore.xcframework
|
||||
curl -L $(CORE_URL)/$(CORE_NAME)-ios.tar.gz | tar xz -C "$(IOS_OUT)"
|
||||
|
||||
get-geo-assets:
|
||||
@@ -224,7 +224,7 @@ build-macos-libs:
|
||||
build-ios-libs:
|
||||
rm -rf $(IOS_OUT)/HiddifyCore.xcframework
|
||||
make -C hiddify-core -f Makefile ios
|
||||
mv $(BINDIR)/HiddifyCore.xcframework $(IOS_OUT)/Libcore.xcframework
|
||||
mv $(BINDIR)/HiddifyCore.xcframework $(IOS_OUT)/HiddifyCore.xcframework
|
||||
|
||||
release: # Create a new tag for release.
|
||||
@CORE_VERSION=$(core.version) bash -c ".github/change_version.sh "
|
||||
|
||||
+1
-1
Submodule hiddify-core updated: 3d52467c73...7dcd1cd527
@@ -26,10 +26,12 @@ class Logger {
|
||||
private var lock = NSLock()
|
||||
|
||||
init(path: URL) {
|
||||
NSLog("H?G1")
|
||||
url = path
|
||||
}
|
||||
|
||||
func write(_ message: String) {
|
||||
NSLog("H?G2")
|
||||
Logger.queue.async { [message, unowned self] () in
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
|
||||
@@ -16,6 +16,7 @@ class PacketTunnelProvider: ExtensionProvider {
|
||||
// var trafficReader: TrafficReader!
|
||||
|
||||
override func startTunnel(options: [String : NSObject]?) async throws {
|
||||
NSLog("H?C1")
|
||||
try await super.startTunnel(options: options)
|
||||
/*trafficReader = TrafficReader { [unowned self] traffic in
|
||||
trafficLock.lock()
|
||||
@@ -26,6 +27,7 @@ class PacketTunnelProvider: ExtensionProvider {
|
||||
}
|
||||
|
||||
override func handleAppMessage(_ messageData: Data) async -> Data? {
|
||||
NSLog("H?C2")
|
||||
let message = String(data: messageData, encoding: .utf8)
|
||||
switch message {
|
||||
case "stats":
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
import NetworkExtension
|
||||
|
||||
func runBlocking<T>(_ block: @escaping () async -> T) -> T {
|
||||
|
||||
@@ -6,10 +6,17 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
import NetworkExtension
|
||||
|
||||
public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtocol, LibboxCommandServerHandlerProtocol {
|
||||
public func writeLog(_ message: String?) {
|
||||
|
||||
}
|
||||
|
||||
public func send(_ notification: LibboxNotification?) throws {
|
||||
}
|
||||
|
||||
public func readWIFIState() -> LibboxWIFIState? {
|
||||
return nil;
|
||||
}
|
||||
@@ -22,12 +29,14 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
|
||||
}
|
||||
|
||||
public func openTun(_ options: LibboxTunOptionsProtocol?, ret0_: UnsafeMutablePointer<Int32>?) throws {
|
||||
NSLog("H?A1")
|
||||
try runBlocking { [self] in
|
||||
try await openTun0(options, ret0_)
|
||||
}
|
||||
}
|
||||
|
||||
private func openTun0(_ options: LibboxTunOptionsProtocol?, _ ret0_: UnsafeMutablePointer<Int32>?) async throws {
|
||||
NSLog("H?A2")
|
||||
guard let options else {
|
||||
throw NSError(domain: "nil options", code: 0)
|
||||
}
|
||||
@@ -140,11 +149,11 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
|
||||
false
|
||||
}
|
||||
|
||||
public func writeLog(_ message: String?) {
|
||||
guard let message else {
|
||||
return
|
||||
}
|
||||
tunnel.writeMessage(message)
|
||||
func writeLogs(_ messageList: (any LibboxStringIteratorProtocol)?) {
|
||||
// guard let message else {
|
||||
// return
|
||||
// }
|
||||
// tunnel.writeMessage(message)
|
||||
}
|
||||
|
||||
public func usePlatformDefaultInterfaceMonitor() -> Bool {
|
||||
@@ -230,10 +239,12 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
|
||||
}
|
||||
|
||||
public func postServiceClose() {
|
||||
NSLog("H?A3")
|
||||
// TODO
|
||||
}
|
||||
|
||||
func reset() {
|
||||
NSLog("H?A4")
|
||||
networkSettings = nil
|
||||
}
|
||||
|
||||
|
||||
@@ -6,33 +6,37 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
import NetworkExtension
|
||||
|
||||
open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
public static let errorFile = FilePath.workingDirectory.appendingPathComponent("network_extension_error")
|
||||
|
||||
private var commandServer: LibboxCommandServer!
|
||||
private var boxService: LibboxBoxService!
|
||||
// private var commandServer: LibboxCommandServer!
|
||||
// private var boxService: LibboxBoxService!
|
||||
private var systemProxyAvailable = false
|
||||
private var systemProxyEnabled = false
|
||||
private var platformInterface: ExtensionPlatformInterface!
|
||||
private var config: String!
|
||||
|
||||
override open func startTunnel(options: [String: NSObject]?) async throws {
|
||||
NSLog("H?1")
|
||||
writeFatalError("(packet-tunnel) starting")
|
||||
|
||||
try? FileManager.default.removeItem(at: ExtensionProvider.errorFile)
|
||||
try? FileManager.default.removeItem(at: FilePath.workingDirectory.appendingPathComponent("TestLog"))
|
||||
|
||||
let disableMemoryLimit = (options?["DisableMemoryLimit"] as? NSString as? String ?? "NO") == "YES"
|
||||
|
||||
// let grpcServiceModePort = (options?["GrpcServiceModePort"] as? NSNumber)?.intValue ?? 17079
|
||||
let grpcServiceModePort = 17079
|
||||
guard let config = options?["Config"] as? NSString as? String else {
|
||||
writeFatalError("(packet-tunnel) error: config not provided")
|
||||
return
|
||||
}
|
||||
guard let config = SingBox.setupConfig(config: config) else {
|
||||
writeFatalError("(packet-tunnel) error: config is invalid")
|
||||
return
|
||||
}
|
||||
// guard let config = SingBox.setupConfig(config: config) else {
|
||||
// writeFatalError("(packet-tunnel) error: config is invalid")
|
||||
// return
|
||||
// }
|
||||
self.config = config
|
||||
|
||||
do {
|
||||
@@ -41,15 +45,18 @@ open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
writeFatalError("(packet-tunnel) error: create working directory: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
|
||||
LibboxSetup(
|
||||
var error: NSError?
|
||||
MobileSetup(
|
||||
FilePath.sharedDirectory.relativePath,
|
||||
FilePath.workingDirectory.relativePath,
|
||||
FilePath.cacheDirectory.relativePath,
|
||||
false
|
||||
4,
|
||||
"127.0.0.1:\(grpcServiceModePort)",
|
||||
"",
|
||||
false,
|
||||
&error
|
||||
)
|
||||
|
||||
var error: NSError?
|
||||
LibboxRedirectStderr(FilePath.cacheDirectory.appendingPathComponent("stderr.log").relativePath, &error)
|
||||
if let error {
|
||||
writeError("(packet-tunnel) redirect stderr error: \(error.localizedDescription)")
|
||||
@@ -60,23 +67,23 @@ open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
if platformInterface == nil {
|
||||
platformInterface = ExtensionPlatformInterface(self)
|
||||
}
|
||||
commandServer = LibboxNewCommandServer(platformInterface, Int32(30))
|
||||
do {
|
||||
try commandServer.start()
|
||||
} catch {
|
||||
writeFatalError("(packet-tunnel): log server start error: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
// commandServer = LibboxNewCommandServer(platformInterface, Int32(30))
|
||||
// do {
|
||||
// try commandServer.start()
|
||||
// } catch {
|
||||
// writeFatalError("(packet-tunnel): log server start error: \(error.localizedDescription)")
|
||||
// return
|
||||
// }
|
||||
writeMessage("(packet-tunnel) log server started")
|
||||
await startService()
|
||||
}
|
||||
|
||||
func writeMessage(_ message: String) {
|
||||
if let commandServer {
|
||||
commandServer.writeMessage(message)
|
||||
} else {
|
||||
NSLog(message)
|
||||
}
|
||||
// if let commandServer {
|
||||
// commandServer.writeMessage(message)
|
||||
// } else {
|
||||
// NSLog(message)
|
||||
// }
|
||||
}
|
||||
|
||||
func writeError(_ message: String) {
|
||||
@@ -88,47 +95,53 @@ open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
#if DEBUG
|
||||
NSLog(message)
|
||||
#endif
|
||||
NSLog(message)
|
||||
writeError(message)
|
||||
cancelTunnelWithError(NSError(domain: message, code: 0))
|
||||
}
|
||||
|
||||
private func startService() async {
|
||||
NSLog("H?2")
|
||||
let configContent = config
|
||||
var error: NSError?
|
||||
let service = LibboxNewService(configContent, platformInterface, &error)
|
||||
|
||||
let service = MobileStart(configContent, platformInterface, &error)
|
||||
if let error {
|
||||
writeError("(packet-tunnel) error: create service: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
guard let service else {
|
||||
return
|
||||
}
|
||||
do {
|
||||
try service.start()
|
||||
} catch {
|
||||
writeError("(packet-tunnel) error: start service: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
boxService = service
|
||||
commandServer.setService(service)
|
||||
// guard let service else {
|
||||
// return
|
||||
// }
|
||||
// do {
|
||||
// try service.start()
|
||||
// } catch {
|
||||
// writeError("(packet-tunnel) error: start service: \(error.localizedDescription)")
|
||||
// return
|
||||
// }
|
||||
// boxService = service
|
||||
// commandServer.setService(service)
|
||||
}
|
||||
|
||||
private func stopService() {
|
||||
if let service = boxService {
|
||||
do {
|
||||
try service.close()
|
||||
} catch {
|
||||
writeError("(packet-tunnel) error: stop service: \(error.localizedDescription)")
|
||||
}
|
||||
boxService = nil
|
||||
commandServer.setService(nil)
|
||||
}
|
||||
NSLog("H?3")
|
||||
// if let service = boxService {
|
||||
// do {
|
||||
// try service.close()
|
||||
// } catch {
|
||||
// writeError("(packet-tunnel) error: stop service: \(error.localizedDescription)")
|
||||
// }
|
||||
// boxService = nil
|
||||
// commandServer.setService(nil)
|
||||
// }
|
||||
MobileClose(4)
|
||||
if let platformInterface {
|
||||
platformInterface.reset()
|
||||
}
|
||||
}
|
||||
|
||||
func reloadService() async {
|
||||
NSLog("H?4")
|
||||
writeMessage("(packet-tunnel) reloading service")
|
||||
reasserting = true
|
||||
defer {
|
||||
@@ -140,13 +153,14 @@ open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
|
||||
|
||||
override open func stopTunnel(with reason: NEProviderStopReason) async {
|
||||
NSLog("H?5")
|
||||
writeMessage("(packet-tunnel) stopping, reason: \(reason)")
|
||||
stopService()
|
||||
if let server = commandServer {
|
||||
try? await Task.sleep(nanoseconds: 100 * NSEC_PER_MSEC)
|
||||
try? server.close()
|
||||
commandServer = nil
|
||||
}
|
||||
// if let server = commandServer {
|
||||
// try? await Task.sleep(nanoseconds: 100 * NSEC_PER_MSEC)
|
||||
// try? server.close()
|
||||
// commandServer = nil
|
||||
// }
|
||||
}
|
||||
|
||||
override open func handleAppMessage(_ messageData: Data) async -> Data? {
|
||||
@@ -154,14 +168,16 @@ open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
}
|
||||
|
||||
override open func sleep() async {
|
||||
if let boxService {
|
||||
boxService.pause()
|
||||
}
|
||||
NSLog("H?6")
|
||||
// if let boxService {
|
||||
// boxService.pause()
|
||||
// }
|
||||
}
|
||||
|
||||
override open func wake() {
|
||||
if let boxService {
|
||||
boxService.wake()
|
||||
}
|
||||
NSLog("H?7")
|
||||
// if let boxService {
|
||||
// boxService.wake()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import Foundation
|
||||
|
||||
class SingBox {
|
||||
static func setupConfig(config: String, mtu: Int = 9000) -> String? {
|
||||
NSLog("H?B1")
|
||||
guard
|
||||
let config = config.data(using: .utf8),
|
||||
var json = try? JSONSerialization
|
||||
|
||||
@@ -18,6 +18,7 @@ class TrafficReader {
|
||||
private let callback: (TrafficReaderUpdate) -> ()
|
||||
|
||||
init(onUpdate: @escaping (TrafficReaderUpdate) -> ()) {
|
||||
NSLog("H?D2")
|
||||
self.callback = onUpdate
|
||||
Task(priority: .background) { [weak self] () in
|
||||
await self?.setup()
|
||||
@@ -25,6 +26,7 @@ class TrafficReader {
|
||||
}
|
||||
|
||||
private func setup() async {
|
||||
NSLog("H?D1")
|
||||
try? await Task.sleep(nanoseconds: 5_000_000_000)
|
||||
//return
|
||||
while true {
|
||||
@@ -46,6 +48,7 @@ class TrafficReader {
|
||||
}
|
||||
|
||||
private func read() {
|
||||
NSLog("H?D3")
|
||||
task.receive { [weak self] result in
|
||||
switch result {
|
||||
case .failure(_):
|
||||
|
||||
@@ -11,16 +11,16 @@ let package = Package(
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Libcore",
|
||||
targets: ["Libcore"]),
|
||||
name: "HiddifyCore",
|
||||
targets: ["HiddifyCore"]),
|
||||
],
|
||||
dependencies: [
|
||||
// No dependencies
|
||||
],
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "Libcore",
|
||||
path: "../Frameworks/Libcore.xcframework"
|
||||
name: "HiddifyCore",
|
||||
path: "../Frameworks/HiddifyCore.xcframework"
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
+2
-2
@@ -79,7 +79,7 @@ PODS:
|
||||
- protocol_handler_ios (0.0.1):
|
||||
- Flutter
|
||||
- Sentry/HybridSDK (8.41.0)
|
||||
- sentry_flutter (8.11.1):
|
||||
- sentry_flutter (8.11.2):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.41.0)
|
||||
@@ -217,7 +217,7 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
|
||||
Sentry: 54d0fe6c0df448497c8ed4cce66ccf7027e1823e
|
||||
sentry_flutter: d8bce6e1d6c4f57d0208e274f745d1eee8bae249
|
||||
sentry_flutter: f8796ae209d02920fa58f9cfd4eae00ec685bf37
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 60;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -34,7 +34,8 @@
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
4132706C2C8A9C44003A1E9B /* Libcore.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 413270682C8A9BA2003A1E9B /* Libcore.xcframework */; };
|
||||
4110F9E22D1AEDAB0085FD09 /* HiddifyPacketTunnel.entitlements in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 03E392BD2ADDA00F000ADF15 /* HiddifyPacketTunnel.entitlements */; };
|
||||
4132706C2C8A9C44003A1E9B /* HiddifyCore.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 413270682C8A9BA2003A1E9B /* HiddifyCore.xcframework */; };
|
||||
59E8864FB99B37076B22F32B /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30560DB3EFDF5E86AAD00AB8 /* Pods_RunnerTests.framework */; };
|
||||
68885DD72B4EF33400D214BA /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E392B72ADDA00E000ADF15 /* NetworkExtension.framework */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
@@ -70,6 +71,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
4110F9E22D1AEDAB0085FD09 /* HiddifyPacketTunnel.entitlements in Embed Foundation Extensions */,
|
||||
03E392C02ADDA00F000ADF15 /* HiddifyPacketTunnel.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
@@ -138,7 +140,7 @@
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
413270682C8A9BA2003A1E9B /* Libcore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Libcore.xcframework; path = Frameworks/Libcore.xcframework; sourceTree = "<group>"; };
|
||||
413270682C8A9BA2003A1E9B /* HiddifyCore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = HiddifyCore.xcframework; path = Frameworks/HiddifyCore.xcframework; sourceTree = "<group>"; };
|
||||
574F12C7748958784380337F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
60F1D4AAC33ACF5C8307310D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6836D3FA2B57FDFF00A79D75 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
|
||||
@@ -170,7 +172,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4132706C2C8A9C44003A1E9B /* Libcore.xcframework in Frameworks */,
|
||||
4132706C2C8A9C44003A1E9B /* HiddifyCore.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -363,7 +365,7 @@
|
||||
B8133545EEE13EDD5549E6A3 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
413270682C8A9BA2003A1E9B /* Libcore.xcframework */,
|
||||
413270682C8A9BA2003A1E9B /* HiddifyCore.xcframework */,
|
||||
0736954E2B1FEB3E007249BE /* mobile_scanner.xcframework */,
|
||||
07A63A932B1E72FB00CAFA4D /* cupertino_http.xcframework */,
|
||||
07A63A972B1E72FB00CAFA4D /* device_info_plus.xcframework */,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class ActiveGroupsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class GroupsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler{
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
class LogsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
static let name = "\(Bundle.main.serviceIdentifier)/service.logs"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import Flutter
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class MethodHandler: NSObject, FlutterPlugin {
|
||||
|
||||
@@ -32,6 +32,10 @@ public class MethodHandler: NSObject, FlutterPlugin {
|
||||
}
|
||||
|
||||
switch call.method {
|
||||
case "get_grpc_server_public_key":
|
||||
result("")
|
||||
case "add_grpc_client_public_key":
|
||||
result("")
|
||||
case "parse_config":
|
||||
guard
|
||||
let args = call.arguments as? [String:Any?],
|
||||
@@ -43,7 +47,7 @@ public class MethodHandler: NSObject, FlutterPlugin {
|
||||
return
|
||||
}
|
||||
var error: NSError?
|
||||
MobileParse(path, tempPath, debug, &error)
|
||||
//MobileParse(path, tempPath, debug, &error)
|
||||
if let error {
|
||||
result(FlutterError(code: String(error.code), message: error.description, details: nil))
|
||||
return
|
||||
@@ -57,83 +61,89 @@ public class MethodHandler: NSObject, FlutterPlugin {
|
||||
VPNConfig.shared.configOptions = options
|
||||
result(true)
|
||||
case "setup":
|
||||
Task {
|
||||
// guard
|
||||
// let args = call.arguments as? [String:Any?],
|
||||
// let path = args["path"] as? String,
|
||||
// let tempPath = args["tempPath"] as? String,
|
||||
// let debug = (args["debug"] as? NSNumber)?.boolValue
|
||||
// else {
|
||||
// result(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
// return
|
||||
// }
|
||||
// var error: NSError?
|
||||
// MobileSetup(path, tempPath, 0, "","" debug, &error)
|
||||
// if let error {
|
||||
// result(FlutterError(code: String(error.code), message: error.description, details: nil))
|
||||
// return
|
||||
// }
|
||||
result("")
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
} catch {
|
||||
await mainResult(FlutterError(code: "SETUP", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
Task {
|
||||
guard
|
||||
let args = call.arguments as? [String: Any?],
|
||||
let baseDir = args["baseDir"] as? String,
|
||||
let workingDir = args["workingDir"] as? String,
|
||||
let tempDir = args["tempDir"] as? String,
|
||||
let mode = args["mode"] as? Int,
|
||||
let grpcPort = args["grpcPort"] as? Int
|
||||
else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
return
|
||||
}
|
||||
VPNConfig.shared.baseDir=baseDir
|
||||
VPNConfig.shared.workingDir=workingDir
|
||||
VPNConfig.shared.tempDir=tempDir
|
||||
var error: NSError?
|
||||
MobileSetup(baseDir, workingDir, tempDir, mode, "127.0.0.1:\(grpcPort)", "", false, &error)
|
||||
if let error {
|
||||
result(FlutterError(code: String(error.code), message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
} catch {
|
||||
result(FlutterError(code: "SETUP", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
result(true)
|
||||
}
|
||||
await mainResult(true)
|
||||
}
|
||||
case "start":
|
||||
Task {
|
||||
guard
|
||||
let args = call.arguments as? [String:Any?],
|
||||
let path = args["path"] as? String
|
||||
let path = args["path"] as? String,
|
||||
let name = args["name"] as? String,
|
||||
let grpcPort=args["grpcPort"] as? Int
|
||||
else {
|
||||
await mainResult(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
return
|
||||
}
|
||||
VPNConfig.shared.activeConfigPath = path
|
||||
VPNConfig.shared.activeProfileName = name
|
||||
VPNConfig.shared.grpcServiceModePort=grpcPort
|
||||
|
||||
var error: NSError?
|
||||
let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
if let error {
|
||||
await mainResult(FlutterError(code: String(error.code), message: error.description, details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
try await VPNManager.shared.connect(with: config, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
} catch {
|
||||
await mainResult(FlutterError(code: "SETUP_CONNECTION", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
await mainResult(true)
|
||||
}
|
||||
case "restart":
|
||||
Task { [unowned self] in
|
||||
guard
|
||||
let args = call.arguments as? [String:Any?],
|
||||
let path = args["path"] as? String
|
||||
else {
|
||||
await mainResult(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
return
|
||||
}
|
||||
VPNConfig.shared.activeConfigPath = path
|
||||
VPNManager.shared.disconnect()
|
||||
await waitForStop().value
|
||||
var error: NSError?
|
||||
let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
if let error {
|
||||
await mainResult(FlutterError(code: "BUILD_CONFIG", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
try await VPNManager.shared.connect(with: config, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
try await VPNManager.shared.connect(with: path,grpcServiceModePort: grpcPort, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
} catch {
|
||||
await mainResult(FlutterError(code: "SETUP_CONNECTION", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
await mainResult(true)
|
||||
}
|
||||
// case "restart":
|
||||
// Task { [unowned self] in
|
||||
// guard
|
||||
// let args = call.arguments as? [String:Any?],
|
||||
// let path = args["path"] as? String,
|
||||
// let name = args["name"] as? String,
|
||||
// let grpcPort=args["grpcPort"] as? Int
|
||||
// else {
|
||||
// await mainResult(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
// return
|
||||
// }
|
||||
// VPNConfig.shared.activeConfigPath = path
|
||||
// VPNConfig.shared.activeProfileName = name
|
||||
// VPNConfig.shared.grpcServiceModePort=grpcPort
|
||||
//
|
||||
//
|
||||
// VPNManager.shared.disconnect()
|
||||
// await waitForStop().value
|
||||
// var error: NSError?
|
||||
// do {
|
||||
// try await VPNManager.shared.setup()
|
||||
// try await VPNManager.shared.connect(with: path, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
// } catch {
|
||||
// await mainResult(FlutterError(code: "SETUP_CONNECTION", message: error.localizedDescription, details: nil))
|
||||
// return
|
||||
// }
|
||||
// await mainResult(true)
|
||||
// }
|
||||
case "stop":
|
||||
VPNManager.shared.disconnect()
|
||||
result(true)
|
||||
@@ -182,12 +192,12 @@ public class MethodHandler: NSObject, FlutterPlugin {
|
||||
return
|
||||
}
|
||||
var error: NSError?
|
||||
let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
if let error {
|
||||
result(FlutterError(code: "BUILD_CONFIG", message: error.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
result(config)
|
||||
// let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
// if let error {
|
||||
// result(FlutterError(code: "BUILD_CONFIG", message: error.localizedDescription, details: nil))
|
||||
// return
|
||||
// }
|
||||
// result(config)
|
||||
case "generate_warp_config":
|
||||
guard let args = call.arguments as? [String: Any],
|
||||
let licenseKey = args["license-key"] as? String,
|
||||
@@ -196,8 +206,8 @@ public class MethodHandler: NSObject, FlutterPlugin {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
|
||||
return
|
||||
}
|
||||
let warpConfig = MobileGenerateWarpConfig(licenseKey, accountId, accessToken, nil)
|
||||
result(warpConfig)
|
||||
// let warpConfig = MobileGenerateWarpConfig(licenseKey, accountId, accessToken, nil)
|
||||
// result(warpConfig)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import Flutter
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class PlatformMethodHandler: NSObject, FlutterPlugin {
|
||||
|
||||
@@ -25,7 +25,7 @@ public class PlatformMethodHandler: NSObject, FlutterPlugin {
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "get_paths":
|
||||
result(getPaths(args: call.arguments))
|
||||
result(getPaths(args: call.arguments) as NSDictionary)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import Flutter
|
||||
import Combine
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class StatsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
|
||||
|
||||
@@ -14,6 +14,25 @@ class VPNConfig: ObservableObject {
|
||||
@Stored(key: "VPN.ActiveConfigPath")
|
||||
var activeConfigPath: String = ""
|
||||
|
||||
@Stored(key: "VPN.ActiveProfileName")
|
||||
var activeProfileName: String = ""
|
||||
|
||||
@Stored(key: "VPN.GrpcServiceModePort")
|
||||
var grpcServiceModePort: Int = 0
|
||||
|
||||
@Stored(key: "VPN.workingDir")
|
||||
var workingDir: String = ""
|
||||
|
||||
@Stored(key: "VPN.tempDir")
|
||||
var tempDir: String = ""
|
||||
|
||||
@Stored(key: "VPN.baseDir")
|
||||
var baseDir: String = ""
|
||||
|
||||
// @Stored(key: "VPN.grpcFlutterPublicKey")
|
||||
// var grpcFlutterPublicKey: String = ""
|
||||
|
||||
|
||||
@Stored(key: "VPN.ConfigOptions")
|
||||
var configOptions: String = ""
|
||||
|
||||
|
||||
@@ -192,15 +192,18 @@ class VPNManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func connect(with config: String, disableMemoryLimit: Bool = false) async throws {
|
||||
func connect(with config: String, grpcServiceModePort:Int, disableMemoryLimit: Bool = false) async throws {
|
||||
|
||||
await set(upload: 0, download: 0)
|
||||
guard state == .disconnected else { return }
|
||||
// guard state == .disconnected else { return }
|
||||
do {
|
||||
try await enableVPNManager()
|
||||
try manager.connection.startVPNTunnel(options: [
|
||||
"Config": config as NSString,
|
||||
// "GrpcServiceModePort":NSNumber(value: grpcServiceModePort),
|
||||
"DisableMemoryLimit": (disableMemoryLimit ? "YES" : "NO") as NSString,
|
||||
])
|
||||
|
||||
} catch {
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
@@ -208,7 +211,7 @@ class VPNManager: ObservableObject {
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
guard state == .connected else { return }
|
||||
// guard state == .connected else { return }
|
||||
manager.connection.stopVPNTunnel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Foundation
|
||||
import Libcore
|
||||
import HiddifyCore
|
||||
|
||||
public class CommandClient: ObservableObject {
|
||||
public enum ConnectionType {
|
||||
@@ -82,6 +82,8 @@ public class CommandClient: ObservableObject {
|
||||
}
|
||||
|
||||
private class clientHandler: NSObject, LibboxCommandClientHandlerProtocol {
|
||||
|
||||
|
||||
private let commandClient: CommandClient
|
||||
|
||||
init(_ commandClient: CommandClient) {
|
||||
@@ -103,22 +105,22 @@ public class CommandClient: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func clearLog() {
|
||||
func clearLogs() {
|
||||
DispatchQueue.main.async { [self] in
|
||||
commandClient.logList.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
func writeLog(_ message: String?) {
|
||||
guard let message else {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async { [self] in
|
||||
if commandClient.logList.count > commandClient.logMaxLines {
|
||||
commandClient.logList.removeFirst()
|
||||
}
|
||||
commandClient.logList.append(message)
|
||||
}
|
||||
func writeLogs(_ messageList: (any LibboxStringIteratorProtocol)?) {
|
||||
// guard let message else {
|
||||
// return
|
||||
// }
|
||||
// DispatchQueue.main.async { [self] in
|
||||
// if commandClient.logList.count > commandClient.logMaxLines {
|
||||
// commandClient.logList.removeFirst()
|
||||
// }
|
||||
// commandClient.logList.append(message)
|
||||
// }
|
||||
}
|
||||
|
||||
func writeStatus(_ message: LibboxStatusMessage?) {
|
||||
@@ -162,5 +164,8 @@ public class CommandClient: ObservableObject {
|
||||
|
||||
func updateClashMode(_ newMode: String?) {
|
||||
}
|
||||
func write(_ message: LibboxConnections?) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,8 @@ class CoreInterface {
|
||||
return true;
|
||||
// return fgClient == bgClient;
|
||||
}
|
||||
|
||||
Future<bool> resetTunnel() async {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class CoreInterfaceMobile extends CoreInterface with InfraLogger {
|
||||
"mode": mode,
|
||||
},
|
||||
);
|
||||
serverPublicKey = await methodChannel.invokeMethod<Uint8List>("get_grpc_server_public_key") ?? Uint8List.fromList([]);
|
||||
// serverPublicKey = await methodChannel.invokeMethod<Uint8List>("get_grpc_server_public_key") ?? Uint8List.fromList([]);
|
||||
await methodChannel.invokeMethod(
|
||||
"add_grpc_client_public_key",
|
||||
{
|
||||
@@ -109,4 +109,10 @@ class CoreInterfaceMobile extends CoreInterface with InfraLogger {
|
||||
Future<bool> isBgClientAvailable() async {
|
||||
return _isBgClientAvailable;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> resetTunnel() async {
|
||||
await methodChannel.invokeMethod("reset");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:hiddify/singbox/model/warp_account.dart';
|
||||
|
||||
import 'package:hiddify/hiddifycore/core_interface/core_interface_wrapper_stub.dart' if (dart.library.io) 'package:hiddify/hiddifycore/core_interface/core_interface_wrapper.dart';
|
||||
import 'package:hiddify/utils/custom_loggers.dart';
|
||||
import 'package:hiddify/utils/platform_utils.dart';
|
||||
import 'package:loggy/loggy.dart' as loggyl;
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
@@ -180,17 +181,18 @@ class HiddifyCoreService with InfraLogger {
|
||||
return TaskEither(
|
||||
() async {
|
||||
// only available on iOS (and macOS later)
|
||||
// if (!Platform.isIOS) {
|
||||
throw UnimplementedError(
|
||||
"reset tunnel function unavailable on platform",
|
||||
);
|
||||
// }
|
||||
if (!PlatformUtils.isIOS) {
|
||||
throw UnimplementedError(
|
||||
"reset tunnel function unavailable on platform",
|
||||
);
|
||||
}
|
||||
|
||||
// loggy.debug("resetting tunnel");
|
||||
// final res = await core.bgClient.resetTunnel();
|
||||
// if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
|
||||
|
||||
// return right(unit);
|
||||
final res = await core.resetTunnel();
|
||||
if (res) {
|
||||
return right(unit);
|
||||
}
|
||||
return left("failed to reset tunnel");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user