diff --git a/lib/foundation/js_engine.dart b/lib/foundation/js_engine.dart index 791215b..40fde70 100644 --- a/lib/foundation/js_engine.dart +++ b/lib/foundation/js_engine.dart @@ -25,6 +25,7 @@ import 'package:venera/components/js_ui.dart'; import 'package:venera/foundation/app.dart'; import 'package:venera/network/app_dio.dart'; import 'package:venera/network/cookie_jar.dart'; +import 'package:venera/network/proxy.dart'; import 'package:venera/utils/init.dart'; import 'comic_source/comic_source.dart'; @@ -194,7 +195,7 @@ class JsEngine with _JSEngineApi, JsUiApi, Init { responseType: ResponseType.plain, validateStatus: (status) => true, )); - var proxy = await AppDio.getProxy(); + var proxy = await getProxy(); dio.httpClientAdapter = IOHttpClientAdapter( createHttpClient: () { return HttpClient() diff --git a/lib/network/app_dio.dart b/lib/network/app_dio.dart index 4dc4393..f39b276 100644 --- a/lib/network/app_dio.dart +++ b/lib/network/app_dio.dart @@ -7,7 +7,7 @@ import 'package:rhttp/rhttp.dart' as rhttp; import 'package:venera/foundation/appdata.dart'; import 'package:venera/foundation/log.dart'; import 'package:venera/network/cache.dart'; -import 'package:venera/utils/ext.dart'; +import 'package:venera/network/proxy.dart'; import '../foundation/app.dart'; import 'cloudflare.dart'; @@ -96,9 +96,11 @@ class MyLogInterceptor implements Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - Log.info("Network", "${options.method} ${options.uri}\n" - "headers:\n${options.headers}\n" - "data:\n${options.data}"); + Log.info( + "Network", + "${options.method} ${options.uri}\n" + "headers:\n${options.headers}\n" + "data:\n${options.data}"); options.connectTimeout = const Duration(seconds: 15); options.receiveTimeout = const Duration(seconds: 15); options.sendTimeout = const Duration(seconds: 15); @@ -107,64 +109,15 @@ class MyLogInterceptor implements Interceptor { } class AppDio with DioMixin { - String? _proxy = proxy; - AppDio([BaseOptions? options]) { this.options = options ?? BaseOptions(); - httpClientAdapter = RHttpAdapter(rhttp.ClientSettings( - proxySettings: proxy == null - ? const rhttp.ProxySettings.noProxy() - : rhttp.ProxySettings.proxy(proxy!), - )); + httpClientAdapter = RHttpAdapter(); interceptors.add(CookieManagerSql(SingleInstanceCookieJar.instance!)); interceptors.add(NetworkCacheManager()); interceptors.add(CloudflareInterceptor()); interceptors.add(MyLogInterceptor()); } - static String? proxy; - - static Future getProxy() async { - if ((appdata.settings['proxy'] as String).removeAllBlank == "direct") { - return null; - } - if (appdata.settings['proxy'] != "system") return appdata.settings['proxy']; - - String res; - if (!App.isLinux) { - const channel = MethodChannel("venera/method_channel"); - try { - res = await channel.invokeMethod("getProxy"); - } catch (e) { - return null; - } - } else { - res = "No Proxy"; - } - if (res == "No Proxy") return null; - - if (res.contains(";")) { - var proxies = res.split(";"); - for (String proxy in proxies) { - proxy = proxy.removeAllBlank; - if (proxy.startsWith('https=')) { - return proxy.substring(6); - } - } - } - - final RegExp regex = RegExp( - r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', - caseSensitive: false, - multiLine: false, - ); - if (!regex.hasMatch(res)) { - return null; - } - - return res; - } - static final Map _requests = {}; @override @@ -184,16 +137,6 @@ class AppDio with DioMixin { _requests[path] = true; options!.headers!.remove('prevent-parallel'); } - proxy = await getProxy(); - if (_proxy != proxy) { - Log.info("Network", "Proxy changed to $proxy"); - _proxy = proxy; - httpClientAdapter = RHttpAdapter(rhttp.ClientSettings( - proxySettings: proxy == null - ? const rhttp.ProxySettings.noProxy() - : rhttp.ProxySettings.proxy(proxy!), - )); - } try { return super.request( path, @@ -213,7 +156,26 @@ class AppDio with DioMixin { } class RHttpAdapter implements HttpClientAdapter { - rhttp.ClientSettings settings; + Future get settings async { + var proxy = await getProxy(); + + return rhttp.ClientSettings( + proxySettings: proxy == null + ? const rhttp.ProxySettings.noProxy() + : rhttp.ProxySettings.proxy(proxy), + redirectSettings: const rhttp.RedirectSettings.limited(5), + timeoutSettings: const rhttp.TimeoutSettings( + connectTimeout: Duration(seconds: 15), + keepAliveTimeout: Duration(seconds: 60), + keepAlivePing: Duration(seconds: 30), + ), + throwOnStatusCode: false, + dnsSettings: rhttp.DnsSettings.static(overrides: _getOverrides()), + tlsSettings: rhttp.TlsSettings( + sni: appdata.settings['sni'] != false, + ), + ); + } static Map> _getOverrides() { if (!appdata.settings['enableDnsOverrides'] == true) { @@ -231,22 +193,6 @@ class RHttpAdapter implements HttpClientAdapter { return result; } - RHttpAdapter([this.settings = const rhttp.ClientSettings()]) { - settings = settings.copyWith( - redirectSettings: const rhttp.RedirectSettings.limited(5), - timeoutSettings: const rhttp.TimeoutSettings( - connectTimeout: Duration(seconds: 15), - keepAliveTimeout: Duration(seconds: 60), - keepAlivePing: Duration(seconds: 30), - ), - throwOnStatusCode: false, - dnsSettings: rhttp.DnsSettings.static(overrides: _getOverrides()), - tlsSettings: rhttp.TlsSettings( - sni: appdata.settings['sni'] != false, - ), - ); - } - @override void close({bool force = false}) {} @@ -256,10 +202,15 @@ class RHttpAdapter implements HttpClientAdapter { Stream? requestStream, Future? cancelFuture, ) async { + if (options.headers['User-Agent'] == null && + options.headers['user-agent'] == null) { + options.headers['User-Agent'] = "venera/v${App.version}"; + } + var res = await rhttp.Rhttp.request( method: rhttp.HttpMethod(options.method), url: options.uri.toString(), - settings: settings, + settings: await settings, expectBody: rhttp.HttpExpectBody.stream, body: requestStream == null ? null : rhttp.HttpBody.stream(requestStream), headers: rhttp.HttpHeaders.rawMap( @@ -289,7 +240,7 @@ class RHttpAdapter implements HttpClientAdapter { } static String _getStatusMessage(int statusCode) { - return switch(statusCode) { + return switch (statusCode) { 200 => "OK", 201 => "Created", 202 => "Accepted", @@ -299,9 +250,11 @@ class RHttpAdapter implements HttpClientAdapter { 302 => "Found", 400 => "Invalid Status Code 400: The Request is invalid.", 401 => "Invalid Status Code 401: The Request is unauthorized.", - 403 => "Invalid Status Code 403: No permission to access the resource. Check your account or network.", + 403 => + "Invalid Status Code 403: No permission to access the resource. Check your account or network.", 404 => "Invalid Status Code 404: Not found.", - 429 => "Invalid Status Code 429: Too many requests. Please try again later.", + 429 => + "Invalid Status Code 429: Too many requests. Please try again later.", _ => "Invalid Status Code $statusCode", }; } diff --git a/lib/network/file_downloader.dart b/lib/network/file_downloader.dart index 3d91643..77bedbc 100644 --- a/lib/network/file_downloader.dart +++ b/lib/network/file_downloader.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:dio/io.dart'; import 'package:venera/network/app_dio.dart'; +import 'package:venera/network/proxy.dart'; import 'package:venera/utils/ext.dart'; class FileDownloader { @@ -105,7 +106,7 @@ class FileDownloader { void _download(StreamController resultStream) async { try { - var proxy = await AppDio.getProxy(); + var proxy = await getProxy(); _dio.httpClientAdapter = IOHttpClientAdapter( createHttpClient: () { return HttpClient() diff --git a/lib/network/proxy.dart b/lib/network/proxy.dart new file mode 100644 index 0000000..400e6a1 --- /dev/null +++ b/lib/network/proxy.dart @@ -0,0 +1,60 @@ +import 'package:flutter/services.dart'; +import 'package:venera/foundation/app.dart'; +import 'package:venera/foundation/appdata.dart'; +import 'package:venera/utils/ext.dart'; + +String? _cachedProxy; + +DateTime? _cachedProxyTime; + +Future getProxy() async { + if (_cachedProxyTime != null && + DateTime.now().difference(_cachedProxyTime!).inSeconds < 1) { + return _cachedProxy; + } + String? proxy = await _getProxy(); + _cachedProxy = proxy; + _cachedProxyTime = DateTime.now(); + return proxy; +} + +Future _getProxy() async { + if ((appdata.settings['proxy'] as String).removeAllBlank == "direct") { + return null; + } + if (appdata.settings['proxy'] != "system") return appdata.settings['proxy']; + + String res; + if (!App.isLinux) { + const channel = MethodChannel("venera/method_channel"); + try { + res = await channel.invokeMethod("getProxy"); + } catch (e) { + return null; + } + } else { + res = "No Proxy"; + } + if (res == "No Proxy") return null; + + if (res.contains(";")) { + var proxies = res.split(";"); + for (String proxy in proxies) { + proxy = proxy.removeAllBlank; + if (proxy.startsWith('https=')) { + return proxy.substring(6); + } + } + } + + final RegExp regex = RegExp( + r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', + caseSensitive: false, + multiLine: false, + ); + if (!regex.hasMatch(res)) { + return null; + } + + return res; +} diff --git a/lib/pages/webview.dart b/lib/pages/webview.dart index c81e140..212daaf 100644 --- a/lib/pages/webview.dart +++ b/lib/pages/webview.dart @@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:venera/components/components.dart'; import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/appdata.dart'; -import 'package:venera/network/app_dio.dart'; +import 'package:venera/network/proxy.dart'; import 'package:venera/utils/ext.dart'; import 'package:venera/utils/translations.dart'; import 'dart:io' as io; @@ -308,7 +308,7 @@ class DesktopWebview { useWindowPositionAndSize: true, userDataFolderWindows: "${App.dataPath}\\webview", title: "webview", - proxy: AppDio.proxy, + proxy: await getProxy(), )); _webview!.addOnWebMessageReceivedCallback(onMessage); _webview!.setOnNavigation((s) { diff --git a/lib/utils/data_sync.dart b/lib/utils/data_sync.dart index 12bd7cc..52b890d 100644 --- a/lib/utils/data_sync.dart +++ b/lib/utils/data_sync.dart @@ -11,7 +11,6 @@ import 'package:venera/network/app_dio.dart'; import 'package:venera/utils/data.dart'; import 'package:venera/utils/ext.dart'; import 'package:webdav_client/webdav_client.dart' hide File; -import 'package:rhttp/rhttp.dart' as rhttp; import 'package:venera/utils/translations.dart'; import 'io.dart'; @@ -119,19 +118,11 @@ class DataSync with ChangeNotifier { String user = config[1]; String pass = config[2]; - var proxy = await AppDio.getProxy(); - var client = newClient( url, user: user, password: pass, - adapter: RHttpAdapter( - rhttp.ClientSettings( - proxySettings: - proxy == null ? null : rhttp.ProxySettings.proxy(proxy), - userAgent: "venera v${App.version}", - ), - ), + adapter: RHttpAdapter(), ); try { @@ -192,19 +183,11 @@ class DataSync with ChangeNotifier { String user = config[1]; String pass = config[2]; - var proxy = await AppDio.getProxy(); - var client = newClient( url, user: user, password: pass, - adapter: RHttpAdapter( - rhttp.ClientSettings( - proxySettings: - proxy == null ? null : rhttp.ProxySettings.proxy(proxy), - userAgent: "venera v${App.version}", - ), - ), + adapter: RHttpAdapter(), ); try {