Add Supa account and search changes
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2026 Fabian Freund.
|
||||
*
|
||||
* This file is part of WebLibre
|
||||
* (see https://weblibre.eu).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/io_client.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:socks5_proxy/socks_client.dart';
|
||||
import 'package:weblibre/features/search_credits/domain/repositories/web_search_settings.dart';
|
||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
||||
|
||||
part 'proxy_client.g.dart';
|
||||
|
||||
/// Resolved Tor SOCKS5 port for search traffic, or `null` when search should
|
||||
/// route directly. Returns non-null only when the user has enabled the
|
||||
/// "route search through Tor" toggle AND Tor is currently running with a
|
||||
/// known SOCKS port.
|
||||
@Riverpod(keepAlive: true)
|
||||
int? searchProxyPort(Ref ref) {
|
||||
final route = ref.watch(
|
||||
webSearchSettingsControllerProvider.select((s) => s.routeThroughTor),
|
||||
);
|
||||
if (!route) return null;
|
||||
final status = ref.watch(torProxyServiceProvider).value;
|
||||
if (status == null || !status.isRunning || status.bootstrapProgress < 100) {
|
||||
return null;
|
||||
}
|
||||
return status.socksPort;
|
||||
}
|
||||
|
||||
/// HttpClient used by both WebSocket (via `IOWebSocketChannel.customClient`)
|
||||
/// and HTTP-based search clients. SOCKS5-routed when Tor toggle is on, plain
|
||||
/// otherwise. Rebuilt when the proxy port changes.
|
||||
@Riverpod(keepAlive: true)
|
||||
HttpClient searchHttpClient(Ref ref) {
|
||||
final port = ref.watch(searchProxyPortProvider);
|
||||
final client = HttpClient()
|
||||
// The default HttpClient has no connection timeout, so a search service
|
||||
// that is unreachable can stall the UI for ~minute(s) before failing.
|
||||
// Cap the TCP/TLS handshake at a few seconds so the user sees an error
|
||||
// quickly and can retry; the WebSocket session itself imposes no
|
||||
// ceiling on long-running streams once connected.
|
||||
..connectionTimeout = const Duration(seconds: 25);
|
||||
if (port != null) {
|
||||
SocksTCPClient.assignToHttpClient(client, [
|
||||
ProxySettings(InternetAddress.loopbackIPv4, port),
|
||||
]);
|
||||
}
|
||||
ref.onDispose(() => client.close(force: true));
|
||||
return client;
|
||||
}
|
||||
|
||||
/// `package:http` Client wrapping [searchHttpClientProvider]. Use for the
|
||||
/// non-WebSocket parts of the search flow (token issuance, one-shot capture,
|
||||
/// capture artifact downloads).
|
||||
@Riverpod(keepAlive: true)
|
||||
http.Client searchProxyHttpClient(Ref ref) {
|
||||
final httpClient = ref.watch(searchHttpClientProvider);
|
||||
// IOClient does not own the HttpClient lifetime here — the underlying
|
||||
// HttpClient is closed by the searchHttpClientProvider's onDispose. Don't
|
||||
// close the IOClient on dispose to avoid prematurely tearing down the
|
||||
// shared HttpClient on rebuild.
|
||||
return IOClient(httpClient);
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'proxy_client.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Resolved Tor SOCKS5 port for search traffic, or `null` when search should
|
||||
/// route directly. Returns non-null only when the user has enabled the
|
||||
/// "route search through Tor" toggle AND Tor is currently running with a
|
||||
/// known SOCKS port.
|
||||
|
||||
@ProviderFor(searchProxyPort)
|
||||
final searchProxyPortProvider = SearchProxyPortProvider._();
|
||||
|
||||
/// Resolved Tor SOCKS5 port for search traffic, or `null` when search should
|
||||
/// route directly. Returns non-null only when the user has enabled the
|
||||
/// "route search through Tor" toggle AND Tor is currently running with a
|
||||
/// known SOCKS port.
|
||||
|
||||
final class SearchProxyPortProvider
|
||||
extends $FunctionalProvider<int?, int?, int?>
|
||||
with $Provider<int?> {
|
||||
/// Resolved Tor SOCKS5 port for search traffic, or `null` when search should
|
||||
/// route directly. Returns non-null only when the user has enabled the
|
||||
/// "route search through Tor" toggle AND Tor is currently running with a
|
||||
/// known SOCKS port.
|
||||
SearchProxyPortProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'searchProxyPortProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$searchProxyPortHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<int?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
int? create(Ref ref) {
|
||||
return searchProxyPort(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(int? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<int?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$searchProxyPortHash() => r'759420a65b9a1375ff9595de2a0dcbf174ae3e79';
|
||||
|
||||
/// HttpClient used by both WebSocket (via `IOWebSocketChannel.customClient`)
|
||||
/// and HTTP-based search clients. SOCKS5-routed when Tor toggle is on, plain
|
||||
/// otherwise. Rebuilt when the proxy port changes.
|
||||
|
||||
@ProviderFor(searchHttpClient)
|
||||
final searchHttpClientProvider = SearchHttpClientProvider._();
|
||||
|
||||
/// HttpClient used by both WebSocket (via `IOWebSocketChannel.customClient`)
|
||||
/// and HTTP-based search clients. SOCKS5-routed when Tor toggle is on, plain
|
||||
/// otherwise. Rebuilt when the proxy port changes.
|
||||
|
||||
final class SearchHttpClientProvider
|
||||
extends $FunctionalProvider<HttpClient, HttpClient, HttpClient>
|
||||
with $Provider<HttpClient> {
|
||||
/// HttpClient used by both WebSocket (via `IOWebSocketChannel.customClient`)
|
||||
/// and HTTP-based search clients. SOCKS5-routed when Tor toggle is on, plain
|
||||
/// otherwise. Rebuilt when the proxy port changes.
|
||||
SearchHttpClientProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'searchHttpClientProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$searchHttpClientHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<HttpClient> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
HttpClient create(Ref ref) {
|
||||
return searchHttpClient(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(HttpClient value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<HttpClient>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$searchHttpClientHash() => r'b3aa4b658e99fb580031ac412fabfbeece5fe830';
|
||||
|
||||
/// `package:http` Client wrapping [searchHttpClientProvider]. Use for the
|
||||
/// non-WebSocket parts of the search flow (token issuance, one-shot capture,
|
||||
/// capture artifact downloads).
|
||||
|
||||
@ProviderFor(searchProxyHttpClient)
|
||||
final searchProxyHttpClientProvider = SearchProxyHttpClientProvider._();
|
||||
|
||||
/// `package:http` Client wrapping [searchHttpClientProvider]. Use for the
|
||||
/// non-WebSocket parts of the search flow (token issuance, one-shot capture,
|
||||
/// capture artifact downloads).
|
||||
|
||||
final class SearchProxyHttpClientProvider
|
||||
extends $FunctionalProvider<http.Client, http.Client, http.Client>
|
||||
with $Provider<http.Client> {
|
||||
/// `package:http` Client wrapping [searchHttpClientProvider]. Use for the
|
||||
/// non-WebSocket parts of the search flow (token issuance, one-shot capture,
|
||||
/// capture artifact downloads).
|
||||
SearchProxyHttpClientProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'searchProxyHttpClientProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$searchProxyHttpClientHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<http.Client> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
http.Client create(Ref ref) {
|
||||
return searchProxyHttpClient(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(http.Client value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<http.Client>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$searchProxyHttpClientHash() =>
|
||||
r'08acee399abc5c6960a82365219af6b5a44ba5bd';
|
||||
Reference in New Issue
Block a user