2024-04-30 23:38:49 +08:00
|
|
|
import 'dart:async';
|
2024-07-13 16:36:08 +08:00
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:ffi';
|
2024-04-30 23:38:49 +08:00
|
|
|
import 'dart:io';
|
|
|
|
|
import 'dart:isolate';
|
2024-07-13 16:36:08 +08:00
|
|
|
import 'package:fl_clash/clash/clash.dart';
|
2024-04-30 23:38:49 +08:00
|
|
|
import 'package:fl_clash/common/common.dart';
|
2024-07-13 16:36:08 +08:00
|
|
|
import 'package:fl_clash/enum/enum.dart';
|
|
|
|
|
import 'package:fl_clash/models/models.dart';
|
|
|
|
|
import 'package:fl_clash/state.dart';
|
2024-07-15 16:14:19 +08:00
|
|
|
import 'package:flutter/material.dart';
|
2024-04-30 23:38:49 +08:00
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
import 'package:proxy/proxy_platform_interface.dart';
|
|
|
|
|
|
|
|
|
|
class Proxy extends ProxyPlatform {
|
|
|
|
|
static Proxy? _instance;
|
|
|
|
|
late MethodChannel methodChannel;
|
2024-07-13 16:36:08 +08:00
|
|
|
ReceivePort? receiver;
|
|
|
|
|
ServiceMessageListener? _serviceMessageHandler;
|
2024-04-30 23:38:49 +08:00
|
|
|
|
|
|
|
|
Proxy._internal() {
|
|
|
|
|
methodChannel = const MethodChannel("proxy");
|
|
|
|
|
methodChannel.setMethodCallHandler((call) async {
|
|
|
|
|
switch (call.method) {
|
2024-07-13 16:36:08 +08:00
|
|
|
case "started":
|
|
|
|
|
final fd = call.arguments;
|
|
|
|
|
onStarted(fd);
|
2024-04-30 23:38:49 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw MissingPluginException();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
factory Proxy() {
|
|
|
|
|
_instance ??= Proxy._internal();
|
|
|
|
|
return _instance!;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-17 17:02:25 +08:00
|
|
|
Future<bool?> initService() async {
|
2024-07-13 16:36:08 +08:00
|
|
|
return await methodChannel.invokeMethod<bool>("initService");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleStop() {
|
|
|
|
|
globalState.stopSystemProxy();
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
@override
|
2024-07-17 17:02:25 +08:00
|
|
|
Future<bool?> startProxy(port) async {
|
|
|
|
|
return await methodChannel.invokeMethod<bool>("startProxy", {
|
|
|
|
|
'port': port,
|
|
|
|
|
'args': json.encode(clashCore.getProps()),
|
|
|
|
|
});
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Future<bool?> stopProxy() async {
|
|
|
|
|
clashCore.stopTun();
|
2024-07-13 16:36:08 +08:00
|
|
|
final isStop = await methodChannel.invokeMethod<bool>("stopProxy");
|
2024-04-30 23:38:49 +08:00
|
|
|
if (isStop == true) {
|
|
|
|
|
startTime = null;
|
|
|
|
|
}
|
|
|
|
|
return isStop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<bool?> setProtect(int fd) async {
|
2024-07-13 16:36:08 +08:00
|
|
|
return await methodChannel.invokeMethod<bool?>("setProtect", {'fd': fd});
|
2024-06-16 19:04:33 +08:00
|
|
|
}
|
|
|
|
|
|
2024-04-30 23:38:49 +08:00
|
|
|
Future<bool?> startForeground({
|
|
|
|
|
required String title,
|
|
|
|
|
required String content,
|
|
|
|
|
}) async {
|
|
|
|
|
return await methodChannel.invokeMethod<bool?>("startForeground", {
|
|
|
|
|
'title': title,
|
|
|
|
|
'content': content,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-03 18:02:05 +08:00
|
|
|
bool get isStart => startTime != null && startTime!.isBeforeNow;
|
2024-04-30 23:38:49 +08:00
|
|
|
|
2024-07-13 16:36:08 +08:00
|
|
|
onStarted(int? fd) {
|
2024-07-15 16:14:19 +08:00
|
|
|
debugPrint("onStarted ==> $fd");
|
2024-07-13 16:36:08 +08:00
|
|
|
if (fd == null) return;
|
|
|
|
|
if (receiver != null) {
|
|
|
|
|
receiver!.close();
|
|
|
|
|
receiver == null;
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
2024-07-13 16:36:08 +08:00
|
|
|
receiver = ReceivePort();
|
|
|
|
|
receiver!.listen((message) {
|
|
|
|
|
_handleServiceMessage(message);
|
|
|
|
|
});
|
|
|
|
|
clashCore.startTun(fd, receiver!.sendPort.nativePort);
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-13 16:36:08 +08:00
|
|
|
updateStartTime() {
|
|
|
|
|
startTime = clashCore.getRunTime();
|
|
|
|
|
}
|
2024-06-16 19:04:33 +08:00
|
|
|
|
2024-07-13 16:36:08 +08:00
|
|
|
setServiceMessageHandler(ServiceMessageListener serviceMessageListener) {
|
|
|
|
|
_serviceMessageHandler = serviceMessageListener;
|
2024-06-16 19:04:33 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-13 16:36:08 +08:00
|
|
|
_handleServiceMessage(String message) {
|
|
|
|
|
final m = ServiceMessage.fromJson(json.decode(message));
|
2024-07-24 01:27:49 +08:00
|
|
|
debugPrint(m.toString());
|
2024-07-13 16:36:08 +08:00
|
|
|
switch (m.type) {
|
|
|
|
|
case ServiceMessageType.protect:
|
|
|
|
|
_serviceMessageHandler?.onProtect(Fd.fromJson(m.data));
|
|
|
|
|
case ServiceMessageType.process:
|
|
|
|
|
_serviceMessageHandler?.onProcess(Process.fromJson(m.data));
|
|
|
|
|
case ServiceMessageType.started:
|
|
|
|
|
_serviceMessageHandler?.onStarted(m.data);
|
|
|
|
|
case ServiceMessageType.loaded:
|
|
|
|
|
_serviceMessageHandler?.onLoaded(m.data);
|
|
|
|
|
}
|
2024-04-30 23:38:49 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final proxy = Platform.isAndroid ? Proxy() : null;
|