LCOV - code coverage report

Current view
top level - src/worker - worker_response.dart
Test
lcov.info
Date
2026-02-21
Legend
Lines
hit
not hit
Branches
taken
not taken
# not executed
HitTotalCoverage
Lines515592.7%
Functions00-
Branches00-
Each row represents a line of source code
LineBranchHitsSource code
1import 'dart:async';
2
3import 'package:logger/web.dart';
4
5import '../_impl/xplat/_time_stamp.dart';
6import '../channel.dart';
7import '../exceptions/squadron_error.dart';
8import '../exceptions/squadron_exception.dart';
9import 'worker_message.dart';
10
11/// [WorkerResponse]s are used to communicate from [Worker]s to clients and
12/// carry a single piece of data. [Future]-based services simply return a
13/// single [WorkerResponse] with the result. [Stream]ing services will return
14/// one [WorkerResponse]s for each stream item and mmust send a
15/// [WorkerResponse.closeStream] message to indicate completion.
16/// [WorkerResponse]s can also send error messages and log events.
17extension type WorkerResponse._(List data) implements WorkerMessage {
1810 factory WorkerResponse.from(List data) {
1920 if (data.length != 5) {
200 throw SquadronErrorImpl.create('Invalid worker response');
21 }
2210 return WorkerResponse._(data);
23 }
24
25 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
26 /// not a [List], it will be converted to a [List] by [wrapInPlace].
270 factory WorkerResponse.ready([bool status = true]) => WorkerResponse._([
280 microsecTimeStamp(), // 0 - travel time
29 status, // 1 - ready
30 null, // 2 - error
31 null, // 3 - end of stream
32 null, // 4 - log message
33 ]);
34
35 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
36 /// not a [List], it will be converted to a [List] by [wrapInPlace].
3730 factory WorkerResponse.withResult(dynamic result) => WorkerResponse._([
3810 microsecTimeStamp(), // 0 - travel time
39 result, // 1 - result
40 null, // 2 - error
41 null, // 3 - end of stream
42 null, // 4 - log message
43 ]);
44
45 /// [WorkerResponse] with an error message and an optional (string) [StackTrace].
465 factory WorkerResponse.withError(SquadronException exception,
47 [StackTrace? stackTrace]) =>
4810 WorkerResponse._([
495 microsecTimeStamp(), // 0 - travel time
50 null, // 1 - result
51 exception, // 2 - error
52 null, // 3 - end of stream
53 null, // 4 - log message
54 ]);
55
56 /// [WorkerResponse] with log event information.
5730 factory WorkerResponse.log(LogEvent message) => WorkerResponse._([
5810 microsecTimeStamp(), // 0 - travel time
59 null, // 1 - result
60 null, // 2 - error
61 null, // 3 - end of stream
6210 message.serialize(), // 4 - log message
63 ]);
64
65 /// Special [WorkerResponse] message to indicate the end of a stream.
6618 factory WorkerResponse.closeStream() => WorkerResponse._([
676 microsecTimeStamp(), // 0 - travel time
68 null, // 1 - result
69 null, // 2 - error
70 true, // 3 - end of stream
71 null, // 4 - log message
72 ]);
73
74 /// Flag indicating the end of the [Stream]ing operation.
7520 bool get endOfStream => data[_$endOfStream];
76
77 /// The [WorkerResponse] exception, if any.
7820 SquadronException? get error => data[_$error];
79
80 /// Retrieves the result associated to this [WorkerResponse]. If the
81 /// [WorkerResponse] contains an error, an the [error] exception is thrown.
8210 dynamic get result {
8310 final err = error;
84 if (err != null) {
85 throw err;
86 } else {
8710 return data[_$result];
88 }
89 }
90
91 /// In-place deserialization of a [WorkerResponse] sent by the worker.
92 /// Returns `false` if the message requires no further processing (currently
93 /// used for log messages only).
9410 bool unwrapInPlace(Channel channel) {
9510 unwrapTravelTime();
9620 final log = _LogEventSerializationExt.deserialize(data[_$log]);
97 if (log != null) {
9819 channel.logger?.log(log.level, log.message,
999 time: log.time, error: log.error, stackTrace: log.stackTrace);
100 return false;
101 } else {
10240 data[_$error] = channel.exceptionManager.deserialize(data[_$error]);
10310 data[_$endOfStream] ??= false;
104 return true;
105 }
106 }
107
108 /// In-place serialization of a [WorkerResponse].
10910 void wrapInPlace() {
11010 final result = data[_$result];
11113 if (result is Iterable && result is! List) {
1122 data[_$result] = result.toList();
113 }
11425 data[_$error] = (data[_$error] as SquadronException?)?.serialize();
115 }
116}
117
118// 0 is reserved for travel time
119const _$result = 1;
120const _$error = 2;
121const _$endOfStream = 3;
122const _$log = 4;
123
124extension _LogEventSerializationExt on LogEvent {
12520 List serialize() => [
12620 level.value,
12720 _stringify(message),
12820 microsecTimeStamp(time),
12910 error?.toString(),
13010 stackTrace?.toString(),
131 ];
132
13310 static LogEvent? deserialize(List? props) => (props == null)
134 ? null
13510 : LogEvent(
13630 _getLevel((props[0] as num?)?.toInt()),
13710 props[1],
13830 time: fromMicrosecTimeStamp((props[2] as num?)?.toInt()),
13910 error: props[3],
14020 stackTrace: SquadronException.loadStackTrace(props[4]),
141 );
142
14320 static final _levelMap =
14450 Map.fromEntries(Level.values.map((l) => MapEntry(l.value, l)));
145
14610 static Level _getLevel(int? value) =>
14720 _levelMap[value ?? Level.debug.value] ?? Level.debug;
148
14910 static String? _stringify(dynamic message) {
15010 if (message is Function) {
151 try {
1524 return message().toString();
153 } catch (ex) {
1540 return 'Deferred message failed with error: $ex';
155 }
156 } else {
15710 return message.toString();
158 }
159 }
160}
Choose Features