LCOV - code coverage report

Current view
top level - src/worker - worker_response.dart
Test
lcov.info
Date
2026-11-07
Legend
Lines
hit
not hit
Branches
taken
not taken
# not executed
HitTotalCoverage
Lines525692.9%
Functions00-
Branches00-
Each row represents a line of source code
LineBranchHitsSource code
1import 'dart:async';
2
3import 'package:logger/web.dart';
4
5import '../build_options.dart';
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.
181extension type WorkerResponse._(List data) implements WorkerMessage {
191 factory WorkerResponse.from(List data) {
202 if (data.length != 5) {
210 throw SquadronErrorImpl.create('Invalid worker response');
22 }
231 return WorkerResponse._(data);
24 }
25
26 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
27 /// not a [List], it will be converted to a [List] by [wrapInPlace].
280 factory WorkerResponse.ready([bool status = true]) => WorkerResponse._([
290 BuildOptions.withTravelTime ? Timestamp.now() : null, // 0 - travel time
30 status, // 1 - ready
31 null, // 2 - error
32 null, // 3 - end of stream
33 null, // 4 - log message
34 ]);
35
36 /// [WorkerResponse] with a valid [result]. If [result] is an [Iterable] but
37 /// not a [List], it will be converted to a [List] by [wrapInPlace].
383 factory WorkerResponse.withResult(dynamic result) => WorkerResponse._([
391 BuildOptions.withTravelTime ? Timestamp.now() : null, // 0 - travel time
40 result, // 1 - result
41 null, // 2 - error
42 null, // 3 - end of stream
43 null, // 4 - log message
44 ]);
45
46 /// [WorkerResponse] with an error message and an optional (string) [StackTrace].
471 factory WorkerResponse.withError(SquadronException exception,
48 [StackTrace? stackTrace]) =>
492 WorkerResponse._([
501 BuildOptions.withTravelTime ? Timestamp.now() : null, // 0 - travel time
51 null, // 1 - result
52 exception, // 2 - error
53 null, // 3 - end of stream
54 null, // 4 - log message
55 ]);
56
57 /// [WorkerResponse] with log event information.
583 factory WorkerResponse.log(LogEvent message) => WorkerResponse._([
591 BuildOptions.withTravelTime ? Timestamp.now() : null, // 0 - travel time
60 null, // 1 - result
61 null, // 2 - error
62 null, // 3 - end of stream
63 BuildOptions.withCrossWorkerLogging
641 ? message.serialize()
65 : null, // 4 - log message
66 ]);
67
68 /// Special [WorkerResponse] message to indicate the end of a stream.
693 factory WorkerResponse.closeStream() => WorkerResponse._([
701 BuildOptions.withTravelTime ? Timestamp.now() : null, // 0 - travel time
71 null, // 1 - result
72 null, // 2 - error
73 true, // 3 - end of stream
74 null, // 4 - log message
75 ]);
76
77 /// Flag indicating the end of the [Stream]ing operation.
782 bool get endOfStream => data[_$endOfStream];
79
80 /// The [WorkerResponse] exception, if any.
812 SquadronException? get error => data[_$error];
82
83 /// Retrieves the result associated to this [WorkerResponse]. If the
84 /// [WorkerResponse] contains an error, an the [error] exception is thrown.
851 dynamic get result {
861 final err = error;
87 if (err != null) {
88 throw err;
89 } else {
901 return data[_$result];
91 }
92 }
93
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).
971 bool unwrapInPlace(Channel channel) {
981 unwrapTravelTime();
99 final log = BuildOptions.withCrossWorkerLogging
1002 ? _LogEventSerializationExt.deserialize(data[_$log])
101 : null;
102 if (log != null) {
1034 channel.logger?.log(log.level, log.message,
1043 time: log.time, error: log.error, stackTrace: log.stackTrace);
105 return false;
106 } else {
1074 data[_$error] = channel.exceptionManager.deserialize(data[_$error]);
1081 data[_$endOfStream] ??= false;
109 return true;
110 }
111 }
112
113 /// In-place serialization of a [WorkerResponse].
1141 void wrapInPlace() {
1151 final result = data[_$result];
1162 if (result is Iterable && result is! List) {
1172 data[_$result] = result.toList();
118 }
1193 data[_$error] = (data[_$error] as SquadronException?)?.serialize();
120 }
121}
122
123// 0 is reserved for travel time
124const _$result = 1;
125const _$error = 2;
126const _$endOfStream = 3;
127const _$log = 4;
128
129extension _LogEventSerializationExt on LogEvent {
1302 List serialize() => [
1312 level.value,
1322 _stringify(message),
1332 Timestamp.from(time),
1341 error?.toString(),
1351 stackTrace?.toString(),
136 ];
137
1381 static LogEvent? deserialize(List? props) => (props == null)
139 ? null
1401 : LogEvent(
1413 _getLevel((props[0] as num?)?.toInt()),
1421 props[1],
1433 time: Timestamp.from(props[2] as num?)?.toDateTime(),
1441 error: props[3],
1452 stackTrace: SquadronException.loadStackTrace(props[4]),
146 );
147
1482 static final _levelMap =
1495 Map.fromEntries(Level.values.map((l) => MapEntry(l.value, l)));
150
1511 static Level _getLevel(int? value) =>
1522 _levelMap[value ?? Level.debug.value] ?? Level.debug;
153
1541 static String? _stringify(dynamic message) {
1551 if (message is Function) {
156 try {
1572 return message().toString();
158 } catch (ex) {
1590 return 'Deferred message failed with error: $ex';
160 }
161 } else {
1621 return message.toString();
163 }
164 }
165}
Choose Features