stack_wallet/lib/services/tor_service.dart

142 lines
3.9 KiB
Dart
Raw Normal View History

import 'dart:io';
2023-08-07 16:39:04 +00:00
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:tor_ffi_plugin/tor_ffi_plugin.dart';
2023-08-07 16:39:04 +00:00
2023-08-07 16:46:34 +00:00
final pTorService = Provider((_) => TorService.sharedInstance);
2023-08-07 16:39:04 +00:00
class TorService {
Tor? _tor;
2023-09-15 18:10:51 +00:00
/// Current status. Same as that fired on the event bus
TorConnectionStatus get status => _status;
// set to some default value
TorConnectionStatus _status = TorConnectionStatus.disconnected;
/// Flag to indicate that a Tor circuit is thought to have been established.
bool _enabled = false;
/// Getter for the enabled flag.
bool get enabled => _enabled;
TorService._();
/// Singleton instance of the TorService.
///
/// Use this to access the TorService and its properties.
static final sharedInstance = TorService._();
2023-08-07 16:39:04 +00:00
/// Getter for the proxyInfo.
({
InternetAddress host,
int port,
}) get proxyInfo => (
host: InternetAddress.loopbackIPv4,
2023-09-15 18:10:51 +00:00
port: _tor!.port!,
);
/// Initialize the tor ffi lib instance if it hasn't already been set. Nothing
/// changes if _tor is already been set.
void init({Tor? mockableOverride}) {
_tor ??= mockableOverride ?? Tor.instance;
}
/// Start the Tor service.
///
/// This will start the Tor service and establish a Tor circuit.
///
/// Throws an exception if the Tor service fails to start.
///
/// Returns a Future that completes when the Tor service has started.
2023-08-07 16:39:04 +00:00
Future<void> start() async {
if (_tor == null) {
throw Exception("TorService.init has not been called!");
}
if (_enabled) {
// already started so just return
return;
}
// Start the Tor service.
try {
2023-09-15 18:10:51 +00:00
_updateStatusAndFireEvent(
status: TorConnectionStatus.connecting,
message: "Tor connection status changed: connecting",
);
2023-09-15 18:10:51 +00:00
await _tor!.start();
// no exception or error so we can (probably?) assume tor
// has started successfully
_enabled = true;
// Fire a TorConnectionStatusChangedEvent on the event bus.
2023-09-15 18:10:51 +00:00
_updateStatusAndFireEvent(
status: TorConnectionStatus.connected,
message: "Tor connection status changed: connect ($_enabled)",
);
} catch (e, s) {
Logging.instance.log(
"TorService.start failed: $e\n$s",
level: LogLevel.Warning,
);
// _enabled should already be false
// Fire a TorConnectionStatusChangedEvent on the event bus.
2023-09-15 18:10:51 +00:00
_updateStatusAndFireEvent(
status: TorConnectionStatus.disconnected,
message: "Tor connection status changed: $_enabled (failed)",
);
rethrow;
}
2023-08-07 16:39:04 +00:00
}
Future<void> stop() async {
if (_tor == null) {
throw Exception("TorService.init has not been called!");
}
if (!_enabled) {
// already stopped so just return
// could throw an exception here or something so the caller
// is explicitly made aware of this
// TODO make sure to kill
return;
}
// Stop the Tor service.
try {
_tor!.disable();
// no exception or error so we can (probably?) assume tor
// has started successfully
_enabled = false;
2023-09-15 18:10:51 +00:00
_updateStatusAndFireEvent(
status: TorConnectionStatus.disconnected,
message: "Tor connection status changed: $_enabled (disabled)",
);
} catch (e, s) {
Logging.instance.log(
"TorService.stop failed: $e\n$s",
level: LogLevel.Warning,
);
rethrow;
}
2023-08-07 16:39:04 +00:00
}
2023-09-15 18:10:51 +00:00
void _updateStatusAndFireEvent({
required TorConnectionStatus status,
required String message,
}) {
_status = status;
GlobalEventBus.instance.fire(
TorConnectionStatusChangedEvent(
_status,
message,
),
);
}
2023-08-07 16:39:04 +00:00
}