mirror of
https://mirror.ghproxy.com/https://github.com/StarCitizenToolBox/app.git
synced 2024-12-23 11:13:46 +08:00
使用 DNS 分流
This commit is contained in:
parent
95b4b8b947
commit
9ee02e9312
@ -8,6 +8,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:starcitizen_doctor/api/analytics.dart';
|
import 'package:starcitizen_doctor/api/analytics.dart';
|
||||||
import 'package:starcitizen_doctor/api/api.dart';
|
import 'package:starcitizen_doctor/api/api.dart';
|
||||||
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
||||||
import 'package:starcitizen_doctor/common/rust/frb_generated.dart';
|
import 'package:starcitizen_doctor/common/rust/frb_generated.dart';
|
||||||
import 'package:starcitizen_doctor/data/app_version_data.dart';
|
import 'package:starcitizen_doctor/data/app_version_data.dart';
|
||||||
import 'package:starcitizen_doctor/global_ui_model.dart';
|
import 'package:starcitizen_doctor/global_ui_model.dart';
|
||||||
@ -67,6 +68,7 @@ class AppConf {
|
|||||||
|
|
||||||
/// check Rust bridge
|
/// check Rust bridge
|
||||||
await RustLib.init();
|
await RustLib.init();
|
||||||
|
await RSHttp.init();
|
||||||
dPrint("---- rust bridge inited -----");
|
dPrint("---- rust bridge inited -----");
|
||||||
await SystemHelper.initPowershellPath();
|
await SystemHelper.initPowershellPath();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:starcitizen_doctor/base/ui_model.dart';
|
import 'package:starcitizen_doctor/base/ui_model.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/http_package.dart';
|
||||||
|
|
||||||
class URLConf {
|
class URLConf {
|
||||||
/// HOME API
|
/// HOME API
|
||||||
@ -7,83 +8,92 @@ class URLConf {
|
|||||||
static String rssApiHome = "https://rss.sctoolbox.sccsgo.com";
|
static String rssApiHome = "https://rss.sctoolbox.sccsgo.com";
|
||||||
static const String xkeycApiHome = "https://sctoolbox.xkeyc.com";
|
static const String xkeycApiHome = "https://sctoolbox.xkeyc.com";
|
||||||
|
|
||||||
static bool isUsingFallback = false;
|
static bool isUrlCheckPass = false;
|
||||||
|
|
||||||
/// URLS
|
/// URLS
|
||||||
static String giteaAttachmentsUrl = "$gitApiHome/SCToolBox/Release";
|
static String get giteaAttachmentsUrl => "$gitApiHome/SCToolBox/Release";
|
||||||
static String gitlabLocalizationUrl =
|
|
||||||
|
static String get gitlabLocalizationUrl =>
|
||||||
"$gitApiHome/SCToolBox/LocalizationData";
|
"$gitApiHome/SCToolBox/LocalizationData";
|
||||||
static String apiRepoPath = "$gitApiHome/SCToolBox/api/raw/branch/main/";
|
|
||||||
|
|
||||||
static String gitlabApiPath = "https://$gitApiHome/api/v1/";
|
static String get apiRepoPath => "$gitApiHome/SCToolBox/api/raw/branch/main/";
|
||||||
|
|
||||||
static String webTranslateHomeUrl =
|
static String get gitlabApiPath => "https://$gitApiHome/api/v1/";
|
||||||
|
|
||||||
|
static String get webTranslateHomeUrl =>
|
||||||
"$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
|
"$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
|
||||||
|
|
||||||
static String rssVideoUrl =
|
static String get rssVideoUrl =>
|
||||||
"$rssApiHome/bilibili/user/channel/27976358/290653";
|
"$rssApiHome/bilibili/user/channel/27976358/290653";
|
||||||
|
|
||||||
static String rssTextUrl1 = "$rssApiHome/bilibili/user/article/40102960";
|
static String get rssTextUrl1 => "$rssApiHome/bilibili/user/article/40102960";
|
||||||
static String rssTextUrl2 =
|
|
||||||
|
static String get rssTextUrl2 =>
|
||||||
"$rssApiHome/baidu/tieba/user/%E7%81%AC%E7%81%ACG%E7%81%AC%E7%81%AC&";
|
"$rssApiHome/baidu/tieba/user/%E7%81%AC%E7%81%ACG%E7%81%AC%E7%81%AC&";
|
||||||
|
|
||||||
static const feedbackUrl = "https://txc.qq.com/products/614843";
|
static const feedbackUrl = "https://txc.qq.com/products/614843";
|
||||||
|
|
||||||
static const devReleaseUrl =
|
static String get devReleaseUrl => "$gitApiHome/SCToolBox/Release/releases";
|
||||||
"https://git.sctoolbox.sccsgo.com/SCToolBox/Release/releases";
|
|
||||||
|
|
||||||
static const _gitApiList = [
|
static Future<bool> checkHost() async {
|
||||||
"https://git.sctoolbox.sccsgo.com",
|
// 使用 DNS 获取可用列表
|
||||||
"https://sctb-git.xkeyc.com"
|
final gitApiList =
|
||||||
];
|
_genFinalList(await RSHttp.dnsLookupTxt("git.dns.scbox.org"));
|
||||||
|
dPrint("DNS gitApiList ==== $gitApiList");
|
||||||
|
final fasterGit = await getFasterUrl(gitApiList);
|
||||||
|
dPrint("gitApiList.Faster ==== $fasterGit");
|
||||||
|
if (fasterGit != null) {
|
||||||
|
gitApiHome = fasterGit;
|
||||||
|
}
|
||||||
|
final rssApiList =
|
||||||
|
_genFinalList(await RSHttp.dnsLookupTxt("rss.dns.scbox.org"));
|
||||||
|
final fasterRss = await getFasterUrl(rssApiList);
|
||||||
|
dPrint("DNS rssApiList ==== $rssApiList");
|
||||||
|
dPrint("rssApiList.Faster ==== $fasterRss");
|
||||||
|
if (fasterRss != null) {
|
||||||
|
rssApiHome = fasterRss;
|
||||||
|
}
|
||||||
|
isUrlCheckPass = fasterGit != null && fasterRss != null;
|
||||||
|
return isUrlCheckPass;
|
||||||
|
}
|
||||||
|
|
||||||
static const _rssApiList = [
|
static Future<String?> getFasterUrl(List<String> urls) async {
|
||||||
"https://rss.sctoolbox.sccsgo.com",
|
String firstUrl = "";
|
||||||
"https://rss.42kit.com"
|
int callLen = 0;
|
||||||
];
|
|
||||||
|
|
||||||
static checkHost() async {
|
void onCall(RustHttpResponse? response, String url) {
|
||||||
final dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 5)));
|
callLen++;
|
||||||
bool hasAvailable = false;
|
if (response != null && response.statusCode == 200 && firstUrl.isEmpty) {
|
||||||
// 寻找可用的 git API
|
firstUrl = url;
|
||||||
for (var value in _gitApiList) {
|
|
||||||
try {
|
|
||||||
final resp = await dio.head(value);
|
|
||||||
if (resp.statusCode == 200) {
|
|
||||||
dPrint("[URLConf].checkHost passed $value");
|
|
||||||
gitApiHome = value;
|
|
||||||
hasAvailable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
isUsingFallback = true;
|
|
||||||
continue;
|
|
||||||
} catch (e) {
|
|
||||||
dPrint("[URLConf].checkHost $value Error= $e");
|
|
||||||
isUsingFallback = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 寻找可用的 RSS API
|
|
||||||
for (var value in _rssApiList) {
|
|
||||||
try {
|
|
||||||
final resp = await dio.head(value);
|
|
||||||
if (resp.statusCode == 200) {
|
|
||||||
rssApiHome = value;
|
|
||||||
hasAvailable = true;
|
|
||||||
dPrint("[URLConf].checkHost passed $value");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
isUsingFallback = true;
|
|
||||||
continue;
|
|
||||||
} catch (e) {
|
|
||||||
dPrint("[URLConf].checkHost $value Error= $e");
|
|
||||||
isUsingFallback = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAvailable) {
|
for (var value in urls) {
|
||||||
isUsingFallback = false;
|
RSHttp.head(value).then((resp) => onCall(resp, value), onError: (err) {
|
||||||
|
callLen++;
|
||||||
|
dPrint("RSHttp.head error $err");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 16));
|
||||||
|
if (firstUrl.isNotEmpty) {
|
||||||
|
return firstUrl;
|
||||||
|
}
|
||||||
|
if (callLen == urls.length && firstUrl.isEmpty) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<String> _genFinalList(List<String> sList) {
|
||||||
|
List<String> list = [];
|
||||||
|
for (var ll in sList) {
|
||||||
|
final ssList = ll.split(",");
|
||||||
|
for (var value in ssList) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:starcitizen_doctor/common/conf/app_conf.dart';
|
||||||
import 'package:starcitizen_doctor/common/rust/api/http_api.dart' as rust_http;
|
import 'package:starcitizen_doctor/common/rust/api/http_api.dart' as rust_http;
|
||||||
import 'package:starcitizen_doctor/common/rust/api/http_api.dart';
|
import 'package:starcitizen_doctor/common/rust/api/http_api.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/rust/http_package.dart';
|
||||||
|
|
||||||
class RSHttp {
|
class RSHttp {
|
||||||
|
static init() async {
|
||||||
|
await rust_http.setDefaultHeader(headers: {
|
||||||
|
"User-Agent":
|
||||||
|
"SCToolBox/${AppConf.appVersion} (${AppConf.appVersionCode}) ${AppConf.isMSE ? "" : " DEV"} RSHttp"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static Future<String> getText(String url,
|
static Future<String> getText(String url,
|
||||||
{Map<String, String>? headers}) async {
|
{Map<String, String>? headers}) async {
|
||||||
final r = await rust_http.fetch(
|
final r = await rust_http.fetch(
|
||||||
@ -26,4 +35,15 @@ class RSHttp {
|
|||||||
method: MyMethod.post, url: url, headers: headers, inputData: data);
|
method: MyMethod.post, url: url, headers: headers, inputData: data);
|
||||||
return r.statusCode == 200;
|
return r.statusCode == 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<RustHttpResponse> head(String url,
|
||||||
|
{Map<String, String>? headers}) async {
|
||||||
|
final r = await rust_http.fetch(
|
||||||
|
method: MyMethod.head, url: url, headers: headers);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<List<String>> dnsLookupTxt(String host) async {
|
||||||
|
return await rust_http.dnsLookupTxt(host: host);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ Future<RustHttpResponse> fetch(
|
|||||||
inputData: inputData,
|
inputData: inputData,
|
||||||
hint: hint);
|
hint: hint);
|
||||||
|
|
||||||
|
Future<List<String>> dnsLookupTxt({required String host, dynamic hint}) =>
|
||||||
|
RustLib.instance.api.dnsLookupTxt(host: host, hint: hint);
|
||||||
|
|
||||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::rust_async::RwLock<reqwest :: Version>>
|
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::rust_async::RwLock<reqwest :: Version>>
|
||||||
@sealed
|
@sealed
|
||||||
class ReqwestVersion extends RustOpaque {
|
class ReqwestVersion extends RustOpaque {
|
||||||
|
@ -74,6 +74,8 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
required int connectionCount,
|
required int connectionCount,
|
||||||
dynamic hint});
|
dynamic hint});
|
||||||
|
|
||||||
|
Future<List<String>> dnsLookupTxt({required String host, dynamic hint});
|
||||||
|
|
||||||
Future<RustHttpResponse> fetch(
|
Future<RustHttpResponse> fetch(
|
||||||
{required MyMethod method,
|
{required MyMethod method,
|
||||||
required String url,
|
required String url,
|
||||||
@ -160,6 +162,31 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
argNames: ["url", "savePath", "fileName", "connectionCount"],
|
argNames: ["url", "savePath", "fileName", "connectionCount"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> dnsLookupTxt({required String host, dynamic hint}) {
|
||||||
|
return handler.executeNormal(NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
sse_encode_String(host, serializer);
|
||||||
|
pdeCallFfi(generalizedFrbRustBinding, serializer,
|
||||||
|
funcId: 5, port: port_);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_list_String,
|
||||||
|
decodeErrorData: null,
|
||||||
|
),
|
||||||
|
constMeta: kDnsLookupTxtConstMeta,
|
||||||
|
argValues: [host],
|
||||||
|
apiImpl: this,
|
||||||
|
hint: hint,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kDnsLookupTxtConstMeta => const TaskConstMeta(
|
||||||
|
debugName: "dns_lookup_txt",
|
||||||
|
argNames: ["host"],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<RustHttpResponse> fetch(
|
Future<RustHttpResponse> fetch(
|
||||||
{required MyMethod method,
|
{required MyMethod method,
|
||||||
@ -283,6 +310,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return raw as int;
|
return raw as int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> dco_decode_list_String(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return (raw as List<dynamic>).map(dco_decode_String).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@ -473,6 +506,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return deserializer.buffer.getInt32();
|
return deserializer.buffer.getInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> sse_decode_list_String(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
|
||||||
|
var len_ = sse_decode_i_32(deserializer);
|
||||||
|
var ans_ = <String>[];
|
||||||
|
for (var idx_ = 0; idx_ < len_; ++idx_) {
|
||||||
|
ans_.add(sse_decode_String(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@ -685,6 +730,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
serializer.buffer.putInt32(self);
|
serializer.buffer.putInt32(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_String(List<String> self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_i_32(self.length, serializer);
|
||||||
|
for (final item in self) {
|
||||||
|
sse_encode_String(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_prim_u_8_strict(
|
void sse_encode_list_prim_u_8_strict(
|
||||||
Uint8List self, SseSerializer serializer) {
|
Uint8List self, SseSerializer serializer) {
|
||||||
|
@ -50,6 +50,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw);
|
int dco_decode_i_32(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> dco_decode_list_String(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
@ -122,6 +125,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer);
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> sse_decode_list_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -202,6 +208,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer);
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_String(List<String> self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_prim_u_8_strict(
|
void sse_encode_list_prim_u_8_strict(
|
||||||
Uint8List self, SseSerializer serializer);
|
Uint8List self, SseSerializer serializer);
|
||||||
|
@ -49,6 +49,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
int dco_decode_i_32(dynamic raw);
|
int dco_decode_i_32(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> dco_decode_list_String(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
|
||||||
|
|
||||||
@ -121,6 +124,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
int sse_decode_i_32(SseDeserializer deserializer);
|
int sse_decode_i_32(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
List<String> sse_decode_list_String(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
|
||||||
|
|
||||||
@ -201,6 +207,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_i_32(int self, SseSerializer serializer);
|
void sse_encode_i_32(int self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_list_String(List<String> self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_list_prim_u_8_strict(
|
void sse_encode_list_prim_u_8_strict(
|
||||||
Uint8List self, SseSerializer serializer);
|
Uint8List self, SseSerializer serializer);
|
||||||
|
@ -35,7 +35,7 @@ class AppGlobalUIModel extends BaseUIModel {
|
|||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
if (AppConf.networkVersionData == null) {
|
if (AppConf.networkVersionData == null) {
|
||||||
showToast(context,
|
showToast(context,
|
||||||
"检查更新失败!请检查网络连接... \n进入离线模式.. \n\n请谨慎在离线模式中使用。\n请尝试更换无污染的DNS。 \n当前版本构建日期:${AppConf.appVersionDate}\n QQ群:940696487 \n错误信息:$checkUpdateError");
|
"网络异常,这可能是服务器正在维护或遭受攻击... \n进入离线模式.. \n\n请谨慎在离线模式中使用。 \n当前版本构建日期:${AppConf.appVersionDate}\n QQ群:940696487 \n错误信息:$checkUpdateError");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final lastVersion = AppConf.isMSE
|
final lastVersion = AppConf.isMSE
|
||||||
|
@ -133,12 +133,6 @@ class HomeUIModel extends BaseUIModel {
|
|||||||
appUpdateTimer = Timer.periodic(const Duration(minutes: 30), (timer) {
|
appUpdateTimer = Timer.periodic(const Duration(minutes: 30), (timer) {
|
||||||
_checkLocalizationUpdate();
|
_checkLocalizationUpdate();
|
||||||
});
|
});
|
||||||
Future.delayed(const Duration(milliseconds: 100)).then((value) {
|
|
||||||
if (URLConf.isUsingFallback) {
|
|
||||||
if (!mounted) return;
|
|
||||||
showToast(context!, "因源服务器异常(机房故障或遭受攻击),当前正在使用备用线路,可能会出现访问速度下降,敬请谅解。");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
super.initModel();
|
super.initModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,3 +40,7 @@ pub async fn fetch(method: MyMethod,
|
|||||||
input_data: Option<Vec<u8>>) -> RustHttpResponse {
|
input_data: Option<Vec<u8>>) -> RustHttpResponse {
|
||||||
http_package::fetch(_my_method_to_hyper_method(method), url, headers, input_data).await.unwrap()
|
http_package::fetch(_my_method_to_hyper_method(method), url, headers, input_data).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn dns_lookup_txt(host: String) -> Vec<String> {
|
||||||
|
http_package::dns_lookup_txt(host).await.unwrap()
|
||||||
|
}
|
@ -94,6 +94,41 @@ let api_connection_count = <u8>::sse_decode(&mut deserializer);deserializer.end(
|
|||||||
})().await)
|
})().await)
|
||||||
} })
|
} })
|
||||||
}
|
}
|
||||||
|
fn wire_dns_lookup_txt_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "dns_lookup_txt",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
let api_host = <String>::sse_decode(&mut deserializer);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| async move {
|
||||||
|
transform_result_sse(
|
||||||
|
(move || async move {
|
||||||
|
Result::<_, ()>::Ok(crate::api::http_api::dns_lookup_txt(api_host).await)
|
||||||
|
})()
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire_fetch_impl(
|
fn wire_fetch_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
@ -244,6 +279,18 @@ impl SseDecode for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseDecode for Vec<String> {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut len_ = <i32>::sse_decode(deserializer);
|
||||||
|
let mut ans_ = vec![];
|
||||||
|
for idx_ in 0..len_ {
|
||||||
|
ans_.push(<String>::sse_decode(deserializer));
|
||||||
|
}
|
||||||
|
return ans_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseDecode for Vec<u8> {
|
impl SseDecode for Vec<u8> {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
@ -448,6 +495,7 @@ fn pde_ffi_dispatcher_primary_impl(
|
|||||||
match func_id {
|
match func_id {
|
||||||
2 => wire_cancel_download_impl(port, ptr, rust_vec_len, data_len),
|
2 => wire_cancel_download_impl(port, ptr, rust_vec_len, data_len),
|
||||||
1 => wire_start_download_impl(port, ptr, rust_vec_len, data_len),
|
1 => wire_start_download_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
5 => wire_dns_lookup_txt_impl(port, ptr, rust_vec_len, data_len),
|
||||||
4 => wire_fetch_impl(port, ptr, rust_vec_len, data_len),
|
4 => wire_fetch_impl(port, ptr, rust_vec_len, data_len),
|
||||||
3 => wire_set_default_header_impl(port, ptr, rust_vec_len, data_len),
|
3 => wire_set_default_header_impl(port, ptr, rust_vec_len, data_len),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -675,6 +723,16 @@ impl SseEncode for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseEncode for Vec<String> {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<i32>::sse_encode(self.len() as _, serializer);
|
||||||
|
for item in self {
|
||||||
|
<String>::sse_encode(item, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseEncode for Vec<u8> {
|
impl SseEncode for Vec<u8> {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
@ -3,8 +3,6 @@ use hickory_resolver::{lookup_ip::LookupIpIntoIter, TokioAsyncResolver};
|
|||||||
use hyper::client::connect::dns::Name;
|
use hyper::client::connect::dns::Name;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use reqwest::dns::{Addrs, Resolve, Resolving};
|
use reqwest::dns::{Addrs, Resolve, Resolving};
|
||||||
|
|
||||||
use std::io;
|
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -35,6 +33,17 @@ impl Resolve for MyHickoryDnsResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MyHickoryDnsResolver {
|
||||||
|
pub(crate) async fn lookup_txt(&self, name: String) -> anyhow::Result<Vec<String>> {
|
||||||
|
let resolver = self.state.get_or_try_init(new_resolver)?;
|
||||||
|
let txt = resolver.txt_lookup(name).await?;
|
||||||
|
let t = txt.iter()
|
||||||
|
.map(|rdata| rdata.to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ok(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Iterator for SocketAddrs {
|
impl Iterator for SocketAddrs {
|
||||||
type Item = SocketAddr;
|
type Item = SocketAddr;
|
||||||
|
|
||||||
|
@ -21,12 +21,13 @@ pub struct RustHttpResponse {
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref DEFAULT_HEADER: RwLock<HeaderMap> = RwLock::from(HeaderMap::new());
|
static ref DEFAULT_HEADER: RwLock<HeaderMap> = RwLock::from(HeaderMap::new());
|
||||||
|
static ref DNS_CLIENT : Arc<dns::MyHickoryDnsResolver> = Arc::from(dns::MyHickoryDnsResolver::default());
|
||||||
static ref HTTP_CLIENT: reqwest::Client = {
|
static ref HTTP_CLIENT: reqwest::Client = {
|
||||||
reqwest::Client::builder()
|
reqwest::Client::builder()
|
||||||
.use_rustls_tls()
|
.use_rustls_tls()
|
||||||
.connect_timeout(Duration::from_secs(10))
|
.connect_timeout(Duration::from_secs(10))
|
||||||
.timeout(Duration::from_secs(10))
|
.timeout(Duration::from_secs(10))
|
||||||
.dns_resolver(Arc::from(dns::MyHickoryDnsResolver::default()))
|
.dns_resolver(DNS_CLIENT.clone())
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
@ -83,6 +84,10 @@ pub async fn fetch(
|
|||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn dns_lookup_txt(name: String) -> anyhow::Result<Vec<String>> {
|
||||||
|
DNS_CLIENT.lookup_txt(name).await
|
||||||
|
}
|
||||||
|
|
||||||
fn _reade_resp_header(r_header: &HeaderMap) -> HashMap<String, String> {
|
fn _reade_resp_header(r_header: &HeaderMap) -> HashMap<String, String> {
|
||||||
let mut resp_headers = HashMap::new();
|
let mut resp_headers = HashMap::new();
|
||||||
for ele in r_header {
|
for ele in r_header {
|
||||||
|
Loading…
Reference in New Issue
Block a user