123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- import 'dart:io';
- import 'dart:async';
- import 'dart:convert';
- import 'package:get/get.dart';
- import 'package:naiyouwl/app/bean/ClashServiceInfo.dart';
- import 'package:naiyouwl/app/clash/service/clash_service.dart';
- import 'package:naiyouwl/app/const/const.dart';
- import 'package:naiyouwl/app/controller/controllers.dart';
- import 'package:naiyouwl/app/utils/logger.dart';
- import 'package:naiyouwl/app/utils/shell.dart';
- import 'package:path/path.dart' as path;
- import 'package:http/http.dart' as http;
- import '../clash/mode/clash_config.dart';
- import '../common/constants.dart';
- import '../utils/utils.dart';
- final headers = {"User-Agent": "ccore-for-flutter/0.0.1"};
- class ServiceController extends GetxController {
- var url = "";
- var client = http.Client();
- var serviceMode = false.obs;
- var coreStatus = RunningState.stoped.obs;
- var serviceStatus = RunningState.stoped.obs;
- var installStatus = false.obs; // 新增变量用于记录安装/卸载状态
- bool get serviceIsRuning => serviceStatus.value == RunningState.running;
- bool get coreIsRuning => coreStatus.value == RunningState.running;
- Future<void> initConfig() async{
- url = "127.0.0.1:${controllers.config.config.value.servicePort}";
- //controllers.config.setSerivcePort(controllers.config.config.value.servicePort);
- }
- Future<void> startTunService() async {
- try {
- while (true) {
- final data = await fetchInfo() ?? ClashServiceInfo.fromJson({'code': -1, 'mode': '', 'status': '-1', 'version': '-1'});
- if (data.mode != 'service-mode') {
- if (serviceStatus.value == RunningState.running) {
- await stopService();
- }
- await install();
- } else {
- break;
- }
- }
- } catch (e) {
- serviceStatus.value = RunningState.error;
- log.debug(e.toString());
- }
- }
- Future<ClashServiceInfo?> fetchInfo() async {
- try {
- final res = await client.post(Uri.http(url, 'info'), headers: headers);
- var jsonResponse = jsonDecode(res.body) as Map<String, dynamic>;
- return ClashServiceInfo.fromJson(jsonResponse);
- } catch (e) {
- print('Exception: $e');
- return null;
- }
- }
- Future<void> fetchStartInit() async {
- await controllers.service.makeInitConfig();
- controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
- controllers.global.updateMsg("服务模式初始化...");
- await fetchStop();
- try {
- var ut = Uri.http(url, 'start');
- final body = json.encode({
- "coreName": Files.assetsCCore.path,
- "args": [
- '-d',
- Paths.config.path,
- '-f',
- path.join(Paths.config.path, controllers.config.config.value.selected)
- ]
- });
- final res = await client.post(ut, body: body, headers: headers);
- var jsonResponse = jsonDecode(res.body) as Map<String, dynamic>;
- if (jsonResponse["code"] != 0) {
- coreStatus.value = RunningState.error;
- throw jsonResponse["msg"];
- }
- controllers.global.updateMsg("服务模式初始化成功..");
- coreStatus.value = RunningState.running;
- } catch (e) {
- print('Exception: $e');
- coreStatus.value = RunningState.error;
- controllers.global.updateMsg("服务模式初始化失败..");
- }
- }
- //应该程序退出调用
- Future<void> fetchStop() async {
- try {
- var ut = Uri.http(url, 'stop');
- await client.post(ut, headers: headers);
- coreStatus.value = RunningState.stoped;
- } catch (e) {
- print('Exception: $e');
- }
- }
- Future<void> fetchSetProxy() async {
- try {
- var dns_ip = "";
- if (controllers.global.routeModesSelect.value == "tun") {
- dns_ip = "198.18.0.2";
- }
- var ut = Uri.http(url, 'on');
- final body = json.encode({
- "http_port": controllers.config.mixedPort.value,
- "https_port": controllers.config.mixedPort.value,
- "socks_port": controllers.config.mixedPort.value,
- "bypass": "127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, 17.0.0.0/8, localhost, *.local, *.crashlytics.com, seed-sequoia.siri.apple.com, sequoia.apple.com,xd.apple.com",
- "dns_ip": dns_ip,
- "dns_type": "",
- "address": "127.0.0.1"
- });
- await client.post(ut, body: body, headers: headers);
- } catch (e) {
- print('Exception: $e');
- }
- }
- Future<void> fetchSetProxyStop() async {
- try {
- var dnsIp = "";
- if (controllers.global.routeModesSelect.value == "tun") {
- dnsIp = "223.5.5.5";
- }
- var ut = Uri.http(url, 'off');
- final body = json.encode({
- "bypass": "",
- "dns_ip": dnsIp
- });
- await client.post(ut, body: body, headers: headers);
- } catch (e) {
- print('Exception: $e');
- }
- }
- Future<void> waitServiceStart() async {
- while (true) {
- await Future.delayed(const Duration(milliseconds: 100));
- try {
- await isCanOperationService();
- break;
- } catch (_) {}
- }
- }
- Future<void> install() async {
- try {
- final res = await runAsAdmin(Files.assetsClashService.path, ["-port", "${controllers.config.config.value.servicePort}", "stop", "uninstall", "install", "start"]);
- log.debug('install', res.stdout, res.stderr);
- if (res.exitCode != 0) {
- throw res.stderr;
- }
- await waitServiceStart();
- serviceStatus.value = RunningState.running;
- if (serviceStatus.value == RunningState.running) {
- await controllers.service.stopClashCore();
- await Future.delayed(Duration(seconds: 3));
- await fetchStartInit();
- }
- installStatus.value = true; // 安装成功
- } catch (e) {
- installStatus.value = false; // 安装失败
- log.debug('安装失败: $e');
- throw e;
- }
- }
- Future<void> uninstall() async {
- try {
- serviceStatus.value = RunningState.uninstall;
- final res = await runAsAdmin(Files.assetsClashService.path, ["stop", "uninstall"]);
- log.debug('uninstall', res.stdout, res.stderr);
- if (res.exitCode != 0) throw res.stderr;
- installStatus.value = false; // 卸载成功
- await Future.delayed(Duration(seconds: 2));
- // final conn = await controllers.core.fetchConnection();
- // if(conn != null)
- // {
- // for (final it in conn.connections) {
- // await controllers.core.fetchCloseConnections(it.id);
- // }
- // }
- await controllers.service.updatePorts();
- await Future.delayed(Duration(seconds: 2));
- await controllers.service.makeInitConfig();
- await Future.delayed(Duration(seconds: 5));
- await controllers.service.startClashCore();
- serviceStatus.value = RunningState.stoped;
- } catch (e) {
- installStatus.value = true; // 卸载失败
- log.debug('卸载失败: $e');
- throw e;
- }
- }
- Future<void> stopService() async {
- serviceStatus.value = RunningState.stopping;
- if (coreStatus.value == RunningState.running) await fetchStop();
- serviceStatus.value = RunningState.stoped;
- }
- Future<void> serviceModeSwitch(bool open) async {
- // if (serviceStatus.value == RunningState.running) await controllers.service.stopClashCore();
- // if (serviceStatus.value == RunningState.running) await fetchStop();
- serviceStatus.value = RunningState.starting;
- try {
- controllers.global.updateMsg(open ? "安装服务" : "卸载服务");
- open ? await install() : await uninstall();
- } catch (e) {
- print(e.toString());
- }
- if(open)
- {
- await fetchStartInit();
- }
- }
- Future<void> stopClash() async {
- controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
- if (coreStatus.value == RunningState.running) {
- await controllers.config.readClashCoreApi();
- controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
- await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
- }
- }
- Future<void> reloadClashCore() async {
- try {
- controllers.config.config.value.selected = Files.makeProxyConfig.path;
- if (coreStatus.value == RunningState.running) {
- controllers.global.updateMsg("切换配置...");
- await controllers.config.readClashCoreApi();
- controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
- await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
- controllers.global.updateMsg("fetchReloadConfig${controllers.config.clashCoreApiAddress.value}...");
- } else {
- controllers.global.updateMsg("重新配置...");
- await controllers.config.readClashCoreApi();
- controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
- await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
- }
- } catch (e) {
- controllers.global.updateMsg("重新配置...");
- await controllers.config.readClashCoreApi();
- controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
- await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
- }
- }
- Future<bool> isCanOperationService() async {
- try {
- final res = await client.post(Uri.http(url, 'info'), headers: headers);
- if(res.statusCode == 200)
- {
- serviceStatus.value = RunningState.running;
- }
- return installStatus.value = res.statusCode == 200;
- } catch (e) {
- serviceStatus.value = RunningState.stoped;
- installStatus.value = false;
- return false;
- print('Exception when checking service: $e');
- return false;
- }
- }
- Future<bool> isClashCoreRunning() async {
- try {
- final res = await client.post(Uri.http(url, 'info'), headers: headers);
- if (res.statusCode == 200) {
- var jsonResponse = jsonDecode(res.body) as Map<String, dynamic>;
- return jsonResponse['status'] == 'running';
- }
- return false;
- } catch (e) {
- print('Exception when checking Clash core: $e');
- return false;
- }
- }
- }
|