Support proxies search Support svg display Optimize config persistence Add some scenes auto close connections Update core Optimize more details
203 lines
5.1 KiB
Dart
203 lines
5.1 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:dio/io.dart';
|
|
import 'package:fl_clash/common/common.dart';
|
|
import 'package:fl_clash/models/models.dart';
|
|
import 'package:fl_clash/state.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
class Request {
|
|
late final Dio _dio;
|
|
late final Dio _clashDio;
|
|
String? userAgent;
|
|
|
|
Request() {
|
|
_dio = Dio(
|
|
BaseOptions(
|
|
headers: {
|
|
"User-Agent": browserUa,
|
|
},
|
|
),
|
|
);
|
|
_clashDio = Dio();
|
|
_clashDio.httpClientAdapter = IOHttpClientAdapter(createHttpClient: () {
|
|
final client = HttpClient();
|
|
client.findProxy = (Uri uri) {
|
|
client.userAgent = globalState.ua;
|
|
return FlClashHttpOverrides.handleFindProxy(uri);
|
|
};
|
|
return client;
|
|
});
|
|
}
|
|
|
|
Future<Response> getFileResponseForUrl(String url) async {
|
|
final response = await _clashDio.get(
|
|
url,
|
|
options: Options(
|
|
responseType: ResponseType.bytes,
|
|
),
|
|
);
|
|
return response;
|
|
}
|
|
|
|
Future<Response> getTextResponseForUrl(String url) async {
|
|
final response = await _clashDio.get(
|
|
url,
|
|
options: Options(
|
|
responseType: ResponseType.plain,
|
|
),
|
|
);
|
|
return response;
|
|
}
|
|
|
|
Future<MemoryImage?> getImage(String url) async {
|
|
if (url.isEmpty) return null;
|
|
final response = await _dio.get<Uint8List>(
|
|
url,
|
|
options: Options(
|
|
responseType: ResponseType.bytes,
|
|
),
|
|
);
|
|
final data = response.data;
|
|
if (data == null) return null;
|
|
return MemoryImage(data);
|
|
}
|
|
|
|
Future<Map<String, dynamic>?> checkForUpdate() async {
|
|
final response = await _dio.get(
|
|
"https://api.github.com/repos/$repository/releases/latest",
|
|
options: Options(
|
|
responseType: ResponseType.json,
|
|
),
|
|
);
|
|
if (response.statusCode != 200) return null;
|
|
final data = response.data as Map<String, dynamic>;
|
|
final remoteVersion = data['tag_name'];
|
|
final version = globalState.packageInfo.version;
|
|
final hasUpdate =
|
|
utils.compareVersions(remoteVersion.replaceAll('v', ''), version) > 0;
|
|
if (!hasUpdate) return null;
|
|
return data;
|
|
}
|
|
|
|
final Map<String, IpInfo Function(Map<String, dynamic>)> _ipInfoSources = {
|
|
"https://ipwho.is/": IpInfo.fromIpwhoIsJson,
|
|
"https://api.ip.sb/geoip/": IpInfo.fromIpSbJson,
|
|
"https://ipapi.co/json/": IpInfo.fromIpApiCoJson,
|
|
"https://ipinfo.io/json/": IpInfo.fromIpInfoIoJson,
|
|
};
|
|
|
|
Future<IpInfo?> checkIp({CancelToken? cancelToken}) async {
|
|
for (final source in _ipInfoSources.entries) {
|
|
try {
|
|
final response = await Dio()
|
|
.get<Map<String, dynamic>>(
|
|
source.key,
|
|
cancelToken: cancelToken,
|
|
options: Options(
|
|
responseType: ResponseType.json,
|
|
),
|
|
)
|
|
.timeout(
|
|
Duration(
|
|
seconds: 30,
|
|
),
|
|
);
|
|
if (response.statusCode != 200 || response.data == null) {
|
|
continue;
|
|
}
|
|
if (response.data == null) {
|
|
continue;
|
|
}
|
|
return source.value(response.data!);
|
|
} catch (e) {
|
|
commonPrint.log("checkIp error ===> $e");
|
|
if (e is DioException && e.type == DioExceptionType.cancel) {
|
|
throw "cancelled";
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<bool> pingHelper() async {
|
|
try {
|
|
final response = await _dio
|
|
.get(
|
|
"http://$localhost:$helperPort/ping",
|
|
options: Options(
|
|
responseType: ResponseType.plain,
|
|
),
|
|
)
|
|
.timeout(
|
|
const Duration(
|
|
milliseconds: 2000,
|
|
),
|
|
);
|
|
if (response.statusCode != HttpStatus.ok) {
|
|
return false;
|
|
}
|
|
return (response.data as String) == globalState.coreSHA256;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<bool> startCoreByHelper(String arg) async {
|
|
try {
|
|
final response = await _dio
|
|
.post(
|
|
"http://$localhost:$helperPort/start",
|
|
data: json.encode({
|
|
"path": appPath.corePath,
|
|
"arg": arg,
|
|
}),
|
|
options: Options(
|
|
responseType: ResponseType.plain,
|
|
),
|
|
)
|
|
.timeout(
|
|
const Duration(
|
|
milliseconds: 2000,
|
|
),
|
|
);
|
|
if (response.statusCode != HttpStatus.ok) {
|
|
return false;
|
|
}
|
|
final data = response.data as String;
|
|
return data.isEmpty;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<bool> stopCoreByHelper() async {
|
|
try {
|
|
final response = await _dio
|
|
.post(
|
|
"http://$localhost:$helperPort/stop",
|
|
options: Options(
|
|
responseType: ResponseType.plain,
|
|
),
|
|
)
|
|
.timeout(
|
|
const Duration(
|
|
milliseconds: 2000,
|
|
),
|
|
);
|
|
if (response.statusCode != HttpStatus.ok) {
|
|
return false;
|
|
}
|
|
final data = response.data as String;
|
|
return data.isEmpty;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
final request = Request();
|