Update m_client.dart

- getCookiesPref() and deleteAllCookies():
Avoid repeated parsing of `Uri.parse(url).host` by creating a variable.

- httpClient():
cache RhttpCompatibleClients and add default IOClient fallback.

- shouldAttemptRetryOnResponse():
Added a delay to avoid busy looping.
This commit is contained in:
Enbiya Olgun 2025-04-25 02:43:33 +02:00
parent 4f1e2cb492
commit ca4cee5751

View file

@ -15,6 +15,8 @@ import 'package:mangayomi/services/http/rhttp/rhttp.dart' as rhttp;
class MClient { class MClient {
MClient(); MClient();
static final defaultClient = IOClient(HttpClient());
static final Map<rhttp.ClientSettings, Client> rhttpPool = {};
static Client httpClient({ static Client httpClient({
Map<String, dynamic>? reqcopyWith, Map<String, dynamic>? reqcopyWith,
rhttp.ClientSettings? settings, rhttp.ClientSettings? settings,
@ -41,10 +43,12 @@ class MClient {
verifyCertificates: reqcopyWith?["verifyCertificates"] ?? false, verifyCertificates: reqcopyWith?["verifyCertificates"] ?? false,
), ),
); );
return rhttp.RhttpCompatibleClient.createSync(settings: settings); return rhttpPool.putIfAbsent(settings, () {
return rhttp.RhttpCompatibleClient.createSync(settings: settings);
});
} catch (_) {} } catch (_) {}
} }
return IOClient(HttpClient()); return defaultClient;
} }
static InterceptedClient init({ static InterceptedClient init({
@ -66,12 +70,11 @@ class MClient {
static Map<String, String> getCookiesPref(String url) { static Map<String, String> getCookiesPref(String url) {
final cookiesList = isar.settings.getSync(227)!.cookiesList ?? []; final cookiesList = isar.settings.getSync(227)!.cookiesList ?? [];
if (cookiesList.isEmpty) return {}; if (cookiesList.isEmpty) return {};
final host = Uri.parse(url).host;
final cookies = final cookies =
cookiesList cookiesList
.firstWhere( .firstWhere(
(element) => (element) => element.host == host || host.contains(element.host!),
element.host == Uri.parse(url).host ||
Uri.parse(url).host.contains(element.host!),
orElse: () => MCookie(cookie: ""), orElse: () => MCookie(cookie: ""),
) )
.cookie!; .cookie!;
@ -93,56 +96,51 @@ class MClient {
.split(RegExp('(?<=)(,)(?=[^;]+?=)')) .split(RegExp('(?<=)(,)(?=[^;]+?=)'))
.where((cookie) => cookie.isNotEmpty) .where((cookie) => cookie.isNotEmpty)
.toList(); .toList();
} else { } else if (!Platform.isLinux) {
if (!Platform.isLinux) { cookies =
cookies = (await flutter_inappwebview.CookieManager.instance(
(await flutter_inappwebview.CookieManager.instance( webViewEnvironment: webViewEnvironment,
webViewEnvironment: webViewEnvironment, ).getCookies(
).getCookies( url: flutter_inappwebview.WebUri(url),
url: flutter_inappwebview.WebUri(url), webViewController: webViewController,
webViewController: webViewController, )).map((e) => "${e.name}=${e.value}").toList();
)).map((e) => "${e.name}=${e.value}").toList();
}
} }
if (cookies.isNotEmpty) { if (cookies.isNotEmpty) {
final host = Uri.parse(url).host; final host = Uri.parse(url).host;
final newCookie = cookies.join("; "); final newCookie = cookies.join("; ");
final settings = isar.settings.getSync(227); final settings = await isar.settings.get(227);
List<MCookie>? cookieList = []; final existingCookies = settings!.cookiesList ?? [];
for (var cookie in settings!.cookiesList ?? []) { final filteredCookies = removeCookiesForHost(existingCookies, host);
if (cookie.host != host || (!host.contains(cookie.host))) { filteredCookies.add(
cookieList.add(cookie);
}
}
cookieList.add(
MCookie() MCookie()
..host = host ..host = host
..cookie = newCookie, ..cookie = newCookie,
); );
isar.writeTxnSync( await isar.writeTxn(
() => isar.settings.putSync(settings..cookiesList = cookieList), () => isar.settings.put(settings..cookiesList = filteredCookies),
); );
} }
if (ua.isNotEmpty) { if (ua.isNotEmpty) {
final settings = isar.settings.getSync(227); final settings = await isar.settings.get(227);
isar.writeTxnSync(() => isar.settings.putSync(settings!..userAgent = ua)); await isar.writeTxn(() => isar.settings.put(settings!..userAgent = ua));
} }
} }
static void deleteAllCookies(String url) { static List<MCookie> removeCookiesForHost(
final cookiesList = isar.settings.getSync(227)!.cookiesList ?? []; List<MCookie> allCookies,
List<MCookie>? cookieList = []; String host,
for (var cookie in cookiesList) { ) {
if (!(cookie.host == Uri.parse(url).host || return allCookies
Uri.parse(url).host.contains(cookie.host!))) { .where((cookie) => cookie.host != host && !host.contains(cookie.host!))
cookieList.add(cookie); .toList();
} }
}
isar.writeTxnSync( static Future<void> deleteAllCookies(String url) async {
() => isar.settings.putSync( final settings = await isar.settings.get(227);
isar.settings.getSync(227)!..cookiesList = cookieList, final oldCookies = settings!.cookiesList ?? [];
), final host = Uri.parse(url).host;
); settings.cookiesList = removeCookiesForHost(oldCookies, host);
await isar.writeTxn(() => isar.settings.put(settings));
} }
} }
@ -154,7 +152,8 @@ class MCookieManager extends InterceptorContract {
Future<BaseRequest> interceptRequest({required BaseRequest request}) async { Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
final cookie = MClient.getCookiesPref(request.url.toString()); final cookie = MClient.getCookiesPref(request.url.toString());
if (cookie.isNotEmpty) { if (cookie.isNotEmpty) {
final userAgent = isar.settings.getSync(227)!.userAgent!; final settings = await isar.settings.get(227);
final userAgent = settings!.userAgent!;
if (request.headers[HttpHeaders.cookieHeader] == null) { if (request.headers[HttpHeaders.cookieHeader] == null) {
request.headers.addAll(cookie); request.headers.addAll(cookie);
} }
@ -211,12 +210,7 @@ class LoggerInterceptor extends InterceptorContract {
required BaseResponse response, required BaseResponse response,
}) async { }) async {
if (showCloudFlareError) { if (showCloudFlareError) {
final cloudflare = final cloudflare = isCloudflare(response);
[403, 503].contains(response.statusCode) &&
[
"cloudflare-nginx",
"cloudflare",
].contains(response.headers["server"]);
final content = final content =
"----- Response -----\n${response.request?.method}: ${response.request?.url}, statusCode: ${response.statusCode} ${cloudflare ? "Failed to bypass Cloudflare" : ""}"; "----- Response -----\n${response.request?.method}: ${response.request?.url}, statusCode: ${response.statusCode} ${cloudflare ? "Failed to bypass Cloudflare" : ""}";
if (kDebugMode) { if (kDebugMode) {
@ -238,6 +232,11 @@ class LoggerInterceptor extends InterceptorContract {
} }
} }
bool isCloudflare(BaseResponse response) {
return [403, 503].contains(response.statusCode) &&
["cloudflare-nginx", "cloudflare"].contains(response.headers["server"]);
}
class ResolveCloudFlareChallenge extends RetryPolicy { class ResolveCloudFlareChallenge extends RetryPolicy {
bool showCloudFlareError; bool showCloudFlareError;
ResolveCloudFlareChallenge(this.showCloudFlareError); ResolveCloudFlareChallenge(this.showCloudFlareError);
@ -249,11 +248,8 @@ class ResolveCloudFlareChallenge extends RetryPolicy {
flutter_inappwebview.HeadlessInAppWebView? headlessWebView; flutter_inappwebview.HeadlessInAppWebView? headlessWebView;
int time = 0; int time = 0;
bool timeOut = false; bool timeOut = false;
final cloudflare = bool isCloudFlare = isCloudflare(response);
[403, 503].contains(response.statusCode) && if (isCloudFlare) {
["cloudflare-nginx", "cloudflare"].contains(response.headers["server"]);
if (cloudflare) {
bool isCloudFlare = true;
headlessWebView = flutter_inappwebview.HeadlessInAppWebView( headlessWebView = flutter_inappwebview.HeadlessInAppWebView(
webViewEnvironment: webViewEnvironment, webViewEnvironment: webViewEnvironment,
initialUrlRequest: flutter_inappwebview.URLRequest( initialUrlRequest: flutter_inappwebview.URLRequest(
@ -270,10 +266,7 @@ class ResolveCloudFlareChallenge extends RetryPolicy {
} }
await Future.doWhile(() async { await Future.doWhile(() async {
if (timeOut == true) { if (!timeOut && isCloudFlare) {
return false;
}
if (isCloudFlare) {
try { try {
isCloudFlare = await controller.platform.evaluateJavascript( isCloudFlare = await controller.platform.evaluateJavascript(
source: source:
@ -282,9 +275,10 @@ class ResolveCloudFlareChallenge extends RetryPolicy {
} catch (_) { } catch (_) {
isCloudFlare = false; isCloudFlare = false;
} }
return true;
} }
return false; if (isCloudFlare) await Future.delayed(Duration(milliseconds: 300));
return isCloudFlare;
}); });
if (!timeOut) { if (!timeOut) {
final ua = final ua =