mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 23:34:24 +01:00
opt.
This commit is contained in:
@@ -2,7 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:server_box/data/provider/app.dart';
|
||||
import 'package:server_box/data/provider/private_key.dart';
|
||||
import 'package:server_box/data/provider/server.dart';
|
||||
import 'package:server_box/data/provider/server/all.dart';
|
||||
import 'package:server_box/data/provider/sftp.dart';
|
||||
import 'package:server_box/data/provider/snippet.dart';
|
||||
|
||||
@@ -45,7 +45,7 @@ final class ReadMyProvider {
|
||||
T call<T>(ProviderBase<T> provider) => ref.read(provider);
|
||||
|
||||
// Specific provider getters
|
||||
ServersState get server => ref.read(serverNotifierProvider);
|
||||
ServersState get server => ref.read(serversNotifierProvider);
|
||||
SnippetState get snippet => ref.read(snippetNotifierProvider);
|
||||
AppState get app => ref.read(appStatesProvider);
|
||||
PrivateKeyState get privateKey => ref.read(privateKeyNotifierProvider);
|
||||
@@ -59,7 +59,7 @@ final class WatchMyProvider {
|
||||
T call<T>(ProviderBase<T> provider) => ref.watch(provider);
|
||||
|
||||
// Specific provider getters
|
||||
ServersState get server => ref.watch(serverNotifierProvider);
|
||||
ServersState get server => ref.watch(serversNotifierProvider);
|
||||
SnippetState get snippet => ref.watch(snippetNotifierProvider);
|
||||
AppState get app => ref.watch(appStatesProvider);
|
||||
PrivateKeyState get privateKey => ref.watch(privateKeyNotifierProvider);
|
||||
@@ -74,7 +74,7 @@ final class UseNotifierMyProvider {
|
||||
ref.read(provider.notifier);
|
||||
|
||||
// Specific provider notifier getters
|
||||
ServerNotifier get server => ref.read(serverNotifierProvider.notifier);
|
||||
ServersNotifier get server => ref.read(serversNotifierProvider.notifier);
|
||||
SnippetNotifier get snippet => ref.read(snippetNotifierProvider.notifier);
|
||||
AppStates get app => ref.read(appStatesProvider.notifier);
|
||||
PrivateKeyNotifier get privateKey => ref.read(privateKeyNotifierProvider.notifier);
|
||||
|
||||
@@ -13,7 +13,7 @@ import 'package:server_box/core/extension/context/locale.dart';
|
||||
import 'package:server_box/data/model/app/error.dart';
|
||||
import 'package:server_box/data/model/server/pve.dart';
|
||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
import 'package:server_box/data/provider/server.dart';
|
||||
import 'package:server_box/data/provider/server/single.dart';
|
||||
|
||||
part 'pve.freezed.dart';
|
||||
part 'pve.g.dart';
|
||||
@@ -45,7 +45,7 @@ class PveNotifier extends _$PveNotifier {
|
||||
@override
|
||||
PveState build(Spi spiParam) {
|
||||
spi = spiParam;
|
||||
final serverState = ref.watch(individualServerNotifierProvider(spi.id));
|
||||
final serverState = ref.watch(serverNotifierProvider(spi.id));
|
||||
final client = serverState.client;
|
||||
if (client == null) {
|
||||
return const PveState(error: PveErr(type: PveErrType.net, message: 'Server client is null'));
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'pve.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$pveNotifierHash() => r'667cfb11cd7118d57b29918d137ef2cda2bad7ad';
|
||||
String _$pveNotifierHash() => r'b5da7240db1b9ee7d61f238cebca45821b7a3445';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
273
lib/data/provider/server/all.dart
Normal file
273
lib/data/provider/server/all.dart
Normal file
@@ -0,0 +1,273 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fl_lib/fl_lib.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:server_box/core/sync.dart';
|
||||
import 'package:server_box/data/model/server/server.dart';
|
||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
import 'package:server_box/data/model/server/try_limiter.dart';
|
||||
import 'package:server_box/data/provider/server/single.dart';
|
||||
import 'package:server_box/data/res/store.dart';
|
||||
import 'package:server_box/data/ssh/session_manager.dart';
|
||||
|
||||
part 'all.freezed.dart';
|
||||
part 'all.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ServersState with _$ServersState {
|
||||
const factory ServersState({
|
||||
@Default({}) Map<String, Spi> servers,
|
||||
@Default([]) List<String> serverOrder,
|
||||
@Default(<String>{}) Set<String> tags,
|
||||
@Default(<String>{}) Set<String> manualDisconnectedIds,
|
||||
Timer? autoRefreshTimer,
|
||||
}) = _ServersState;
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class ServersNotifier extends _$ServersNotifier {
|
||||
@override
|
||||
ServersState build() {
|
||||
// Initialize with empty state, load data asynchronously
|
||||
Future.microtask(() => _load());
|
||||
return const ServersState();
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
final spis = Stores.server.fetch();
|
||||
final newServers = <String, Spi>{};
|
||||
final newServerOrder = <String>[];
|
||||
|
||||
for (final spi in spis) {
|
||||
newServers[spi.id] = spi;
|
||||
}
|
||||
|
||||
final serverOrder_ = Stores.setting.serverOrder.fetch();
|
||||
if (serverOrder_.isNotEmpty) {
|
||||
spis.reorder(order: serverOrder_, finder: (n, id) => n.id == id);
|
||||
newServerOrder.addAll(spis.map((e) => e.id));
|
||||
} else {
|
||||
newServerOrder.addAll(newServers.keys);
|
||||
}
|
||||
|
||||
// Must use [equals] to compare [Order] here.
|
||||
if (!newServerOrder.equals(serverOrder_)) {
|
||||
Stores.setting.serverOrder.put(newServerOrder);
|
||||
}
|
||||
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newServerOrder, tags: newTags);
|
||||
}
|
||||
|
||||
Set<String> _calculateTags(Map<String, Spi> servers) {
|
||||
final tags = <String>{};
|
||||
for (final spi in servers.values) {
|
||||
final spiTags = spi.tags;
|
||||
if (spiTags == null) continue;
|
||||
for (final t in spiTags) {
|
||||
tags.add(t);
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/// Get a [Spi] by [spi] or [id].
|
||||
///
|
||||
/// Priority: [spi] > [id]
|
||||
Spi? pick({Spi? spi, String? id}) {
|
||||
if (spi != null) {
|
||||
return state.servers[spi.id];
|
||||
}
|
||||
if (id != null) {
|
||||
return state.servers[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// if [spi] is specificed then only refresh this server
|
||||
/// [onlyFailed] only refresh failed servers
|
||||
Future<void> refresh({Spi? spi, bool onlyFailed = false}) async {
|
||||
if (spi != null) {
|
||||
final newManualDisconnected = Set<String>.from(state.manualDisconnectedIds)..remove(spi.id);
|
||||
state = state.copyWith(manualDisconnectedIds: newManualDisconnected);
|
||||
final serverNotifier = ref.read(serverNotifierProvider(spi.id).notifier);
|
||||
await serverNotifier.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
await Future.wait(
|
||||
state.servers.entries.map((entry) async {
|
||||
final serverId = entry.key;
|
||||
final spi = entry.value;
|
||||
|
||||
if (onlyFailed) {
|
||||
final serverState = ref.read(serverNotifierProvider(serverId));
|
||||
if (serverState.conn != ServerConn.failed) return;
|
||||
TryLimiter.reset(serverId);
|
||||
}
|
||||
|
||||
if (state.manualDisconnectedIds.contains(serverId)) return;
|
||||
|
||||
final serverState = ref.read(serverNotifierProvider(serverId));
|
||||
if (serverState.conn == ServerConn.disconnected && !spi.autoConnect) {
|
||||
return;
|
||||
}
|
||||
|
||||
final serverNotifier = ref.read(serverNotifierProvider(serverId).notifier);
|
||||
await serverNotifier.refresh();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> startAutoRefresh() async {
|
||||
var duration = Stores.setting.serverStatusUpdateInterval.fetch();
|
||||
stopAutoRefresh();
|
||||
if (duration == 0) return;
|
||||
if (duration < 0 || duration > 10 || duration == 1) {
|
||||
duration = 3;
|
||||
Loggers.app.warning('Invalid duration: $duration, use default 3');
|
||||
}
|
||||
final timer = Timer.periodic(Duration(seconds: duration), (_) async {
|
||||
await refresh();
|
||||
});
|
||||
state = state.copyWith(autoRefreshTimer: timer);
|
||||
}
|
||||
|
||||
void stopAutoRefresh() {
|
||||
final timer = state.autoRefreshTimer;
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
state = state.copyWith(autoRefreshTimer: null);
|
||||
}
|
||||
}
|
||||
|
||||
bool get isAutoRefreshOn => state.autoRefreshTimer != null;
|
||||
|
||||
void setDisconnected() {
|
||||
for (final serverId in state.servers.keys) {
|
||||
final serverNotifier = ref.read(serverNotifierProvider(serverId).notifier);
|
||||
serverNotifier.updateConnection(ServerConn.disconnected);
|
||||
|
||||
// Update SSH session status to disconnected
|
||||
final sessionId = 'ssh_$serverId';
|
||||
TermSessionManager.updateStatus(sessionId, TermSessionStatus.disconnected);
|
||||
}
|
||||
//TryLimiter.clear();
|
||||
}
|
||||
|
||||
void closeServer({String? id}) {
|
||||
if (id == null) {
|
||||
for (final serverId in state.servers.keys) {
|
||||
closeOneServer(serverId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
closeOneServer(id);
|
||||
}
|
||||
|
||||
void closeOneServer(String id) {
|
||||
final spi = state.servers[id];
|
||||
if (spi == null) {
|
||||
Loggers.app.warning('Server with id $id not found');
|
||||
return;
|
||||
}
|
||||
|
||||
final serverNotifier = ref.read(serverNotifierProvider(id).notifier);
|
||||
serverNotifier.closeConnection();
|
||||
|
||||
final newManualDisconnected = Set<String>.from(state.manualDisconnectedIds)..add(id);
|
||||
state = state.copyWith(manualDisconnectedIds: newManualDisconnected);
|
||||
|
||||
// Remove SSH session when server is manually closed
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
}
|
||||
|
||||
void addServer(Spi spi) {
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
newServers[spi.id] = spi;
|
||||
|
||||
final newOrder = List<String>.from(state.serverOrder)..add(spi.id);
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
Stores.server.put(spi);
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
refresh(spi: spi);
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
void delServer(String id) {
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
newServers.remove(id);
|
||||
|
||||
final newOrder = List<String>.from(state.serverOrder)..remove(id);
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
Stores.server.delete(id);
|
||||
|
||||
// Remove SSH session when server is deleted
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
void deleteAll() {
|
||||
// Remove all SSH sessions before clearing servers
|
||||
for (final id in state.servers.keys) {
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
}
|
||||
|
||||
state = const ServersState();
|
||||
|
||||
Stores.setting.serverOrder.put([]);
|
||||
Stores.server.clear();
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
Future<void> updateServer(Spi old, Spi newSpi) async {
|
||||
if (old != newSpi) {
|
||||
Stores.server.update(old, newSpi);
|
||||
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
final newOrder = List<String>.from(state.serverOrder);
|
||||
|
||||
if (newSpi.id != old.id) {
|
||||
newServers[newSpi.id] = newSpi;
|
||||
newServers.remove(old.id);
|
||||
newOrder.update(old.id, newSpi.id);
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
|
||||
// Update SSH session ID when server ID changes
|
||||
final oldSessionId = 'ssh_${old.id}';
|
||||
TermSessionManager.remove(oldSessionId);
|
||||
// Session will be re-added when reconnecting if necessary
|
||||
} else {
|
||||
newServers[old.id] = newSpi;
|
||||
// Update SPI in the corresponding IndividualServerNotifier
|
||||
final serverNotifier = ref.read(serverNotifierProvider(old.id).notifier);
|
||||
serverNotifier.updateSpi(newSpi);
|
||||
}
|
||||
|
||||
final newTags = _calculateTags(newServers);
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
// Only reconnect if neccessary
|
||||
if (newSpi.shouldReconnect(old)) {
|
||||
// Use [newSpi.id] instead of [old.id] because [old.id] may be changed
|
||||
TryLimiter.reset(newSpi.id);
|
||||
refresh(spi: newSpi);
|
||||
}
|
||||
}
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'server.dart';
|
||||
part of 'all.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
@@ -304,291 +304,4 @@ as Timer?,
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ServerState {
|
||||
|
||||
Spi get spi; ServerStatus get status; ServerConn get conn; SSHClient? get client; Future<void>? get updateFuture;
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ServerStateCopyWith<ServerState> get copyWith => _$ServerStateCopyWithImpl<ServerState>(this as ServerState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ServerState&&(identical(other.spi, spi) || other.spi == spi)&&(identical(other.status, status) || other.status == status)&&(identical(other.conn, conn) || other.conn == conn)&&(identical(other.client, client) || other.client == client)&&(identical(other.updateFuture, updateFuture) || other.updateFuture == updateFuture));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,spi,status,conn,client,updateFuture);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerState(spi: $spi, status: $status, conn: $conn, client: $client, updateFuture: $updateFuture)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ServerStateCopyWith<$Res> {
|
||||
factory $ServerStateCopyWith(ServerState value, $Res Function(ServerState) _then) = _$ServerStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture
|
||||
});
|
||||
|
||||
|
||||
$SpiCopyWith<$Res> get spi;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ServerStateCopyWithImpl<$Res>
|
||||
implements $ServerStateCopyWith<$Res> {
|
||||
_$ServerStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ServerState _self;
|
||||
final $Res Function(ServerState) _then;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? spi = null,Object? status = null,Object? conn = null,Object? client = freezed,Object? updateFuture = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
spi: null == spi ? _self.spi : spi // ignore: cast_nullable_to_non_nullable
|
||||
as Spi,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as ServerStatus,conn: null == conn ? _self.conn : conn // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConn,client: freezed == client ? _self.client : client // ignore: cast_nullable_to_non_nullable
|
||||
as SSHClient?,updateFuture: freezed == updateFuture ? _self.updateFuture : updateFuture // ignore: cast_nullable_to_non_nullable
|
||||
as Future<void>?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SpiCopyWith<$Res> get spi {
|
||||
|
||||
return $SpiCopyWith<$Res>(_self.spi, (value) {
|
||||
return _then(_self.copyWith(spi: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ServerState].
|
||||
extension ServerStatePatterns on ServerState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ServerState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ServerState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ServerState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState():
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _ServerState implements ServerState {
|
||||
const _ServerState({required this.spi, required this.status, this.conn = ServerConn.disconnected, this.client, this.updateFuture});
|
||||
|
||||
|
||||
@override final Spi spi;
|
||||
@override final ServerStatus status;
|
||||
@override@JsonKey() final ServerConn conn;
|
||||
@override final SSHClient? client;
|
||||
@override final Future<void>? updateFuture;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ServerStateCopyWith<_ServerState> get copyWith => __$ServerStateCopyWithImpl<_ServerState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ServerState&&(identical(other.spi, spi) || other.spi == spi)&&(identical(other.status, status) || other.status == status)&&(identical(other.conn, conn) || other.conn == conn)&&(identical(other.client, client) || other.client == client)&&(identical(other.updateFuture, updateFuture) || other.updateFuture == updateFuture));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,spi,status,conn,client,updateFuture);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerState(spi: $spi, status: $status, conn: $conn, client: $client, updateFuture: $updateFuture)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ServerStateCopyWith<$Res> implements $ServerStateCopyWith<$Res> {
|
||||
factory _$ServerStateCopyWith(_ServerState value, $Res Function(_ServerState) _then) = __$ServerStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture
|
||||
});
|
||||
|
||||
|
||||
@override $SpiCopyWith<$Res> get spi;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ServerStateCopyWithImpl<$Res>
|
||||
implements _$ServerStateCopyWith<$Res> {
|
||||
__$ServerStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ServerState _self;
|
||||
final $Res Function(_ServerState) _then;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? spi = null,Object? status = null,Object? conn = null,Object? client = freezed,Object? updateFuture = freezed,}) {
|
||||
return _then(_ServerState(
|
||||
spi: null == spi ? _self.spi : spi // ignore: cast_nullable_to_non_nullable
|
||||
as Spi,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as ServerStatus,conn: null == conn ? _self.conn : conn // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConn,client: freezed == client ? _self.client : client // ignore: cast_nullable_to_non_nullable
|
||||
as SSHClient?,updateFuture: freezed == updateFuture ? _self.updateFuture : updateFuture // ignore: cast_nullable_to_non_nullable
|
||||
as Future<void>?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SpiCopyWith<$Res> get spi {
|
||||
|
||||
return $SpiCopyWith<$Res>(_self.spi, (value) {
|
||||
return _then(_self.copyWith(spi: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
26
lib/data/provider/server/all.g.dart
Normal file
26
lib/data/provider/server/all.g.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'all.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$serversNotifierHash() => r'2ae641188f772794a32e8700c008f51ba0cc1ec9';
|
||||
|
||||
/// See also [ServersNotifier].
|
||||
@ProviderFor(ServersNotifier)
|
||||
final serversNotifierProvider =
|
||||
NotifierProvider<ServersNotifier, ServersState>.internal(
|
||||
ServersNotifier.new,
|
||||
name: r'serversNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$serversNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ServersNotifier = Notifier<ServersState>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -8,7 +8,6 @@ import 'package:flutter_gbk2utf8/flutter_gbk2utf8.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:server_box/core/extension/ssh_client.dart';
|
||||
import 'package:server_box/core/sync.dart';
|
||||
import 'package:server_box/core/utils/server.dart';
|
||||
import 'package:server_box/core/utils/ssh_auth.dart';
|
||||
import 'package:server_box/data/helper/system_detector.dart';
|
||||
@@ -20,23 +19,13 @@ import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
import 'package:server_box/data/model/server/server_status_update_req.dart';
|
||||
import 'package:server_box/data/model/server/system.dart';
|
||||
import 'package:server_box/data/model/server/try_limiter.dart';
|
||||
import 'package:server_box/data/provider/server/all.dart';
|
||||
import 'package:server_box/data/res/status.dart';
|
||||
import 'package:server_box/data/res/store.dart';
|
||||
import 'package:server_box/data/ssh/session_manager.dart';
|
||||
|
||||
part 'server.freezed.dart';
|
||||
part 'server.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ServersState with _$ServersState {
|
||||
const factory ServersState({
|
||||
@Default({}) Map<String, Spi> servers,
|
||||
@Default([]) List<String> serverOrder,
|
||||
@Default(<String>{}) Set<String> tags,
|
||||
@Default(<String>{}) Set<String> manualDisconnectedIds,
|
||||
Timer? autoRefreshTimer,
|
||||
}) = _ServersState;
|
||||
}
|
||||
part 'single.g.dart';
|
||||
part 'single.freezed.dart';
|
||||
|
||||
// Individual server state, including connection and status information
|
||||
@freezed
|
||||
@@ -50,20 +39,12 @@ abstract class ServerState with _$ServerState {
|
||||
}) = _ServerState;
|
||||
}
|
||||
|
||||
extension IndividualServerStateExtension on ServerState {
|
||||
bool get needGenClient => conn < ServerConn.connecting;
|
||||
|
||||
bool get canViewDetails => conn == ServerConn.finished;
|
||||
|
||||
String get id => spi.id;
|
||||
}
|
||||
|
||||
// Individual server state management
|
||||
@riverpod
|
||||
class IndividualServerNotifier extends _$IndividualServerNotifier {
|
||||
class ServerNotifier extends _$ServerNotifier {
|
||||
@override
|
||||
ServerState build(String serverId) {
|
||||
final serverNotifier = ref.read(serverNotifierProvider);
|
||||
final serverNotifier = ref.read(serversNotifierProvider);
|
||||
final spi = serverNotifier.servers[serverId];
|
||||
if (spi == null) {
|
||||
throw StateError('Server $serverId not found');
|
||||
@@ -169,7 +150,7 @@ class IndividualServerNotifier extends _$IndividualServerNotifier {
|
||||
id: sessionId,
|
||||
spi: spi,
|
||||
startTimeMs: time1.millisecondsSinceEpoch,
|
||||
disconnect: () => ref.read(serverNotifierProvider.notifier)._closeOneServer(spi.id),
|
||||
disconnect: () => ref.read(serversNotifierProvider.notifier).closeOneServer(spi.id),
|
||||
status: TermSessionStatus.connecting,
|
||||
);
|
||||
TermSessionManager.setActive(sessionId, hasTerminal: false);
|
||||
@@ -371,249 +352,10 @@ class IndividualServerNotifier extends _$IndividualServerNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class ServerNotifier extends _$ServerNotifier {
|
||||
@override
|
||||
ServersState build() {
|
||||
// Initialize with empty state, load data asynchronously
|
||||
Future.microtask(() => _load());
|
||||
return const ServersState();
|
||||
}
|
||||
extension IndividualServerStateExtension on ServerState {
|
||||
bool get needGenClient => conn < ServerConn.connecting;
|
||||
|
||||
Future<void> _load() async {
|
||||
final spis = Stores.server.fetch();
|
||||
final newServers = <String, Spi>{};
|
||||
final newServerOrder = <String>[];
|
||||
bool get canViewDetails => conn == ServerConn.finished;
|
||||
|
||||
for (final spi in spis) {
|
||||
newServers[spi.id] = spi;
|
||||
}
|
||||
|
||||
final serverOrder_ = Stores.setting.serverOrder.fetch();
|
||||
if (serverOrder_.isNotEmpty) {
|
||||
spis.reorder(order: serverOrder_, finder: (n, id) => n.id == id);
|
||||
newServerOrder.addAll(spis.map((e) => e.id));
|
||||
} else {
|
||||
newServerOrder.addAll(newServers.keys);
|
||||
}
|
||||
|
||||
// Must use [equals] to compare [Order] here.
|
||||
if (!newServerOrder.equals(serverOrder_)) {
|
||||
Stores.setting.serverOrder.put(newServerOrder);
|
||||
}
|
||||
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newServerOrder, tags: newTags);
|
||||
}
|
||||
|
||||
Set<String> _calculateTags(Map<String, Spi> servers) {
|
||||
final tags = <String>{};
|
||||
for (final spi in servers.values) {
|
||||
final spiTags = spi.tags;
|
||||
if (spiTags == null) continue;
|
||||
for (final t in spiTags) {
|
||||
tags.add(t);
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/// Get a [Spi] by [spi] or [id].
|
||||
///
|
||||
/// Priority: [spi] > [id]
|
||||
Spi? pick({Spi? spi, String? id}) {
|
||||
if (spi != null) {
|
||||
return state.servers[spi.id];
|
||||
}
|
||||
if (id != null) {
|
||||
return state.servers[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// if [spi] is specificed then only refresh this server
|
||||
/// [onlyFailed] only refresh failed servers
|
||||
Future<void> refresh({Spi? spi, bool onlyFailed = false}) async {
|
||||
if (spi != null) {
|
||||
final newManualDisconnected = Set<String>.from(state.manualDisconnectedIds)..remove(spi.id);
|
||||
state = state.copyWith(manualDisconnectedIds: newManualDisconnected);
|
||||
final serverNotifier = ref.read(individualServerNotifierProvider(spi.id).notifier);
|
||||
await serverNotifier.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
await Future.wait(
|
||||
state.servers.entries.map((entry) async {
|
||||
final serverId = entry.key;
|
||||
final spi = entry.value;
|
||||
|
||||
if (onlyFailed) {
|
||||
final serverState = ref.read(individualServerNotifierProvider(serverId));
|
||||
if (serverState.conn != ServerConn.failed) return;
|
||||
TryLimiter.reset(serverId);
|
||||
}
|
||||
|
||||
if (state.manualDisconnectedIds.contains(serverId)) return;
|
||||
|
||||
final serverState = ref.read(individualServerNotifierProvider(serverId));
|
||||
if (serverState.conn == ServerConn.disconnected && !spi.autoConnect) {
|
||||
return;
|
||||
}
|
||||
|
||||
final serverNotifier = ref.read(individualServerNotifierProvider(serverId).notifier);
|
||||
await serverNotifier.refresh();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> startAutoRefresh() async {
|
||||
var duration = Stores.setting.serverStatusUpdateInterval.fetch();
|
||||
stopAutoRefresh();
|
||||
if (duration == 0) return;
|
||||
if (duration < 0 || duration > 10 || duration == 1) {
|
||||
duration = 3;
|
||||
Loggers.app.warning('Invalid duration: $duration, use default 3');
|
||||
}
|
||||
final timer = Timer.periodic(Duration(seconds: duration), (_) async {
|
||||
await refresh();
|
||||
});
|
||||
state = state.copyWith(autoRefreshTimer: timer);
|
||||
}
|
||||
|
||||
void stopAutoRefresh() {
|
||||
final timer = state.autoRefreshTimer;
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
state = state.copyWith(autoRefreshTimer: null);
|
||||
}
|
||||
}
|
||||
|
||||
bool get isAutoRefreshOn => state.autoRefreshTimer != null;
|
||||
|
||||
void setDisconnected() {
|
||||
for (final serverId in state.servers.keys) {
|
||||
final serverNotifier = ref.read(individualServerNotifierProvider(serverId).notifier);
|
||||
serverNotifier.updateConnection(ServerConn.disconnected);
|
||||
|
||||
// Update SSH session status to disconnected
|
||||
final sessionId = 'ssh_$serverId';
|
||||
TermSessionManager.updateStatus(sessionId, TermSessionStatus.disconnected);
|
||||
}
|
||||
//TryLimiter.clear();
|
||||
}
|
||||
|
||||
void closeServer({String? id}) {
|
||||
if (id == null) {
|
||||
for (final serverId in state.servers.keys) {
|
||||
_closeOneServer(serverId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_closeOneServer(id);
|
||||
}
|
||||
|
||||
void _closeOneServer(String id) {
|
||||
final spi = state.servers[id];
|
||||
if (spi == null) {
|
||||
Loggers.app.warning('Server with id $id not found');
|
||||
return;
|
||||
}
|
||||
|
||||
final serverNotifier = ref.read(individualServerNotifierProvider(id).notifier);
|
||||
serverNotifier.closeConnection();
|
||||
|
||||
final newManualDisconnected = Set<String>.from(state.manualDisconnectedIds)..add(id);
|
||||
state = state.copyWith(manualDisconnectedIds: newManualDisconnected);
|
||||
|
||||
// Remove SSH session when server is manually closed
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
}
|
||||
|
||||
void addServer(Spi spi) {
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
newServers[spi.id] = spi;
|
||||
|
||||
final newOrder = List<String>.from(state.serverOrder)..add(spi.id);
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
Stores.server.put(spi);
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
refresh(spi: spi);
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
void delServer(String id) {
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
newServers.remove(id);
|
||||
|
||||
final newOrder = List<String>.from(state.serverOrder)..remove(id);
|
||||
final newTags = _calculateTags(newServers);
|
||||
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
Stores.server.delete(id);
|
||||
|
||||
// Remove SSH session when server is deleted
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
void deleteAll() {
|
||||
// Remove all SSH sessions before clearing servers
|
||||
for (final id in state.servers.keys) {
|
||||
final sessionId = 'ssh_$id';
|
||||
TermSessionManager.remove(sessionId);
|
||||
}
|
||||
|
||||
state = const ServersState();
|
||||
|
||||
Stores.setting.serverOrder.put([]);
|
||||
Stores.server.clear();
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
|
||||
Future<void> updateServer(Spi old, Spi newSpi) async {
|
||||
if (old != newSpi) {
|
||||
Stores.server.update(old, newSpi);
|
||||
|
||||
final newServers = Map<String, Spi>.from(state.servers);
|
||||
final newOrder = List<String>.from(state.serverOrder);
|
||||
|
||||
if (newSpi.id != old.id) {
|
||||
newServers[newSpi.id] = newSpi;
|
||||
newServers.remove(old.id);
|
||||
newOrder.update(old.id, newSpi.id);
|
||||
Stores.setting.serverOrder.put(newOrder);
|
||||
|
||||
// Update SSH session ID when server ID changes
|
||||
final oldSessionId = 'ssh_${old.id}';
|
||||
TermSessionManager.remove(oldSessionId);
|
||||
// Session will be re-added when reconnecting if necessary
|
||||
} else {
|
||||
newServers[old.id] = newSpi;
|
||||
// Update SPI in the corresponding IndividualServerNotifier
|
||||
final serverNotifier = ref.read(individualServerNotifierProvider(old.id).notifier);
|
||||
serverNotifier.updateSpi(newSpi);
|
||||
}
|
||||
|
||||
final newTags = _calculateTags(newServers);
|
||||
state = state.copyWith(servers: newServers, serverOrder: newOrder, tags: newTags);
|
||||
|
||||
// Only reconnect if neccessary
|
||||
if (newSpi.shouldReconnect(old)) {
|
||||
// Use [newSpi.id] instead of [old.id] because [old.id] may be changed
|
||||
TryLimiter.reset(newSpi.id);
|
||||
refresh(spi: newSpi);
|
||||
}
|
||||
}
|
||||
bakSync.sync(milliDelay: 1000);
|
||||
}
|
||||
String get id => spi.id;
|
||||
}
|
||||
|
||||
301
lib/data/provider/server/single.freezed.dart
Normal file
301
lib/data/provider/server/single.freezed.dart
Normal file
@@ -0,0 +1,301 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'single.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$ServerState {
|
||||
|
||||
Spi get spi; ServerStatus get status; ServerConn get conn; SSHClient? get client; Future<void>? get updateFuture;
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ServerStateCopyWith<ServerState> get copyWith => _$ServerStateCopyWithImpl<ServerState>(this as ServerState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ServerState&&(identical(other.spi, spi) || other.spi == spi)&&(identical(other.status, status) || other.status == status)&&(identical(other.conn, conn) || other.conn == conn)&&(identical(other.client, client) || other.client == client)&&(identical(other.updateFuture, updateFuture) || other.updateFuture == updateFuture));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,spi,status,conn,client,updateFuture);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerState(spi: $spi, status: $status, conn: $conn, client: $client, updateFuture: $updateFuture)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ServerStateCopyWith<$Res> {
|
||||
factory $ServerStateCopyWith(ServerState value, $Res Function(ServerState) _then) = _$ServerStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture
|
||||
});
|
||||
|
||||
|
||||
$SpiCopyWith<$Res> get spi;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ServerStateCopyWithImpl<$Res>
|
||||
implements $ServerStateCopyWith<$Res> {
|
||||
_$ServerStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ServerState _self;
|
||||
final $Res Function(ServerState) _then;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? spi = null,Object? status = null,Object? conn = null,Object? client = freezed,Object? updateFuture = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
spi: null == spi ? _self.spi : spi // ignore: cast_nullable_to_non_nullable
|
||||
as Spi,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as ServerStatus,conn: null == conn ? _self.conn : conn // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConn,client: freezed == client ? _self.client : client // ignore: cast_nullable_to_non_nullable
|
||||
as SSHClient?,updateFuture: freezed == updateFuture ? _self.updateFuture : updateFuture // ignore: cast_nullable_to_non_nullable
|
||||
as Future<void>?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SpiCopyWith<$Res> get spi {
|
||||
|
||||
return $SpiCopyWith<$Res>(_self.spi, (value) {
|
||||
return _then(_self.copyWith(spi: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ServerState].
|
||||
extension ServerStatePatterns on ServerState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ServerState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ServerState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ServerState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState():
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ServerState() when $default != null:
|
||||
return $default(_that.spi,_that.status,_that.conn,_that.client,_that.updateFuture);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _ServerState implements ServerState {
|
||||
const _ServerState({required this.spi, required this.status, this.conn = ServerConn.disconnected, this.client, this.updateFuture});
|
||||
|
||||
|
||||
@override final Spi spi;
|
||||
@override final ServerStatus status;
|
||||
@override@JsonKey() final ServerConn conn;
|
||||
@override final SSHClient? client;
|
||||
@override final Future<void>? updateFuture;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ServerStateCopyWith<_ServerState> get copyWith => __$ServerStateCopyWithImpl<_ServerState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ServerState&&(identical(other.spi, spi) || other.spi == spi)&&(identical(other.status, status) || other.status == status)&&(identical(other.conn, conn) || other.conn == conn)&&(identical(other.client, client) || other.client == client)&&(identical(other.updateFuture, updateFuture) || other.updateFuture == updateFuture));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,spi,status,conn,client,updateFuture);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerState(spi: $spi, status: $status, conn: $conn, client: $client, updateFuture: $updateFuture)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ServerStateCopyWith<$Res> implements $ServerStateCopyWith<$Res> {
|
||||
factory _$ServerStateCopyWith(_ServerState value, $Res Function(_ServerState) _then) = __$ServerStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
Spi spi, ServerStatus status, ServerConn conn, SSHClient? client, Future<void>? updateFuture
|
||||
});
|
||||
|
||||
|
||||
@override $SpiCopyWith<$Res> get spi;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ServerStateCopyWithImpl<$Res>
|
||||
implements _$ServerStateCopyWith<$Res> {
|
||||
__$ServerStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ServerState _self;
|
||||
final $Res Function(_ServerState) _then;
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? spi = null,Object? status = null,Object? conn = null,Object? client = freezed,Object? updateFuture = freezed,}) {
|
||||
return _then(_ServerState(
|
||||
spi: null == spi ? _self.spi : spi // ignore: cast_nullable_to_non_nullable
|
||||
as Spi,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||
as ServerStatus,conn: null == conn ? _self.conn : conn // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConn,client: freezed == client ? _self.client : client // ignore: cast_nullable_to_non_nullable
|
||||
as SSHClient?,updateFuture: freezed == updateFuture ? _self.updateFuture : updateFuture // ignore: cast_nullable_to_non_nullable
|
||||
as Future<void>?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of ServerState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SpiCopyWith<$Res> get spi {
|
||||
|
||||
return $SpiCopyWith<$Res>(_self.spi, (value) {
|
||||
return _then(_self.copyWith(spi: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -1,13 +1,12 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'server.dart';
|
||||
part of 'single.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$individualServerNotifierHash() =>
|
||||
r'e3d74fb95ca994cd8419b1deab743e8b3e21bee2';
|
||||
String _$serverNotifierHash() => r'5625b0a4762c28efdbc124809c03b84a51d213b1';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
@@ -30,30 +29,30 @@ class _SystemHash {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$IndividualServerNotifier
|
||||
abstract class _$ServerNotifier
|
||||
extends BuildlessAutoDisposeNotifier<ServerState> {
|
||||
late final String serverId;
|
||||
|
||||
ServerState build(String serverId);
|
||||
}
|
||||
|
||||
/// See also [IndividualServerNotifier].
|
||||
@ProviderFor(IndividualServerNotifier)
|
||||
const individualServerNotifierProvider = IndividualServerNotifierFamily();
|
||||
/// See also [ServerNotifier].
|
||||
@ProviderFor(ServerNotifier)
|
||||
const serverNotifierProvider = ServerNotifierFamily();
|
||||
|
||||
/// See also [IndividualServerNotifier].
|
||||
class IndividualServerNotifierFamily extends Family<ServerState> {
|
||||
/// See also [IndividualServerNotifier].
|
||||
const IndividualServerNotifierFamily();
|
||||
/// See also [ServerNotifier].
|
||||
class ServerNotifierFamily extends Family<ServerState> {
|
||||
/// See also [ServerNotifier].
|
||||
const ServerNotifierFamily();
|
||||
|
||||
/// See also [IndividualServerNotifier].
|
||||
IndividualServerNotifierProvider call(String serverId) {
|
||||
return IndividualServerNotifierProvider(serverId);
|
||||
/// See also [ServerNotifier].
|
||||
ServerNotifierProvider call(String serverId) {
|
||||
return ServerNotifierProvider(serverId);
|
||||
}
|
||||
|
||||
@override
|
||||
IndividualServerNotifierProvider getProviderOverride(
|
||||
covariant IndividualServerNotifierProvider provider,
|
||||
ServerNotifierProvider getProviderOverride(
|
||||
covariant ServerNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.serverId);
|
||||
}
|
||||
@@ -70,29 +69,28 @@ class IndividualServerNotifierFamily extends Family<ServerState> {
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'individualServerNotifierProvider';
|
||||
String? get name => r'serverNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [IndividualServerNotifier].
|
||||
class IndividualServerNotifierProvider
|
||||
extends
|
||||
AutoDisposeNotifierProviderImpl<IndividualServerNotifier, ServerState> {
|
||||
/// See also [IndividualServerNotifier].
|
||||
IndividualServerNotifierProvider(String serverId)
|
||||
/// See also [ServerNotifier].
|
||||
class ServerNotifierProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ServerNotifier, ServerState> {
|
||||
/// See also [ServerNotifier].
|
||||
ServerNotifierProvider(String serverId)
|
||||
: this._internal(
|
||||
() => IndividualServerNotifier()..serverId = serverId,
|
||||
from: individualServerNotifierProvider,
|
||||
name: r'individualServerNotifierProvider',
|
||||
() => ServerNotifier()..serverId = serverId,
|
||||
from: serverNotifierProvider,
|
||||
name: r'serverNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$individualServerNotifierHash,
|
||||
dependencies: IndividualServerNotifierFamily._dependencies,
|
||||
: _$serverNotifierHash,
|
||||
dependencies: ServerNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
IndividualServerNotifierFamily._allTransitiveDependencies,
|
||||
ServerNotifierFamily._allTransitiveDependencies,
|
||||
serverId: serverId,
|
||||
);
|
||||
|
||||
IndividualServerNotifierProvider._internal(
|
||||
ServerNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
@@ -105,15 +103,15 @@ class IndividualServerNotifierProvider
|
||||
final String serverId;
|
||||
|
||||
@override
|
||||
ServerState runNotifierBuild(covariant IndividualServerNotifier notifier) {
|
||||
ServerState runNotifierBuild(covariant ServerNotifier notifier) {
|
||||
return notifier.build(serverId);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(IndividualServerNotifier Function() create) {
|
||||
Override overrideWith(ServerNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: IndividualServerNotifierProvider._internal(
|
||||
override: ServerNotifierProvider._internal(
|
||||
() => create()..serverId = serverId,
|
||||
from: from,
|
||||
name: null,
|
||||
@@ -126,15 +124,14 @@ class IndividualServerNotifierProvider
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<IndividualServerNotifier, ServerState>
|
||||
AutoDisposeNotifierProviderElement<ServerNotifier, ServerState>
|
||||
createElement() {
|
||||
return _IndividualServerNotifierProviderElement(this);
|
||||
return _ServerNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is IndividualServerNotifierProvider &&
|
||||
other.serverId == serverId;
|
||||
return other is ServerNotifierProvider && other.serverId == serverId;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -148,40 +145,19 @@ class IndividualServerNotifierProvider
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin IndividualServerNotifierRef
|
||||
on AutoDisposeNotifierProviderRef<ServerState> {
|
||||
mixin ServerNotifierRef on AutoDisposeNotifierProviderRef<ServerState> {
|
||||
/// The parameter `serverId` of this provider.
|
||||
String get serverId;
|
||||
}
|
||||
|
||||
class _IndividualServerNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeNotifierProviderElement<
|
||||
IndividualServerNotifier,
|
||||
ServerState
|
||||
>
|
||||
with IndividualServerNotifierRef {
|
||||
_IndividualServerNotifierProviderElement(super.provider);
|
||||
class _ServerNotifierProviderElement
|
||||
extends AutoDisposeNotifierProviderElement<ServerNotifier, ServerState>
|
||||
with ServerNotifierRef {
|
||||
_ServerNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get serverId => (origin as IndividualServerNotifierProvider).serverId;
|
||||
String get serverId => (origin as ServerNotifierProvider).serverId;
|
||||
}
|
||||
|
||||
String _$serverNotifierHash() => r'8e2bc3aef3c56263f88df3c2bb1ba88b6cf83c8f';
|
||||
|
||||
/// See also [ServerNotifier].
|
||||
@ProviderFor(ServerNotifier)
|
||||
final serverNotifierProvider =
|
||||
NotifierProvider<ServerNotifier, ServersState>.internal(
|
||||
ServerNotifier.new,
|
||||
name: r'serverNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$serverNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ServerNotifier = Notifier<ServersState>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -5,7 +5,7 @@ import 'package:server_box/core/extension/ssh_client.dart';
|
||||
import 'package:server_box/data/model/app/scripts/script_consts.dart';
|
||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
import 'package:server_box/data/model/server/systemd.dart';
|
||||
import 'package:server_box/data/provider/server.dart';
|
||||
import 'package:server_box/data/provider/server/single.dart';
|
||||
|
||||
part 'systemd.freezed.dart';
|
||||
part 'systemd.g.dart';
|
||||
@@ -25,7 +25,7 @@ class SystemdNotifier extends _$SystemdNotifier {
|
||||
|
||||
@override
|
||||
SystemdState build(Spi spi) {
|
||||
final si = ref.read(individualServerNotifierProvider(spi.id));
|
||||
final si = ref.read(serverNotifierProvider(spi.id));
|
||||
_si = si;
|
||||
// Async initialization
|
||||
Future.microtask(() => getUnits());
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'systemd.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$systemdNotifierHash() => r'617fb7637fbc5c5100e5b522d246984f22b44cca';
|
||||
String _$systemdNotifierHash() => r'98466bd176518545be49cae52f8dbe12af3a88a6';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
Reference in New Issue
Block a user