From 3edc3fc9560e324807eea98bfe42a1bd2d86b02d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= <i@sekai.icu>
Date: Wed, 13 Nov 2024 10:46:38 +0800
Subject: [PATCH] Implement new interface api

---
 .../Network/ExtensionPlatformInterface.swift  | 82 +++++++++++++++++--
 1 file changed, 73 insertions(+), 9 deletions(-)

diff --git a/Library/Network/ExtensionPlatformInterface.swift b/Library/Network/ExtensionPlatformInterface.swift
index 15eeb10..3af6378 100644
--- a/Library/Network/ExtensionPlatformInterface.swift
+++ b/Library/Network/ExtensionPlatformInterface.swift
@@ -191,7 +191,7 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
     }
 
     public func usePlatformAutoDetectControl() -> Bool {
-        true
+        false
     }
 
     public func autoDetectControl(_: Int32) throws {}
@@ -219,20 +219,84 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
         tunnel.writeMessage(message)
     }
 
-    public func usePlatformDefaultInterfaceMonitor() -> Bool {
-        false
-    }
+    private var nwMonitor: NWPathMonitor? = nil
 
-    public func startDefaultInterfaceMonitor(_: LibboxInterfaceUpdateListenerProtocol?) throws {}
+    public func startDefaultInterfaceMonitor(_ listener: LibboxInterfaceUpdateListenerProtocol?) throws {
+        guard let listener else {
+            return
+        }
+        let monitor = NWPathMonitor()
+        nwMonitor = monitor
+        let semaphore = DispatchSemaphore(value: 0)
+        monitor.pathUpdateHandler = { path in
+            self.onUpdateDefaultInterface(listener, path)
+            semaphore.signal()
+            monitor.pathUpdateHandler = { path in
+                self.onUpdateDefaultInterface(listener, path)
+            }
+        }
+        monitor.start(queue: DispatchQueue.global())
+        semaphore.wait()
+    }
 
-    public func closeDefaultInterfaceMonitor(_: LibboxInterfaceUpdateListenerProtocol?) throws {}
+    private func onUpdateDefaultInterface(_ listener: LibboxInterfaceUpdateListenerProtocol, _ path: Network.NWPath) {
+        if path.status == .unsatisfied {
+            listener.updateDefaultInterface("", interfaceIndex: -1, isExpensive: false, isConstrained: false)
+        } else {
+            let defaultInterface = path.availableInterfaces.first!
+            listener.updateDefaultInterface(defaultInterface.name, interfaceIndex: Int32(defaultInterface.index), isExpensive: path.isExpensive, isConstrained: path.isConstrained)
+        }
+    }
 
-    public func useGetter() -> Bool {
-        false
+    public func closeDefaultInterfaceMonitor(_: LibboxInterfaceUpdateListenerProtocol?) throws {
+        nwMonitor?.cancel()
+        nwMonitor = nil
     }
 
     public func getInterfaces() throws -> LibboxNetworkInterfaceIteratorProtocol {
-        throw NSError(domain: "not implemented", code: 0)
+        guard let nwMonitor else {
+            throw NSError(domain: "NWMonitor not started", code: 0)
+        }
+        let path = nwMonitor.currentPath
+        if path.status == .unsatisfied {
+            return networkInterfaceArray([])
+        }
+        var interfaces: [LibboxNetworkInterface] = []
+        for it in path.availableInterfaces {
+            let interface = LibboxNetworkInterface()
+            interface.name = it.name
+            interface.index = Int32(it.index)
+            switch it.type {
+            case .wifi:
+                interface.type = LibboxInterfaceTypeWIFI
+            case .cellular:
+                interface.type = LibboxInterfaceTypeCellular
+            case .wiredEthernet:
+                interface.type = LibboxInterfaceTypeEthernet
+            default:
+                interface.type = LibboxInterfaceTypeOther
+            }
+            interfaces.append(interface)
+        }
+        return networkInterfaceArray(interfaces)
+    }
+
+    class networkInterfaceArray: NSObject, LibboxNetworkInterfaceIteratorProtocol {
+        private var iterator: IndexingIterator<[LibboxNetworkInterface]>
+        init(_ array: [LibboxNetworkInterface]) {
+            iterator = array.makeIterator()
+        }
+
+        private var nextValue: LibboxNetworkInterface? = nil
+
+        func hasNext() -> Bool {
+            nextValue = iterator.next()
+            return nextValue != nil
+        }
+
+        func next() -> LibboxNetworkInterface? {
+            nextValue
+        }
     }
 
     public func underNetworkExtension() -> Bool {