mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-13 11:42:17 -04:00
more refactor and dhtrecord multiple-open support
This commit is contained in:
parent
c4c7b264aa
commit
e262b0f777
19 changed files with 782 additions and 419 deletions
|
@ -10,41 +10,20 @@ class AsyncTransformerCubit<T, S> extends Cubit<AsyncValue<T>> {
|
|||
_subscription = input.stream.listen(_asyncTransform);
|
||||
}
|
||||
void _asyncTransform(AsyncValue<S> newInputState) {
|
||||
// Use a singlefuture here to ensure we get dont lose any updates
|
||||
// If the input stream gives us an update while we are
|
||||
// still processing the last update, the most recent input state will
|
||||
// be saved and processed eventually.
|
||||
singleFuture(this, () async {
|
||||
var newState = newInputState;
|
||||
var done = false;
|
||||
while (!done) {
|
||||
// Emit the transformed state
|
||||
try {
|
||||
if (newState is AsyncLoading) {
|
||||
return AsyncValue<T>.loading();
|
||||
}
|
||||
if (newState is AsyncError) {
|
||||
final newStateError = newState as AsyncError<S>;
|
||||
return AsyncValue<T>.error(
|
||||
newStateError.error, newStateError.stackTrace);
|
||||
}
|
||||
_singleStateProcessor.updateState(newInputState, closure: (newState) async {
|
||||
// Emit the transformed state
|
||||
try {
|
||||
if (newState is AsyncLoading<S>) {
|
||||
emit(const AsyncValue.loading());
|
||||
} else if (newState is AsyncError<S>) {
|
||||
emit(AsyncValue.error(newState.error, newState.stackTrace));
|
||||
} else {
|
||||
final transformedState = await transform(newState.data!.value);
|
||||
emit(transformedState);
|
||||
} on Exception catch (e, st) {
|
||||
emit(AsyncValue.error(e, st));
|
||||
}
|
||||
// See if there's another state change to process
|
||||
final next = _nextInputState;
|
||||
_nextInputState = null;
|
||||
if (next != null) {
|
||||
newState = next;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
} on Exception catch (e, st) {
|
||||
emit(AsyncValue.error(e, st));
|
||||
}
|
||||
}, onBusy: () {
|
||||
// Keep this state until we process again
|
||||
_nextInputState = newInputState;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -56,7 +35,8 @@ class AsyncTransformerCubit<T, S> extends Cubit<AsyncValue<T>> {
|
|||
}
|
||||
|
||||
Cubit<AsyncValue<S>> input;
|
||||
AsyncValue<S>? _nextInputState;
|
||||
final SingleStateProcessor<AsyncValue<S>> _singleStateProcessor =
|
||||
SingleStateProcessor();
|
||||
Future<AsyncValue<T>> Function(S) transform;
|
||||
late final StreamSubscription<AsyncValue<S>> _subscription;
|
||||
}
|
||||
|
|
|
@ -30,49 +30,29 @@ abstract mixin class StateFollower<S extends Object, K, V> {
|
|||
Future<void> updateState(K key, V value);
|
||||
|
||||
void _updateFollow(S newInputState) {
|
||||
// Use a singlefuture here to ensure we get dont lose any updates
|
||||
// If the input stream gives us an update while we are
|
||||
// still processing the last update, the most recent input state will
|
||||
// be saved and processed eventually.
|
||||
final newInputStateMap = getStateMap(newInputState);
|
||||
|
||||
singleFuture(this, () async {
|
||||
var newStateMap = newInputStateMap;
|
||||
var done = false;
|
||||
while (!done) {
|
||||
for (final k in _lastInputStateMap.keys) {
|
||||
if (!newStateMap.containsKey(k)) {
|
||||
// deleted
|
||||
await removeFromState(k);
|
||||
}
|
||||
}
|
||||
for (final newEntry in newStateMap.entries) {
|
||||
final v = _lastInputStateMap.get(newEntry.key);
|
||||
if (v == null || v != newEntry.value) {
|
||||
// added or changed
|
||||
await updateState(newEntry.key, newEntry.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep this state map for the next time
|
||||
_lastInputStateMap = newStateMap;
|
||||
|
||||
// See if there's another state change to process
|
||||
final next = _nextInputStateMap;
|
||||
_nextInputStateMap = null;
|
||||
if (next != null) {
|
||||
newStateMap = next;
|
||||
} else {
|
||||
done = true;
|
||||
_singleStateProcessor.updateState(getStateMap(newInputState),
|
||||
closure: (newStateMap) async {
|
||||
for (final k in _lastInputStateMap.keys) {
|
||||
if (!newStateMap.containsKey(k)) {
|
||||
// deleted
|
||||
await removeFromState(k);
|
||||
}
|
||||
}
|
||||
}, onBusy: () {
|
||||
// Keep this state until we process again
|
||||
_nextInputStateMap = newInputStateMap;
|
||||
for (final newEntry in newStateMap.entries) {
|
||||
final v = _lastInputStateMap.get(newEntry.key);
|
||||
if (v == null || v != newEntry.value) {
|
||||
// added or changed
|
||||
await updateState(newEntry.key, newEntry.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep this state map for the next time
|
||||
_lastInputStateMap = newStateMap;
|
||||
});
|
||||
}
|
||||
|
||||
late IMap<K, V> _lastInputStateMap;
|
||||
IMap<K, V>? _nextInputStateMap;
|
||||
final SingleStateProcessor<IMap<K, V>> _singleStateProcessor =
|
||||
SingleStateProcessor();
|
||||
late final StreamSubscription<S> _subscription;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue