Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection status stream for iOS/macOS fixed #36

Merged
merged 16 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 0 additions & 63 deletions .github/workflows/release.yml

This file was deleted.

36 changes: 36 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# file options

--symlinks ignore
--swiftversion 5.7

# rules
--enable isEmpty
--disable andOperator
--disable wrapMultilineStatementBraces

# format options

--commas inline
--comments indent
--decimalgrouping 3,5
--exponentcase lowercase
--exponentgrouping disabled
--extensionacl on-declarations
--fractiongrouping disabled
--ifdef no-indent
--importgrouping testable-top
--operatorfunc no-space
--nospaceoperators ..<, ...
--selfrequired validate
--someAny false
--stripunusedargs closure-only
--wraparguments preserve
--wrapcollections preserve
--wrapparameters preserve


# rules

--enable isEmpty
--disable wrapMultilineStatementBraces
--disable opaqueGenericParameters
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.5.0](https://github.com/mysteriumnetwork/wireguard_dart/tree/0.5.0) (2024-01-18)

- darwin: Fix connection status streaming. Two available methods are `.status()` and `.statusStream()`
- `.status()` now returns an unwrapped status instead of a map
- Add a required `tunnelName` option in addition to `bundleId`

[Full Changelog](https://github.com/mysteriumnetwork/wireguard_dart/compare/0.4.5...0.5.0)

## [0.4.5](https://github.com/mysteriumnetwork/wireguard_dart/tree/0.4.5) (2023-08-04)

[Full Changelog](https://github.com/mysteriumnetwork/wireguard_dart/compare/0.4.4...0.4.5)
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

A flutter plugin to setup and control VPN connection via [Wireguard](https://www.wireguard.com/) tunnel.

It includes [Wireguard implementation for the corresponding OS](https://www.wireguard.com/embedding/) (WireGuardKit for darwin, com.wireguard.android:tunnel for android, etc.) and does not require any additional dependencies.


| | Android | iOS | Linux | macOS | Windows |
|-------------|---------|-------|-------|-------|-------------|
| **Support** | 21+ | 15.0+ | TBD | 12+ | 10+ |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class WireguardDartPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart")
statusChannel = EventChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart.status")
statusChannel = EventChannel(flutterPluginBinding.binaryMessenger, "wireguard_dart/status")
statusBroadcaster = ConnectionStatusBroadcaster()
statusChannel.setStreamHandler(statusBroadcaster)
context = flutterPluginBinding.applicationContext
Expand Down
25 changes: 25 additions & 0 deletions darwin/Classes/ConnectionStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation
import NetworkExtension

/// ConnectionStatus returned to Dart
enum ConnectionStatus: String {
case connected
case disconnected
case connecting
case disconnecting
case unknown

static func fromNEVPNStatus(status: NEVPNStatus) -> ConnectionStatus {
switch status {
case .connected: return ConnectionStatus.connected
case .disconnected: return ConnectionStatus.disconnected
case .connecting: return ConnectionStatus.connecting
case .disconnecting: return ConnectionStatus.disconnecting
default: return ConnectionStatus.unknown
}
}

func string() -> String {
rawValue
}
}
101 changes: 40 additions & 61 deletions darwin/Classes/ConnectionStatusObserver.swift
Original file line number Diff line number Diff line change
@@ -1,73 +1,52 @@
#if os(iOS)
import Flutter
import UIKit
#elseif os(macOS)
import Cocoa
import FlutterMacOS
#else
#error("Unsupported platform")
#endif

import NetworkExtension
import os
import WireGuardKit

public class ConnectionStatusObserver: NSObject, FlutterStreamHandler {

private var _sink: FlutterEventSink?
private var _vpnManager: NETunnelProviderManager

private var pIsRunning: Bool = false
var isRunning: Bool {
pIsRunning
}

init(vpnManager: NETunnelProviderManager) {
_vpnManager = vpnManager
}

public func _statusChanged(_: Notification?) {
guard let sink = _sink else {
return
}
let status = _vpnManager.connection.status
let mappedStatus: Dictionary<String, String> = {
switch status {
case .connected:
return ["status": "connected"]
case .disconnected:
return ["status": "connected"]
case .connecting:
return ["status": "connecting"]
case .disconnecting:
return ["status": "disconnecting"]
default:
return ["status": "unknown"]
}
}()
sink(mappedStatus)
}

public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink)
-> FlutterError?
{
_sink = events

if !pIsRunning {
NotificationCenter.default.addObserver(
forName: NSNotification.Name.NEVPNStatusDidChange,
object: nil,
queue: OperationQueue.main,
using: _statusChanged
)
class ConnectionStatusObserver: NSObject, FlutterStreamHandler {
private var eventSink: FlutterEventSink?
private var isRunning: Bool = false

override init() {
super.init()
NotificationCenter.default.addObserver(
forName: NSNotification.Name.NEVPNStatusDidChange,
object: nil,
queue: OperationQueue.main,
using: handleStatusChanged
)
}

pIsRunning = true

// Send the initial data.

// No errors.
return nil
}
deinit {
NotificationCenter.default.removeObserver(self)
}

public func onCancel(withArguments arguments: Any?) -> FlutterError? {
pIsRunning = false
public func handleStatusChanged(notification: Notification?) {
guard let conn = notification?.object as? NEVPNConnection else {
return
}
let newStatus = ConnectionStatus.fromNEVPNStatus(status: conn.status)

NotificationCenter.default.removeObserver(self)
Logger.main.debug("VPN status changed: \(newStatus.string())")
eventSink?(newStatus.string())
}

_sink = nil
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
eventSink = events
return nil
}

return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
11 changes: 11 additions & 0 deletions darwin/Classes/FlutterError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform")
#endif

func nativeFlutterError(message: String) -> FlutterError {
FlutterError(code: "NATIVE_ERR", message: message, details: nil)
}
7 changes: 7 additions & 0 deletions darwin/Classes/Logger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation
import os.log

extension Logger {
private static var subsystem = Bundle.main.bundleIdentifier!
public static let main = Logger(subsystem: subsystem, category: "main")
}
Loading