mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-06-06 21:58:49 -04:00
fix deadlock
clean up async handling improve styled alerts
This commit is contained in:
parent
22390f31ff
commit
8edccb8a0f
21 changed files with 125 additions and 108 deletions
|
@ -4,6 +4,7 @@
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"accounts_menu_tooltip": "Accounts Menu",
|
"accounts_menu_tooltip": "Accounts Menu",
|
||||||
|
"settings_tooltip": "Settings",
|
||||||
"contacts_tooltip": "Contacts List",
|
"contacts_tooltip": "Contacts List",
|
||||||
"new_chat_tooltip": "Start New Chat",
|
"new_chat_tooltip": "Start New Chat",
|
||||||
"add_account_tooltip": "Add Account",
|
"add_account_tooltip": "Add Account",
|
||||||
|
|
|
@ -8,7 +8,7 @@ import '../../proto/proto.dart' as proto;
|
||||||
import '../account_manager.dart';
|
import '../account_manager.dart';
|
||||||
|
|
||||||
typedef AccountRecordState = proto.Account;
|
typedef AccountRecordState = proto.Account;
|
||||||
typedef _sspUpdateState = (
|
typedef _SspUpdateState = (
|
||||||
AccountSpec accountSpec,
|
AccountSpec accountSpec,
|
||||||
Future<void> Function() onSuccess
|
Future<void> Function() onSuccess
|
||||||
);
|
);
|
||||||
|
@ -96,5 +96,5 @@ class AccountRecordCubit extends DefaultDHTRecordCubit<AccountRecordState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final _sspUpdate = SingleStateProcessor<_sspUpdateState>();
|
final _sspUpdate = SingleStateProcessor<_SspUpdateState>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,13 @@ class PerAccountCollectionBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
// Add account record cubit
|
// Add account record cubit
|
||||||
Future<void> _addPerAccountCollectionCubit(
|
Future<void> _addPerAccountCollectionCubit(
|
||||||
{required TypedKey superIdentityRecordKey}) async =>
|
{required TypedKey superIdentityRecordKey}) async =>
|
||||||
add(() => MapEntry(
|
add(
|
||||||
superIdentityRecordKey,
|
superIdentityRecordKey,
|
||||||
PerAccountCollectionCubit(
|
() async => PerAccountCollectionCubit(
|
||||||
locator: _locator,
|
locator: _locator,
|
||||||
accountInfoCubit: AccountInfoCubit(
|
accountInfoCubit: AccountInfoCubit(
|
||||||
accountRepository: _accountRepository,
|
accountRepository: _accountRepository,
|
||||||
superIdentityRecordKey: superIdentityRecordKey))));
|
superIdentityRecordKey: superIdentityRecordKey)));
|
||||||
|
|
||||||
/// StateFollower /////////////////////////
|
/// StateFollower /////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -78,13 +78,13 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
|
||||||
await _accountRecordSubscription?.cancel();
|
await _accountRecordSubscription?.cancel();
|
||||||
_accountRecordSubscription = null;
|
_accountRecordSubscription = null;
|
||||||
|
|
||||||
// Update state to 'loading'
|
|
||||||
nextState = _updateAccountRecordState(nextState, null);
|
|
||||||
emit(nextState);
|
|
||||||
|
|
||||||
// Close AccountRecordCubit
|
// Close AccountRecordCubit
|
||||||
await accountRecordCubit?.close();
|
await accountRecordCubit?.close();
|
||||||
accountRecordCubit = null;
|
accountRecordCubit = null;
|
||||||
|
|
||||||
|
// Update state to 'loading'
|
||||||
|
nextState = _updateAccountRecordState(nextState, null);
|
||||||
|
emit(nextState);
|
||||||
} else {
|
} else {
|
||||||
///////////////// Logged in ///////////////////
|
///////////////// Logged in ///////////////////
|
||||||
|
|
||||||
|
|
|
@ -120,23 +120,23 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
|
||||||
try {
|
try {
|
||||||
final success = await AccountRepository.instance.deleteLocalAccount(
|
final success = await AccountRepository.instance.deleteLocalAccount(
|
||||||
widget.superIdentityRecordKey, widget.accountRecord);
|
widget.superIdentityRecordKey, widget.accountRecord);
|
||||||
if (success && mounted) {
|
if (mounted) {
|
||||||
|
if (success) {
|
||||||
context
|
context
|
||||||
.read<NotificationsCubit>()
|
.read<NotificationsCubit>()
|
||||||
.info(text: translate('edit_account_page.account_removed'));
|
.info(text: translate('edit_account_page.account_removed'));
|
||||||
GoRouterHelper(context).pop();
|
GoRouterHelper(context).pop();
|
||||||
} else if (mounted) {
|
} else {
|
||||||
context
|
context
|
||||||
.read<NotificationsCubit>()
|
.read<NotificationsCubit>()
|
||||||
.error(text: translate('edit_account_page.failed_to_remove'));
|
.error(text: translate('edit_account_page.failed_to_remove'));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isInAsyncCall = false;
|
_isInAsyncCall = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} on Exception catch (e, st) {
|
} on Exception catch (e, st) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
await showErrorStacktraceModal(
|
await showErrorStacktraceModal(
|
||||||
|
@ -188,23 +188,22 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
|
||||||
try {
|
try {
|
||||||
final success = await AccountRepository.instance.destroyAccount(
|
final success = await AccountRepository.instance.destroyAccount(
|
||||||
widget.superIdentityRecordKey, widget.accountRecord);
|
widget.superIdentityRecordKey, widget.accountRecord);
|
||||||
if (success && mounted) {
|
if (mounted) {
|
||||||
|
if (success) {
|
||||||
context
|
context
|
||||||
.read<NotificationsCubit>()
|
.read<NotificationsCubit>()
|
||||||
.info(text: translate('edit_account_page.account_destroyed'));
|
.info(text: translate('edit_account_page.account_destroyed'));
|
||||||
GoRouterHelper(context).pop();
|
GoRouterHelper(context).pop();
|
||||||
} else if (mounted) {
|
} else {
|
||||||
context
|
context.read<NotificationsCubit>().error(
|
||||||
.read<NotificationsCubit>()
|
text: translate('edit_account_page.failed_to_destroy'));
|
||||||
.error(text: translate('edit_account_page.failed_to_destroy'));
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isInAsyncCall = false;
|
_isInAsyncCall = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} on Exception catch (e, st) {
|
} on Exception catch (e, st) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
await showErrorStacktraceModal(
|
await showErrorStacktraceModal(
|
||||||
|
|
|
@ -252,7 +252,7 @@ class ContactInvitationListCubit
|
||||||
.openRecordRead(contactRequestInboxKey,
|
.openRecordRead(contactRequestInboxKey,
|
||||||
debugName: 'ContactInvitationListCubit::validateInvitation::'
|
debugName: 'ContactInvitationListCubit::validateInvitation::'
|
||||||
'ContactRequestInbox',
|
'ContactRequestInbox',
|
||||||
parent: pool.getParentRecordKey(contactRequestInboxKey) ??
|
parent: await pool.getParentRecordKey(contactRequestInboxKey) ??
|
||||||
_accountInfo.accountRecordKey)
|
_accountInfo.accountRecordKey)
|
||||||
.withCancel(cancelRequest))
|
.withCancel(cancelRequest))
|
||||||
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
||||||
|
|
|
@ -48,15 +48,15 @@ class WaitingInvitationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
Future<void> _addWaitingInvitation(
|
Future<void> _addWaitingInvitation(
|
||||||
{required proto.ContactInvitationRecord
|
{required proto.ContactInvitationRecord
|
||||||
contactInvitationRecord}) async =>
|
contactInvitationRecord}) async =>
|
||||||
add(() => MapEntry(
|
add(
|
||||||
contactInvitationRecord.contactRequestInbox.recordKey.toVeilid(),
|
contactInvitationRecord.contactRequestInbox.recordKey.toVeilid(),
|
||||||
WaitingInvitationCubit(
|
() async => WaitingInvitationCubit(
|
||||||
ContactRequestInboxCubit(
|
ContactRequestInboxCubit(
|
||||||
accountInfo: _accountInfo,
|
accountInfo: _accountInfo,
|
||||||
contactInvitationRecord: contactInvitationRecord),
|
contactInvitationRecord: contactInvitationRecord),
|
||||||
accountInfo: _accountInfo,
|
accountInfo: _accountInfo,
|
||||||
accountRecordCubit: _accountRecordCubit,
|
accountRecordCubit: _accountRecordCubit,
|
||||||
contactInvitationRecord: contactInvitationRecord)));
|
contactInvitationRecord: contactInvitationRecord));
|
||||||
|
|
||||||
// Process all accepted or rejected invitations
|
// Process all accepted or rejected invitations
|
||||||
Future<void> _invitationStatusListener(
|
Future<void> _invitationStatusListener(
|
||||||
|
|
|
@ -37,7 +37,7 @@ class ValidContactInvitation {
|
||||||
return (await pool.openRecordWrite(_contactRequestInboxKey, _writer,
|
return (await pool.openRecordWrite(_contactRequestInboxKey, _writer,
|
||||||
debugName: 'ValidContactInvitation::accept::'
|
debugName: 'ValidContactInvitation::accept::'
|
||||||
'ContactRequestInbox',
|
'ContactRequestInbox',
|
||||||
parent: pool.getParentRecordKey(_contactRequestInboxKey) ??
|
parent: await pool.getParentRecordKey(_contactRequestInboxKey) ??
|
||||||
_accountInfo.accountRecordKey))
|
_accountInfo.accountRecordKey))
|
||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
|
||||||
|
|
|
@ -78,7 +78,7 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
{required TypedKey remoteIdentityPublicKey,
|
{required TypedKey remoteIdentityPublicKey,
|
||||||
required TypedKey localConversationRecordKey,
|
required TypedKey localConversationRecordKey,
|
||||||
required TypedKey remoteConversationRecordKey}) async =>
|
required TypedKey remoteConversationRecordKey}) async =>
|
||||||
add(() {
|
add(localConversationRecordKey, () async {
|
||||||
// Conversation cubit the tracks the state between the local
|
// Conversation cubit the tracks the state between the local
|
||||||
// and remote halves of a contact's relationship with this account
|
// and remote halves of a contact's relationship with this account
|
||||||
final conversationCubit = ConversationCubit(
|
final conversationCubit = ConversationCubit(
|
||||||
|
@ -123,7 +123,7 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
loading: AsyncValue.loading,
|
loading: AsyncValue.loading,
|
||||||
error: AsyncValue.error));
|
error: AsyncValue.error));
|
||||||
|
|
||||||
return MapEntry(localConversationRecordKey, transformedCubit);
|
return transformedCubit;
|
||||||
});
|
});
|
||||||
|
|
||||||
/// StateFollower /////////////////////////
|
/// StateFollower /////////////////////////
|
||||||
|
|
|
@ -55,24 +55,17 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
|
|
||||||
Future<void> _addConversationMessages(_SingleContactChatState state) async {
|
Future<void> _addConversationMessages(_SingleContactChatState state) async {
|
||||||
// xxx could use atomic update() function
|
// xxx could use atomic update() function
|
||||||
|
await update(state.localConversationRecordKey,
|
||||||
final cubit = await tryOperateAsync<SingleContactMessagesCubit>(
|
onUpdate: (cubit) async =>
|
||||||
state.localConversationRecordKey, closure: (cubit) async {
|
cubit.updateRemoteMessagesRecordKey(state.remoteMessagesRecordKey),
|
||||||
await cubit.updateRemoteMessagesRecordKey(state.remoteMessagesRecordKey);
|
onCreate: () async => SingleContactMessagesCubit(
|
||||||
return cubit;
|
|
||||||
});
|
|
||||||
if (cubit == null) {
|
|
||||||
await add(() => MapEntry(
|
|
||||||
state.localConversationRecordKey,
|
|
||||||
SingleContactMessagesCubit(
|
|
||||||
accountInfo: _accountInfo,
|
accountInfo: _accountInfo,
|
||||||
remoteIdentityPublicKey: state.remoteIdentityPublicKey,
|
remoteIdentityPublicKey: state.remoteIdentityPublicKey,
|
||||||
localConversationRecordKey: state.localConversationRecordKey,
|
localConversationRecordKey: state.localConversationRecordKey,
|
||||||
remoteConversationRecordKey: state.remoteConversationRecordKey,
|
remoteConversationRecordKey: state.remoteConversationRecordKey,
|
||||||
localMessagesRecordKey: state.localMessagesRecordKey,
|
localMessagesRecordKey: state.localMessagesRecordKey,
|
||||||
remoteMessagesRecordKey: state.remoteMessagesRecordKey,
|
remoteMessagesRecordKey: state.remoteMessagesRecordKey,
|
||||||
)));
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_SingleContactChatState? _mapStateValue(
|
_SingleContactChatState? _mapStateValue(
|
||||||
|
|
|
@ -73,7 +73,8 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
|
|
||||||
final record = await pool.openRecordRead(_remoteConversationRecordKey,
|
final record = await pool.openRecordRead(_remoteConversationRecordKey,
|
||||||
debugName: 'ConversationCubit::RemoteConversation',
|
debugName: 'ConversationCubit::RemoteConversation',
|
||||||
parent: pool.getParentRecordKey(_remoteConversationRecordKey) ??
|
parent:
|
||||||
|
await pool.getParentRecordKey(_remoteConversationRecordKey) ??
|
||||||
accountInfo.accountRecordKey,
|
accountInfo.accountRecordKey,
|
||||||
crypto: crypto);
|
crypto: crypto);
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,8 @@ Future<void> showErrorModal(
|
||||||
required String title,
|
required String title,
|
||||||
required String text}) async {
|
required String text}) async {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
// final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
// final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
await Alert(
|
await Alert(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -145,8 +145,8 @@ Future<void> showWarningModal(
|
||||||
required String title,
|
required String title,
|
||||||
required String text}) async {
|
required String text}) async {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
// final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
// final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
await Alert(
|
await Alert(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -184,8 +184,8 @@ Future<void> showWarningWidgetModal(
|
||||||
required String title,
|
required String title,
|
||||||
required Widget child}) async {
|
required Widget child}) async {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
// final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
// final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
await Alert(
|
await Alert(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -223,8 +223,8 @@ Future<bool> showConfirmModal(
|
||||||
required String title,
|
required String title,
|
||||||
required String text}) async {
|
required String text}) async {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
// final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
// final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
var confirm = false;
|
var confirm = false;
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,7 @@ class BackgroundTickerState extends State<BackgroundTicker> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
final tickTimer = _tickTimer;
|
_tickTimer?.cancel();
|
||||||
if (tickTimer != null) {
|
|
||||||
tickTimer.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: async_tools
|
name: async_tools
|
||||||
sha256: "9166e8fe65fc65eb79202a6d540f4de768553d78141b885f5bd3f8d7d30eef5e"
|
sha256: "93df8b92d54d92e3323c630277e902b4ad4f05f798b55cfbc451e98c3e2fb7ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.6"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -53,10 +53,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: bloc_advanced_tools
|
name: bloc_advanced_tools
|
||||||
sha256: "2b2dd492a350e7192a933d09f15ea04d5d00e7bd3fe2a906fe629cd461ddbf94"
|
sha256: f0b2dbe028792c97d1eb30480ed4e8035b5c70ea3bcc95a9c5255142592857f7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.7"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -650,7 +650,7 @@ packages:
|
||||||
path: "../../../../veilid/veilid-flutter"
|
path: "../../../../veilid/veilid-flutter"
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.3.3"
|
version: "0.3.4"
|
||||||
veilid_support:
|
veilid_support:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -14,7 +14,7 @@ dependencies:
|
||||||
path: ../
|
path: ../
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
async_tools: ^0.1.5
|
async_tools: ^0.1.6
|
||||||
integration_test:
|
integration_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
lint_hard: ^4.0.0
|
lint_hard: ^4.0.0
|
||||||
|
|
|
@ -79,7 +79,7 @@ class DHTRecord implements DHTDeleteable<DHTRecord> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
await serialFuturePause((this, _sfListen));
|
await serialFutureClose((this, _sfListen));
|
||||||
await _watchController?.close();
|
await _watchController?.close();
|
||||||
_watchController = null;
|
_watchController = null;
|
||||||
await DHTRecordPool.instance._recordClosed(this);
|
await DHTRecordPool.instance._recordClosed(this);
|
||||||
|
|
|
@ -65,7 +65,7 @@ class OwnedDHTRecordPointer with _$OwnedDHTRecordPointer {
|
||||||
class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
DHTRecordPool._(Veilid veilid, VeilidRoutingContext routingContext)
|
DHTRecordPool._(Veilid veilid, VeilidRoutingContext routingContext)
|
||||||
: _state = const DHTRecordPoolAllocations(),
|
: _state = const DHTRecordPoolAllocations(),
|
||||||
_mutex = Mutex(),
|
_mutex = Mutex(debugLockTimeout: 30),
|
||||||
_recordTagLock = AsyncTagLock(),
|
_recordTagLock = AsyncTagLock(),
|
||||||
_opened = <TypedKey, _OpenedRecordInfo>{},
|
_opened = <TypedKey, _OpenedRecordInfo>{},
|
||||||
_markedForDelete = <TypedKey>{},
|
_markedForDelete = <TypedKey>{},
|
||||||
|
@ -207,10 +207,8 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Get the parent of a DHTRecord key if it exists
|
/// Get the parent of a DHTRecord key if it exists
|
||||||
TypedKey? getParentRecordKey(TypedKey child) {
|
Future<TypedKey?> getParentRecordKey(TypedKey child) =>
|
||||||
final childJson = child.toJson();
|
_mutex.protect(() async => _getParentRecordKeyInner(child));
|
||||||
return _state.parentByChild[childJson];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if record is allocated
|
/// Check if record is allocated
|
||||||
Future<bool> isValidRecordKey(TypedKey key) =>
|
Future<bool> isValidRecordKey(TypedKey key) =>
|
||||||
|
@ -505,12 +503,16 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
// Check to see if this key can finally be deleted
|
// Check to see if this key can finally be deleted
|
||||||
// If any parents are marked for deletion, try them first
|
// If any parents are marked for deletion, try them first
|
||||||
Future<void> _checkForLateDeletesInner(TypedKey key) async {
|
Future<void> _checkForLateDeletesInner(TypedKey key) async {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
// Get parent list in bottom up order including our own key
|
// Get parent list in bottom up order including our own key
|
||||||
final parents = <TypedKey>[];
|
final parents = <TypedKey>[];
|
||||||
TypedKey? nextParent = key;
|
TypedKey? nextParent = key;
|
||||||
while (nextParent != null) {
|
while (nextParent != null) {
|
||||||
parents.add(nextParent);
|
parents.add(nextParent);
|
||||||
nextParent = getParentRecordKey(nextParent);
|
nextParent = _getParentRecordKeyInner(nextParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any parent is ready to delete all its children do it
|
// If any parent is ready to delete all its children do it
|
||||||
|
@ -547,6 +549,10 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
|
|
||||||
// Actual delete function
|
// Actual delete function
|
||||||
Future<void> _finalizeDeleteRecordInner(TypedKey recordKey) async {
|
Future<void> _finalizeDeleteRecordInner(TypedKey recordKey) async {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
log('_finalizeDeleteRecordInner: key=$recordKey');
|
log('_finalizeDeleteRecordInner: key=$recordKey');
|
||||||
|
|
||||||
// Remove this child from parents
|
// Remove this child from parents
|
||||||
|
@ -557,6 +563,10 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
|
|
||||||
// Deep delete mechanism inside mutex
|
// Deep delete mechanism inside mutex
|
||||||
Future<bool> _deleteRecordInner(TypedKey recordKey) async {
|
Future<bool> _deleteRecordInner(TypedKey recordKey) async {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
final toDelete = _readyForDeleteInner(recordKey);
|
final toDelete = _readyForDeleteInner(recordKey);
|
||||||
if (toDelete.isNotEmpty) {
|
if (toDelete.isNotEmpty) {
|
||||||
// delete now
|
// delete now
|
||||||
|
@ -656,7 +666,20 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypedKey? _getParentRecordKeyInner(TypedKey child) {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
|
final childJson = child.toJson();
|
||||||
|
return _state.parentByChild[childJson];
|
||||||
|
}
|
||||||
|
|
||||||
bool _isValidRecordKeyInner(TypedKey key) {
|
bool _isValidRecordKeyInner(TypedKey key) {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
if (_state.rootRecords.contains(key)) {
|
if (_state.rootRecords.contains(key)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -667,6 +690,10 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isDeletedRecordKeyInner(TypedKey key) {
|
bool _isDeletedRecordKeyInner(TypedKey key) {
|
||||||
|
if (!_mutex.isLocked) {
|
||||||
|
throw StateError('should be locked here');
|
||||||
|
}
|
||||||
|
|
||||||
// Is this key gone?
|
// Is this key gone?
|
||||||
if (!_isValidRecordKeyInner(key)) {
|
if (!_isValidRecordKeyInner(key)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -679,7 +706,7 @@ class DHTRecordPool with TableDBBackedJson<DHTRecordPoolAllocations> {
|
||||||
if (_markedForDelete.contains(nextParent)) {
|
if (_markedForDelete.contains(nextParent)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
nextParent = getParentRecordKey(nextParent);
|
nextParent = _getParentRecordKeyInner(nextParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -37,10 +37,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: async_tools
|
name: async_tools
|
||||||
sha256: "9166e8fe65fc65eb79202a6d540f4de768553d78141b885f5bd3f8d7d30eef5e"
|
sha256: "93df8b92d54d92e3323c630277e902b4ad4f05f798b55cfbc451e98c3e2fb7ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.6"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -53,10 +53,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: bloc_advanced_tools
|
name: bloc_advanced_tools
|
||||||
sha256: "2ad82be752ab5e983ad9097ed9f334e47a4472c04d5c6b61c99a1bb14a039053"
|
sha256: f0b2dbe028792c97d1eb30480ed4e8035b5c70ea3bcc95a9c5255142592857f7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.6"
|
version: "0.1.7"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -7,9 +7,9 @@ environment:
|
||||||
sdk: '>=3.2.0 <4.0.0'
|
sdk: '>=3.2.0 <4.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
async_tools: ^0.1.5
|
async_tools: ^0.1.6
|
||||||
bloc: ^8.1.4
|
bloc: ^8.1.4
|
||||||
bloc_advanced_tools: ^0.1.6
|
bloc_advanced_tools: ^0.1.7
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
|
|
|
@ -85,10 +85,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: async_tools
|
name: async_tools
|
||||||
sha256: "9166e8fe65fc65eb79202a6d540f4de768553d78141b885f5bd3f8d7d30eef5e"
|
sha256: "93df8b92d54d92e3323c630277e902b4ad4f05f798b55cfbc451e98c3e2fb7ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.6"
|
||||||
awesome_extensions:
|
awesome_extensions:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -141,10 +141,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: bloc_advanced_tools
|
name: bloc_advanced_tools
|
||||||
sha256: "2ad82be752ab5e983ad9097ed9f334e47a4472c04d5c6b61c99a1bb14a039053"
|
sha256: f0b2dbe028792c97d1eb30480ed4e8035b5c70ea3bcc95a9c5255142592857f7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.6"
|
version: "0.1.7"
|
||||||
blurry_modal_progress_hud:
|
blurry_modal_progress_hud:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -14,12 +14,12 @@ dependencies:
|
||||||
animated_theme_switcher: ^2.0.10
|
animated_theme_switcher: ^2.0.10
|
||||||
ansicolor: ^2.0.2
|
ansicolor: ^2.0.2
|
||||||
archive: ^3.6.1
|
archive: ^3.6.1
|
||||||
async_tools: ^0.1.5
|
async_tools: ^0.1.6
|
||||||
awesome_extensions: ^2.0.16
|
awesome_extensions: ^2.0.16
|
||||||
badges: ^3.1.2
|
badges: ^3.1.2
|
||||||
basic_utils: ^5.7.0
|
basic_utils: ^5.7.0
|
||||||
bloc: ^8.1.4
|
bloc: ^8.1.4
|
||||||
bloc_advanced_tools: ^0.1.6
|
bloc_advanced_tools: ^0.1.7
|
||||||
blurry_modal_progress_hud: ^1.1.1
|
blurry_modal_progress_hud: ^1.1.1
|
||||||
change_case: ^2.1.0
|
change_case: ^2.1.0
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue