LCOV - code coverage report

Current view
top level - src/worker - worker_response.dart
Test
lcov.info
Date
2025-03-26
Legend
Lines
hit
not hit
Branches
taken
not taken
# not executed
HitTotalCoverage
Lines495392.5%
Functions00-
Branches00-
Each row represents a line of source code
LineBranchHitsSource code
1import 'dart:async';
2
3import 'package:logger/web.dart';
4import 'package:meta/meta.dart';
5
6import '../_impl/xplat/_time_stamp.dart';
7import '../channel.dart';
8import '../exceptions/squadron_error.dart';
9import '../exceptions/squadron_exception.dart';
10import 'worker_message.dart';
11
12/// [WorkerResponse]s are used to communicate from [Worker]s to clients and
13/// carry a single piece of data. [Future]-based services simply return a
14/// single [WorkerResponse] with the result. [Stream]ing services will return
15/// one [WorkerResponse]s for each stream item and mmust send a
16/// [WorkerResponse.closeStream] message to indicate completion.
17/// [WorkerResponse]s can also send error messages and log events.
18extension type WorkerResponse._(List data) implements WorkerMessage {
19 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
20 /// not a [List], it will be converted to a [List] by [wrapInPlace].
210 static WorkerResponse ready([bool status = true]) => WorkerResponse._([
220 microsecTimeStamp(), // 0 - travel time
23 status, // 1 - ready
24 null, // 2 - error
25 null, // 3 - end of stream
26 null, // 4 - log message
27 ]);
28
29 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
30 /// not a [List], it will be converted to a [List] by [wrapInPlace].
3130 static WorkerResponse withResult(dynamic result) => WorkerResponse._([
3210 microsecTimeStamp(), // 0 - travel time
33 result, // 1 - result
34 null, // 2 - error
35 null, // 3 - end of stream
36 null, // 4 - log message
37 ]);
38
39 /// [WorkerResponse] with an error message and an optional (string) [StackTrace].
405 static WorkerResponse withError(SquadronException exception,
41 [StackTrace? stackTrace]) =>
4210 WorkerResponse._([
435 microsecTimeStamp(), // 0 - travel time
44 null, // 1 - result
45 exception, // 2 - error
46 null, // 3 - end of stream
47 null, // 4 - log message
48 ]);
49
50 /// [WorkerResponse] with log event information.
5130 static WorkerResponse log(LogEvent message) => WorkerResponse._([
5210 microsecTimeStamp(), // 0 - travel time
53 null, // 1 - result
54 null, // 2 - error
55 null, // 3 - end of stream
5610 message.serialize(), // 4 - log message
57 ]);
58
59 /// Special [WorkerResponse] message to indicate the end of a stream.
6018 static WorkerResponse closeStream() => WorkerResponse._([
616 microsecTimeStamp(), // 0 - travel time
62 null, // 1 - result
63 null, // 2 - error
64 true, // 3 - end of stream
65 null, // 4 - log message
66 ]);
67
68 /// Flag indicating the end of the [Stream]ing operation.
6920 bool get endOfStream => data[_$endOfStream];
70
71 /// The [WorkerResponse] exception, if any.
7220 SquadronException? get error => data[_$error];
73
74 /// Retrieves the result associated to this [WorkerResponse]. If the
75 /// [WorkerResponse] contains an error, an the [error] exception is thrown.
7610 dynamic get result {
7710 final err = error;
78 if (err != null) {
79 throw err;
80 } else {
8110 return data[_$result];
82 }
83 }
84}
85
86// 0 is reserved for travel time
87const _$result = 1;
88const _$error = 2;
89const _$endOfStream = 3;
90const _$log = 4;
91
92@internal
93extension WorkerResponseImpl on WorkerResponse {
94 /// In-place deserialization of a [WorkerResponse] sent by the worker.
95 /// Returns `false` if the message requires no further processing (currently
96 /// used for log messages only).
9710 bool unwrapInPlace(Channel channel) {
9810 unwrapTravelTime();
9920 final log = _LogEventSerializationExt.deserialize(data[_$log]);
100 if (log != null) {
10119 channel.logger?.log(log.level, log.message,
1029 time: log.time, error: log.error, stackTrace: log.stackTrace);
103 return false;
104 } else {
10540 data[_$error] = channel.exceptionManager.deserialize(data[_$error]);
10610 data[_$endOfStream] ??= false;
107 return true;
108 }
109 }
110
111 /// In-place serialization of a [WorkerResponse].
11210 List wrapInPlace() {
11310 final result = data[_$result];
11413 if (result is Iterable && result is! List) {
1152 data[_$result] = result.toList();
116 }
11725 data[_$error] = (data[_$error] as SquadronException?)?.serialize();
118 return data;
119 }
120
12110 static WorkerResponse from(List data) {
12220 if (data.length != 5) {
1230 throw SquadronErrorImpl.create('Invalid worker response');
124 }
12510 return WorkerResponse._(data);
126 }
127}
128
129extension _LogEventSerializationExt on LogEvent {
13020 List serialize() => [
13120 level.value,
13220 _stringify(message),
13320 microsecTimeStamp(time),
13410 error?.toString(),
13510 stackTrace?.toString(),
136 ];
137
13810 static LogEvent? deserialize(List? props) => (props == null)
139 ? null
14010 : LogEvent(
14130 _getLevel((props[0] as num?)?.toInt()),
14210 props[1],
14330 time: fromMicrosecTimeStamp((props[2] as num?)?.toInt()),
14410 error: props[3],
14520 stackTrace: SquadronException.loadStackTrace(props[4]),
146 );
147
14810 static Level _getLevel(int? value) {
149 if (value == null) return Level.debug;
15050 return Level.values.where((l) => l.value == value).first;
151 }
152
15310 static String? _stringify(dynamic message) {
15410 if (message is Function) {
155 try {
1564 return message().toString();
157 } catch (ex) {
1580 return 'Deferred message failed with error: $ex';
159 }
160 } else {
16110 return message.toString();
162 }
163 }
164}
Choose Features