mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
contact reject
This commit is contained in:
parent
9be3d100e4
commit
b12cbcf684
@ -34,9 +34,10 @@
|
||||
3. Set ContactRequest unicastinbox DHT record writer subkey with SignedContactResponse, encrypted with writer secret
|
||||
|
||||
## Receiving an accept/reject
|
||||
1. Decrypt with writer secret
|
||||
2. Get DHT record for contact's AccountMaster
|
||||
3. Validate the SignedContactResponse signature
|
||||
1. Open and get SignedContactResponse from ContactRequest unicaseinbox DHT record
|
||||
2. Decrypt with writer secret
|
||||
3. Get DHT record for contact's AccountMaster
|
||||
4. Validate the SignedContactResponse signature
|
||||
|
||||
If accept == false:
|
||||
1. Announce rejection
|
||||
|
@ -57,6 +57,7 @@ class ContactInvitationItemWidget extends ConsumerWidget {
|
||||
await ref.read(fetchActiveAccountProvider.future);
|
||||
if (activeAccountInfo != null) {
|
||||
await deleteContactInvitation(
|
||||
accepted: false,
|
||||
activeAccountInfo: activeAccountInfo,
|
||||
contactInvitationRecord: contactInvitationRecord);
|
||||
ref.invalidate(fetchContactInvitationRecordsProvider);
|
||||
|
@ -1575,7 +1575,7 @@ class ContactResponse extends $pb.GeneratedMessage {
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ContactResponse', createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'accept')
|
||||
..aOM<TypedKey>(2, _omitFieldNames ? '' : 'accountMasterRecordKey', subBuilder: TypedKey.create)
|
||||
..aOM<TypedKey>(2, _omitFieldNames ? '' : 'identityMasterRecordKey', subBuilder: TypedKey.create)
|
||||
..aOM<TypedKey>(3, _omitFieldNames ? '' : 'remoteConversationKey', subBuilder: TypedKey.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
@ -1611,15 +1611,15 @@ class ContactResponse extends $pb.GeneratedMessage {
|
||||
void clearAccept() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
TypedKey get accountMasterRecordKey => $_getN(1);
|
||||
TypedKey get identityMasterRecordKey => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set accountMasterRecordKey(TypedKey v) { setField(2, v); }
|
||||
set identityMasterRecordKey(TypedKey v) { setField(2, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasAccountMasterRecordKey() => $_has(1);
|
||||
$core.bool hasIdentityMasterRecordKey() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearAccountMasterRecordKey() => clearField(2);
|
||||
void clearIdentityMasterRecordKey() => clearField(2);
|
||||
@$pb.TagNumber(2)
|
||||
TypedKey ensureAccountMasterRecordKey() => $_ensure(1);
|
||||
TypedKey ensureIdentityMasterRecordKey() => $_ensure(1);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
TypedKey get remoteConversationKey => $_getN(2);
|
||||
|
@ -427,17 +427,17 @@ const ContactResponse$json = {
|
||||
'1': 'ContactResponse',
|
||||
'2': [
|
||||
{'1': 'accept', '3': 1, '4': 1, '5': 8, '10': 'accept'},
|
||||
{'1': 'account_master_record_key', '3': 2, '4': 1, '5': 11, '6': '.TypedKey', '10': 'accountMasterRecordKey'},
|
||||
{'1': 'identity_master_record_key', '3': 2, '4': 1, '5': 11, '6': '.TypedKey', '10': 'identityMasterRecordKey'},
|
||||
{'1': 'remote_conversation_key', '3': 3, '4': 1, '5': 11, '6': '.TypedKey', '10': 'remoteConversationKey'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ContactResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List contactResponseDescriptor = $convert.base64Decode(
|
||||
'Cg9Db250YWN0UmVzcG9uc2USFgoGYWNjZXB0GAEgASgIUgZhY2NlcHQSRAoZYWNjb3VudF9tYX'
|
||||
'N0ZXJfcmVjb3JkX2tleRgCIAEoCzIJLlR5cGVkS2V5UhZhY2NvdW50TWFzdGVyUmVjb3JkS2V5'
|
||||
'EkEKF3JlbW90ZV9jb252ZXJzYXRpb25fa2V5GAMgASgLMgkuVHlwZWRLZXlSFXJlbW90ZUNvbn'
|
||||
'ZlcnNhdGlvbktleQ==');
|
||||
'Cg9Db250YWN0UmVzcG9uc2USFgoGYWNjZXB0GAEgASgIUgZhY2NlcHQSRgoaaWRlbnRpdHlfbW'
|
||||
'FzdGVyX3JlY29yZF9rZXkYAiABKAsyCS5UeXBlZEtleVIXaWRlbnRpdHlNYXN0ZXJSZWNvcmRL'
|
||||
'ZXkSQQoXcmVtb3RlX2NvbnZlcnNhdGlvbl9rZXkYAyABKAsyCS5UeXBlZEtleVIVcmVtb3RlQ2'
|
||||
'9udmVyc2F0aW9uS2V5');
|
||||
|
||||
@$core.Deprecated('Use signedContactResponseDescriptor instead')
|
||||
const SignedContactResponse$json = {
|
||||
|
@ -307,7 +307,7 @@ message ContactRequestPrivate {
|
||||
CryptoKey writer_key = 1;
|
||||
// Snapshot of profile
|
||||
Profile profile = 2;
|
||||
// Identity master dht key
|
||||
// Identity master DHT record key
|
||||
TypedKey identity_master_record_key = 3;
|
||||
// Local chat DHT record key
|
||||
TypedKey chat_record_key = 4;
|
||||
@ -319,8 +319,8 @@ message ContactRequestPrivate {
|
||||
message ContactResponse {
|
||||
// Accept or reject
|
||||
bool accept = 1;
|
||||
// Account master record key
|
||||
TypedKey account_master_record_key = 2;
|
||||
// Remote identity master DHT record key
|
||||
TypedKey identity_master_record_key = 2;
|
||||
// Remote chat DHT record key if accepted
|
||||
TypedKey remote_conversation_key = 3;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@ -5,10 +7,13 @@ import 'package:split_view/split_view.dart';
|
||||
import 'package:signal_strength_indicator/signal_strength_indicator.dart';
|
||||
|
||||
import '../components/chat_component.dart';
|
||||
import '../providers/account.dart';
|
||||
import '../providers/contact.dart';
|
||||
import '../providers/local_accounts.dart';
|
||||
import '../providers/logins.dart';
|
||||
import '../providers/window_control.dart';
|
||||
import '../tools/tools.dart';
|
||||
import '../veilid_support/dht_support/dht_record_pool.dart';
|
||||
import 'main_pager/main_pager.dart';
|
||||
|
||||
class HomePage extends ConsumerStatefulWidget {
|
||||
@ -19,10 +24,17 @@ class HomePage extends ConsumerStatefulWidget {
|
||||
HomePageState createState() => HomePageState();
|
||||
}
|
||||
|
||||
// XXX Eliminate this when we have ValueChanged
|
||||
const int ticksPerContactInvitationCheck = 5;
|
||||
|
||||
class HomePageState extends ConsumerState<HomePage>
|
||||
with TickerProviderStateMixin {
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
Timer? _homeTickTimer;
|
||||
bool _inHomeTick = false;
|
||||
int _contactInvitationCheckTick = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -31,15 +43,69 @@ class HomePageState extends ConsumerState<HomePage>
|
||||
setState(() {});
|
||||
await ref.read(windowControlProvider.notifier).changeWindowSetup(
|
||||
TitleBarStyle.normal, OrientationCapability.normal);
|
||||
|
||||
_homeTickTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (!_inHomeTick) {
|
||||
unawaited(_onHomeTick());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
final homeTickTimer = _homeTickTimer;
|
||||
if (homeTickTimer != null) {
|
||||
homeTickTimer.cancel();
|
||||
}
|
||||
_unfocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _onHomeTick() async {
|
||||
_inHomeTick = true;
|
||||
try {
|
||||
// Check extant contact invitations once every 5 seconds
|
||||
_contactInvitationCheckTick += 1;
|
||||
if (_contactInvitationCheckTick >= ticksPerContactInvitationCheck) {
|
||||
_contactInvitationCheckTick = 0;
|
||||
await _doContactInvitationCheck();
|
||||
}
|
||||
} finally {
|
||||
_inHomeTick = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _doContactInvitationCheck() async {
|
||||
final contactInvitationRecords =
|
||||
await ref.read(fetchContactInvitationRecordsProvider.future);
|
||||
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
|
||||
if (contactInvitationRecords == null || activeAccountInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final allChecks = <Future<void>>[];
|
||||
for (final contactInvitationRecord in contactInvitationRecords) {
|
||||
allChecks.add(() async {
|
||||
final acceptReject = await checkAcceptRejectContact(
|
||||
activeAccountInfo: activeAccountInfo,
|
||||
contactInvitationRecord: contactInvitationRecord);
|
||||
if (acceptReject != null) {
|
||||
if (acceptReject) {
|
||||
// Accept
|
||||
ref
|
||||
..invalidate(fetchContactInvitationRecordsProvider)
|
||||
..invalidate(fetchContactListProvider);
|
||||
} else {
|
||||
// Reject
|
||||
ref.invalidate(fetchContactInvitationRecordsProvider);
|
||||
}
|
||||
}
|
||||
}());
|
||||
}
|
||||
await Future.wait(allChecks);
|
||||
}
|
||||
|
||||
// ignore: prefer_expression_function_bodies
|
||||
Widget buildPhone(BuildContext context) {
|
||||
//
|
||||
|
@ -14,8 +14,8 @@ import '../entities/proto.dart'
|
||||
ContactInvitationRecord,
|
||||
ContactRequest,
|
||||
ContactRequestPrivate,
|
||||
SignedContactInvitation,
|
||||
ContactResponse,
|
||||
SignedContactInvitation,
|
||||
SignedContactResponse;
|
||||
import '../log/loggy.dart';
|
||||
import '../tools/tools.dart';
|
||||
@ -24,9 +24,90 @@ import 'account.dart';
|
||||
|
||||
part 'contact.g.dart';
|
||||
|
||||
Future<void> deleteContactInvitation(
|
||||
Future<bool?> checkAcceptRejectContact(
|
||||
{required ActiveAccountInfo activeAccountInfo,
|
||||
required ContactInvitationRecord contactInvitationRecord}) async {
|
||||
// Open the contact request inbox
|
||||
try {
|
||||
final pool = await DHTRecordPool.instance();
|
||||
final accountRecordKey =
|
||||
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
final writerKey =
|
||||
proto.CryptoKeyProto.fromProto(contactInvitationRecord.writerKey);
|
||||
final writerSecret =
|
||||
proto.CryptoKeyProto.fromProto(contactInvitationRecord.writerSecret);
|
||||
final writer = TypedKeyPair(
|
||||
kind: contactInvitationRecord.contactRequestInbox.recordKey.kind,
|
||||
key: writerKey,
|
||||
secret: writerSecret);
|
||||
final acceptReject = await (await pool.openRead(
|
||||
proto.TypedKeyProto.fromProto(
|
||||
contactInvitationRecord.contactRequestInbox.recordKey),
|
||||
crypto: await DHTRecordCryptoPrivate.fromTypedKeyPair(writer),
|
||||
parent: accountRecordKey,
|
||||
defaultSubkey: 1))
|
||||
.scope((contactRequestInbox) async {
|
||||
//
|
||||
final signedContactResponse = await contactRequestInbox
|
||||
.getProtobuf(SignedContactResponse.fromBuffer, forceRefresh: true);
|
||||
if (signedContactResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final contactResponseBytes =
|
||||
Uint8List.fromList(signedContactResponse.contactResponse);
|
||||
final contactResponse = ContactResponse.fromBuffer(contactResponseBytes);
|
||||
final contactIdentityMasterRecordKey = proto.TypedKeyProto.fromProto(
|
||||
contactResponse.identityMasterRecordKey);
|
||||
final cs = await pool.veilid.getCryptoSystem(
|
||||
contactInvitationRecord.contactRequestInbox.recordKey.kind);
|
||||
|
||||
// Fetch the remote contact's account master
|
||||
final contactIdentityMaster = await openIdentityMaster(
|
||||
identityMasterRecordKey: contactIdentityMasterRecordKey);
|
||||
|
||||
// Verify
|
||||
final signature = proto.SignatureProto.fromProto(
|
||||
signedContactResponse.identitySignature);
|
||||
try {
|
||||
await cs.verify(contactIdentityMaster.identityPublicKey,
|
||||
contactResponseBytes, signature);
|
||||
} on Exception catch (e) {
|
||||
log.error('Bad identity used, failed to verify: $e');
|
||||
return false;
|
||||
}
|
||||
return contactResponse.accept;
|
||||
});
|
||||
|
||||
if (acceptReject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add contact if accepted
|
||||
if (acceptReject) {
|
||||
//
|
||||
await deleteContactInvitation(
|
||||
accepted: true,
|
||||
activeAccountInfo: activeAccountInfo,
|
||||
contactInvitationRecord: contactInvitationRecord);
|
||||
return true;
|
||||
} else {
|
||||
await deleteContactInvitation(
|
||||
accepted: false,
|
||||
activeAccountInfo: activeAccountInfo,
|
||||
contactInvitationRecord: contactInvitationRecord);
|
||||
return false;
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
log.error('Exception in checkAcceptRejectContact: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteContactInvitation(
|
||||
{required bool accepted,
|
||||
required ActiveAccountInfo activeAccountInfo,
|
||||
required ContactInvitationRecord contactInvitationRecord}) async {
|
||||
final pool = await DHTRecordPool.instance();
|
||||
final accountRecordKey =
|
||||
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
@ -53,12 +134,18 @@ Future<void> deleteContactInvitation(
|
||||
proto.OwnedDHTRecordPointerProto.fromProto(
|
||||
contactInvitationRecord.contactRequestInbox),
|
||||
parent: accountRecordKey))
|
||||
.delete();
|
||||
await (await pool.openOwned(
|
||||
proto.OwnedDHTRecordPointerProto.fromProto(
|
||||
contactInvitationRecord.localConversation),
|
||||
parent: accountRecordKey))
|
||||
.delete();
|
||||
.scope((contactRequestInbox) async {
|
||||
// Wipe out old invitation so it shows up as invalid
|
||||
await contactRequestInbox.tryWriteBytes(Uint8List(0));
|
||||
await contactRequestInbox.delete();
|
||||
});
|
||||
if (!accepted) {
|
||||
await (await pool.openOwned(
|
||||
proto.OwnedDHTRecordPointerProto.fromProto(
|
||||
contactInvitationRecord.localConversation),
|
||||
parent: accountRecordKey))
|
||||
.delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -255,7 +342,7 @@ Future<void> acceptContactInvitation(ActiveAccountInfo activeAccountInfo,
|
||||
// xxx
|
||||
final contactResponse = ContactResponse()
|
||||
..accept = false
|
||||
..accountMasterRecordKey = activeAccountInfo
|
||||
..identityMasterRecordKey = activeAccountInfo
|
||||
.localAccount.identityMaster.masterRecordKey
|
||||
.toProto();
|
||||
final contactResponseBytes = contactResponse.writeToBuffer();
|
||||
@ -290,7 +377,7 @@ Future<void> rejectContactInvitation(ActiveAccountInfo activeAccountInfo,
|
||||
|
||||
final contactResponse = ContactResponse()
|
||||
..accept = false
|
||||
..accountMasterRecordKey = activeAccountInfo
|
||||
..identityMasterRecordKey = activeAccountInfo
|
||||
.localAccount.identityMaster.masterRecordKey
|
||||
.toProto();
|
||||
final contactResponseBytes = contactResponse.writeToBuffer();
|
||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'package:veilid/veilid.dart';
|
||||
|
||||
import '../../tools/tools.dart';
|
||||
import '../veilid_support.dart';
|
||||
@ -51,7 +50,7 @@ class DHTRecord {
|
||||
}
|
||||
final pool = await DHTRecordPool.instance();
|
||||
await _routingContext.closeDHTRecord(_recordDescriptor.key);
|
||||
pool.recordClosed(this);
|
||||
pool.recordClosed(_recordDescriptor.key);
|
||||
_open = false;
|
||||
}
|
||||
|
||||
@ -71,7 +70,9 @@ class DHTRecord {
|
||||
try {
|
||||
return await scopeFunction(this);
|
||||
} finally {
|
||||
await close();
|
||||
if (_valid) {
|
||||
await close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,10 +80,14 @@ class DHTRecord {
|
||||
FutureOr<T> Function(DHTRecord) scopeFunction) async {
|
||||
try {
|
||||
final out = await scopeFunction(this);
|
||||
await close();
|
||||
if (_valid && _open) {
|
||||
await close();
|
||||
}
|
||||
return out;
|
||||
} on Exception catch (_) {
|
||||
await delete();
|
||||
if (_valid) {
|
||||
await delete();
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
import '../../log/loggy.dart';
|
||||
import '../veilid_support.dart';
|
||||
@ -38,14 +39,14 @@ class DHTRecordPool with AsyncTableDBBacked<DHTRecordPoolAllocations> {
|
||||
DHTRecordPool._(Veilid veilid, VeilidRoutingContext routingContext)
|
||||
: _state = DHTRecordPoolAllocations(
|
||||
childrenByParent: IMap(), parentByChild: IMap()),
|
||||
_opened = <TypedKey, DHTRecord>{},
|
||||
_opened = <TypedKey, Mutex>{},
|
||||
_routingContext = routingContext,
|
||||
_veilid = veilid;
|
||||
|
||||
// Persistent DHT record list
|
||||
DHTRecordPoolAllocations _state;
|
||||
// Which DHT records are currently open
|
||||
final Map<TypedKey, DHTRecord> _opened;
|
||||
final Map<TypedKey, Mutex> _opened;
|
||||
// Default routing context to use for new keys
|
||||
final VeilidRoutingContext _routingContext;
|
||||
// Convenience accessor
|
||||
@ -89,14 +90,20 @@ class DHTRecordPool with AsyncTableDBBacked<DHTRecordPoolAllocations> {
|
||||
|
||||
Veilid get veilid => _veilid;
|
||||
|
||||
void _recordOpened(DHTRecord record) {
|
||||
assert(!_opened.containsKey(record.key), 'record already opened');
|
||||
_opened[record.key] = record;
|
||||
Future<void> _recordOpened(TypedKey key) async {
|
||||
// no race because dart is single threaded until async breaks
|
||||
final m = _opened[key] ?? Mutex();
|
||||
_opened[key] = m;
|
||||
await m.acquire();
|
||||
_opened[key] = m;
|
||||
}
|
||||
|
||||
void recordClosed(DHTRecord record) {
|
||||
assert(_opened.containsKey(record.key), 'record already closed');
|
||||
_opened.remove(record.key);
|
||||
void recordClosed(TypedKey key) {
|
||||
final m = _opened.remove(key);
|
||||
if (m == null) {
|
||||
throw StateError('record already closed');
|
||||
}
|
||||
m.release();
|
||||
}
|
||||
|
||||
Future<void> deleteDeep(TypedKey parent) async {
|
||||
@ -191,7 +198,8 @@ class DHTRecordPool with AsyncTableDBBacked<DHTRecordPoolAllocations> {
|
||||
if (parent != null) {
|
||||
await _addDependency(parent, rec.key);
|
||||
}
|
||||
_recordOpened(rec);
|
||||
|
||||
await _recordOpened(rec.key);
|
||||
|
||||
return rec;
|
||||
}
|
||||
@ -202,25 +210,32 @@ class DHTRecordPool with AsyncTableDBBacked<DHTRecordPoolAllocations> {
|
||||
TypedKey? parent,
|
||||
int defaultSubkey = 0,
|
||||
DHTRecordCrypto? crypto}) async {
|
||||
// If we are opening a key that already exists
|
||||
// make sure we are using the same parent if one was specified
|
||||
final existingParent = _state.parentByChild[recordKey.toJson()];
|
||||
assert(existingParent == parent, 'wrong parent for opened key');
|
||||
await _recordOpened(recordKey);
|
||||
|
||||
// Open from the veilid api
|
||||
final dhtctx = routingContext ?? _routingContext;
|
||||
final recordDescriptor = await dhtctx.openDHTRecord(recordKey, null);
|
||||
final rec = DHTRecord(
|
||||
routingContext: dhtctx,
|
||||
recordDescriptor: recordDescriptor,
|
||||
defaultSubkey: defaultSubkey,
|
||||
crypto: crypto ?? const DHTRecordCryptoPublic());
|
||||
late final DHTRecord rec;
|
||||
try {
|
||||
// If we are opening a key that already exists
|
||||
// make sure we are using the same parent if one was specified
|
||||
final existingParent = _state.parentByChild[recordKey.toJson()];
|
||||
assert(existingParent == parent, 'wrong parent for opened key');
|
||||
|
||||
// Register the dependency if specified
|
||||
if (parent != null) {
|
||||
await _addDependency(parent, rec.key);
|
||||
// Open from the veilid api
|
||||
final dhtctx = routingContext ?? _routingContext;
|
||||
final recordDescriptor = await dhtctx.openDHTRecord(recordKey, null);
|
||||
rec = DHTRecord(
|
||||
routingContext: dhtctx,
|
||||
recordDescriptor: recordDescriptor,
|
||||
defaultSubkey: defaultSubkey,
|
||||
crypto: crypto ?? const DHTRecordCryptoPublic());
|
||||
|
||||
// Register the dependency if specified
|
||||
if (parent != null) {
|
||||
await _addDependency(parent, rec.key);
|
||||
}
|
||||
} on Exception catch (_) {
|
||||
recordClosed(recordKey);
|
||||
rethrow;
|
||||
}
|
||||
_recordOpened(rec);
|
||||
|
||||
return rec;
|
||||
}
|
||||
@ -234,28 +249,35 @@ class DHTRecordPool with AsyncTableDBBacked<DHTRecordPoolAllocations> {
|
||||
int defaultSubkey = 0,
|
||||
DHTRecordCrypto? crypto,
|
||||
}) async {
|
||||
// If we are opening a key that already exists
|
||||
// make sure we are using the same parent if one was specified
|
||||
final existingParent = _state.parentByChild[recordKey.toJson()];
|
||||
assert(existingParent == parent, 'wrong parent for opened key');
|
||||
await _recordOpened(recordKey);
|
||||
|
||||
// Open from the veilid api
|
||||
final dhtctx = routingContext ?? _routingContext;
|
||||
final recordDescriptor = await dhtctx.openDHTRecord(recordKey, writer);
|
||||
final rec = DHTRecord(
|
||||
routingContext: dhtctx,
|
||||
recordDescriptor: recordDescriptor,
|
||||
defaultSubkey: defaultSubkey,
|
||||
writer: writer,
|
||||
crypto: crypto ??
|
||||
await DHTRecordCryptoPrivate.fromTypedKeyPair(
|
||||
TypedKeyPair.fromKeyPair(recordKey.kind, writer)));
|
||||
late final DHTRecord rec;
|
||||
try {
|
||||
// If we are opening a key that already exists
|
||||
// make sure we are using the same parent if one was specified
|
||||
final existingParent = _state.parentByChild[recordKey.toJson()];
|
||||
assert(existingParent == parent, 'wrong parent for opened key');
|
||||
|
||||
// Register the dependency if specified
|
||||
if (parent != null) {
|
||||
await _addDependency(parent, rec.key);
|
||||
// Open from the veilid api
|
||||
final dhtctx = routingContext ?? _routingContext;
|
||||
final recordDescriptor = await dhtctx.openDHTRecord(recordKey, writer);
|
||||
rec = DHTRecord(
|
||||
routingContext: dhtctx,
|
||||
recordDescriptor: recordDescriptor,
|
||||
defaultSubkey: defaultSubkey,
|
||||
writer: writer,
|
||||
crypto: crypto ??
|
||||
await DHTRecordCryptoPrivate.fromTypedKeyPair(
|
||||
TypedKeyPair.fromKeyPair(recordKey.kind, writer)));
|
||||
|
||||
// Register the dependency if specified
|
||||
if (parent != null) {
|
||||
await _addDependency(parent, rec.key);
|
||||
}
|
||||
} on Exception catch (_) {
|
||||
recordClosed(recordKey);
|
||||
rethrow;
|
||||
}
|
||||
_recordOpened(rec);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
@ -781,6 +781,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.8"
|
||||
mutex:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mutex
|
||||
sha256: "03116a4e46282a671b46c12de649d72c0ed18188ffe12a8d0fc63e83f4ad88f4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -44,6 +44,7 @@ dependencies:
|
||||
json_annotation: ^4.8.1
|
||||
loggy: ^2.0.3
|
||||
motion_toast: ^2.7.8
|
||||
mutex: ^3.0.1
|
||||
path: ^1.8.2
|
||||
path_provider: ^2.0.11
|
||||
pinput: ^2.3.0
|
||||
|
Loading…
Reference in New Issue
Block a user