mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-12-11 06:26:03 -05:00
better message status support
This commit is contained in:
parent
4f02435964
commit
809f6d69bf
31 changed files with 1046 additions and 248 deletions
|
|
@ -86,7 +86,7 @@ class DHTRecord {
|
|||
if (_open) {
|
||||
await close();
|
||||
}
|
||||
await DHTRecordPool.instance.delete(key);
|
||||
await DHTRecordPool.instance.deleteRecord(key);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ class OpenedRecordInfo {
|
|||
String get sharedDetails => shared.toString();
|
||||
}
|
||||
|
||||
class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
||||
class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||
DHTRecordPool._(Veilid veilid, VeilidRoutingContext routingContext)
|
||||
: _state = const DHTRecordPoolAllocations(),
|
||||
_mutex = Mutex(),
|
||||
|
|
@ -150,7 +150,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
? DHTRecordPoolAllocations.fromJson(obj)
|
||||
: const DHTRecordPoolAllocations();
|
||||
@override
|
||||
Object? valueToJson(DHTRecordPoolAllocations val) => val.toJson();
|
||||
Object? valueToJson(DHTRecordPoolAllocations? val) => val?.toJson();
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
final globalPool = DHTRecordPool._(Veilid.instance, routingContext);
|
||||
globalPool
|
||||
.._logger = logger
|
||||
.._state = await globalPool.load();
|
||||
.._state = await globalPool.load() ?? const DHTRecordPoolAllocations();
|
||||
_singleton = globalPool;
|
||||
}
|
||||
|
||||
|
|
@ -279,7 +279,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
if (openedRecordInfo.records.isEmpty) {
|
||||
await _routingContext.closeDHTRecord(key);
|
||||
if (openedRecordInfo.shared.deleteOnClose) {
|
||||
await _deleteInner(key);
|
||||
await _deleteRecordInner(key);
|
||||
}
|
||||
_opened.remove(key);
|
||||
}
|
||||
|
|
@ -316,7 +316,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteInner(TypedKey recordKey) async {
|
||||
Future<void> _deleteRecordInner(TypedKey recordKey) async {
|
||||
log('deleteDHTRecord: key=$recordKey');
|
||||
|
||||
// Remove this child from parents
|
||||
|
|
@ -324,7 +324,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
await _routingContext.deleteDHTRecord(recordKey);
|
||||
}
|
||||
|
||||
Future<void> delete(TypedKey recordKey) async {
|
||||
Future<void> deleteRecord(TypedKey recordKey) async {
|
||||
await _mutex.protect(() async {
|
||||
final allDeps = _collectChildrenInner(recordKey);
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ class DHTRecordPool with TableDBBacked<DHTRecordPoolAllocations> {
|
|||
ori.shared.deleteOnClose = true;
|
||||
} else {
|
||||
// delete now
|
||||
await _deleteInner(recordKey);
|
||||
await _deleteRecordInner(recordKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class DHTShortArray {
|
|||
return dhtShortArray;
|
||||
} on Exception catch (_) {
|
||||
await dhtRecord.close();
|
||||
await pool.delete(dhtRecord.key);
|
||||
await pool.deleteRecord(dhtRecord.key);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ class DHTShortArray {
|
|||
/// Free all resources for the DHTShortArray and delete it from the DHT
|
||||
Future<void> delete() async {
|
||||
await close();
|
||||
await DHTRecordPool.instance.delete(recordKey);
|
||||
await DHTRecordPool.instance.deleteRecord(recordKey);
|
||||
}
|
||||
|
||||
/// Runs a closure that guarantees the DHTShortArray
|
||||
|
|
@ -212,6 +212,8 @@ class DHTShortArray {
|
|||
return closure(writer);
|
||||
}, timeout: timeout);
|
||||
|
||||
/// Listen to and any all changes to the structure of this short array
|
||||
/// regardless of where the changes are coming from
|
||||
Future<StreamSubscription<void>> listen(
|
||||
void Function() onChanged,
|
||||
) =>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,24 @@ import 'dart:async';
|
|||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:bloc_tools/bloc_tools.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../../../veilid_support.dart';
|
||||
|
||||
typedef DHTShortArrayState<T> = AsyncValue<IList<T>>;
|
||||
@immutable
|
||||
class DHTShortArrayElementState<T> extends Equatable {
|
||||
const DHTShortArrayElementState(
|
||||
{required this.value, required this.isOffline});
|
||||
final T value;
|
||||
final bool isOffline;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [value, isOffline];
|
||||
}
|
||||
|
||||
typedef DHTShortArrayState<T> = AsyncValue<IList<DHTShortArrayElementState<T>>>;
|
||||
typedef DHTShortArrayBusyState<T> = BlocBusyState<DHTShortArrayState<T>>;
|
||||
|
||||
class DHTShortArrayCubit<T> extends Cubit<DHTShortArrayBusyState<T>>
|
||||
|
|
@ -49,13 +62,19 @@ class DHTShortArrayCubit<T> extends Cubit<DHTShortArrayBusyState<T>>
|
|||
Future<void> _refreshNoWait({bool forceRefresh = false}) async =>
|
||||
busy((emit) async => _refreshInner(emit, forceRefresh: forceRefresh));
|
||||
|
||||
Future<void> _refreshInner(void Function(AsyncValue<IList<T>>) emit,
|
||||
Future<void> _refreshInner(void Function(DHTShortArrayState<T>) emit,
|
||||
{bool forceRefresh = false}) async {
|
||||
try {
|
||||
final newState = (await _shortArray.operate(
|
||||
(reader) => reader.getAllItems(forceRefresh: forceRefresh)))
|
||||
?.map(_decodeElement)
|
||||
.toIList();
|
||||
final newState = await _shortArray.operate((reader) async {
|
||||
final offlinePositions = await reader.getOfflinePositions();
|
||||
final allItems = (await reader.getAllItems(forceRefresh: forceRefresh))
|
||||
?.indexed
|
||||
.map((x) => DHTShortArrayElementState(
|
||||
value: _decodeElement(x.$2),
|
||||
isOffline: offlinePositions.contains(x.$1)))
|
||||
.toIList();
|
||||
return allItems;
|
||||
});
|
||||
if (newState != null) {
|
||||
emit(AsyncValue.data(newState));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ abstract class DHTShortArrayRead {
|
|||
/// is specified, the network will always be checked for newer values
|
||||
/// rather than returning the existing locally stored copy of the elements.
|
||||
Future<List<Uint8List>?> getAllItems({bool forceRefresh = false});
|
||||
|
||||
/// Get a list of the positions that were written offline and not flushed yet
|
||||
Future<Set<int>> getOfflinePositions();
|
||||
}
|
||||
|
||||
extension DHTShortArrayReadExt on DHTShortArrayRead {
|
||||
|
|
@ -96,6 +99,40 @@ class _DHTShortArrayRead implements DHTShortArrayRead {
|
|||
return out;
|
||||
}
|
||||
|
||||
/// Get a list of the positions that were written offline and not flushed yet
|
||||
@override
|
||||
Future<Set<int>> getOfflinePositions() async {
|
||||
final indexOffline = <int>{};
|
||||
final inspects = await [
|
||||
_head._headRecord.inspect(),
|
||||
..._head._linkedRecords.map((lr) => lr.inspect())
|
||||
].wait;
|
||||
|
||||
// Add to offline index
|
||||
var strideOffset = 0;
|
||||
for (final inspect in inspects) {
|
||||
for (final r in inspect.offlineSubkeys) {
|
||||
for (var i = r.low; i <= r.high; i++) {
|
||||
// If this is the head record, ignore the first head subkey
|
||||
if (strideOffset != 0 || i != 0) {
|
||||
indexOffline.add(i + ((strideOffset == 0) ? -1 : strideOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
strideOffset += _head._stride;
|
||||
}
|
||||
|
||||
// See which positions map to offline indexes
|
||||
final positionOffline = <int>{};
|
||||
for (var i = 0; i < _head._index.length; i++) {
|
||||
final idx = _head._index[i];
|
||||
if (indexOffline.contains(idx)) {
|
||||
positionOffline.add(i);
|
||||
}
|
||||
}
|
||||
return positionOffline;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Fields
|
||||
final _DHTShortArrayHead _head;
|
||||
|
|
|
|||
|
|
@ -92,12 +92,11 @@ extension DHTShortArrayWriteExt on DHTShortArrayWrite {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Writer-only implementation
|
||||
// Writer implementation
|
||||
|
||||
class _DHTShortArrayWrite implements DHTShortArrayWrite {
|
||||
_DHTShortArrayWrite._(_DHTShortArrayHead head)
|
||||
: _head = head,
|
||||
_reader = _DHTShortArrayRead._(head);
|
||||
class _DHTShortArrayWrite extends _DHTShortArrayRead
|
||||
implements DHTShortArrayWrite {
|
||||
_DHTShortArrayWrite._(super.head) : super._();
|
||||
|
||||
@override
|
||||
Future<bool> tryAddItem(Uint8List value) async {
|
||||
|
|
@ -187,23 +186,4 @@ class _DHTShortArrayWrite implements DHTShortArrayWrite {
|
|||
}
|
||||
return (oldValue, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Reader passthrough
|
||||
|
||||
@override
|
||||
int get length => _reader.length;
|
||||
|
||||
@override
|
||||
Future<Uint8List?> getItem(int pos, {bool forceRefresh = false}) =>
|
||||
_reader.getItem(pos, forceRefresh: forceRefresh);
|
||||
|
||||
@override
|
||||
Future<List<Uint8List>?> getAllItems({bool forceRefresh = false}) =>
|
||||
_reader.getAllItems(forceRefresh: forceRefresh);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Fields
|
||||
final _DHTShortArrayHead _head;
|
||||
final _DHTShortArrayRead _reader;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue