core.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. import 'dart:convert';
  2. import 'package:dio/dio.dart';
  3. import 'package:get/get.dart';
  4. import 'package:naiyouwl/app/bean/clash_core.dart';
  5. import 'package:naiyouwl/app/bean/connect.dart';
  6. import 'package:naiyouwl/app/bean/proxie.dart';
  7. import 'package:naiyouwl/app/bean/rule.dart';
  8. import 'package:naiyouwl/app/common/LogHelper.dart';
  9. import 'package:naiyouwl/app/controller/controllers.dart';
  10. import 'package:naiyouwl/app/controller/service.dart';
  11. import 'package:naiyouwl/app/utils/system_proxy.dart';
  12. import 'package:web_socket_channel/io.dart';
  13. import 'package:http/http.dart' as http;
  14. class CoreController extends GetxController {
  15. // late final dio = Dio(BaseOptions(
  16. // baseUrl: 'http://127.0.0.1:9799',
  17. // ));
  18. var ip = "127.0.0.1";
  19. var url = "";
  20. var client = http.Client();
  21. var headers = Map<String,String>();
  22. late final LogHelper _logger = LogHelper();
  23. var version = ClashCoreVersion(premium: true, version: '').obs;
  24. var address = ''.obs;
  25. var secret = ''.obs;
  26. var config = ClashCoreConfig(
  27. port: 0,
  28. socksPort: 0,
  29. redirPort: 0,
  30. tproxyPort: 0,
  31. mixedPort: 0,
  32. allowLan: false,
  33. bindAddress: '',
  34. mode: 'rule',
  35. logLevel: '',
  36. ipv6: false,
  37. ).obs;
  38. var ruleProvider = RuleProvider(providers: {}).obs;
  39. var rule = Rule(rules: []).obs;
  40. CoreController(){
  41. // dio.interceptors.add(LogInterceptor(
  42. // request: true,
  43. // requestBody: true,
  44. // responseBody: true,
  45. // error: true,
  46. // logPrint: _logger.d, // 使用 Logger 插件打印日志
  47. // ));
  48. //dio.interceptors.add(FriendlyErrorInterceptor());
  49. }
  50. SystemProxyConfig get proxyConfig {
  51. final mixedPort = config.value.mixedPort == 0 ? null : config.value.mixedPort;
  52. final httpPort = mixedPort ?? config.value.port;
  53. final httpsPort = mixedPort ?? config.value.port;
  54. final socksPort = mixedPort ?? config.value.socksPort;
  55. return SystemProxyConfig(
  56. http: httpPort == 0 ? null : '127.0.0.1:$httpPort',
  57. https: httpsPort == 0 ? null : '127.0.0.1:$httpsPort',
  58. socks: socksPort == 0 ? null : '127.0.0.1:$socksPort',
  59. );
  60. }
  61. setApi(String apiAddress, String apiSecret) {
  62. address.value = apiAddress;
  63. secret.value = apiSecret;
  64. // dio.close(force: true);
  65. url = "${address.value}";
  66. headers["Authorization"] = 'Bearer ${secret.value}';
  67. //client.head(Uri.http(url,'info'))
  68. // dio.options.baseUrl = 'http://${address.value}';
  69. // print("dio baseUrl api ${dio.options.baseUrl}");
  70. // dio.options.headers['Authorization'] = 'Bearer ${secret.value}';
  71. }
  72. Future<dynamic> fetchHello() async {
  73. try {
  74. var ut = Uri.parse('http://$url/info');
  75. final res = await client.get(ut,headers: headers);
  76. if(res.statusCode == 200) {
  77. var jsonResponse =
  78. jsonDecode(res.body) as Map<String, dynamic>;
  79. return jsonResponse;
  80. }
  81. } on http.ClientException catch (e) {
  82. // 处理客户端异常,例如没有网络连接
  83. print('Client fetchHello Exception: ${e.message}');
  84. return null;
  85. } on Exception catch (e) {
  86. // 处理其他类型的异常
  87. print('Exception: $e');
  88. return null;
  89. }
  90. }
  91. Future<ClashCoreVersion?> updateVersion() async {
  92. try {
  93. var ut = Uri.parse('http://$url/version');
  94. final res = await client.get(ut,headers: headers);
  95. if(res.statusCode == 200) {
  96. var jsonResponse =
  97. jsonDecode(res.body) as Map<String, dynamic>;
  98. version.value = ClashCoreVersion.fromJson(jsonResponse);
  99. return version.value;
  100. }
  101. } on http.ClientException catch (e) {
  102. // 处理客户端异常,例如没有网络连接
  103. print('Client updateVersion Exception: ${e.message}');
  104. return null;
  105. } on Exception catch (e) {
  106. // 处理其他类型的异常
  107. print('Exception: $e');
  108. return null;
  109. }
  110. return null;
  111. }
  112. Future<void> updateConfig() async {
  113. try {
  114. var ut = Uri.parse('http://$url/configs');
  115. final res = await client.get(ut,headers: headers);
  116. print("updateConfig ---- ${res.statusCode}");
  117. if(res.statusCode == 200) {
  118. var jsonResponse =
  119. jsonDecode(res.body) as Map<String, dynamic>;
  120. config.value = ClashCoreConfig.fromJson(jsonResponse);
  121. }
  122. } on http.ClientException catch (e) {
  123. // 处理客户端异常,例如没有网络连接
  124. print('Client updateConfig Exception: ${e.message}');
  125. } on Exception catch (e) {
  126. // 处理其他类型的异常
  127. print('Exception updateConfig: $e');
  128. }
  129. }
  130. Future<void> fetchConfigUpdate(Map<String, dynamic> config) async {
  131. try {
  132. ///configs
  133. ///
  134. // {"mode":"global"}
  135. //请求 URL:
  136. // http://127.0.0.1:9799/configs
  137. // 请求方法:
  138. // PATCH
  139. var ut = Uri.parse('http://$url/configs');
  140. final res = await client.patch(ut, headers: headers, body: jsonEncode(config));
  141. print("fetchConfigUpdate ---- ${res.statusCode}");
  142. if (res.statusCode == 204) {
  143. print("配置更新成功");
  144. } else {
  145. print("配置更新失败,状态码: ${res.statusCode}");
  146. }
  147. // var jsonResponse =
  148. // jsonDecode(res.body) as Map<String, dynamic>;
  149. // print(jsonResponse);
  150. await updateConfig();
  151. } on http.ClientException catch (e) {
  152. // 处理客户端异常,例如没有网络连接
  153. print('Client fetchConfigUpdate Exception: ${e.message}');
  154. } on Exception catch (e) {
  155. // 处理其他类型的异常
  156. print('Exception fetchConfigUpdate: $e');
  157. }
  158. }
  159. Future<void> changeConfig(String configPath) async{
  160. for (var i = 0 ; i< 5; i++) {
  161. try {
  162. final body = json.encode({
  163. "path": configPath
  164. });
  165. var ut = Uri.parse('http://$url/configs');
  166. final res = await client.put(ut,body:body,headers: headers);
  167. print("changeConfig ---- ${res.statusCode}");
  168. if(res.statusCode == 204)
  169. {
  170. await updateConfig();
  171. break;
  172. }
  173. } on http.ClientException catch (e) {
  174. // 处理客户端异常,例如没有网络连接
  175. print('Client changeConfig Exception: ${e.message}');
  176. continue;
  177. } on Exception catch (e) {
  178. // 处理其他类型的异常
  179. print('Exception changeConfig : $e');
  180. continue;
  181. }
  182. }
  183. }
  184. // type updateConfigRequest struct {
  185. // Path string `json:"path"`
  186. // Payload string `json:"payload"`
  187. // }
  188. // https://github.com/Dreamacro/clash/blob/c231fd14666d6ea05d6a75eaba6db69f9eee5ae9/hub/route/configs.go#L95
  189. // Future<void> fetchReloadConfig(Map<String, String> config) async {
  190. // print("fetchReloadConfig $config");
  191. // await dio.put('/configs', data: config);
  192. // }
  193. Future<void> fetchCloseConnections(String id) async {
  194. //await dio.delete('/connections/${Uri.encodeComponent(id)}');
  195. try {
  196. var ut = Uri.parse('http://$url/connections/${Uri.encodeComponent(id)}');
  197. final res = await client.delete(ut,headers: headers);
  198. print("fetchCloseConnections ---- ${res.statusCode}");
  199. if(res.statusCode == 204){
  200. var jsonResponse =
  201. jsonDecode(res.body) as Map<String, dynamic>;
  202. print(jsonResponse);
  203. await updateConfig();
  204. }
  205. } on http.ClientException catch (e) {
  206. // 处理客户端异常,例如没有网络连接
  207. print('Client fetchCloseConnections Exception: ${e.message}');
  208. } on Exception catch (e) {
  209. // 处理其他类型的异常
  210. print('Exception: $e');
  211. }
  212. }
  213. IOWebSocketChannel fetchConnectionsWs() {
  214. return IOWebSocketChannel.connect(
  215. Uri.parse('ws://${address.value}/connections'),
  216. headers: headers,
  217. );
  218. }
  219. Future updateRuleProvider() async {
  220. // final res = await dio.get('/providers/rules');
  221. // ruleProvider.value = RuleProvider.fromJson(res.data);
  222. // ruleProvider.refresh();
  223. try {
  224. var ut = Uri.parse('http://$url/poviders/rules');
  225. final res = await client.get(ut,headers: headers);
  226. if(res.statusCode == 200){
  227. var jsonResponse =
  228. jsonDecode(res.body) as Map<String, dynamic>;
  229. ruleProvider.value = RuleProvider.fromJson(jsonResponse);
  230. ruleProvider.refresh();
  231. }
  232. } on http.ClientException catch (e) {
  233. // 处理客户端异常,例如没有网络连接
  234. print('Client updateRuleProvider Exception: ${e.message}');
  235. } on Exception catch (e) {
  236. // 处理其他类型的异常
  237. print('Exception: $e');
  238. }
  239. }
  240. Future updateRule() async {
  241. // final res = await dio.get('/rules');
  242. // rule.value = Rule.fromJson(res.data);
  243. // rule.refresh();
  244. try {
  245. var ut = Uri.parse('http://$url/rules');
  246. final res = await client.get(ut,headers: headers);
  247. if(res.statusCode == 200){
  248. var jsonResponse =
  249. jsonDecode(res.body) as Map<String, dynamic>;
  250. rule.value = Rule.fromJson(jsonResponse);
  251. rule.refresh();
  252. }
  253. } on http.ClientException catch (e) {
  254. // 处理客户端异常,例如没有网络连接
  255. print('Client updateRule Exception: ${e.message}');
  256. } on Exception catch (e) {
  257. // 处理其他类型的异常
  258. print('Exception: $e');
  259. }
  260. }
  261. // Future<void> fetchRuleProviderUpdate(String name) async {
  262. // await dio.put('/providers/rules/${Uri.encodeComponent(name)}');
  263. // }
  264. // Future<Proxie> fetchProxie() async {
  265. // final res = await dio.get('/proxies');
  266. // return Proxie.fromJson(res.data);
  267. // }
  268. // Future<ProxieProvider> fetchProxieProvider() async {
  269. // final res = await dio.get('/providers/proxies');
  270. // return ProxieProvider.fromJson(res.data);
  271. // }
  272. // Future<void> fetchProxieProviderHealthCheck(String provider) async {
  273. // await dio.get('/providers/proxies/${Uri.encodeComponent(provider)}/healthcheck');
  274. // }
  275. Future<void> fetchSetProxieGroup(String group, String value) async {
  276. try {
  277. // 构建请求体
  278. final body = json.encode({
  279. 'name': value // 确认 value 是正确的代理名称
  280. });
  281. // 构建 URL,确保 group 是正确的代理组名称
  282. var ut = Uri.parse('http://$url/proxies/${Uri.encodeComponent(group)}');
  283. // 发起 PUT 请求,选择代理
  284. final ret = await client.put(ut, body: body, headers: headers);
  285. // 输出返回的状态码,确保请求成功
  286. print("fetchSetProxieGroup ${ret.statusCode}");
  287. // 检查状态码,确保请求成功
  288. if (ret.statusCode == 200) {
  289. print('Proxy group updated successfully.');
  290. } else {
  291. print('Failed to update proxy group: ${ret.statusCode}');
  292. }
  293. } on http.ClientException catch (e) {
  294. // 处理客户端异常,例如没有网络连接
  295. print('fetchSetProxieGroup ClientException: ${e.message}');
  296. } on Exception catch (e) {
  297. // 处理其他类型的异常
  298. print('fetchSetProxieGroup Exception: $e');
  299. }
  300. }
  301. //
  302. // Future<void> fetchProxieProviderUpdate(String name) async {
  303. // await dio.put('/providers/proxies/${Uri.encodeComponent(name)}');
  304. // }
  305. // Future<int> fetchProxieDelay(String name) async {
  306. // final query = {'timeout': 5000, 'url': 'http://www.gstatic.com/generate_204'};
  307. // final res = await dio.get('/proxies/${Uri.encodeComponent(name)}/delay', queryParameters: query);
  308. // return res.data['delay'] ?? 0;
  309. // }
  310. //
  311. Future<Connect?> fetchConnection() async {
  312. // final res = await dio.get('/connections');
  313. // if(res.data !=null){
  314. // // LogHelper().d("没有连接");
  315. // //return Connect();
  316. // }
  317. try {
  318. var ut = Uri.parse('http://$url/connections');
  319. final res = await client.get(ut,headers: headers);
  320. if(res.statusCode == 200){
  321. var jsonResponse =
  322. jsonDecode(res.body) as Map<String, dynamic>;
  323. return Connect.fromJson(jsonResponse);
  324. }
  325. } on http.ClientException catch (e) {
  326. // 处理客户端异常,例如没有网络连接
  327. print('fetchConnection Exception: ${e.message}');
  328. return null;
  329. } on Exception catch (e) {
  330. // 处理其他类型的异常
  331. print('fetchConnection Exception: $e');
  332. return null;
  333. }
  334. }
  335. }