LCOV - code coverage report

Current view
top level - src/worker - worker_response.dart
Test
lcov.info
Date
2024-11-13
Legend
Lines
hit
not hit
Branches
taken
not taken
# not executed
HitTotalCoverage
Lines596590.8%
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].
3127 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._([
436 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.
5127 static WorkerResponse log(LogEvent message) => WorkerResponse._([
529 microsecTimeStamp(), // 0 - travel time
53 null, // 1 - result
54 null, // 2 - error
55 null, // 3 - end of stream
569 message.serialize(), // 4 - log message
57 ]);
58
59 /// Special [WorkerResponse] message to indicate the end of a stream.
6018 static WorkerResponse closeStream() => WorkerResponse._([
617 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.
6928 bool get endOfStream => data[_$endOfStream];
70
71 /// The [WorkerResponse] exception, if any.
7230 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.
7620 dynamic get result {
779 final err = error;
7811 if (err != null) {
790 throw err;
80 } else {
8120 return data[_$result];
82 }
8311 }
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 WorkerResponseExt 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).
9721 bool unwrapInPlace(Channel channel) {
9810 unwrapTravelTime();
9930 final log = _LogEventSerializationExt.deserialize(data[_$log]);
10012 if (log != null) {
10124 channel.logger?.log(log.level, log.message,
1028 time: log.time, error: log.error, stackTrace: log.stackTrace);
1039 return false;
104 } else {
10548 data[_$error] = channel.exceptionManager.deserialize(data[_$error]);
10621 data[_$endOfStream] ??= false;
10712 return true;
108 }
10912 }
110
111 /// In-place serialization of a [WorkerResponse].
11210 List wrapInPlace() {
11310 final result = data[_$result];
11412 if (result is Iterable && result is! List) {
1150 data[_$result] = result.toList();
116 }
11724 data[_$error] = (data[_$error] as SquadronException?)?.serialize();
1181 return data;
1191 }
120
12121 static WorkerResponse from(List data) {
12230 if (data.length != 5) {
1230 throw SquadronErrorExt.create('Invalid worker response');
124 }
12521 return WorkerResponse._(data);
12612 }
127}
128
129extension _LogEventSerializationExt on LogEvent {
13018 List serialize() => [
13118 level.value,
13218 _stringify(message),
13318 microsecTimeStamp(time),
1349 error?.toString(),
1359 stackTrace?.toString(),
136 ];
137
1389 static LogEvent? deserialize(List? props) => (props == null)
139 ? null
1409 : LogEvent(
14136 _getLevel((props[0] as num?)?.toInt()),
14218 props[1],
14336 time: fromMicrosecTimeStamp((props[2] as num?)?.toInt()),
14418 error: props[3],
14527 stackTrace: SquadronException.loadStackTrace(props[4]),
146 );
147
14818 static Level _getLevel(int? value) {
1499 if (value == null) return Level.debug;
15056 return Level.values.where((l) => l.value == value).first;
1519 }
152
1539 static String? _stringify(dynamic message) {
1549 if (message is Function) {
155 try {
1564 return _stringify(message());
157 } catch (ex) {
1580 return 'Deferred message failed with error: $ex';
159 }
160 } else {
1619 return message.toString();
162 }
163 }
164}
Choose Features