switch to smpl key

This commit is contained in:
Christien Rioux 2023-08-07 11:02:29 -04:00
parent e68cbb26eb
commit ee80dbf3a5
13 changed files with 192 additions and 136 deletions

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart';
@ -61,13 +60,13 @@ class ChatComponentState extends ConsumerState<ChatComponent> {
} }
Future<void> _loadMessages() async { Future<void> _loadMessages() async {
final localConversationOwned = proto.OwnedDHTRecordPointerProto.fromProto( final localConversationRecordKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.localConversation); widget.activeChatContact.localConversationRecordKey);
final remoteIdentityPublicKey = proto.TypedKeyProto.fromProto( final remoteIdentityPublicKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.identityPublicKey); widget.activeChatContact.identityPublicKey);
final protoMessages = await getLocalConversationMessages( final protoMessages = await getLocalConversationMessages(
activeAccountInfo: widget.activeAccountInfo, activeAccountInfo: widget.activeAccountInfo,
localConversationOwned: localConversationOwned, localConversationRecordKey: localConversationRecordKey,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
if (protoMessages == null) { if (protoMessages == null) {
return; return;
@ -108,14 +107,14 @@ class ChatComponentState extends ConsumerState<ChatComponent> {
}); });
// Now add the message to the conversation messages // Now add the message to the conversation messages
final localConversationOwned = proto.OwnedDHTRecordPointerProto.fromProto( final localConversationRecordKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.localConversation); widget.activeChatContact.localConversationRecordKey);
final remoteIdentityPublicKey = proto.TypedKeyProto.fromProto( final remoteIdentityPublicKey = proto.TypedKeyProto.fromProto(
widget.activeChatContact.identityPublicKey); widget.activeChatContact.identityPublicKey);
await addLocalConversationMessage( await addLocalConversationMessage(
activeAccountInfo: widget.activeAccountInfo, activeAccountInfo: widget.activeAccountInfo,
localConversationOwned: localConversationOwned, localConversationRecordKey: localConversationRecordKey,
remoteIdentityPublicKey: remoteIdentityPublicKey, remoteIdentityPublicKey: remoteIdentityPublicKey,
message: protoMessage); message: protoMessage);
} }

View File

@ -23,8 +23,9 @@ class ChatSingleContactItemWidget extends ConsumerWidget {
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final activeChat = ref.watch(activeChatStateProvider).asData?.value; final activeChat = ref.watch(activeChatStateProvider).asData?.value;
final selected = activeChat == final remoteConversationRecordKey =
proto.TypedKeyProto.fromProto(contact.remoteConversationKey); proto.TypedKeyProto.fromProto(contact.remoteConversationRecordKey);
final selected = activeChat == remoteConversationRecordKey;
return Container( return Container(
margin: const EdgeInsets.fromLTRB(4, 4, 4, 0), margin: const EdgeInsets.fromLTRB(4, 4, 4, 0),
@ -47,8 +48,7 @@ class ChatSingleContactItemWidget extends ConsumerWidget {
await deleteChat( await deleteChat(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteConversationRecordKey: remoteConversationRecordKey:
proto.TypedKeyProto.fromProto( remoteConversationRecordKey);
contact.remoteConversationKey));
ref.invalidate(fetchChatListProvider); ref.invalidate(fetchChatListProvider);
} }
}, },
@ -71,8 +71,7 @@ class ChatSingleContactItemWidget extends ConsumerWidget {
// component is not dragged. // component is not dragged.
child: ListTile( child: ListTile(
onTap: () async { onTap: () async {
activeChatState.add(proto.TypedKeyProto.fromProto( activeChatState.add(remoteConversationRecordKey);
contact.remoteConversationKey));
ref.invalidate(fetchChatListProvider); ref.invalidate(fetchChatListProvider);
}, },
title: Text(contact.editedProfile.name), title: Text(contact.editedProfile.name),

View File

@ -19,7 +19,8 @@ class ChatSingleContactListWidget extends ConsumerWidget {
required this.chatList, required this.chatList,
super.key}) super.key})
: contactMap = IMap.fromIterable(contactList, : contactMap = IMap.fromIterable(contactList,
keyMapper: (c) => c.remoteConversationKey, valueMapper: (c) => c); keyMapper: (c) => c.remoteConversationRecordKey,
valueMapper: (c) => c);
final IMap<proto.TypedKey, proto.Contact> contactMap; final IMap<proto.TypedKey, proto.Contact> contactMap;
final IList<proto.Chat> chatList; final IList<proto.Chat> chatList;

View File

@ -24,7 +24,7 @@ class ContactItemWidget extends ConsumerWidget {
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final remoteConversationKey = final remoteConversationKey =
proto.TypedKeyProto.fromProto(contact.remoteConversationKey); proto.TypedKeyProto.fromProto(contact.remoteConversationRecordKey);
return Container( return Container(
margin: const EdgeInsets.fromLTRB(4, 4, 4, 0), margin: const EdgeInsets.fromLTRB(4, 4, 4, 0),
@ -80,8 +80,12 @@ class ContactItemWidget extends ConsumerWidget {
remoteConversationRecordKey: remoteConversationKey); remoteConversationRecordKey: remoteConversationKey);
// Click over to chats // Click over to chats
await MainPager.of(context)?.pageController.animateToPage(1, if (context.mounted) {
duration: 250.ms, curve: Curves.easeInOut); await MainPager.of(context)?.pageController.animateToPage(
1,
duration: 250.ms,
curve: Curves.easeInOut);
}
} }
// // ignore: use_build_context_synchronously // // ignore: use_build_context_synchronously

View File

@ -116,8 +116,10 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
profile: acceptedContact.profile, profile: acceptedContact.profile,
remoteIdentity: acceptedContact.remoteIdentity, remoteIdentity: acceptedContact.remoteIdentity,
remoteConversationKey: acceptedContact.remoteConversationKey, remoteConversationRecordKey:
localConversation: acceptedContact.localConversation, acceptedContact.remoteConversationRecordKey,
localConversationRecordKey:
acceptedContact.localConversationRecordKey,
); );
ref ref
..invalidate(fetchContactInvitationRecordsProvider) ..invalidate(fetchContactInvitationRecordsProvider)

View File

@ -1000,8 +1000,8 @@ class Contact extends $pb.GeneratedMessage {
..aOM<Profile>(2, _omitFieldNames ? '' : 'remoteProfile', subBuilder: Profile.create) ..aOM<Profile>(2, _omitFieldNames ? '' : 'remoteProfile', subBuilder: Profile.create)
..aOS(3, _omitFieldNames ? '' : 'identityMasterJson') ..aOS(3, _omitFieldNames ? '' : 'identityMasterJson')
..aOM<TypedKey>(4, _omitFieldNames ? '' : 'identityPublicKey', subBuilder: TypedKey.create) ..aOM<TypedKey>(4, _omitFieldNames ? '' : 'identityPublicKey', subBuilder: TypedKey.create)
..aOM<TypedKey>(5, _omitFieldNames ? '' : 'remoteConversationKey', subBuilder: TypedKey.create) ..aOM<TypedKey>(5, _omitFieldNames ? '' : 'remoteConversationRecordKey', subBuilder: TypedKey.create)
..aOM<OwnedDHTRecordPointer>(6, _omitFieldNames ? '' : 'localConversation', subBuilder: OwnedDHTRecordPointer.create) ..aOM<TypedKey>(6, _omitFieldNames ? '' : 'localConversationRecordKey', subBuilder: TypedKey.create)
..aOB(7, _omitFieldNames ? '' : 'showAvailability') ..aOB(7, _omitFieldNames ? '' : 'showAvailability')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -1070,26 +1070,26 @@ class Contact extends $pb.GeneratedMessage {
TypedKey ensureIdentityPublicKey() => $_ensure(3); TypedKey ensureIdentityPublicKey() => $_ensure(3);
@$pb.TagNumber(5) @$pb.TagNumber(5)
TypedKey get remoteConversationKey => $_getN(4); TypedKey get remoteConversationRecordKey => $_getN(4);
@$pb.TagNumber(5) @$pb.TagNumber(5)
set remoteConversationKey(TypedKey v) { setField(5, v); } set remoteConversationRecordKey(TypedKey v) { setField(5, v); }
@$pb.TagNumber(5) @$pb.TagNumber(5)
$core.bool hasRemoteConversationKey() => $_has(4); $core.bool hasRemoteConversationRecordKey() => $_has(4);
@$pb.TagNumber(5) @$pb.TagNumber(5)
void clearRemoteConversationKey() => clearField(5); void clearRemoteConversationRecordKey() => clearField(5);
@$pb.TagNumber(5) @$pb.TagNumber(5)
TypedKey ensureRemoteConversationKey() => $_ensure(4); TypedKey ensureRemoteConversationRecordKey() => $_ensure(4);
@$pb.TagNumber(6) @$pb.TagNumber(6)
OwnedDHTRecordPointer get localConversation => $_getN(5); TypedKey get localConversationRecordKey => $_getN(5);
@$pb.TagNumber(6) @$pb.TagNumber(6)
set localConversation(OwnedDHTRecordPointer v) { setField(6, v); } set localConversationRecordKey(TypedKey v) { setField(6, v); }
@$pb.TagNumber(6) @$pb.TagNumber(6)
$core.bool hasLocalConversation() => $_has(5); $core.bool hasLocalConversationRecordKey() => $_has(5);
@$pb.TagNumber(6) @$pb.TagNumber(6)
void clearLocalConversation() => clearField(6); void clearLocalConversationRecordKey() => clearField(6);
@$pb.TagNumber(6) @$pb.TagNumber(6)
OwnedDHTRecordPointer ensureLocalConversation() => $_ensure(5); TypedKey ensureLocalConversationRecordKey() => $_ensure(5);
@$pb.TagNumber(7) @$pb.TagNumber(7)
$core.bool get showAvailability => $_getBF(6); $core.bool get showAvailability => $_getBF(6);
@ -1654,7 +1654,7 @@ class ContactResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ContactResponse', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ContactResponse', createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'accept') ..aOB(1, _omitFieldNames ? '' : 'accept')
..aOM<TypedKey>(2, _omitFieldNames ? '' : 'identityMasterRecordKey', subBuilder: TypedKey.create) ..aOM<TypedKey>(2, _omitFieldNames ? '' : 'identityMasterRecordKey', subBuilder: TypedKey.create)
..aOM<TypedKey>(3, _omitFieldNames ? '' : 'remoteConversationKey', subBuilder: TypedKey.create) ..aOM<TypedKey>(3, _omitFieldNames ? '' : 'remoteConversationRecordKey', subBuilder: TypedKey.create)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -1700,15 +1700,15 @@ class ContactResponse extends $pb.GeneratedMessage {
TypedKey ensureIdentityMasterRecordKey() => $_ensure(1); TypedKey ensureIdentityMasterRecordKey() => $_ensure(1);
@$pb.TagNumber(3) @$pb.TagNumber(3)
TypedKey get remoteConversationKey => $_getN(2); TypedKey get remoteConversationRecordKey => $_getN(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
set remoteConversationKey(TypedKey v) { setField(3, v); } set remoteConversationRecordKey(TypedKey v) { setField(3, v); }
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.bool hasRemoteConversationKey() => $_has(2); $core.bool hasRemoteConversationRecordKey() => $_has(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
void clearRemoteConversationKey() => clearField(3); void clearRemoteConversationRecordKey() => clearField(3);
@$pb.TagNumber(3) @$pb.TagNumber(3)
TypedKey ensureRemoteConversationKey() => $_ensure(2); TypedKey ensureRemoteConversationRecordKey() => $_ensure(2);
} }
class SignedContactResponse extends $pb.GeneratedMessage { class SignedContactResponse extends $pb.GeneratedMessage {
@ -1775,7 +1775,7 @@ class ContactInvitationRecord extends $pb.GeneratedMessage {
..aOM<OwnedDHTRecordPointer>(1, _omitFieldNames ? '' : 'contactRequestInbox', subBuilder: OwnedDHTRecordPointer.create) ..aOM<OwnedDHTRecordPointer>(1, _omitFieldNames ? '' : 'contactRequestInbox', subBuilder: OwnedDHTRecordPointer.create)
..aOM<CryptoKey>(2, _omitFieldNames ? '' : 'writerKey', subBuilder: CryptoKey.create) ..aOM<CryptoKey>(2, _omitFieldNames ? '' : 'writerKey', subBuilder: CryptoKey.create)
..aOM<CryptoKey>(3, _omitFieldNames ? '' : 'writerSecret', subBuilder: CryptoKey.create) ..aOM<CryptoKey>(3, _omitFieldNames ? '' : 'writerSecret', subBuilder: CryptoKey.create)
..aOM<OwnedDHTRecordPointer>(4, _omitFieldNames ? '' : 'localConversation', subBuilder: OwnedDHTRecordPointer.create) ..aOM<TypedKey>(4, _omitFieldNames ? '' : 'localConversationRecordKey', subBuilder: TypedKey.create)
..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'expiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'expiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
..a<$core.List<$core.int>>(6, _omitFieldNames ? '' : 'invitation', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>(6, _omitFieldNames ? '' : 'invitation', $pb.PbFieldType.OY)
..aOS(7, _omitFieldNames ? '' : 'message') ..aOS(7, _omitFieldNames ? '' : 'message')
@ -1837,15 +1837,15 @@ class ContactInvitationRecord extends $pb.GeneratedMessage {
CryptoKey ensureWriterSecret() => $_ensure(2); CryptoKey ensureWriterSecret() => $_ensure(2);
@$pb.TagNumber(4) @$pb.TagNumber(4)
OwnedDHTRecordPointer get localConversation => $_getN(3); TypedKey get localConversationRecordKey => $_getN(3);
@$pb.TagNumber(4) @$pb.TagNumber(4)
set localConversation(OwnedDHTRecordPointer v) { setField(4, v); } set localConversationRecordKey(TypedKey v) { setField(4, v); }
@$pb.TagNumber(4) @$pb.TagNumber(4)
$core.bool hasLocalConversation() => $_has(3); $core.bool hasLocalConversationRecordKey() => $_has(3);
@$pb.TagNumber(4) @$pb.TagNumber(4)
void clearLocalConversation() => clearField(4); void clearLocalConversationRecordKey() => clearField(4);
@$pb.TagNumber(4) @$pb.TagNumber(4)
OwnedDHTRecordPointer ensureLocalConversation() => $_ensure(3); TypedKey ensureLocalConversationRecordKey() => $_ensure(3);
@$pb.TagNumber(5) @$pb.TagNumber(5)
$fixnum.Int64 get expiration => $_getI64(4); $fixnum.Int64 get expiration => $_getI64(4);

View File

@ -303,8 +303,8 @@ const Contact$json = {
{'1': 'remote_profile', '3': 2, '4': 1, '5': 11, '6': '.Profile', '10': 'remoteProfile'}, {'1': 'remote_profile', '3': 2, '4': 1, '5': 11, '6': '.Profile', '10': 'remoteProfile'},
{'1': 'identity_master_json', '3': 3, '4': 1, '5': 9, '10': 'identityMasterJson'}, {'1': 'identity_master_json', '3': 3, '4': 1, '5': 9, '10': 'identityMasterJson'},
{'1': 'identity_public_key', '3': 4, '4': 1, '5': 11, '6': '.TypedKey', '10': 'identityPublicKey'}, {'1': 'identity_public_key', '3': 4, '4': 1, '5': 11, '6': '.TypedKey', '10': 'identityPublicKey'},
{'1': 'remote_conversation_key', '3': 5, '4': 1, '5': 11, '6': '.TypedKey', '10': 'remoteConversationKey'}, {'1': 'remote_conversation_record_key', '3': 5, '4': 1, '5': 11, '6': '.TypedKey', '10': 'remoteConversationRecordKey'},
{'1': 'local_conversation', '3': 6, '4': 1, '5': 11, '6': '.OwnedDHTRecordPointer', '10': 'localConversation'}, {'1': 'local_conversation_record_key', '3': 6, '4': 1, '5': 11, '6': '.TypedKey', '10': 'localConversationRecordKey'},
{'1': 'show_availability', '3': 7, '4': 1, '5': 8, '10': 'showAvailability'}, {'1': 'show_availability', '3': 7, '4': 1, '5': 8, '10': 'showAvailability'},
], ],
}; };
@ -314,11 +314,11 @@ final $typed_data.Uint8List contactDescriptor = $convert.base64Decode(
'CgdDb250YWN0Ei8KDmVkaXRlZF9wcm9maWxlGAEgASgLMgguUHJvZmlsZVINZWRpdGVkUHJvZm' 'CgdDb250YWN0Ei8KDmVkaXRlZF9wcm9maWxlGAEgASgLMgguUHJvZmlsZVINZWRpdGVkUHJvZm'
'lsZRIvCg5yZW1vdGVfcHJvZmlsZRgCIAEoCzIILlByb2ZpbGVSDXJlbW90ZVByb2ZpbGUSMAoU' 'lsZRIvCg5yZW1vdGVfcHJvZmlsZRgCIAEoCzIILlByb2ZpbGVSDXJlbW90ZVByb2ZpbGUSMAoU'
'aWRlbnRpdHlfbWFzdGVyX2pzb24YAyABKAlSEmlkZW50aXR5TWFzdGVySnNvbhI5ChNpZGVudG' 'aWRlbnRpdHlfbWFzdGVyX2pzb24YAyABKAlSEmlkZW50aXR5TWFzdGVySnNvbhI5ChNpZGVudG'
'l0eV9wdWJsaWNfa2V5GAQgASgLMgkuVHlwZWRLZXlSEWlkZW50aXR5UHVibGljS2V5EkEKF3Jl' 'l0eV9wdWJsaWNfa2V5GAQgASgLMgkuVHlwZWRLZXlSEWlkZW50aXR5UHVibGljS2V5Ek4KHnJl'
'bW90ZV9jb252ZXJzYXRpb25fa2V5GAUgASgLMgkuVHlwZWRLZXlSFXJlbW90ZUNvbnZlcnNhdG' 'bW90ZV9jb252ZXJzYXRpb25fcmVjb3JkX2tleRgFIAEoCzIJLlR5cGVkS2V5UhtyZW1vdGVDb2'
'lvbktleRJFChJsb2NhbF9jb252ZXJzYXRpb24YBiABKAsyFi5Pd25lZERIVFJlY29yZFBvaW50' '52ZXJzYXRpb25SZWNvcmRLZXkSTAodbG9jYWxfY29udmVyc2F0aW9uX3JlY29yZF9rZXkYBiAB'
'ZXJSEWxvY2FsQ29udmVyc2F0aW9uEisKEXNob3dfYXZhaWxhYmlsaXR5GAcgASgIUhBzaG93QX' 'KAsyCS5UeXBlZEtleVIabG9jYWxDb252ZXJzYXRpb25SZWNvcmRLZXkSKwoRc2hvd19hdmFpbG'
'ZhaWxhYmlsaXR5'); 'FiaWxpdHkYByABKAhSEHNob3dBdmFpbGFiaWxpdHk=');
@$core.Deprecated('Use profileDescriptor instead') @$core.Deprecated('Use profileDescriptor instead')
const Profile$json = { const Profile$json = {
@ -462,7 +462,7 @@ const ContactResponse$json = {
'2': [ '2': [
{'1': 'accept', '3': 1, '4': 1, '5': 8, '10': 'accept'}, {'1': 'accept', '3': 1, '4': 1, '5': 8, '10': 'accept'},
{'1': 'identity_master_record_key', '3': 2, '4': 1, '5': 11, '6': '.TypedKey', '10': 'identityMasterRecordKey'}, {'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'}, {'1': 'remote_conversation_record_key', '3': 3, '4': 1, '5': 11, '6': '.TypedKey', '10': 'remoteConversationRecordKey'},
], ],
}; };
@ -470,8 +470,8 @@ const ContactResponse$json = {
final $typed_data.Uint8List contactResponseDescriptor = $convert.base64Decode( final $typed_data.Uint8List contactResponseDescriptor = $convert.base64Decode(
'Cg9Db250YWN0UmVzcG9uc2USFgoGYWNjZXB0GAEgASgIUgZhY2NlcHQSRgoaaWRlbnRpdHlfbW' 'Cg9Db250YWN0UmVzcG9uc2USFgoGYWNjZXB0GAEgASgIUgZhY2NlcHQSRgoaaWRlbnRpdHlfbW'
'FzdGVyX3JlY29yZF9rZXkYAiABKAsyCS5UeXBlZEtleVIXaWRlbnRpdHlNYXN0ZXJSZWNvcmRL' 'FzdGVyX3JlY29yZF9rZXkYAiABKAsyCS5UeXBlZEtleVIXaWRlbnRpdHlNYXN0ZXJSZWNvcmRL'
'ZXkSQQoXcmVtb3RlX2NvbnZlcnNhdGlvbl9rZXkYAyABKAsyCS5UeXBlZEtleVIVcmVtb3RlQ2' 'ZXkSTgoecmVtb3RlX2NvbnZlcnNhdGlvbl9yZWNvcmRfa2V5GAMgASgLMgkuVHlwZWRLZXlSG3'
'9udmVyc2F0aW9uS2V5'); 'JlbW90ZUNvbnZlcnNhdGlvblJlY29yZEtleQ==');
@$core.Deprecated('Use signedContactResponseDescriptor instead') @$core.Deprecated('Use signedContactResponseDescriptor instead')
const SignedContactResponse$json = { const SignedContactResponse$json = {
@ -495,7 +495,7 @@ const ContactInvitationRecord$json = {
{'1': 'contact_request_inbox', '3': 1, '4': 1, '5': 11, '6': '.OwnedDHTRecordPointer', '10': 'contactRequestInbox'}, {'1': 'contact_request_inbox', '3': 1, '4': 1, '5': 11, '6': '.OwnedDHTRecordPointer', '10': 'contactRequestInbox'},
{'1': 'writer_key', '3': 2, '4': 1, '5': 11, '6': '.CryptoKey', '10': 'writerKey'}, {'1': 'writer_key', '3': 2, '4': 1, '5': 11, '6': '.CryptoKey', '10': 'writerKey'},
{'1': 'writer_secret', '3': 3, '4': 1, '5': 11, '6': '.CryptoKey', '10': 'writerSecret'}, {'1': 'writer_secret', '3': 3, '4': 1, '5': 11, '6': '.CryptoKey', '10': 'writerSecret'},
{'1': 'local_conversation', '3': 4, '4': 1, '5': 11, '6': '.OwnedDHTRecordPointer', '10': 'localConversation'}, {'1': 'local_conversation_record_key', '3': 4, '4': 1, '5': 11, '6': '.TypedKey', '10': 'localConversationRecordKey'},
{'1': 'expiration', '3': 5, '4': 1, '5': 4, '10': 'expiration'}, {'1': 'expiration', '3': 5, '4': 1, '5': 4, '10': 'expiration'},
{'1': 'invitation', '3': 6, '4': 1, '5': 12, '10': 'invitation'}, {'1': 'invitation', '3': 6, '4': 1, '5': 12, '10': 'invitation'},
{'1': 'message', '3': 7, '4': 1, '5': 9, '10': 'message'}, {'1': 'message', '3': 7, '4': 1, '5': 9, '10': 'message'},
@ -507,8 +507,8 @@ final $typed_data.Uint8List contactInvitationRecordDescriptor = $convert.base64D
'ChdDb250YWN0SW52aXRhdGlvblJlY29yZBJKChVjb250YWN0X3JlcXVlc3RfaW5ib3gYASABKA' 'ChdDb250YWN0SW52aXRhdGlvblJlY29yZBJKChVjb250YWN0X3JlcXVlc3RfaW5ib3gYASABKA'
'syFi5Pd25lZERIVFJlY29yZFBvaW50ZXJSE2NvbnRhY3RSZXF1ZXN0SW5ib3gSKQoKd3JpdGVy' 'syFi5Pd25lZERIVFJlY29yZFBvaW50ZXJSE2NvbnRhY3RSZXF1ZXN0SW5ib3gSKQoKd3JpdGVy'
'X2tleRgCIAEoCzIKLkNyeXB0b0tleVIJd3JpdGVyS2V5Ei8KDXdyaXRlcl9zZWNyZXQYAyABKA' 'X2tleRgCIAEoCzIKLkNyeXB0b0tleVIJd3JpdGVyS2V5Ei8KDXdyaXRlcl9zZWNyZXQYAyABKA'
'syCi5DcnlwdG9LZXlSDHdyaXRlclNlY3JldBJFChJsb2NhbF9jb252ZXJzYXRpb24YBCABKAsy' 'syCi5DcnlwdG9LZXlSDHdyaXRlclNlY3JldBJMCh1sb2NhbF9jb252ZXJzYXRpb25fcmVjb3Jk'
'Fi5Pd25lZERIVFJlY29yZFBvaW50ZXJSEWxvY2FsQ29udmVyc2F0aW9uEh4KCmV4cGlyYXRpb2' 'X2tleRgEIAEoCzIJLlR5cGVkS2V5Uhpsb2NhbENvbnZlcnNhdGlvblJlY29yZEtleRIeCgpleH'
'4YBSABKARSCmV4cGlyYXRpb24SHgoKaW52aXRhdGlvbhgGIAEoDFIKaW52aXRhdGlvbhIYCgdt' 'BpcmF0aW9uGAUgASgEUgpleHBpcmF0aW9uEh4KCmludml0YXRpb24YBiABKAxSCmludml0YXRp'
'ZXNzYWdlGAcgASgJUgdtZXNzYWdl'); 'b24SGAoHbWVzc2FnZRgHIAEoCVIHbWVzc2FnZQ==');

View File

@ -204,9 +204,9 @@ message Contact {
// Copy of friend's most recent identity public key from their identityMaster // Copy of friend's most recent identity public key from their identityMaster
TypedKey identity_public_key = 4; TypedKey identity_public_key = 4;
// Remote conversation key to sync from friend // Remote conversation key to sync from friend
TypedKey remote_conversation_key = 5; TypedKey remote_conversation_record_key = 5;
// Our conversation key for friend to sync // Our conversation key for friend to sync
OwnedDHTRecordPointer local_conversation = 6; TypedKey local_conversation_record_key = 6;
// Show availability // Show availability
bool show_availability = 7; bool show_availability = 7;
} }
@ -343,7 +343,7 @@ message ContactResponse {
// Remote identity master DHT record key // Remote identity master DHT record key
TypedKey identity_master_record_key = 2; TypedKey identity_master_record_key = 2;
// Remote chat DHT record key if accepted // Remote chat DHT record key if accepted
TypedKey remote_conversation_key = 3; TypedKey remote_conversation_record_key = 3;
} }
// Signature of response with identity // Signature of response with identity
@ -364,7 +364,7 @@ message ContactInvitationRecord {
// Writer secret sent encrypted in the invitation // Writer secret sent encrypted in the invitation
CryptoKey writer_secret = 3; CryptoKey writer_secret = 3;
// Local chat DHT record key (parent is accountkey, will be moved to Contact if accepted) // Local chat DHT record key (parent is accountkey, will be moved to Contact if accepted)
OwnedDHTRecordPointer local_conversation = 4; TypedKey local_conversation_record_key = 4;
// Expiration timestamp // Expiration timestamp
uint64 expiration = 5; uint64 expiration = 5;
// A copy of the raw SignedContactInvitation invitation bytes post-encryption and signing // A copy of the raw SignedContactInvitation invitation bytes post-encryption and signing

View File

@ -14,6 +14,7 @@ import '../providers/account.dart';
import '../providers/chat.dart'; import '../providers/chat.dart';
import '../providers/contact.dart'; import '../providers/contact.dart';
import '../providers/contact_invite.dart'; import '../providers/contact_invite.dart';
import '../providers/conversation.dart';
import '../providers/window_control.dart'; import '../providers/window_control.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import 'main_pager/main_pager.dart'; import 'main_pager/main_pager.dart';
@ -113,8 +114,10 @@ class HomePageState extends ConsumerState<HomePage>
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
profile: acceptedContact.profile, profile: acceptedContact.profile,
remoteIdentity: acceptedContact.remoteIdentity, remoteIdentity: acceptedContact.remoteIdentity,
remoteConversationKey: acceptedContact.remoteConversationKey, remoteConversationRecordKey:
localConversation: acceptedContact.localConversation, acceptedContact.remoteConversationRecordKey,
localConversationRecordKey:
acceptedContact.localConversationRecordKey,
); );
ref ref
..invalidate(fetchContactInvitationRecordsProvider) ..invalidate(fetchContactInvitationRecordsProvider)
@ -134,19 +137,34 @@ class HomePageState extends ConsumerState<HomePage>
if (activeChat == null) { if (activeChat == null) {
return; return;
} }
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
return;
}
final contactList = ref.read(fetchContactListProvider).asData?.value ?? final contactList = ref.read(fetchContactListProvider).asData?.value ??
const IListConst([]); const IListConst([]);
final activeChatContactIdx = contactList.indexWhere( final activeChatContactIdx = contactList.indexWhere(
(c) => (c) =>
proto.TypedKeyProto.fromProto(c.remoteConversationKey) == activeChat, proto.TypedKeyProto.fromProto(c.remoteConversationRecordKey) ==
activeChat,
); );
if (activeChatContactIdx == -1) { if (activeChatContactIdx == -1) {
return; return;
} }
final activeChatContact = contactList[activeChatContactIdx]; final activeChatContact = contactList[activeChatContactIdx];
final remoteIdentityPublicKey =
proto.TypedKeyProto.fromProto(activeChatContact.identityPublicKey);
final remoteConversationRecordKey = proto.TypedKeyProto.fromProto(
activeChatContact.remoteConversationRecordKey);
//activeChatContact.rem await getRemoteConversationMessages(
activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey,
remoteConversationRecordKey: remoteConversationRecordKey);
// xxx add messages
} }
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
@ -186,7 +204,8 @@ class HomePageState extends ConsumerState<HomePage>
final activeChatContactIdx = contactList.indexWhere( final activeChatContactIdx = contactList.indexWhere(
(c) => (c) =>
proto.TypedKeyProto.fromProto(c.remoteConversationKey) == activeChat, proto.TypedKeyProto.fromProto(c.remoteConversationRecordKey) ==
activeChat,
); );
if (activeChatContactIdx == -1) { if (activeChatContactIdx == -1) {
activeChatState.add(null); activeChatState.add(null);

View File

@ -17,8 +17,8 @@ Future<void> createContact({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required proto.Profile profile, required proto.Profile profile,
required IdentityMaster remoteIdentity, required IdentityMaster remoteIdentity,
required TypedKey remoteConversationKey, required TypedKey remoteConversationRecordKey,
required OwnedDHTRecordPointer localConversation, required TypedKey localConversationRecordKey,
}) async { }) async {
final accountRecordKey = final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
@ -32,8 +32,8 @@ Future<void> createContact({
kind: remoteIdentity.identityRecordKey.kind, kind: remoteIdentity.identityRecordKey.kind,
value: remoteIdentity.identityPublicKey) value: remoteIdentity.identityPublicKey)
.toProto() .toProto()
..remoteConversationKey = remoteConversationKey.toProto() ..remoteConversationRecordKey = remoteConversationRecordKey.toProto()
..localConversation = localConversation.toProto() ..localConversationRecordKey = localConversationRecordKey.toProto()
..showAvailability = false; ..showAvailability = false;
// Add Contact to account's list // Add Contact to account's list
@ -56,7 +56,7 @@ Future<void> deleteContact(
final accountRecordKey = final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
final remoteConversationKey = final remoteConversationKey =
proto.TypedKeyProto.fromProto(contact.remoteConversationKey); proto.TypedKeyProto.fromProto(contact.remoteConversationRecordKey);
// Remove any chats for this contact // Remove any chats for this contact
await deleteChat( await deleteChat(
@ -75,14 +75,14 @@ Future<void> deleteContact(
if (item == null) { if (item == null) {
throw Exception('Failed to get contact'); throw Exception('Failed to get contact');
} }
if (item.remoteConversationKey == contact.remoteConversationKey) { if (item.remoteConversationRecordKey ==
contact.remoteConversationRecordKey) {
await contactList.tryRemoveItem(i); await contactList.tryRemoveItem(i);
break; break;
} }
} }
await (await pool.openOwned( await (await pool.openRead(
proto.OwnedDHTRecordPointerProto.fromProto( proto.TypedKeyProto.fromProto(contact.localConversationRecordKey),
contact.localConversation),
parent: accountRecordKey)) parent: accountRecordKey))
.delete(); .delete();
await (await pool.openRead(remoteConversationKey, parent: accountRecordKey)) await (await pool.openRead(remoteConversationKey, parent: accountRecordKey))

View File

@ -28,14 +28,14 @@ class AcceptedContact {
AcceptedContact({ AcceptedContact({
required this.profile, required this.profile,
required this.remoteIdentity, required this.remoteIdentity,
required this.remoteConversationKey, required this.remoteConversationRecordKey,
required this.localConversation, required this.localConversationRecordKey,
}); });
proto.Profile profile; proto.Profile profile;
IdentityMaster remoteIdentity; IdentityMaster remoteIdentity;
TypedKey remoteConversationKey; TypedKey remoteConversationRecordKey;
OwnedDHTRecordPointer localConversation; TypedKey localConversationRecordKey;
} }
class AcceptedOrRejectedContact { class AcceptedOrRejectedContact {
@ -92,33 +92,33 @@ Future<AcceptedOrRejectedContact?> checkAcceptRejectContact(
contactResponseBytes, signature); contactResponseBytes, signature);
// Pull profile from remote conversation key // Pull profile from remote conversation key
final remoteConversationKey = final remoteConversationRecordKey = proto.TypedKeyProto.fromProto(
proto.TypedKeyProto.fromProto(contactResponse.remoteConversationKey); contactResponse.remoteConversationRecordKey);
final remoteConversation = await readRemoteConversation( final remoteConversation = await readRemoteConversation(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey:
contactIdentityMaster.identityPublicTypedKey(), contactIdentityMaster.identityPublicTypedKey(),
remoteConversationKey: remoteConversationKey); remoteConversationRecordKey: remoteConversationRecordKey);
if (remoteConversation == null) { if (remoteConversation == null) {
log.info('Remote conversation could not be read. Waiting...'); log.info('Remote conversation could not be read. Waiting...');
return null; return null;
} }
// Complete the local conversation now that we have the remote profile // Complete the local conversation now that we have the remote profile
final localConversationOwned = proto.OwnedDHTRecordPointerProto.fromProto( final localConversationRecordKey = proto.TypedKeyProto.fromProto(
contactInvitationRecord.localConversation); contactInvitationRecord.localConversationRecordKey);
return createConversation( return createConversation(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey:
contactIdentityMaster.identityPublicTypedKey(), contactIdentityMaster.identityPublicTypedKey(),
existingConversationOwned: localConversationOwned, existingConversationRecordKey: localConversationRecordKey,
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
callback: (localConversation) async { callback: (localConversation) async {
return AcceptedOrRejectedContact( return AcceptedOrRejectedContact(
acceptedContact: AcceptedContact( acceptedContact: AcceptedContact(
profile: remoteConversation.profile, profile: remoteConversation.profile,
remoteIdentity: contactIdentityMaster, remoteIdentity: contactIdentityMaster,
remoteConversationKey: remoteConversationKey, remoteConversationRecordKey: remoteConversationRecordKey,
localConversation: localConversationOwned)); localConversationRecordKey: localConversationRecordKey));
}); });
}); });
@ -182,9 +182,9 @@ Future<void> deleteContactInvitation(
await contactRequestInbox.delete(); await contactRequestInbox.delete();
}); });
if (!accepted) { if (!accepted) {
await (await pool.openOwned( await (await pool.openRead(
proto.OwnedDHTRecordPointerProto.fromProto( proto.TypedKeyProto.fromProto(
contactInvitationRecord.localConversation), contactInvitationRecord.localConversationRecordKey),
parent: accountRecordKey)) parent: accountRecordKey))
.delete(); .delete();
} }
@ -206,11 +206,13 @@ Future<Uint8List> createContactInvitation(
// Generate writer keypair to share with new contact // Generate writer keypair to share with new contact
final cs = await pool.veilid.bestCryptoSystem(); final cs = await pool.veilid.bestCryptoSystem();
final writer = await cs.generateKeyPair(); final contactRequestWriter = await cs.generateKeyPair();
final conversationWriter =
getConversationWriter(activeAccountInfo: activeAccountInfo);
// Encrypt the writer secret with the encryption key // Encrypt the writer secret with the encryption key
final encryptedSecret = await encryptSecretToBytes( final encryptedSecret = await encryptSecretToBytes(
secret: writer.secret, secret: contactRequestWriter.secret,
cryptoKind: cs.kind(), cryptoKind: cs.kind(),
encryptionKey: encryptionKey, encryptionKey: encryptionKey,
encryptionKeyType: encryptionKeyType); encryptionKeyType: encryptionKeyType);
@ -220,19 +222,24 @@ Future<Uint8List> createContactInvitation(
// to and it will be eventually encrypted with the DH of the contact's // to and it will be eventually encrypted with the DH of the contact's
// identity key // identity key
late final Uint8List signedContactInvitationBytes; late final Uint8List signedContactInvitationBytes;
await (await pool.create(parent: accountRecordKey)) await (await pool.create(
parent: accountRecordKey,
schema: DHTSchema.smpl(oCnt: 0, members: [
DHTSchemaMember(mKey: conversationWriter.key, mCnt: 1)
])))
.deleteScope((localConversation) async { .deleteScope((localConversation) async {
// dont bother reopening localConversation with writer
// Make ContactRequestPrivate and encrypt with the writer secret // Make ContactRequestPrivate and encrypt with the writer secret
final crpriv = ContactRequestPrivate() final crpriv = ContactRequestPrivate()
..writerKey = writer.key.toProto() ..writerKey = contactRequestWriter.key.toProto()
..profile = activeAccountInfo.account.profile ..profile = activeAccountInfo.account.profile
..identityMasterRecordKey = ..identityMasterRecordKey =
activeAccountInfo.userLogin.accountMasterRecordKey.toProto() activeAccountInfo.userLogin.accountMasterRecordKey.toProto()
..chatRecordKey = localConversation.key.toProto() ..chatRecordKey = localConversation.key.toProto()
..expiration = expiration?.toInt64() ?? Int64.ZERO; ..expiration = expiration?.toInt64() ?? Int64.ZERO;
final crprivbytes = crpriv.writeToBuffer(); final crprivbytes = crpriv.writeToBuffer();
final encryptedContactRequestPrivate = final encryptedContactRequestPrivate = await cs.encryptNoAuthWithNonce(
await cs.encryptNoAuthWithNonce(crprivbytes, writer.secret); crprivbytes, contactRequestWriter.secret);
// Create ContactRequest and embed contactrequestprivate // Create ContactRequest and embed contactrequestprivate
final creq = ContactRequest() final creq = ContactRequest()
@ -242,8 +249,9 @@ Future<Uint8List> createContactInvitation(
// Create DHT unicast inbox for ContactRequest // Create DHT unicast inbox for ContactRequest
await (await pool.create( await (await pool.create(
parent: accountRecordKey, parent: accountRecordKey,
schema: DHTSchema.smpl( schema: DHTSchema.smpl(oCnt: 1, members: [
oCnt: 1, members: [DHTSchemaMember(mCnt: 1, mKey: writer.key)]), DHTSchemaMember(mCnt: 1, mKey: contactRequestWriter.key)
]),
crypto: const DHTRecordCryptoPublic())) crypto: const DHTRecordCryptoPublic()))
.deleteScope((contactRequestInbox) async { .deleteScope((contactRequestInbox) async {
// Store ContactRequest in owner subkey // Store ContactRequest in owner subkey
@ -264,9 +272,9 @@ Future<Uint8List> createContactInvitation(
final cinvrec = ContactInvitationRecord() final cinvrec = ContactInvitationRecord()
..contactRequestInbox = ..contactRequestInbox =
contactRequestInbox.ownedDHTRecordPointer.toProto() contactRequestInbox.ownedDHTRecordPointer.toProto()
..writerKey = writer.key.toProto() ..writerKey = contactRequestWriter.key.toProto()
..writerSecret = writer.secret.toProto() ..writerSecret = contactRequestWriter.secret.toProto()
..localConversation = localConversation.ownedDHTRecordPointer.toProto() ..localConversationRecordKey = localConversation.key.toProto()
..expiration = expiration?.toInt64() ?? Int64.ZERO ..expiration = expiration?.toInt64() ?? Int64.ZERO
..invitation = signedContactInvitationBytes ..invitation = signedContactInvitationBytes
..message = message; ..message = message;
@ -390,7 +398,7 @@ Future<AcceptedContact?> acceptContactInvitation(
callback: (localConversation) async { callback: (localConversation) async {
final contactResponse = ContactResponse() final contactResponse = ContactResponse()
..accept = true ..accept = true
..remoteConversationKey = localConversation.key.toProto() ..remoteConversationRecordKey = localConversation.key.toProto()
..identityMasterRecordKey = activeAccountInfo ..identityMasterRecordKey = activeAccountInfo
.localAccount.identityMaster.masterRecordKey .localAccount.identityMaster.masterRecordKey
.toProto(); .toProto();
@ -418,9 +426,9 @@ Future<AcceptedContact?> acceptContactInvitation(
return AcceptedContact( return AcceptedContact(
profile: validContactInvitation.contactRequestPrivate.profile, profile: validContactInvitation.contactRequestPrivate.profile,
remoteIdentity: validContactInvitation.contactIdentityMaster, remoteIdentity: validContactInvitation.contactIdentityMaster,
remoteConversationKey: proto.TypedKeyProto.fromProto( remoteConversationRecordKey: proto.TypedKeyProto.fromProto(
validContactInvitation.contactRequestPrivate.chatRecordKey), validContactInvitation.contactRequestPrivate.chatRecordKey),
localConversation: localConversation.ownedDHTRecordPointer, localConversationRecordKey: localConversation.key,
); );
}); });
}); });

View File

@ -24,6 +24,15 @@ Future<DHTRecordCrypto> getConversationCrypto({
return DHTRecordCryptoPrivate.fromSecret(identitySecret.kind, sharedSecret); return DHTRecordCryptoPrivate.fromSecret(identitySecret.kind, sharedSecret);
} }
KeyPair getConversationWriter({
required ActiveAccountInfo activeAccountInfo,
}) {
final identityKey =
activeAccountInfo.localAccount.identityMaster.identityPublicKey;
final identitySecret = activeAccountInfo.userLogin.identitySecret;
return KeyPair(key: identityKey, secret: identitySecret.value);
}
// Create a conversation // Create a conversation
// If we were the initator of the conversation there may be an // If we were the initator of the conversation there may be an
// incomplete 'existingConversationRecord' that we need to fill // incomplete 'existingConversationRecord' that we need to fill
@ -32,7 +41,7 @@ Future<T> createConversation<T>(
{required ActiveAccountInfo activeAccountInfo, {required ActiveAccountInfo activeAccountInfo,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
required FutureOr<T> Function(DHTRecord) callback, required FutureOr<T> Function(DHTRecord) callback,
OwnedDHTRecordPointer? existingConversationOwned}) async { TypedKey? existingConversationRecordKey}) async {
final pool = await DHTRecordPool.instance(); final pool = await DHTRecordPool.instance();
final accountRecordKey = final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
@ -40,28 +49,38 @@ Future<T> createConversation<T>(
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
final writer = getConversationWriter(activeAccountInfo: activeAccountInfo);
// Open with SMPL scheme for identity writer
late final DHTRecord localConversationRecord; late final DHTRecord localConversationRecord;
if (existingConversationOwned != null) { if (existingConversationRecordKey != null) {
localConversationRecord = await pool.openOwned(existingConversationOwned, localConversationRecord = await pool.openWrite(
existingConversationRecordKey, writer,
parent: accountRecordKey, crypto: crypto); parent: accountRecordKey, crypto: crypto);
} else { } else {
localConversationRecord = final localConversationRecordCreate = await pool.create(
await pool.create(parent: accountRecordKey, crypto: crypto); parent: accountRecordKey,
crypto: crypto,
schema: DHTSchema.smpl(
oCnt: 0, members: [DHTSchemaMember(mKey: writer.key, mCnt: 1)]));
await localConversationRecordCreate.close();
localConversationRecord = await pool.openWrite(
localConversationRecordCreate.key, writer,
parent: accountRecordKey, crypto: crypto);
} }
return localConversationRecord return localConversationRecord
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
.deleteScope((localConversation) async { .deleteScope((localConversation) async {
// Make messages log // Make messages log
return (await DHTShortArray.create( return (await DHTShortArray.create(
parent: localConversation.key, crypto: crypto)) parent: localConversation.key, crypto: crypto, smplWriter: writer))
.deleteScope((messages) async { .deleteScope((messages) async {
// Write local conversation key // Write local conversation key
final conversation = Conversation() final conversation = Conversation()
..profile = activeAccountInfo.account.profile ..profile = activeAccountInfo.account.profile
..identityMasterJson = ..identityMasterJson =
jsonEncode(activeAccountInfo.localAccount.identityMaster.toJson()) jsonEncode(activeAccountInfo.localAccount.identityMaster.toJson())
..messages = messages.record.ownedDHTRecordPointer.toProto(); ..messages = messages.record.key.toProto();
// //
final update = await localConversation.tryWriteProtobuf( final update = await localConversation.tryWriteProtobuf(
@ -76,8 +95,8 @@ Future<T> createConversation<T>(
Future<Conversation?> readRemoteConversation({ Future<Conversation?> readRemoteConversation({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required TypedKey remoteConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
required TypedKey remoteConversationKey,
}) async { }) async {
final accountRecordKey = final accountRecordKey =
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey; activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
@ -86,7 +105,7 @@ Future<Conversation?> readRemoteConversation({
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
return (await pool.openRead(remoteConversationKey, return (await pool.openRead(remoteConversationRecordKey,
parent: accountRecordKey, crypto: crypto)) parent: accountRecordKey, crypto: crypto))
.scope((remoteConversation) async { .scope((remoteConversation) async {
// //
@ -98,7 +117,7 @@ Future<Conversation?> readRemoteConversation({
Future<Conversation?> writeLocalConversation({ Future<Conversation?> writeLocalConversation({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required OwnedDHTRecordPointer localConversationOwned, required TypedKey localConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
required Conversation conversation, required Conversation conversation,
}) async { }) async {
@ -109,8 +128,9 @@ Future<Conversation?> writeLocalConversation({
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
final writer = getConversationWriter(activeAccountInfo: activeAccountInfo);
return (await pool.openOwned(localConversationOwned, return (await pool.openWrite(localConversationRecordKey, writer,
parent: accountRecordKey, crypto: crypto)) parent: accountRecordKey, crypto: crypto))
.scope((localConversation) async { .scope((localConversation) async {
// //
@ -125,7 +145,7 @@ Future<Conversation?> writeLocalConversation({
Future<Conversation?> readLocalConversation({ Future<Conversation?> readLocalConversation({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required OwnedDHTRecordPointer localConversationOwned, required TypedKey localConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
}) async { }) async {
final accountRecordKey = final accountRecordKey =
@ -136,7 +156,7 @@ Future<Conversation?> readLocalConversation({
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
return (await pool.openOwned(localConversationOwned, return (await pool.openRead(localConversationRecordKey,
parent: accountRecordKey, crypto: crypto)) parent: accountRecordKey, crypto: crypto))
.scope((localConversation) async { .scope((localConversation) async {
// //
@ -150,24 +170,25 @@ Future<Conversation?> readLocalConversation({
Future<void> addLocalConversationMessage( Future<void> addLocalConversationMessage(
{required ActiveAccountInfo activeAccountInfo, {required ActiveAccountInfo activeAccountInfo,
required OwnedDHTRecordPointer localConversationOwned, required TypedKey localConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
required proto.Message message}) async { required proto.Message message}) async {
final conversation = await readLocalConversation( final conversation = await readLocalConversation(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
localConversationOwned: localConversationOwned, localConversationRecordKey: localConversationRecordKey,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
if (conversation == null) { if (conversation == null) {
return; return;
} }
final messagesOwned = final messagesRecordKey =
proto.OwnedDHTRecordPointerProto.fromProto(conversation.messages); proto.TypedKeyProto.fromProto(conversation.messages);
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
final writer = getConversationWriter(activeAccountInfo: activeAccountInfo);
await (await DHTShortArray.openOwned(messagesOwned, await (await DHTShortArray.openWrite(messagesRecordKey, writer,
parent: localConversationOwned.recordKey, crypto: crypto)) parent: localConversationRecordKey, crypto: crypto))
.scope((messages) async { .scope((messages) async {
await messages.tryAddItem(message.writeToBuffer()); await messages.tryAddItem(message.writeToBuffer());
}); });
@ -175,24 +196,24 @@ Future<void> addLocalConversationMessage(
Future<IList<proto.Message>?> getLocalConversationMessages({ Future<IList<proto.Message>?> getLocalConversationMessages({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required OwnedDHTRecordPointer localConversationOwned, required TypedKey localConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
}) async { }) async {
final conversation = await readLocalConversation( final conversation = await readLocalConversation(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
localConversationOwned: localConversationOwned, localConversationRecordKey: localConversationRecordKey,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
if (conversation == null) { if (conversation == null) {
return null; return null;
} }
final messagesOwned = final messagesRecordKey =
proto.OwnedDHTRecordPointerProto.fromProto(conversation.messages); proto.TypedKeyProto.fromProto(conversation.messages);
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
return (await DHTShortArray.openOwned(messagesOwned, return (await DHTShortArray.openRead(messagesRecordKey,
parent: localConversationOwned.recordKey, crypto: crypto)) parent: localConversationRecordKey, crypto: crypto))
.scope((messages) async { .scope((messages) async {
var out = IList<proto.Message>(); var out = IList<proto.Message>();
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {
@ -208,24 +229,24 @@ Future<IList<proto.Message>?> getLocalConversationMessages({
Future<IList<proto.Message>?> getRemoteConversationMessages({ Future<IList<proto.Message>?> getRemoteConversationMessages({
required ActiveAccountInfo activeAccountInfo, required ActiveAccountInfo activeAccountInfo,
required TypedKey remoteConversationKey, required TypedKey remoteConversationRecordKey,
required TypedKey remoteIdentityPublicKey, required TypedKey remoteIdentityPublicKey,
}) async { }) async {
final conversation = await readRemoteConversation( final conversation = await readRemoteConversation(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteConversationKey: remoteConversationKey, remoteConversationRecordKey: remoteConversationRecordKey,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
if (conversation == null) { if (conversation == null) {
return null; return null;
} }
final messagesOwned = final messagesRecordKey =
proto.OwnedDHTRecordPointerProto.fromProto(conversation.messages); proto.TypedKeyProto.fromProto(conversation.messages);
final crypto = await getConversationCrypto( final crypto = await getConversationCrypto(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
remoteIdentityPublicKey: remoteIdentityPublicKey); remoteIdentityPublicKey: remoteIdentityPublicKey);
return (await DHTShortArray.openOwned(messagesOwned, return (await DHTShortArray.openRead(messagesRecordKey,
parent: localConversationOwned.recordKey, crypto: crypto)) parent: remoteConversationRecordKey, crypto: crypto))
.scope((messages) async { .scope((messages) async {
var out = IList<proto.Message>(); var out = IList<proto.Message>();
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {

View File

@ -60,6 +60,9 @@ class DHTShortArray {
// Cached representation refreshed from head record // Cached representation refreshed from head record
_DHTShortArrayCache _head; _DHTShortArrayCache _head;
// Create a DHTShortArray
// if smplWriter is specified, uses a SMPL schema with a single writer
// rather than the key owner
static Future<DHTShortArray> create( static Future<DHTShortArray> create(
{int stride = maxElements, {int stride = maxElements,
VeilidRoutingContext? routingContext, VeilidRoutingContext? routingContext,