improved settings replication
This commit is contained in:
+45
-12
@@ -18,21 +18,20 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import 'package:fast_equatable/fast_equatable.dart';
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
|
||||||
import 'package:nullability/nullability.dart';
|
import 'package:nullability/nullability.dart';
|
||||||
import 'package:riverpod/riverpod.dart';
|
import 'package:riverpod/riverpod.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:weblibre/core/logger.dart';
|
import 'package:weblibre/core/logger.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||||
|
import 'package:weblibre/features/tor/domain/repositories/tor_proxy.dart';
|
||||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
||||||
|
import 'package:weblibre/features/user/data/models/tor_settings.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
|
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
|
||||||
|
|
||||||
part 'proxy_settings_replication.g.dart';
|
part 'proxy_settings_replication.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class ProxySettingsReplication extends _$ProxySettingsReplication {
|
class ProxySettingsReplication extends _$ProxySettingsReplication {
|
||||||
final _service = GeckoContainerProxyService();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void build() {
|
void build() {
|
||||||
ref.listen(
|
ref.listen(
|
||||||
@@ -40,7 +39,9 @@ class ProxySettingsReplication extends _$ProxySettingsReplication {
|
|||||||
torProxyServiceProvider.select((data) => data.value),
|
torProxyServiceProvider.select((data) => data.value),
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
await _service.setProxyPort(next);
|
await ref
|
||||||
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
|
.setProxyPort(next);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (error, stackTrace) {
|
onError: (error, stackTrace) {
|
||||||
@@ -62,13 +63,15 @@ class ProxySettingsReplication extends _$ProxySettingsReplication {
|
|||||||
for (final container in next.value!) {
|
for (final container in next.value!) {
|
||||||
if (container.metadata.contextualIdentity.isNotEmpty) {
|
if (container.metadata.contextualIdentity.isNotEmpty) {
|
||||||
if (container.metadata.useProxy) {
|
if (container.metadata.useProxy) {
|
||||||
await _service.addContainerProxy(
|
await ref
|
||||||
container.metadata.contextualIdentity!,
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
);
|
.addContainerProxy(container.metadata.contextualIdentity!);
|
||||||
} else {
|
} else {
|
||||||
await _service.removeContainerProxy(
|
await ref
|
||||||
container.metadata.contextualIdentity!,
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
);
|
.removeContainerProxy(
|
||||||
|
container.metadata.contextualIdentity!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,9 +93,39 @@ class ProxySettingsReplication extends _$ProxySettingsReplication {
|
|||||||
),
|
),
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
if (next) {
|
if (next) {
|
||||||
await _service.addContainerProxy('private');
|
await ref
|
||||||
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
|
.addContainerProxy('private');
|
||||||
} else {
|
} else {
|
||||||
await _service.removeContainerProxy('private');
|
await ref
|
||||||
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
|
.removeContainerProxy('private');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error, stackTrace) {
|
||||||
|
logger.e(
|
||||||
|
'Error listening to generalSettingsRepositoryProvider',
|
||||||
|
error: error,
|
||||||
|
stackTrace: stackTrace,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.listen(
|
||||||
|
fireImmediately: true,
|
||||||
|
torSettingsWithDefaultsProvider.select(
|
||||||
|
(value) => value.proxyRegularTabsMode,
|
||||||
|
),
|
||||||
|
(previous, next) async {
|
||||||
|
switch (next) {
|
||||||
|
case TorRegularTabProxyMode.container:
|
||||||
|
await ref
|
||||||
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
|
.removeContainerProxy('general');
|
||||||
|
case TorRegularTabProxyMode.all:
|
||||||
|
await ref
|
||||||
|
.read(torProxyRepositoryProvider.notifier)
|
||||||
|
.addContainerProxy('general');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (error, stackTrace) {
|
onError: (error, stackTrace) {
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ final class ProxySettingsReplicationProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$proxySettingsReplicationHash() =>
|
String _$proxySettingsReplicationHash() =>
|
||||||
r'787545f882b97274dc67007a6404f170d40bdb64';
|
r'46063662e3aca4f38a6876f4265ada9a87bde6dc';
|
||||||
|
|
||||||
abstract class _$ProxySettingsReplication extends $Notifier<void> {
|
abstract class _$ProxySettingsReplication extends $Notifier<void> {
|
||||||
void build();
|
void build();
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
part 'tor_proxy.g.dart';
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class TorProxyRepository extends _$TorProxyRepository {
|
||||||
|
final _service = GeckoContainerProxyService();
|
||||||
|
final _serviceLock = Lock();
|
||||||
|
|
||||||
|
Future<void> setProxyPort(int port) {
|
||||||
|
return _serviceLock.synchronized(() async {
|
||||||
|
await _waitHealthcheck().timeout(const Duration(seconds: 10));
|
||||||
|
|
||||||
|
return _service.setProxyPort(port);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addContainerProxy(String contextId) {
|
||||||
|
return _serviceLock.synchronized(() async {
|
||||||
|
await _waitHealthcheck().timeout(const Duration(seconds: 10));
|
||||||
|
|
||||||
|
return _service.addContainerProxy(contextId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeContainerProxy(String contextId) {
|
||||||
|
return _serviceLock.synchronized(() async {
|
||||||
|
await _waitHealthcheck().timeout(const Duration(seconds: 10));
|
||||||
|
|
||||||
|
return _service.removeContainerProxy(contextId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _waitHealthcheck({
|
||||||
|
Duration timeout = const Duration(seconds: 15),
|
||||||
|
}) async {
|
||||||
|
final startTime = DateTime.now();
|
||||||
|
|
||||||
|
var healthy = await _service.healthcheck();
|
||||||
|
while (!healthy) {
|
||||||
|
if (DateTime.now().difference(startTime) > timeout) {
|
||||||
|
throw TimeoutException('Timed out waiting for proxy service');
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(milliseconds: 25));
|
||||||
|
healthy = await _service.healthcheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void build() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'tor_proxy.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
|
@ProviderFor(TorProxyRepository)
|
||||||
|
const torProxyRepositoryProvider = TorProxyRepositoryProvider._();
|
||||||
|
|
||||||
|
final class TorProxyRepositoryProvider
|
||||||
|
extends $NotifierProvider<TorProxyRepository, void> {
|
||||||
|
const TorProxyRepositoryProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'torProxyRepositoryProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$torProxyRepositoryHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
TorProxyRepository create() => TorProxyRepository();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(void value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<void>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$torProxyRepositoryHash() =>
|
||||||
|
r'dd565140620a1f66090e84e541d5ea8e34ab0094';
|
||||||
|
|
||||||
|
abstract class _$TorProxyRepository extends $Notifier<void> {
|
||||||
|
void build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
build();
|
||||||
|
final ref = this.ref as $Ref<void, void>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<void, void>,
|
||||||
|
void,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,15 +25,19 @@ part 'tor_settings.g.dart';
|
|||||||
|
|
||||||
enum TorConnectionConfig { auto, direct, obfs4, snowflake }
|
enum TorConnectionConfig { auto, direct, obfs4, snowflake }
|
||||||
|
|
||||||
|
enum TorRegularTabProxyMode { container, all }
|
||||||
|
|
||||||
@CopyWith()
|
@CopyWith()
|
||||||
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
||||||
class TorSettings with FastEquatable {
|
class TorSettings with FastEquatable {
|
||||||
|
final TorRegularTabProxyMode proxyRegularTabsMode;
|
||||||
final bool proxyPrivateTabsTor;
|
final bool proxyPrivateTabsTor;
|
||||||
final TorConnectionConfig config;
|
final TorConnectionConfig config;
|
||||||
final bool requireBridge;
|
final bool requireBridge;
|
||||||
final bool fetchRemoteBridges;
|
final bool fetchRemoteBridges;
|
||||||
|
|
||||||
TorSettings({
|
TorSettings({
|
||||||
|
required this.proxyRegularTabsMode,
|
||||||
required this.proxyPrivateTabsTor,
|
required this.proxyPrivateTabsTor,
|
||||||
required this.config,
|
required this.config,
|
||||||
required this.requireBridge,
|
required this.requireBridge,
|
||||||
@@ -41,11 +45,14 @@ class TorSettings with FastEquatable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
TorSettings.withDefaults({
|
TorSettings.withDefaults({
|
||||||
|
TorRegularTabProxyMode? proxyRegularTabsMode,
|
||||||
bool? proxyPrivateTabsTor,
|
bool? proxyPrivateTabsTor,
|
||||||
TorConnectionConfig? config,
|
TorConnectionConfig? config,
|
||||||
bool? requireBridge,
|
bool? requireBridge,
|
||||||
bool? fetchRemoteBridges,
|
bool? fetchRemoteBridges,
|
||||||
}) : proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
}) : proxyRegularTabsMode =
|
||||||
|
proxyRegularTabsMode ?? TorRegularTabProxyMode.container,
|
||||||
|
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
||||||
config = config ?? TorConnectionConfig.auto,
|
config = config ?? TorConnectionConfig.auto,
|
||||||
requireBridge = requireBridge ?? false,
|
requireBridge = requireBridge ?? false,
|
||||||
fetchRemoteBridges = fetchRemoteBridges ?? true;
|
fetchRemoteBridges = fetchRemoteBridges ?? true;
|
||||||
@@ -57,6 +64,7 @@ class TorSettings with FastEquatable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get hashParameters => [
|
List<Object?> get hashParameters => [
|
||||||
|
proxyRegularTabsMode,
|
||||||
proxyPrivateTabsTor,
|
proxyPrivateTabsTor,
|
||||||
config,
|
config,
|
||||||
requireBridge,
|
requireBridge,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ part of 'tor_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
abstract class _$TorSettingsCWProxy {
|
abstract class _$TorSettingsCWProxy {
|
||||||
|
TorSettings proxyRegularTabsMode(TorRegularTabProxyMode proxyRegularTabsMode);
|
||||||
|
|
||||||
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
||||||
|
|
||||||
TorSettings config(TorConnectionConfig config);
|
TorSettings config(TorConnectionConfig config);
|
||||||
@@ -23,6 +25,7 @@ abstract class _$TorSettingsCWProxy {
|
|||||||
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
||||||
/// ```
|
/// ```
|
||||||
TorSettings call({
|
TorSettings call({
|
||||||
|
TorRegularTabProxyMode proxyRegularTabsMode,
|
||||||
bool proxyPrivateTabsTor,
|
bool proxyPrivateTabsTor,
|
||||||
TorConnectionConfig config,
|
TorConnectionConfig config,
|
||||||
bool requireBridge,
|
bool requireBridge,
|
||||||
@@ -37,6 +40,11 @@ class _$TorSettingsCWProxyImpl implements _$TorSettingsCWProxy {
|
|||||||
|
|
||||||
final TorSettings _value;
|
final TorSettings _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TorSettings proxyRegularTabsMode(
|
||||||
|
TorRegularTabProxyMode proxyRegularTabsMode,
|
||||||
|
) => call(proxyRegularTabsMode: proxyRegularTabsMode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
||||||
call(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
call(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||||
@@ -61,12 +69,19 @@ class _$TorSettingsCWProxyImpl implements _$TorSettingsCWProxy {
|
|||||||
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
||||||
/// ```
|
/// ```
|
||||||
TorSettings call({
|
TorSettings call({
|
||||||
|
Object? proxyRegularTabsMode = const $CopyWithPlaceholder(),
|
||||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
Object? config = const $CopyWithPlaceholder(),
|
Object? config = const $CopyWithPlaceholder(),
|
||||||
Object? requireBridge = const $CopyWithPlaceholder(),
|
Object? requireBridge = const $CopyWithPlaceholder(),
|
||||||
Object? fetchRemoteBridges = const $CopyWithPlaceholder(),
|
Object? fetchRemoteBridges = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return TorSettings(
|
return TorSettings(
|
||||||
|
proxyRegularTabsMode:
|
||||||
|
proxyRegularTabsMode == const $CopyWithPlaceholder() ||
|
||||||
|
proxyRegularTabsMode == null
|
||||||
|
? _value.proxyRegularTabsMode
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: proxyRegularTabsMode as TorRegularTabProxyMode,
|
||||||
proxyPrivateTabsTor:
|
proxyPrivateTabsTor:
|
||||||
proxyPrivateTabsTor == const $CopyWithPlaceholder() ||
|
proxyPrivateTabsTor == const $CopyWithPlaceholder() ||
|
||||||
proxyPrivateTabsTor == null
|
proxyPrivateTabsTor == null
|
||||||
@@ -105,6 +120,10 @@ extension $TorSettingsCopyWith on TorSettings {
|
|||||||
|
|
||||||
TorSettings _$TorSettingsFromJson(Map<String, dynamic> json) =>
|
TorSettings _$TorSettingsFromJson(Map<String, dynamic> json) =>
|
||||||
TorSettings.withDefaults(
|
TorSettings.withDefaults(
|
||||||
|
proxyRegularTabsMode: $enumDecodeNullable(
|
||||||
|
_$TorRegularTabProxyModeEnumMap,
|
||||||
|
json['proxyRegularTabsMode'],
|
||||||
|
),
|
||||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||||
config: $enumDecodeNullable(_$TorConnectionConfigEnumMap, json['config']),
|
config: $enumDecodeNullable(_$TorConnectionConfigEnumMap, json['config']),
|
||||||
requireBridge: json['requireBridge'] as bool?,
|
requireBridge: json['requireBridge'] as bool?,
|
||||||
@@ -113,12 +132,19 @@ TorSettings _$TorSettingsFromJson(Map<String, dynamic> json) =>
|
|||||||
|
|
||||||
Map<String, dynamic> _$TorSettingsToJson(TorSettings instance) =>
|
Map<String, dynamic> _$TorSettingsToJson(TorSettings instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
|
'proxyRegularTabsMode':
|
||||||
|
_$TorRegularTabProxyModeEnumMap[instance.proxyRegularTabsMode]!,
|
||||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||||
'config': _$TorConnectionConfigEnumMap[instance.config]!,
|
'config': _$TorConnectionConfigEnumMap[instance.config]!,
|
||||||
'requireBridge': instance.requireBridge,
|
'requireBridge': instance.requireBridge,
|
||||||
'fetchRemoteBridges': instance.fetchRemoteBridges,
|
'fetchRemoteBridges': instance.fetchRemoteBridges,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _$TorRegularTabProxyModeEnumMap = {
|
||||||
|
TorRegularTabProxyMode.container: 'container',
|
||||||
|
TorRegularTabProxyMode.all: 'all',
|
||||||
|
};
|
||||||
|
|
||||||
const _$TorConnectionConfigEnumMap = {
|
const _$TorConnectionConfigEnumMap = {
|
||||||
TorConnectionConfig.auto: 'auto',
|
TorConnectionConfig.auto: 'auto',
|
||||||
TorConnectionConfig.direct: 'direct',
|
TorConnectionConfig.direct: 'direct',
|
||||||
|
|||||||
Reference in New Issue
Block a user