better logging

This commit is contained in:
Christien Rioux 2024-03-01 16:25:56 -05:00
parent f896fc822c
commit 2cf1c5f4e9
9 changed files with 147 additions and 120 deletions

View File

@ -178,7 +178,9 @@ class AccountRepository {
/// Creates a new master identity, an account associated with the master /// Creates a new master identity, an account associated with the master
/// identity, stores the account in the identity key and then logs into /// identity, stores the account in the identity key and then logs into
/// that account with no password set at this time /// that account with no password set at this time
Future<void> createMasterIdentity(NewProfileSpec newProfileSpec) async { Future<void> createWithNewMasterIdentity(
NewProfileSpec newProfileSpec) async {
log.debug('Creating master identity');
final imws = await IdentityMasterWithSecrets.create(); final imws = await IdentityMasterWithSecrets.create();
try { try {
final localAccount = await _newLocalAccount( final localAccount = await _newLocalAccount(
@ -204,6 +206,8 @@ class AccountRepository {
required NewProfileSpec newProfileSpec, required NewProfileSpec newProfileSpec,
EncryptionKeyType encryptionKeyType = EncryptionKeyType.none, EncryptionKeyType encryptionKeyType = EncryptionKeyType.none,
String encryptionKey = ''}) async { String encryptionKey = ''}) async {
log.debug('Creating new local account');
final localAccounts = await _localAccounts.get(); final localAccounts = await _localAccounts.get();
// Add account with profile to DHT // Add account with profile to DHT
@ -212,15 +216,18 @@ class AccountRepository {
accountKey: veilidChatAccountKey, accountKey: veilidChatAccountKey,
createAccountCallback: (parent) async { createAccountCallback: (parent) async {
// Make empty contact list // Make empty contact list
log.debug('Creating contacts list');
final contactList = await (await DHTShortArray.create(parent: parent)) final contactList = await (await DHTShortArray.create(parent: parent))
.scope((r) async => r.record.ownedDHTRecordPointer); .scope((r) async => r.record.ownedDHTRecordPointer);
// Make empty contact invitation record list // Make empty contact invitation record list
log.debug('Creating contact invitation records list');
final contactInvitationRecords = final contactInvitationRecords =
await (await DHTShortArray.create(parent: parent)) await (await DHTShortArray.create(parent: parent))
.scope((r) async => r.record.ownedDHTRecordPointer); .scope((r) async => r.record.ownedDHTRecordPointer);
// Make empty chat record list // Make empty chat record list
log.debug('Creating chat records list');
final chatRecords = await (await DHTShortArray.create(parent: parent)) final chatRecords = await (await DHTShortArray.create(parent: parent))
.scope((r) async => r.record.ownedDHTRecordPointer); .scope((r) async => r.record.ownedDHTRecordPointer);

View File

@ -122,7 +122,7 @@ class NewAccountPageState extends State<NewAccountPage> {
NewProfileSpec(name: name, pronouns: pronouns); NewProfileSpec(name: name, pronouns: pronouns);
await AccountRepository.instance await AccountRepository.instance
.createMasterIdentity(newProfileSpec); .createWithNewMasterIdentity(newProfileSpec);
} on Exception catch (e) { } on Exception catch (e) {
if (context.mounted) { if (context.mounted) {
await showErrorModal(context, translate('new_account_page.error'), await showErrorModal(context, translate('new_account_page.error'),

View File

@ -25,29 +25,20 @@ class MessagesCubit extends Cubit<AsyncValue<IList<proto.Message>>> {
required TypedKey remoteConversationRecordKey, required TypedKey remoteConversationRecordKey,
required TypedKey remoteMessagesRecordKey}) required TypedKey remoteMessagesRecordKey})
: _activeAccountInfo = activeAccountInfo, : _activeAccountInfo = activeAccountInfo,
_localMessagesRecordKey = localMessagesRecordKey,
_remoteIdentityPublicKey = remoteIdentityPublicKey, _remoteIdentityPublicKey = remoteIdentityPublicKey,
_remoteMessagesRecordKey = remoteMessagesRecordKey,
_remoteMessagesQueue = StreamController(), _remoteMessagesQueue = StreamController(),
super(const AsyncValue.loading()) { super(const AsyncValue.loading()) {
// Local messages key // Local messages key
Future.delayed(Duration.zero, () async { Future.delayed(
final crypto = await getMessagesCrypto(); Duration.zero,
final writer = _activeAccountInfo.conversationWriter; () async => _initLocalMessages(
final record = await DHTShortArray.openWrite( localConversationRecordKey, localMessagesRecordKey));
_localMessagesRecordKey, writer,
parent: localConversationRecordKey, crypto: crypto);
await _setLocalMessages(record);
});
// Remote messages key // Remote messages key
Future.delayed(Duration.zero, () async { Future.delayed(
// Open remote record key if it is specified Duration.zero,
final crypto = await getMessagesCrypto(); () async => _initRemoteMessages(
final record = await DHTShortArray.openRead(_remoteMessagesRecordKey, remoteConversationRecordKey, remoteMessagesRecordKey));
parent: remoteConversationRecordKey, crypto: crypto);
await _setRemoteMessages(record);
});
// Remote messages listener // Remote messages listener
Future.delayed(Duration.zero, () async { Future.delayed(Duration.zero, () async {
@ -59,8 +50,11 @@ class MessagesCubit extends Cubit<AsyncValue<IList<proto.Message>>> {
@override @override
Future<void> close() async { Future<void> close() async {
await _remoteMessagesQueue.close();
await _localSubscription?.cancel(); await _localSubscription?.cancel();
await _remoteSubscription?.cancel(); await _remoteSubscription?.cancel();
await _localMessagesCubit?.close();
await _remoteMessagesCubit?.close();
await super.close(); await super.close();
} }
@ -129,20 +123,29 @@ class MessagesCubit extends Cubit<AsyncValue<IList<proto.Message>>> {
} }
// Open local messages key // Open local messages key
Future<void> _setLocalMessages(DHTShortArray localMessagesRecord) async { Future<void> _initLocalMessages(TypedKey localConversationRecordKey,
assert(_localMessagesCubit == null, 'shoud not set local messages twice'); TypedKey localMessagesRecordKey) async {
_localMessagesCubit = DHTShortArrayCubit.value( final crypto = await getMessagesCrypto();
shortArray: localMessagesRecord, final writer = _activeAccountInfo.conversationWriter;
_localMessagesCubit = DHTShortArrayCubit(
open: () async => DHTShortArray.openWrite(
localMessagesRecordKey, writer,
parent: localConversationRecordKey, crypto: crypto),
decodeElement: proto.Message.fromBuffer); decodeElement: proto.Message.fromBuffer);
_localSubscription = _localSubscription =
_localMessagesCubit!.stream.listen(updateLocalMessagesState); _localMessagesCubit!.stream.listen(updateLocalMessagesState);
} }
// Open remote messages key // Open remote messages key
Future<void> _setRemoteMessages(DHTShortArray remoteMessagesRecord) async { Future<void> _initRemoteMessages(TypedKey remoteConversationRecordKey,
assert(_remoteMessagesCubit == null, 'shoud not set remote messages twice'); TypedKey remoteMessagesRecordKey) async {
_remoteMessagesCubit = DHTShortArrayCubit.value( // Open remote record key if it is specified
shortArray: remoteMessagesRecord, final crypto = await getMessagesCrypto();
_remoteMessagesCubit = DHTShortArrayCubit(
open: () async => DHTShortArray.openRead(remoteMessagesRecordKey,
parent: remoteConversationRecordKey, crypto: crypto),
decodeElement: proto.Message.fromBuffer); decodeElement: proto.Message.fromBuffer);
_remoteSubscription = _remoteSubscription =
_remoteMessagesCubit!.stream.listen(updateRemoteMessagesState); _remoteMessagesCubit!.stream.listen(updateRemoteMessagesState);
@ -208,8 +211,6 @@ class MessagesCubit extends Cubit<AsyncValue<IList<proto.Message>>> {
final ActiveAccountInfo _activeAccountInfo; final ActiveAccountInfo _activeAccountInfo;
final TypedKey _remoteIdentityPublicKey; final TypedKey _remoteIdentityPublicKey;
final TypedKey _localMessagesRecordKey;
final TypedKey _remoteMessagesRecordKey;
DHTShortArrayCubit<proto.Message>? _localMessagesCubit; DHTShortArrayCubit<proto.Message>? _localMessagesCubit;
DHTShortArrayCubit<proto.Message>? _remoteMessagesCubit; DHTShortArrayCubit<proto.Message>? _remoteMessagesCubit;
final StreamController<_MessageQueueEntry> _remoteMessagesQueue; final StreamController<_MessageQueueEntry> _remoteMessagesQueue;

View File

@ -2,31 +2,44 @@ import 'package:veilid/veilid.dart';
Map<String, dynamic> getDefaultVeilidPlatformConfig( Map<String, dynamic> getDefaultVeilidPlatformConfig(
bool isWeb, String appName) { bool isWeb, String appName) {
final ignoreLogTargetsStr =
// ignore: do_not_use_environment
const String.fromEnvironment('IGNORE_LOG_TARGETS').trim();
final ignoreLogTargets = ignoreLogTargetsStr.isEmpty
? <String>[]
: ignoreLogTargetsStr.split(',').map((e) => e.trim()).toList();
if (isWeb) { if (isWeb) {
return const VeilidWASMConfig( return VeilidWASMConfig(
logging: VeilidWASMConfigLogging( logging: VeilidWASMConfigLogging(
performance: VeilidWASMConfigLoggingPerformance( performance: VeilidWASMConfigLoggingPerformance(
enabled: true, enabled: true,
level: VeilidConfigLogLevel.debug, level: VeilidConfigLogLevel.debug,
logsInTimings: true, logsInTimings: true,
logsInConsole: false), logsInConsole: false,
ignoreLogTargets: ignoreLogTargets),
api: VeilidWASMConfigLoggingApi( api: VeilidWASMConfigLoggingApi(
enabled: true, level: VeilidConfigLogLevel.info))) enabled: true,
level: VeilidConfigLogLevel.info,
ignoreLogTargets: ignoreLogTargets)))
.toJson(); .toJson();
} }
return VeilidFFIConfig( return VeilidFFIConfig(
logging: VeilidFFIConfigLogging( logging: VeilidFFIConfigLogging(
terminal: const VeilidFFIConfigLoggingTerminal( terminal: VeilidFFIConfigLoggingTerminal(
enabled: false, enabled: false,
level: VeilidConfigLogLevel.debug, level: VeilidConfigLogLevel.debug,
), ignoreLogTargets: ignoreLogTargets),
otlp: VeilidFFIConfigLoggingOtlp( otlp: VeilidFFIConfigLoggingOtlp(
enabled: false, enabled: false,
level: VeilidConfigLogLevel.trace, level: VeilidConfigLogLevel.trace,
grpcEndpoint: '127.0.0.1:4317', grpcEndpoint: '127.0.0.1:4317',
serviceName: appName), serviceName: appName,
api: const VeilidFFIConfigLoggingApi( ignoreLogTargets: ignoreLogTargets),
enabled: true, level: VeilidConfigLogLevel.info))) api: VeilidFFIConfigLoggingApi(
enabled: true,
level: VeilidConfigLogLevel.info,
ignoreLogTargets: ignoreLogTargets)))
.toJson(); .toJson();
} }

View File

@ -3,9 +3,9 @@ import 'dart:typed_data';
import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:protobuf/protobuf.dart'; import 'package:protobuf/protobuf.dart';
import 'package:veilid/veilid.dart';
import '../dht_support/dht_support.dart'; import '../veilid_support.dart';
import 'veilid_log.dart';
part 'identity.freezed.dart'; part 'identity.freezed.dart';
part 'identity.g.dart'; part 'identity.g.dart';
@ -161,42 +161,44 @@ extension IdentityMasterExtension on IdentityMaster {
/////// Add account with profile to DHT /////// Add account with profile to DHT
// Open identity key for writing // Open identity key for writing
veilidLoggy.debug('Opening master identity');
return (await pool.openWrite( return (await pool.openWrite(
identityRecordKey, identityWriter(identitySecret), identityRecordKey, identityWriter(identitySecret),
parent: masterRecordKey)) parent: masterRecordKey))
.scope((identityRec) async => .scope((identityRec) async {
// Create new account to insert into identity // Create new account to insert into identity
(await pool.create(parent: identityRec.key)) veilidLoggy.debug('Creating new account');
.deleteScope((accountRec) async { return (await pool.create(parent: identityRec.key))
final account = await createAccountCallback(accountRec.key); .deleteScope((accountRec) async {
// Write account key final account = await createAccountCallback(accountRec.key);
await accountRec.eventualWriteProtobuf(account); // Write account key
veilidLoggy.debug('Writing account record');
await accountRec.eventualWriteProtobuf(account);
// Update identity key to include account // Update identity key to include account
final newAccountRecordInfo = AccountRecordInfo( final newAccountRecordInfo = AccountRecordInfo(
accountRecord: OwnedDHTRecordPointer( accountRecord: OwnedDHTRecordPointer(
recordKey: accountRec.key, recordKey: accountRec.key, owner: accountRec.ownerKeyPair!));
owner: accountRec.ownerKeyPair!));
await identityRec.eventualUpdateJson(Identity.fromJson, veilidLoggy.debug('Updating identity with new account');
(oldIdentity) async { await identityRec.eventualUpdateJson(Identity.fromJson,
if (oldIdentity == null) { (oldIdentity) async {
throw IdentityException.readError; if (oldIdentity == null) {
} throw IdentityException.readError;
final oldAccountRecords = }
IMapOfSets.from(oldIdentity.accountRecords); final oldAccountRecords = IMapOfSets.from(oldIdentity.accountRecords);
if (oldAccountRecords.get(accountKey).length >= maxAccounts) { if (oldAccountRecords.get(accountKey).length >= maxAccounts) {
throw IdentityException.limitExceeded; throw IdentityException.limitExceeded;
} }
final accountRecords = oldAccountRecords final accountRecords =
.add(accountKey, newAccountRecordInfo) oldAccountRecords.add(accountKey, newAccountRecordInfo).asIMap();
.asIMap(); return oldIdentity.copyWith(accountRecords: accountRecords);
return oldIdentity.copyWith(accountRecords: accountRecords); });
});
return newAccountRecordInfo; return newAccountRecordInfo;
})); });
});
} }
} }
@ -219,56 +221,58 @@ class IdentityMasterWithSecrets {
final pool = DHTRecordPool.instance; final pool = DHTRecordPool.instance;
// IdentityMaster DHT record is public/unencrypted // IdentityMaster DHT record is public/unencrypted
veilidLoggy.debug('Creating master identity record');
return (await pool.create(crypto: const DHTRecordCryptoPublic())) return (await pool.create(crypto: const DHTRecordCryptoPublic()))
.deleteScope((masterRec) async => .deleteScope((masterRec) async {
// Identity record is private veilidLoggy.debug('Creating identity record');
(await pool.create(parent: masterRec.key)) // Identity record is private
.scope((identityRec) async { return (await pool.create(parent: masterRec.key))
// Make IdentityMaster .scope((identityRec) async {
final masterRecordKey = masterRec.key; // Make IdentityMaster
final masterOwner = masterRec.ownerKeyPair!; final masterRecordKey = masterRec.key;
final masterSigBuf = BytesBuilder() final masterOwner = masterRec.ownerKeyPair!;
..add(masterRecordKey.decode()) final masterSigBuf = BytesBuilder()
..add(masterOwner.key.decode()); ..add(masterRecordKey.decode())
..add(masterOwner.key.decode());
final identityRecordKey = identityRec.key; final identityRecordKey = identityRec.key;
final identityOwner = identityRec.ownerKeyPair!; final identityOwner = identityRec.ownerKeyPair!;
final identitySigBuf = BytesBuilder() final identitySigBuf = BytesBuilder()
..add(identityRecordKey.decode()) ..add(identityRecordKey.decode())
..add(identityOwner.key.decode()); ..add(identityOwner.key.decode());
assert(masterRecordKey.kind == identityRecordKey.kind, assert(masterRecordKey.kind == identityRecordKey.kind,
'new master and identity should have same cryptosystem'); 'new master and identity should have same cryptosystem');
final crypto = final crypto = await pool.veilid.getCryptoSystem(masterRecordKey.kind);
await pool.veilid.getCryptoSystem(masterRecordKey.kind);
final identitySignature = await crypto.signWithKeyPair( final identitySignature =
masterOwner, identitySigBuf.toBytes()); await crypto.signWithKeyPair(masterOwner, identitySigBuf.toBytes());
final masterSignature = await crypto.signWithKeyPair( final masterSignature =
identityOwner, masterSigBuf.toBytes()); await crypto.signWithKeyPair(identityOwner, masterSigBuf.toBytes());
final identityMaster = IdentityMaster( final identityMaster = IdentityMaster(
identityRecordKey: identityRecordKey, identityRecordKey: identityRecordKey,
identityPublicKey: identityOwner.key, identityPublicKey: identityOwner.key,
masterRecordKey: masterRecordKey, masterRecordKey: masterRecordKey,
masterPublicKey: masterOwner.key, masterPublicKey: masterOwner.key,
identitySignature: identitySignature, identitySignature: identitySignature,
masterSignature: masterSignature); masterSignature: masterSignature);
// Write identity master to master dht key // Write identity master to master dht key
await masterRec.eventualWriteJson(identityMaster); await masterRec.eventualWriteJson(identityMaster);
// Make empty identity // Make empty identity
const identity = Identity(accountRecords: IMapConst({})); const identity = Identity(accountRecords: IMapConst({}));
// Write empty identity to identity dht key // Write empty identity to identity dht key
await identityRec.eventualWriteJson(identity); await identityRec.eventualWriteJson(identity);
return IdentityMasterWithSecrets._( return IdentityMasterWithSecrets._(
identityMaster: identityMaster, identityMaster: identityMaster,
masterSecret: masterOwner.secret, masterSecret: masterOwner.secret,
identitySecret: identityOwner.secret); identitySecret: identityOwner.secret);
})); });
});
} }
} }

View File

@ -1,4 +1,5 @@
import 'package:loggy/loggy.dart'; import 'package:loggy/loggy.dart';
import 'package:meta/meta.dart';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
// Loggy tools // Loggy tools
@ -37,7 +38,8 @@ class VeilidLoggy implements LoggyType {
Loggy<VeilidLoggy> get loggy => Loggy<VeilidLoggy>('Veilid'); Loggy<VeilidLoggy> get loggy => Loggy<VeilidLoggy>('Veilid');
} }
Loggy get _veilidLoggy => Loggy<VeilidLoggy>('Veilid'); @internal
Loggy get veilidLoggy => Loggy<VeilidLoggy>('Veilid');
void processLog(VeilidLog log) { void processLog(VeilidLog log) {
StackTrace? stackTrace; StackTrace? stackTrace;
@ -50,19 +52,19 @@ void processLog(VeilidLog log) {
switch (log.logLevel) { switch (log.logLevel) {
case VeilidLogLevel.error: case VeilidLogLevel.error:
_veilidLoggy.error(log.message, error, stackTrace); veilidLoggy.error(log.message, error, stackTrace);
break; break;
case VeilidLogLevel.warn: case VeilidLogLevel.warn:
_veilidLoggy.warning(log.message, error, stackTrace); veilidLoggy.warning(log.message, error, stackTrace);
break; break;
case VeilidLogLevel.info: case VeilidLogLevel.info:
_veilidLoggy.info(log.message, error, stackTrace); veilidLoggy.info(log.message, error, stackTrace);
break; break;
case VeilidLogLevel.debug: case VeilidLogLevel.debug:
_veilidLoggy.debug(log.message, error, stackTrace); veilidLoggy.debug(log.message, error, stackTrace);
break; break;
case VeilidLogLevel.trace: case VeilidLogLevel.trace:
_veilidLoggy.trace(log.message, error, stackTrace); veilidLoggy.trace(log.message, error, stackTrace);
break; break;
} }
} }

View File

@ -12,4 +12,4 @@ export 'src/json_tools.dart';
export 'src/memory_tools.dart'; export 'src/memory_tools.dart';
export 'src/protobuf_tools.dart'; export 'src/protobuf_tools.dart';
export 'src/table_db.dart'; export 'src/table_db.dart';
export 'src/veilid_log.dart'; export 'src/veilid_log.dart' hide veilidLoggy;

View File

@ -1618,4 +1618,4 @@ packages:
version: "1.1.2" version: "1.1.2"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.19.1"

View File

@ -5,7 +5,7 @@ version: 1.0.2+0
environment: environment:
sdk: '>=3.2.0 <4.0.0' sdk: '>=3.2.0 <4.0.0'
flutter: ">=3.10.0" flutter: '>=3.19.1'
dependencies: dependencies:
animated_theme_switcher: ^2.0.10 animated_theme_switcher: ^2.0.10