core.dart 12 KB

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