Support core status check and force restart Optimize proxies page and access page Update flutter and pub dependencies
118 lines
3.0 KiB
Dart
118 lines
3.0 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:isolate';
|
|
|
|
import 'package:fl_clash/common/constant.dart';
|
|
import 'package:fl_clash/common/system.dart';
|
|
import 'package:fl_clash/models/common.dart';
|
|
import 'package:fl_clash/models/core.dart';
|
|
import 'package:fl_clash/state.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
abstract mixin class ServiceListener {
|
|
void onServiceEvent(CoreEvent event) {}
|
|
|
|
void onServiceCrash(String message) {}
|
|
}
|
|
|
|
class Service {
|
|
static Service? _instance;
|
|
late MethodChannel methodChannel;
|
|
ReceivePort? receiver;
|
|
|
|
final ObserverList<ServiceListener> _listeners =
|
|
ObserverList<ServiceListener>();
|
|
|
|
factory Service() {
|
|
_instance ??= Service._internal();
|
|
return _instance!;
|
|
}
|
|
|
|
Service._internal() {
|
|
methodChannel = const MethodChannel('$packageName/service');
|
|
methodChannel.setMethodCallHandler((call) async {
|
|
switch (call.method) {
|
|
case 'getVpnOptions':
|
|
return handleGetVpnOptions();
|
|
case 'event':
|
|
final data = call.arguments as String? ?? '';
|
|
final result = ActionResult.fromJson(json.decode(data));
|
|
for (final listener in _listeners) {
|
|
listener.onServiceEvent(CoreEvent.fromJson(result.data));
|
|
}
|
|
break;
|
|
case 'crash':
|
|
final message = call.arguments as String? ?? '';
|
|
for (final listener in _listeners) {
|
|
listener.onServiceCrash(message);
|
|
}
|
|
break;
|
|
default:
|
|
throw MissingPluginException();
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<ActionResult?> invokeAction(Action action) async {
|
|
final data = await methodChannel.invokeMethod<String>(
|
|
'invokeAction',
|
|
json.encode(action),
|
|
);
|
|
if (data == null) {
|
|
return null;
|
|
}
|
|
return ActionResult.fromJson(json.decode(data));
|
|
}
|
|
|
|
String handleGetVpnOptions() {
|
|
return json.encode(globalState.getVpnOptions());
|
|
}
|
|
|
|
Future<bool> start() async {
|
|
return await methodChannel.invokeMethod<bool>('start') ?? false;
|
|
}
|
|
|
|
Future<bool> stop() async {
|
|
return await methodChannel.invokeMethod<bool>('stop') ?? false;
|
|
}
|
|
|
|
Future<String> syncAndroidState(AndroidState state) async {
|
|
return await methodChannel.invokeMethod<String>(
|
|
'syncState',
|
|
json.encode(state),
|
|
) ??
|
|
'';
|
|
}
|
|
|
|
Future<String> init() async {
|
|
return await methodChannel.invokeMethod<String>('init') ?? '';
|
|
}
|
|
|
|
Future<bool> shutdown() async {
|
|
return await methodChannel.invokeMethod<bool>('shutdown') ?? true;
|
|
}
|
|
|
|
Future<DateTime?> getRunTime() async {
|
|
final ms = await methodChannel.invokeMethod<int>('getRunTime') ?? 0;
|
|
if (ms == 0) {
|
|
return null;
|
|
}
|
|
return DateTime.fromMillisecondsSinceEpoch(ms);
|
|
}
|
|
|
|
bool get hasListeners {
|
|
return _listeners.isNotEmpty;
|
|
}
|
|
|
|
void addListener(ServiceListener listener) {
|
|
_listeners.add(listener);
|
|
}
|
|
|
|
void removeListener(ServiceListener listener) {
|
|
_listeners.remove(listener);
|
|
}
|
|
}
|
|
|
|
Service? get service => system.isAndroid ? Service() : null;
|