|
| 1 | +import 'dart:async'; |
| 2 | + |
| 3 | +import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart'; |
| 4 | +import 'package:meta/meta.dart'; |
| 5 | + |
| 6 | +import 'network_manager.dart'; |
| 7 | + |
| 8 | +typedef _DeviceGetter = Future<String> Function(NMDevice device); |
| 9 | +typedef _ConnectionGetter = Future<String> Function(NMConnection connection); |
| 10 | + |
| 11 | +@visibleForTesting |
| 12 | +typedef NetworkManagerFactory = NetworkManager Function(); |
| 13 | + |
| 14 | +/// The Linux implementation of ConnectivityPlatform. |
| 15 | +class ConnectivityLinux extends ConnectivityPlatform { |
| 16 | + /// Checks the connection status of the device. |
| 17 | + @override |
| 18 | + Future<ConnectivityResult> checkConnectivity() { |
| 19 | + return _getConnectivity(_ref()).whenComplete(_deref); |
| 20 | + } |
| 21 | + |
| 22 | + /// Obtains the wifi name (SSID) of the connected network |
| 23 | + @override |
| 24 | + Future<String> getWifiName() { |
| 25 | + return _getConnectionValue((connection) => connection.getId()); |
| 26 | + } |
| 27 | + |
| 28 | + /// Obtains the IP address of the connected wifi network |
| 29 | + @override |
| 30 | + Future<String> getWifiIP() { |
| 31 | + return _getDeviceValue((device) => device.getIp4()); |
| 32 | + } |
| 33 | + |
| 34 | + /// Obtains the wifi BSSID of the connected network. |
| 35 | + @override |
| 36 | + Future<String> getWifiBSSID() { |
| 37 | + return _getDeviceValue((device) { |
| 38 | + return device |
| 39 | + .asWirelessDevice() |
| 40 | + .then((wireless) => wireless?.getHwAddress()); |
| 41 | + }); |
| 42 | + } |
| 43 | + |
| 44 | + Future<String> _getDeviceValue(_DeviceGetter getter) { |
| 45 | + return _getConnectionValue((connection) { |
| 46 | + return connection.createDevice().then((device) { |
| 47 | + return device != null ? getter(device) : null; |
| 48 | + }); |
| 49 | + }); |
| 50 | + } |
| 51 | + |
| 52 | + Future<String> _getConnectionValue(_ConnectionGetter getter) { |
| 53 | + return _ref().createConnection().then((connection) { |
| 54 | + return connection != null ? getter(connection) : null; |
| 55 | + }).whenComplete(_deref); |
| 56 | + } |
| 57 | + |
| 58 | + int _refCount = 0; |
| 59 | + NetworkManager _manager; |
| 60 | + StreamController<ConnectivityResult> _controller; |
| 61 | + |
| 62 | + /// Returns a Stream of ConnectivityResults changes. |
| 63 | + @override |
| 64 | + Stream<ConnectivityResult> get onConnectivityChanged { |
| 65 | + _controller ??= StreamController<ConnectivityResult>.broadcast( |
| 66 | + onListen: _startListenConnectivity, |
| 67 | + onCancel: _deref, |
| 68 | + ); |
| 69 | + return _controller.stream; |
| 70 | + } |
| 71 | + |
| 72 | + Future<ConnectivityResult> _getConnectivity(NetworkManager manager) { |
| 73 | + return manager.getType().then((value) => value.toConnectivityResult()); |
| 74 | + } |
| 75 | + |
| 76 | + void _startListenConnectivity() { |
| 77 | + final manager = _ref(); |
| 78 | + manager.getType().then((type) => _addConnectivity(type)); |
| 79 | + manager.subscribeTypeChanged().listen((type) { |
| 80 | + _addConnectivity(type); |
| 81 | + }); |
| 82 | + } |
| 83 | + |
| 84 | + void _addConnectivity(String type) { |
| 85 | + _controller.add(type.toConnectivityResult()); |
| 86 | + } |
| 87 | + |
| 88 | + NetworkManager _ref() { |
| 89 | + _manager ??= createManager(); |
| 90 | + ++_refCount; |
| 91 | + return _manager; |
| 92 | + } |
| 93 | + |
| 94 | + void _deref() { |
| 95 | + // schedules an asynchronous disposal when the last reference is removed |
| 96 | + if (--_refCount == 0) { |
| 97 | + scheduleMicrotask(() { |
| 98 | + if (_refCount == 0) { |
| 99 | + _manager.dispose(); |
| 100 | + _manager = null; |
| 101 | + } |
| 102 | + }); |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + @visibleForTesting |
| 107 | + NetworkManagerFactory createManager = () => NetworkManager.system(); |
| 108 | +} |
| 109 | + |
| 110 | +extension _NMConnectivityType on String { |
| 111 | + ConnectivityResult toConnectivityResult() { |
| 112 | + if (isEmpty) { |
| 113 | + return ConnectivityResult.none; |
| 114 | + } |
| 115 | + if (contains('wireless')) { |
| 116 | + return ConnectivityResult.wifi; |
| 117 | + } |
| 118 | + // ### TODO: ethernet |
| 119 | + //if (contains('ethernet')) { |
| 120 | + // return ConnectivityResult.ethernet; |
| 121 | + //} |
| 122 | + // gsm, cdma, bluetooth, ... |
| 123 | + return ConnectivityResult.mobile; |
| 124 | + } |
| 125 | +} |
0 commit comments