diff --git a/Cargo.lock b/Cargo.lock index c2aa676c..60f09339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5992,6 +5992,7 @@ dependencies = [ "tokio-stream", "tokio-util", "tracing", + "tracing-flame", "tracing-opentelemetry", "tracing-subscriber", "veilid-core", diff --git a/veilid-flutter/example/integration_test/test_dht.dart b/veilid-flutter/example/integration_test/test_dht.dart index 6e9edb77..1edc2955 100644 --- a/veilid-flutter/example/integration_test/test_dht.dart +++ b/veilid-flutter/example/integration_test/test_dht.dart @@ -153,6 +153,9 @@ Future testOpenWriterDHTValue() async { // Different value should trigger sequence number update expect(await rc.setDHTValue(key, 1, vb), isNull); + await settle(rc, key, 0); + await settle(rc, key, 1); + // Now that we initialized some subkeys // and verified they stored correctly // Delete things locally and reopen and see if we can write @@ -224,6 +227,14 @@ Future testOpenWriterDHTValue() async { } } +Future settle(VeilidRoutingContext rc, TypedKey key, int subkey) async { + // Wait for set to settle + do { + await Future.delayed(const Duration(milliseconds: 100)); + } while ( + (await rc.inspectDHTRecord(key)).offlineSubkeys.containsSubkey(subkey)); +} + Future testWatchDHTValues(Stream updateStream) async { final valueChangeQueue = StreamController.broadcast(); @@ -263,6 +274,9 @@ Future testWatchDHTValues(Stream updateStream) async { // Now set the subkey and trigger an update expect(await rcSet.setDHTValue(rec.key, 3, utf8.encode('BLAH')), isNull); + // Wait for set to settle + await settle(rcSet, rec.key, 3); + // Now we should NOT get an update because the update // is the same as our local copy if (await valueChangeQueueIterator @@ -281,10 +295,13 @@ Future testWatchDHTValues(Stream updateStream) async { ].wait, equals([null, null])); + await settle(rcSet, rec.key, 3); + await settle(rcSet, rec.key, 4); + // Wait for the update await valueChangeQueueIterator .moveNext() - .timeout(const Duration(seconds: 5), onTimeout: () { + .timeout(const Duration(seconds: 10), onTimeout: () { fail('should have a change'); }); @@ -315,10 +332,13 @@ Future testWatchDHTValues(Stream updateStream) async { ].wait, equals([null, null])); + await settle(rcSet, rec.key, 3); + await settle(rcSet, rec.key, 5); + // Wait for the update await valueChangeQueueIterator .moveNext() - .timeout(const Duration(seconds: 5), onTimeout: () { + .timeout(const Duration(seconds: 10), onTimeout: () { fail('should have a change'); }); @@ -350,10 +370,13 @@ Future testWatchDHTValues(Stream updateStream) async { ].wait, equals([null, null])); + await settle(rcSet, rec.key, 3); + await settle(rcSet, rec.key, 5); + // Now we should NOT get an update if (await valueChangeQueueIterator .moveNext() - .timeout(const Duration(seconds: 5), onTimeout: () => false)) { + .timeout(const Duration(seconds: 10), onTimeout: () => false)) { fail('should not have a change'); } diff --git a/veilid-flutter/example/lib/veilid_init.dart b/veilid-flutter/example/lib/veilid_init.dart index 6068fe60..465bab3f 100644 --- a/veilid-flutter/example/lib/veilid_init.dart +++ b/veilid-flutter/example/lib/veilid_init.dart @@ -28,7 +28,8 @@ void veilidInit() { grpcEndpoint: 'localhost:4317', serviceName: 'VeilidExample'), api: VeilidFFIConfigLoggingApi( - enabled: true, level: VeilidConfigLogLevel.info))); + enabled: true, level: VeilidConfigLogLevel.info), + flame: VeilidFFIConfigLoggingFlame(enabled: false, path: ''))); Veilid.instance.initializeVeilidCore(platformConfig.toJson()); } } diff --git a/veilid-flutter/lib/routing_context.g.dart b/veilid-flutter/lib/routing_context.g.dart index 922f429f..1749f260 100644 --- a/veilid-flutter/lib/routing_context.g.dart +++ b/veilid-flutter/lib/routing_context.g.dart @@ -8,7 +8,7 @@ part of 'routing_context.dart'; _$DHTSchemaDFLTImpl _$$DHTSchemaDFLTImplFromJson(Map json) => _$DHTSchemaDFLTImpl( - oCnt: json['o_cnt'] as int, + oCnt: (json['o_cnt'] as num).toInt(), $type: json['kind'] as String?, ); @@ -20,7 +20,7 @@ Map _$$DHTSchemaDFLTImplToJson(_$DHTSchemaDFLTImpl instance) => _$DHTSchemaSMPLImpl _$$DHTSchemaSMPLImplFromJson(Map json) => _$DHTSchemaSMPLImpl( - oCnt: json['o_cnt'] as int, + oCnt: (json['o_cnt'] as num).toInt(), members: (json['members'] as List) .map(DHTSchemaMember.fromJson) .toList(), @@ -38,7 +38,7 @@ _$DHTSchemaMemberImpl _$$DHTSchemaMemberImplFromJson( Map json) => _$DHTSchemaMemberImpl( mKey: FixedEncodedString43.fromJson(json['m_key']), - mCnt: json['m_cnt'] as int, + mCnt: (json['m_cnt'] as num).toInt(), ); Map _$$DHTSchemaMemberImplToJson( @@ -70,7 +70,7 @@ Map _$$DHTRecordDescriptorImplToJson( _$ValueDataImpl _$$ValueDataImplFromJson(Map json) => _$ValueDataImpl( - seq: json['seq'] as int, + seq: (json['seq'] as num).toInt(), data: const Uint8ListJsonConverter.jsIsArray().fromJson(json['data']), writer: FixedEncodedString43.fromJson(json['writer']), ); @@ -84,7 +84,7 @@ Map _$$ValueDataImplToJson(_$ValueDataImpl instance) => _$SafetySpecImpl _$$SafetySpecImplFromJson(Map json) => _$SafetySpecImpl( - hopCount: json['hop_count'] as int, + hopCount: (json['hop_count'] as num).toInt(), stability: Stability.fromJson(json['stability']), sequencing: Sequencing.fromJson(json['sequencing']), preferredRoute: json['preferred_route'] as String?, @@ -119,10 +119,12 @@ _$DHTRecordReportImpl _$$DHTRecordReportImplFromJson( offlineSubkeys: (json['offline_subkeys'] as List) .map(ValueSubkeyRange.fromJson) .toList(), - localSeqs: - (json['local_seqs'] as List).map((e) => e as int).toList(), - networkSeqs: - (json['network_seqs'] as List).map((e) => e as int).toList(), + localSeqs: (json['local_seqs'] as List) + .map((e) => (e as num).toInt()) + .toList(), + networkSeqs: (json['network_seqs'] as List) + .map((e) => (e as num).toInt()) + .toList(), ); Map _$$DHTRecordReportImplToJson( diff --git a/veilid-flutter/lib/veilid_config.dart b/veilid-flutter/lib/veilid_config.dart index 8a0d6871..addde72c 100644 --- a/veilid-flutter/lib/veilid_config.dart +++ b/veilid-flutter/lib/veilid_config.dart @@ -47,12 +47,24 @@ class VeilidFFIConfigLoggingApi with _$VeilidFFIConfigLoggingApi { _$VeilidFFIConfigLoggingApiFromJson(json as Map); } +@freezed +class VeilidFFIConfigLoggingFlame with _$VeilidFFIConfigLoggingFlame { + const factory VeilidFFIConfigLoggingFlame({ + required bool enabled, + required String path, + }) = _VeilidFFIConfigLoggingFlame; + + factory VeilidFFIConfigLoggingFlame.fromJson(dynamic json) => + _$VeilidFFIConfigLoggingFlameFromJson(json as Map); +} + @freezed class VeilidFFIConfigLogging with _$VeilidFFIConfigLogging { const factory VeilidFFIConfigLogging( {required VeilidFFIConfigLoggingTerminal terminal, required VeilidFFIConfigLoggingOtlp otlp, - required VeilidFFIConfigLoggingApi api}) = _VeilidFFIConfigLogging; + required VeilidFFIConfigLoggingApi api, + required VeilidFFIConfigLoggingFlame flame}) = _VeilidFFIConfigLogging; factory VeilidFFIConfigLogging.fromJson(dynamic json) => _$VeilidFFIConfigLoggingFromJson(json as Map); diff --git a/veilid-flutter/lib/veilid_config.freezed.dart b/veilid-flutter/lib/veilid_config.freezed.dart index f7a00931..ed022547 100644 --- a/veilid-flutter/lib/veilid_config.freezed.dart +++ b/veilid-flutter/lib/veilid_config.freezed.dart @@ -692,6 +692,182 @@ abstract class _VeilidFFIConfigLoggingApi implements VeilidFFIConfigLoggingApi { get copyWith => throw _privateConstructorUsedError; } +VeilidFFIConfigLoggingFlame _$VeilidFFIConfigLoggingFlameFromJson( + Map json) { + return _VeilidFFIConfigLoggingFlame.fromJson(json); +} + +/// @nodoc +mixin _$VeilidFFIConfigLoggingFlame { + bool get enabled => throw _privateConstructorUsedError; + String get path => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $VeilidFFIConfigLoggingFlameCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $VeilidFFIConfigLoggingFlameCopyWith<$Res> { + factory $VeilidFFIConfigLoggingFlameCopyWith( + VeilidFFIConfigLoggingFlame value, + $Res Function(VeilidFFIConfigLoggingFlame) then) = + _$VeilidFFIConfigLoggingFlameCopyWithImpl<$Res, + VeilidFFIConfigLoggingFlame>; + @useResult + $Res call({bool enabled, String path}); +} + +/// @nodoc +class _$VeilidFFIConfigLoggingFlameCopyWithImpl<$Res, + $Val extends VeilidFFIConfigLoggingFlame> + implements $VeilidFFIConfigLoggingFlameCopyWith<$Res> { + _$VeilidFFIConfigLoggingFlameCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? enabled = null, + Object? path = null, + }) { + return _then(_value.copyWith( + enabled: null == enabled + ? _value.enabled + : enabled // ignore: cast_nullable_to_non_nullable + as bool, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$VeilidFFIConfigLoggingFlameImplCopyWith<$Res> + implements $VeilidFFIConfigLoggingFlameCopyWith<$Res> { + factory _$$VeilidFFIConfigLoggingFlameImplCopyWith( + _$VeilidFFIConfigLoggingFlameImpl value, + $Res Function(_$VeilidFFIConfigLoggingFlameImpl) then) = + __$$VeilidFFIConfigLoggingFlameImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool enabled, String path}); +} + +/// @nodoc +class __$$VeilidFFIConfigLoggingFlameImplCopyWithImpl<$Res> + extends _$VeilidFFIConfigLoggingFlameCopyWithImpl<$Res, + _$VeilidFFIConfigLoggingFlameImpl> + implements _$$VeilidFFIConfigLoggingFlameImplCopyWith<$Res> { + __$$VeilidFFIConfigLoggingFlameImplCopyWithImpl( + _$VeilidFFIConfigLoggingFlameImpl _value, + $Res Function(_$VeilidFFIConfigLoggingFlameImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? enabled = null, + Object? path = null, + }) { + return _then(_$VeilidFFIConfigLoggingFlameImpl( + enabled: null == enabled + ? _value.enabled + : enabled // ignore: cast_nullable_to_non_nullable + as bool, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$VeilidFFIConfigLoggingFlameImpl + with DiagnosticableTreeMixin + implements _VeilidFFIConfigLoggingFlame { + const _$VeilidFFIConfigLoggingFlameImpl( + {required this.enabled, required this.path}); + + factory _$VeilidFFIConfigLoggingFlameImpl.fromJson( + Map json) => + _$$VeilidFFIConfigLoggingFlameImplFromJson(json); + + @override + final bool enabled; + @override + final String path; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'VeilidFFIConfigLoggingFlame(enabled: $enabled, path: $path)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'VeilidFFIConfigLoggingFlame')) + ..add(DiagnosticsProperty('enabled', enabled)) + ..add(DiagnosticsProperty('path', path)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$VeilidFFIConfigLoggingFlameImpl && + (identical(other.enabled, enabled) || other.enabled == enabled) && + (identical(other.path, path) || other.path == path)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, enabled, path); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$VeilidFFIConfigLoggingFlameImplCopyWith<_$VeilidFFIConfigLoggingFlameImpl> + get copyWith => __$$VeilidFFIConfigLoggingFlameImplCopyWithImpl< + _$VeilidFFIConfigLoggingFlameImpl>(this, _$identity); + + @override + Map toJson() { + return _$$VeilidFFIConfigLoggingFlameImplToJson( + this, + ); + } +} + +abstract class _VeilidFFIConfigLoggingFlame + implements VeilidFFIConfigLoggingFlame { + const factory _VeilidFFIConfigLoggingFlame( + {required final bool enabled, + required final String path}) = _$VeilidFFIConfigLoggingFlameImpl; + + factory _VeilidFFIConfigLoggingFlame.fromJson(Map json) = + _$VeilidFFIConfigLoggingFlameImpl.fromJson; + + @override + bool get enabled; + @override + String get path; + @override + @JsonKey(ignore: true) + _$$VeilidFFIConfigLoggingFlameImplCopyWith<_$VeilidFFIConfigLoggingFlameImpl> + get copyWith => throw _privateConstructorUsedError; +} + VeilidFFIConfigLogging _$VeilidFFIConfigLoggingFromJson( Map json) { return _VeilidFFIConfigLogging.fromJson(json); @@ -703,6 +879,7 @@ mixin _$VeilidFFIConfigLogging { throw _privateConstructorUsedError; VeilidFFIConfigLoggingOtlp get otlp => throw _privateConstructorUsedError; VeilidFFIConfigLoggingApi get api => throw _privateConstructorUsedError; + VeilidFFIConfigLoggingFlame get flame => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -719,11 +896,13 @@ abstract class $VeilidFFIConfigLoggingCopyWith<$Res> { $Res call( {VeilidFFIConfigLoggingTerminal terminal, VeilidFFIConfigLoggingOtlp otlp, - VeilidFFIConfigLoggingApi api}); + VeilidFFIConfigLoggingApi api, + VeilidFFIConfigLoggingFlame flame}); $VeilidFFIConfigLoggingTerminalCopyWith<$Res> get terminal; $VeilidFFIConfigLoggingOtlpCopyWith<$Res> get otlp; $VeilidFFIConfigLoggingApiCopyWith<$Res> get api; + $VeilidFFIConfigLoggingFlameCopyWith<$Res> get flame; } /// @nodoc @@ -743,6 +922,7 @@ class _$VeilidFFIConfigLoggingCopyWithImpl<$Res, Object? terminal = null, Object? otlp = null, Object? api = null, + Object? flame = null, }) { return _then(_value.copyWith( terminal: null == terminal @@ -757,6 +937,10 @@ class _$VeilidFFIConfigLoggingCopyWithImpl<$Res, ? _value.api : api // ignore: cast_nullable_to_non_nullable as VeilidFFIConfigLoggingApi, + flame: null == flame + ? _value.flame + : flame // ignore: cast_nullable_to_non_nullable + as VeilidFFIConfigLoggingFlame, ) as $Val); } @@ -784,6 +968,14 @@ class _$VeilidFFIConfigLoggingCopyWithImpl<$Res, return _then(_value.copyWith(api: value) as $Val); }); } + + @override + @pragma('vm:prefer-inline') + $VeilidFFIConfigLoggingFlameCopyWith<$Res> get flame { + return $VeilidFFIConfigLoggingFlameCopyWith<$Res>(_value.flame, (value) { + return _then(_value.copyWith(flame: value) as $Val); + }); + } } /// @nodoc @@ -798,7 +990,8 @@ abstract class _$$VeilidFFIConfigLoggingImplCopyWith<$Res> $Res call( {VeilidFFIConfigLoggingTerminal terminal, VeilidFFIConfigLoggingOtlp otlp, - VeilidFFIConfigLoggingApi api}); + VeilidFFIConfigLoggingApi api, + VeilidFFIConfigLoggingFlame flame}); @override $VeilidFFIConfigLoggingTerminalCopyWith<$Res> get terminal; @@ -806,6 +999,8 @@ abstract class _$$VeilidFFIConfigLoggingImplCopyWith<$Res> $VeilidFFIConfigLoggingOtlpCopyWith<$Res> get otlp; @override $VeilidFFIConfigLoggingApiCopyWith<$Res> get api; + @override + $VeilidFFIConfigLoggingFlameCopyWith<$Res> get flame; } /// @nodoc @@ -824,6 +1019,7 @@ class __$$VeilidFFIConfigLoggingImplCopyWithImpl<$Res> Object? terminal = null, Object? otlp = null, Object? api = null, + Object? flame = null, }) { return _then(_$VeilidFFIConfigLoggingImpl( terminal: null == terminal @@ -838,6 +1034,10 @@ class __$$VeilidFFIConfigLoggingImplCopyWithImpl<$Res> ? _value.api : api // ignore: cast_nullable_to_non_nullable as VeilidFFIConfigLoggingApi, + flame: null == flame + ? _value.flame + : flame // ignore: cast_nullable_to_non_nullable + as VeilidFFIConfigLoggingFlame, )); } } @@ -848,7 +1048,10 @@ class _$VeilidFFIConfigLoggingImpl with DiagnosticableTreeMixin implements _VeilidFFIConfigLogging { const _$VeilidFFIConfigLoggingImpl( - {required this.terminal, required this.otlp, required this.api}); + {required this.terminal, + required this.otlp, + required this.api, + required this.flame}); factory _$VeilidFFIConfigLoggingImpl.fromJson(Map json) => _$$VeilidFFIConfigLoggingImplFromJson(json); @@ -859,10 +1062,12 @@ class _$VeilidFFIConfigLoggingImpl final VeilidFFIConfigLoggingOtlp otlp; @override final VeilidFFIConfigLoggingApi api; + @override + final VeilidFFIConfigLoggingFlame flame; @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'VeilidFFIConfigLogging(terminal: $terminal, otlp: $otlp, api: $api)'; + return 'VeilidFFIConfigLogging(terminal: $terminal, otlp: $otlp, api: $api, flame: $flame)'; } @override @@ -872,7 +1077,8 @@ class _$VeilidFFIConfigLoggingImpl ..add(DiagnosticsProperty('type', 'VeilidFFIConfigLogging')) ..add(DiagnosticsProperty('terminal', terminal)) ..add(DiagnosticsProperty('otlp', otlp)) - ..add(DiagnosticsProperty('api', api)); + ..add(DiagnosticsProperty('api', api)) + ..add(DiagnosticsProperty('flame', flame)); } @override @@ -883,12 +1089,13 @@ class _$VeilidFFIConfigLoggingImpl (identical(other.terminal, terminal) || other.terminal == terminal) && (identical(other.otlp, otlp) || other.otlp == otlp) && - (identical(other.api, api) || other.api == api)); + (identical(other.api, api) || other.api == api) && + (identical(other.flame, flame) || other.flame == flame)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, terminal, otlp, api); + int get hashCode => Object.hash(runtimeType, terminal, otlp, api, flame); @JsonKey(ignore: true) @override @@ -909,7 +1116,8 @@ abstract class _VeilidFFIConfigLogging implements VeilidFFIConfigLogging { const factory _VeilidFFIConfigLogging( {required final VeilidFFIConfigLoggingTerminal terminal, required final VeilidFFIConfigLoggingOtlp otlp, - required final VeilidFFIConfigLoggingApi api}) = + required final VeilidFFIConfigLoggingApi api, + required final VeilidFFIConfigLoggingFlame flame}) = _$VeilidFFIConfigLoggingImpl; factory _VeilidFFIConfigLogging.fromJson(Map json) = @@ -922,6 +1130,8 @@ abstract class _VeilidFFIConfigLogging implements VeilidFFIConfigLogging { @override VeilidFFIConfigLoggingApi get api; @override + VeilidFFIConfigLoggingFlame get flame; + @override @JsonKey(ignore: true) _$$VeilidFFIConfigLoggingImplCopyWith<_$VeilidFFIConfigLoggingImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/veilid-flutter/lib/veilid_config.g.dart b/veilid-flutter/lib/veilid_config.g.dart index b5011a1b..1e881819 100644 --- a/veilid-flutter/lib/veilid_config.g.dart +++ b/veilid-flutter/lib/veilid_config.g.dart @@ -67,12 +67,27 @@ Map _$$VeilidFFIConfigLoggingApiImplToJson( 'ignore_log_targets': instance.ignoreLogTargets, }; +_$VeilidFFIConfigLoggingFlameImpl _$$VeilidFFIConfigLoggingFlameImplFromJson( + Map json) => + _$VeilidFFIConfigLoggingFlameImpl( + enabled: json['enabled'] as bool, + path: json['path'] as String, + ); + +Map _$$VeilidFFIConfigLoggingFlameImplToJson( + _$VeilidFFIConfigLoggingFlameImpl instance) => + { + 'enabled': instance.enabled, + 'path': instance.path, + }; + _$VeilidFFIConfigLoggingImpl _$$VeilidFFIConfigLoggingImplFromJson( Map json) => _$VeilidFFIConfigLoggingImpl( terminal: VeilidFFIConfigLoggingTerminal.fromJson(json['terminal']), otlp: VeilidFFIConfigLoggingOtlp.fromJson(json['otlp']), api: VeilidFFIConfigLoggingApi.fromJson(json['api']), + flame: VeilidFFIConfigLoggingFlame.fromJson(json['flame']), ); Map _$$VeilidFFIConfigLoggingImplToJson( @@ -81,6 +96,7 @@ Map _$$VeilidFFIConfigLoggingImplToJson( 'terminal': instance.terminal.toJson(), 'otlp': instance.otlp.toJson(), 'api': instance.api.toJson(), + 'flame': instance.flame.toJson(), }; _$VeilidFFIConfigImpl _$$VeilidFFIConfigImplFromJson( @@ -219,7 +235,7 @@ _$VeilidConfigUDPImpl _$$VeilidConfigUDPImplFromJson( Map json) => _$VeilidConfigUDPImpl( enabled: json['enabled'] as bool, - socketPoolSize: json['socket_pool_size'] as int, + socketPoolSize: (json['socket_pool_size'] as num).toInt(), listenAddress: json['listen_address'] as String, publicAddress: json['public_address'] as String?, ); @@ -238,7 +254,7 @@ _$VeilidConfigTCPImpl _$$VeilidConfigTCPImplFromJson( _$VeilidConfigTCPImpl( connect: json['connect'] as bool, listen: json['listen'] as bool, - maxConnections: json['max_connections'] as int, + maxConnections: (json['max_connections'] as num).toInt(), listenAddress: json['listen_address'] as String, publicAddress: json['public_address'] as String?, ); @@ -257,7 +273,7 @@ _$VeilidConfigWSImpl _$$VeilidConfigWSImplFromJson(Map json) => _$VeilidConfigWSImpl( connect: json['connect'] as bool, listen: json['listen'] as bool, - maxConnections: json['max_connections'] as int, + maxConnections: (json['max_connections'] as num).toInt(), listenAddress: json['listen_address'] as String, path: json['path'] as String, url: json['url'] as String?, @@ -279,7 +295,7 @@ _$VeilidConfigWSSImpl _$$VeilidConfigWSSImplFromJson( _$VeilidConfigWSSImpl( connect: json['connect'] as bool, listen: json['listen'] as bool, - maxConnections: json['max_connections'] as int, + maxConnections: (json['max_connections'] as num).toInt(), listenAddress: json['listen_address'] as String, path: json['path'] as String, url: json['url'] as String?, @@ -319,7 +335,8 @@ _$VeilidConfigTLSImpl _$$VeilidConfigTLSImplFromJson( _$VeilidConfigTLSImpl( certificatePath: json['certificate_path'] as String, privateKeyPath: json['private_key_path'] as String, - connectionInitialTimeoutMs: json['connection_initial_timeout_ms'] as int, + connectionInitialTimeoutMs: + (json['connection_initial_timeout_ms'] as num).toInt(), ); Map _$$VeilidConfigTLSImplToJson( @@ -333,31 +350,32 @@ Map _$$VeilidConfigTLSImplToJson( _$VeilidConfigDHTImpl _$$VeilidConfigDHTImplFromJson( Map json) => _$VeilidConfigDHTImpl( - resolveNodeTimeoutMs: json['resolve_node_timeout_ms'] as int, - resolveNodeCount: json['resolve_node_count'] as int, - resolveNodeFanout: json['resolve_node_fanout'] as int, - maxFindNodeCount: json['max_find_node_count'] as int, - getValueTimeoutMs: json['get_value_timeout_ms'] as int, - getValueCount: json['get_value_count'] as int, - getValueFanout: json['get_value_fanout'] as int, - setValueTimeoutMs: json['set_value_timeout_ms'] as int, - setValueCount: json['set_value_count'] as int, - setValueFanout: json['set_value_fanout'] as int, - minPeerCount: json['min_peer_count'] as int, - minPeerRefreshTimeMs: json['min_peer_refresh_time_ms'] as int, + resolveNodeTimeoutMs: (json['resolve_node_timeout_ms'] as num).toInt(), + resolveNodeCount: (json['resolve_node_count'] as num).toInt(), + resolveNodeFanout: (json['resolve_node_fanout'] as num).toInt(), + maxFindNodeCount: (json['max_find_node_count'] as num).toInt(), + getValueTimeoutMs: (json['get_value_timeout_ms'] as num).toInt(), + getValueCount: (json['get_value_count'] as num).toInt(), + getValueFanout: (json['get_value_fanout'] as num).toInt(), + setValueTimeoutMs: (json['set_value_timeout_ms'] as num).toInt(), + setValueCount: (json['set_value_count'] as num).toInt(), + setValueFanout: (json['set_value_fanout'] as num).toInt(), + minPeerCount: (json['min_peer_count'] as num).toInt(), + minPeerRefreshTimeMs: (json['min_peer_refresh_time_ms'] as num).toInt(), validateDialInfoReceiptTimeMs: - json['validate_dial_info_receipt_time_ms'] as int, - localSubkeyCacheSize: json['local_subkey_cache_size'] as int, + (json['validate_dial_info_receipt_time_ms'] as num).toInt(), + localSubkeyCacheSize: (json['local_subkey_cache_size'] as num).toInt(), localMaxSubkeyCacheMemoryMb: - json['local_max_subkey_cache_memory_mb'] as int, - remoteSubkeyCacheSize: json['remote_subkey_cache_size'] as int, - remoteMaxRecords: json['remote_max_records'] as int, + (json['local_max_subkey_cache_memory_mb'] as num).toInt(), + remoteSubkeyCacheSize: (json['remote_subkey_cache_size'] as num).toInt(), + remoteMaxRecords: (json['remote_max_records'] as num).toInt(), remoteMaxSubkeyCacheMemoryMb: - json['remote_max_subkey_cache_memory_mb'] as int, - remoteMaxStorageSpaceMb: json['remote_max_storage_space_mb'] as int, - publicWatchLimit: json['public_watch_limit'] as int, - memberWatchLimit: json['member_watch_limit'] as int, - maxWatchExpirationMs: json['max_watch_expiration_ms'] as int, + (json['remote_max_subkey_cache_memory_mb'] as num).toInt(), + remoteMaxStorageSpaceMb: + (json['remote_max_storage_space_mb'] as num).toInt(), + publicWatchLimit: (json['public_watch_limit'] as num).toInt(), + memberWatchLimit: (json['member_watch_limit'] as num).toInt(), + maxWatchExpirationMs: (json['max_watch_expiration_ms'] as num).toInt(), ); Map _$$VeilidConfigDHTImplToJson( @@ -392,13 +410,13 @@ Map _$$VeilidConfigDHTImplToJson( _$VeilidConfigRPCImpl _$$VeilidConfigRPCImplFromJson( Map json) => _$VeilidConfigRPCImpl( - concurrency: json['concurrency'] as int, - queueSize: json['queue_size'] as int, - timeoutMs: json['timeout_ms'] as int, - maxRouteHopCount: json['max_route_hop_count'] as int, - defaultRouteHopCount: json['default_route_hop_count'] as int, - maxTimestampBehindMs: json['max_timestamp_behind_ms'] as int?, - maxTimestampAheadMs: json['max_timestamp_ahead_ms'] as int?, + concurrency: (json['concurrency'] as num).toInt(), + queueSize: (json['queue_size'] as num).toInt(), + timeoutMs: (json['timeout_ms'] as num).toInt(), + maxRouteHopCount: (json['max_route_hop_count'] as num).toInt(), + defaultRouteHopCount: (json['default_route_hop_count'] as num).toInt(), + maxTimestampBehindMs: (json['max_timestamp_behind_ms'] as num?)?.toInt(), + maxTimestampAheadMs: (json['max_timestamp_ahead_ms'] as num?)?.toInt(), ); Map _$$VeilidConfigRPCImplToJson( @@ -424,11 +442,11 @@ _$VeilidConfigRoutingTableImpl _$$VeilidConfigRoutingTableImplFromJson( .toList(), bootstrap: (json['bootstrap'] as List).map((e) => e as String).toList(), - limitOverAttached: json['limit_over_attached'] as int, - limitFullyAttached: json['limit_fully_attached'] as int, - limitAttachedStrong: json['limit_attached_strong'] as int, - limitAttachedGood: json['limit_attached_good'] as int, - limitAttachedWeak: json['limit_attached_weak'] as int, + limitOverAttached: (json['limit_over_attached'] as num).toInt(), + limitFullyAttached: (json['limit_fully_attached'] as num).toInt(), + limitAttachedStrong: (json['limit_attached_strong'] as num).toInt(), + limitAttachedGood: (json['limit_attached_good'] as num).toInt(), + limitAttachedWeak: (json['limit_attached_weak'] as num).toInt(), ); Map _$$VeilidConfigRoutingTableImplToJson( @@ -447,25 +465,29 @@ Map _$$VeilidConfigRoutingTableImplToJson( _$VeilidConfigNetworkImpl _$$VeilidConfigNetworkImplFromJson( Map json) => _$VeilidConfigNetworkImpl( - connectionInitialTimeoutMs: json['connection_initial_timeout_ms'] as int, + connectionInitialTimeoutMs: + (json['connection_initial_timeout_ms'] as num).toInt(), connectionInactivityTimeoutMs: - json['connection_inactivity_timeout_ms'] as int, - maxConnectionsPerIp4: json['max_connections_per_ip4'] as int, - maxConnectionsPerIp6Prefix: json['max_connections_per_ip6_prefix'] as int, + (json['connection_inactivity_timeout_ms'] as num).toInt(), + maxConnectionsPerIp4: (json['max_connections_per_ip4'] as num).toInt(), + maxConnectionsPerIp6Prefix: + (json['max_connections_per_ip6_prefix'] as num).toInt(), maxConnectionsPerIp6PrefixSize: - json['max_connections_per_ip6_prefix_size'] as int, + (json['max_connections_per_ip6_prefix_size'] as num).toInt(), maxConnectionFrequencyPerMin: - json['max_connection_frequency_per_min'] as int, - clientAllowlistTimeoutMs: json['client_allowlist_timeout_ms'] as int, + (json['max_connection_frequency_per_min'] as num).toInt(), + clientAllowlistTimeoutMs: + (json['client_allowlist_timeout_ms'] as num).toInt(), reverseConnectionReceiptTimeMs: - json['reverse_connection_receipt_time_ms'] as int, - holePunchReceiptTimeMs: json['hole_punch_receipt_time_ms'] as int, + (json['reverse_connection_receipt_time_ms'] as num).toInt(), + holePunchReceiptTimeMs: + (json['hole_punch_receipt_time_ms'] as num).toInt(), routingTable: VeilidConfigRoutingTable.fromJson(json['routing_table']), rpc: VeilidConfigRPC.fromJson(json['rpc']), dht: VeilidConfigDHT.fromJson(json['dht']), upnp: json['upnp'] as bool, detectAddressChanges: json['detect_address_changes'] as bool, - restrictedNatRetries: json['restricted_nat_retries'] as int, + restrictedNatRetries: (json['restricted_nat_retries'] as num).toInt(), tls: VeilidConfigTLS.fromJson(json['tls']), application: VeilidConfigApplication.fromJson(json['application']), protocol: VeilidConfigProtocol.fromJson(json['protocol']), diff --git a/veilid-flutter/lib/veilid_state.g.dart b/veilid-flutter/lib/veilid_state.g.dart index 11453507..b7e42369 100644 --- a/veilid-flutter/lib/veilid_state.g.dart +++ b/veilid-flutter/lib/veilid_state.g.dart @@ -52,9 +52,9 @@ Map _$$TransferStatsDownUpImplToJson( _$RPCStatsImpl _$$RPCStatsImplFromJson(Map json) => _$RPCStatsImpl( - messagesSent: json['messages_sent'] as int, - messagesRcvd: json['messages_rcvd'] as int, - questionsInFlight: json['questions_in_flight'] as int, + messagesSent: (json['messages_sent'] as num).toInt(), + messagesRcvd: (json['messages_rcvd'] as num).toInt(), + questionsInFlight: (json['questions_in_flight'] as num).toInt(), lastQuestion: json['last_question'] == null ? null : Timestamp.fromJson(json['last_question']), @@ -64,8 +64,8 @@ _$RPCStatsImpl _$$RPCStatsImplFromJson(Map json) => firstConsecutiveSeenTs: json['first_consecutive_seen_ts'] == null ? null : Timestamp.fromJson(json['first_consecutive_seen_ts']), - recentLostAnswers: json['recent_lost_answers'] as int, - failedToSend: json['failed_to_send'] as int, + recentLostAnswers: (json['recent_lost_answers'] as num).toInt(), + failedToSend: (json['failed_to_send'] as num).toInt(), ); Map _$$RPCStatsImplToJson(_$RPCStatsImpl instance) => @@ -254,7 +254,7 @@ _$VeilidUpdateValueChangeImpl _$$VeilidUpdateValueChangeImplFromJson( subkeys: (json['subkeys'] as List) .map(ValueSubkeyRange.fromJson) .toList(), - count: json['count'] as int, + count: (json['count'] as num).toInt(), value: json['value'] == null ? null : ValueData.fromJson(json['value']), $type: json['kind'] as String?, ); diff --git a/veilid-flutter/packages/veilid_test/lib/src/veilid_fixture.dart b/veilid-flutter/packages/veilid_test/lib/src/veilid_fixture.dart index 9e128b53..52bd6491 100644 --- a/veilid-flutter/packages/veilid_test/lib/src/veilid_fixture.dart +++ b/veilid-flutter/packages/veilid_test/lib/src/veilid_fixture.dart @@ -42,6 +42,9 @@ class DefaultVeilidFixture implements VeilidFixture { // ignore: do_not_use_environment const String.fromEnvironment('LOG_LEVEL', defaultValue: 'info')); + // ignore: do_not_use_environment + final flamePathStr = const String.fromEnvironment('FLAME').trim(); + final Map platformConfigJson; if (kIsWeb) { final platformConfig = VeilidWASMConfig( @@ -78,7 +81,9 @@ class DefaultVeilidFixture implements VeilidFixture { enabled: true, level: logLevel, ignoreLogTargets: ignoreLogTargets, - ))); + ), + flame: VeilidFFIConfigLoggingFlame( + enabled: flamePathStr.isNotEmpty, path: flamePathStr))); platformConfigJson = platformConfig.toJson(); } Veilid.instance.initializeVeilidCore(platformConfigJson); diff --git a/veilid-flutter/rust/Cargo.toml b/veilid-flutter/rust/Cargo.toml index 37538ce6..febc9799 100644 --- a/veilid-flutter/rust/Cargo.toml +++ b/veilid-flutter/rust/Cargo.toml @@ -42,6 +42,7 @@ futures-util = { version = "0.3.29", default-features = false, features = [ ] } cfg-if = "1.0.0" data-encoding = { version = "2.5.0" } +tracing-flame = "0.2.0" # Dependencies for native builds only # Linux, Windows, Mac, iOS, Android diff --git a/veilid-flutter/rust/src/dart_ffi.rs b/veilid-flutter/rust/src/dart_ffi.rs index 4bd84126..5ef8d69f 100644 --- a/veilid-flutter/rust/src/dart_ffi.rs +++ b/veilid-flutter/rust/src/dart_ffi.rs @@ -13,6 +13,7 @@ use std::io::Write; use std::os::raw::c_char; use std::sync::Arc; use tracing::*; +use tracing_flame::FlameLayer; use tracing_subscriber::prelude::*; use veilid_core::{tools::*, Encodable}; @@ -65,6 +66,8 @@ lazy_static! { static ref TABLE_DBS: Mutex> = Mutex::new(BTreeMap::new()); static ref TABLE_DB_TRANSACTIONS: Mutex> = Mutex::new(BTreeMap::new()); + static ref FLAME_GUARD: Mutex>>> = + Mutex::new(None); } async fn get_veilid_api() -> veilid_core::VeilidAPIResult { @@ -118,11 +121,18 @@ pub struct VeilidFFIConfigLoggingApi { pub ignore_log_targets: Vec, } +#[derive(Debug, Deserialize, Serialize)] +pub struct VeilidFFIConfigLoggingFlame { + pub enabled: bool, + pub path: String, +} + #[derive(Debug, Deserialize, Serialize)] pub struct VeilidFFIConfigLogging { pub terminal: VeilidFFIConfigLoggingTerminal, pub otlp: VeilidFFIConfigLoggingOtlp, pub api: VeilidFFIConfigLoggingApi, + pub flame: VeilidFFIConfigLoggingFlame, } #[derive(Debug, Deserialize, Serialize)] @@ -307,6 +317,23 @@ pub extern "C" fn initialize_veilid_core(platform_config: FfiStr) { layers.push(layer.boxed()); } + // Flamegraph logger + if platform_config.logging.flame.enabled { + let filter = + veilid_core::VeilidLayerFilter::new(veilid_core::VeilidConfigLogLevel::Trace, &[]); + let (flame_layer, guard) = + FlameLayer::with_file(&platform_config.logging.flame.path).unwrap(); + *FLAME_GUARD.lock() = Some(guard); + filters.insert("flame", filter.clone()); + layers.push( + flame_layer + .with_threads_collapsed(true) + .with_empty_samples(false) + .with_filter(filter) + .boxed(), + ); + } + // API logger if platform_config.logging.api.enabled { let filter = veilid_core::VeilidLayerFilter::new(