Skip to content

Commit cd76013

Browse files
committed
Merge branch 'main' into interface-abstraction
2 parents 0968085 + 0e5c7b9 commit cd76013

File tree

9 files changed

+88
-40
lines changed

9 files changed

+88
-40
lines changed

packages/sane/example/main.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dart:typed_data';
55

66
import 'package:logging/logging.dart';
77
import 'package:sane/sane.dart';
8-
import 'package:sane/src/impl/sane_dev.dart';
8+
import 'package:sane/src/impl/sane_mock.dart';
99
import 'package:sane/src/impl/sane_native.dart';
1010

1111
void main(List<String> args) async {
@@ -79,4 +79,6 @@ void main(List<String> args) async {
7979
);
8080
final rawPixelData = mergeUint8Lists(rawPixelDataList);
8181
file.writeAsBytesSync(rawPixelData, mode: FileMode.append);
82+
83+
await sane.dispose();
8284
}

packages/sane/lib/src/extensions.dart

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:logging/logging.dart';
12
import 'package:meta/meta.dart';
23
import 'package:sane/src/bindings.g.dart';
34
import 'package:sane/src/exceptions.dart';
@@ -12,3 +13,16 @@ extension SaneStatusExtension on SANE_Status {
1213
}
1314
}
1415
}
16+
17+
@internal
18+
extension LoggerExtension on Logger {
19+
void redirect(LogRecord record) {
20+
log(
21+
record.level,
22+
record.message,
23+
record.error,
24+
record.stackTrace,
25+
record.zone,
26+
);
27+
}
28+
}

packages/sane/lib/src/impl/sane_dev.dart renamed to packages/sane/lib/src/impl/sane_mock.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'dart:typed_data';
44
import 'package:logging/logging.dart';
55
import 'package:sane/sane.dart';
66

7-
final _logger = Logger('sane.dev');
7+
final _logger = Logger('sane.mock');
88

99
class MockSane implements Sane {
1010
@override

packages/sane/lib/src/impl/sane_native.dart

+8-7
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class NativeSane implements Sane {
6666
SaneIsolate? _isolate;
6767

6868
Future<SaneIsolate> _getIsolate() async {
69-
if (_isolate?.exited == true || _disposed) throw SaneDisposedError();
69+
if (_disposed) throw SaneDisposedError();
7070
return _isolate ??= await SaneIsolate.spawn(backingSane);
7171
}
7272

@@ -81,17 +81,18 @@ class NativeSane implements Sane {
8181
Future<void> dispose({bool force = false}) async {
8282
final isolate = _isolate;
8383

84-
if (force) {
85-
isolate?.kill();
86-
return;
87-
}
88-
8984
if (_disposed) return;
9085

9186
_disposed = true;
9287
_instance = null;
9388

94-
await isolate?.sendMessage(ExitMessage());
89+
if (isolate == null) return;
90+
91+
if (force) {
92+
isolate.kill();
93+
} else {
94+
await isolate.sendMessage(ExitMessage());
95+
}
9596

9697
_isolate = null;
9798
}

packages/sane/lib/src/impl/sane_sync.dart

+8-4
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ class SyncSaneDevice implements SaneDevice, ffi.Finalizable {
393393
SaneOptionResult<bool> controlBoolOption(
394394
int index,
395395
SaneAction action,
396-
bool? value,) {
396+
bool? value,
397+
) {
397398
return _controlOption<bool>(
398399
index: index,
399400
action: action,
@@ -405,7 +406,8 @@ class SyncSaneDevice implements SaneDevice, ffi.Finalizable {
405406
SaneOptionResult<int> controlIntOption(
406407
int index,
407408
SaneAction action,
408-
int? value,) {
409+
int? value,
410+
) {
409411
return _controlOption<int>(
410412
index: index,
411413
action: action,
@@ -417,7 +419,8 @@ class SyncSaneDevice implements SaneDevice, ffi.Finalizable {
417419
SaneOptionResult<double> controlFixedOption(
418420
int index,
419421
SaneAction action,
420-
double? value,) {
422+
double? value,
423+
) {
421424
return _controlOption<double>(
422425
index: index,
423426
action: action,
@@ -429,7 +432,8 @@ class SyncSaneDevice implements SaneDevice, ffi.Finalizable {
429432
SaneOptionResult<String> controlStringOption(
430433
int index,
431434
SaneAction action,
432-
String? value,) {
435+
String? value,
436+
) {
433437
return _controlOption<String>(
434438
index: index,
435439
action: action,

packages/sane/lib/src/isolate.dart

+37-20
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,54 @@
11
import 'dart:async';
22
import 'dart:isolate';
33

4+
import 'package:logging/logging.dart';
5+
import 'package:meta/meta.dart';
46
import 'package:sane/src/exceptions.dart';
7+
import 'package:sane/src/extensions.dart';
58
import 'package:sane/src/isolate_messages/exception.dart';
9+
import 'package:sane/src/isolate_messages/exit.dart';
610
import 'package:sane/src/isolate_messages/interface.dart';
711
import 'package:sane/src/sane.dart';
812

13+
final _logger = Logger('sane.isolate');
14+
15+
@internal
916
class SaneIsolate {
1017
SaneIsolate._(
1118
this._isolate,
1219
this._sendPort,
13-
this._exitReceivePort,
14-
) : _exited = false {
15-
_exitReceivePort.listen((message) {
16-
assert(message == null);
17-
_exited = true;
18-
});
19-
}
20+
);
2021

2122
final Isolate _isolate;
2223
final SendPort _sendPort;
23-
final ReceivePort _exitReceivePort;
24-
25-
bool _exited;
26-
27-
bool get exited => _exited;
2824

2925
static Future<SaneIsolate> spawn(Sane sane) async {
3026
final receivePort = ReceivePort();
31-
final exitReceivePort = ReceivePort();
3227

3328
final isolate = await Isolate.spawn(
3429
_entryPoint,
3530
(receivePort.sendPort, sane),
36-
onExit: exitReceivePort.sendPort,
31+
onExit: receivePort.sendPort,
3732
);
3833

39-
final sendPort = await receivePort.first as SendPort;
40-
return SaneIsolate._(isolate, sendPort, exitReceivePort);
41-
}
34+
final sendPortCompleter = Completer<SendPort>();
35+
receivePort.listen((message) {
36+
switch (message) {
37+
case SendPort():
38+
sendPortCompleter.complete(message);
39+
case LogRecord():
40+
_logger.redirect(message);
41+
case null:
42+
receivePort.close();
43+
}
44+
});
4245

43-
void kill() {
44-
_isolate.kill(priority: Isolate.immediate);
46+
final sendPort = await sendPortCompleter.future;
47+
return SaneIsolate._(isolate, sendPort);
4548
}
4649

50+
void kill() => _isolate.kill(priority: Isolate.immediate);
51+
4752
Future<T> sendMessage<T extends IsolateResponse>(
4853
IsolateMessage<T> message,
4954
) async {
@@ -75,10 +80,16 @@ typedef _EntryPointArgs = (SendPort sendPort, Sane sane);
7580
void _entryPoint(_EntryPointArgs args) {
7681
final (sendPort, sane) = args;
7782

83+
Logger.root.level = Level.ALL;
84+
Logger.root.onRecord.forEach(sendPort.send);
85+
7886
final receivePort = ReceivePort();
7987
sendPort.send(receivePort.sendPort);
8088

81-
receivePort.cast<_IsolateMessageEnvelope>().listen((envelope) async {
89+
late StreamSubscription<_IsolateMessageEnvelope> subscription;
90+
91+
subscription =
92+
receivePort.cast<_IsolateMessageEnvelope>().listen((envelope) async {
8293
final _IsolateMessageEnvelope(:message, :replyPort) = envelope;
8394

8495
IsolateResponse response;
@@ -93,6 +104,10 @@ void _entryPoint(_EntryPointArgs args) {
93104
}
94105

95106
replyPort.send(response);
107+
108+
if (message is ExitMessage) {
109+
await subscription.cancel();
110+
}
96111
});
97112
}
98113

@@ -108,8 +123,10 @@ class _IsolateMessageEnvelope {
108123

109124
late Map<String, SaneDevice> _devices;
110125

126+
@internal
111127
SaneDevice getDevice(String name) => _devices[name]!;
112128

129+
@internal
113130
void setDevices(Iterable<SaneDevice> devices) {
114131
_devices = {
115132
for (final device in devices) device.name: device,
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:sane/src/isolate.dart';
12
import 'package:sane/src/isolate_messages/interface.dart';
23
import 'package:sane/src/sane.dart';
34

@@ -8,14 +9,14 @@ class GetDevicesMessage implements IsolateMessage<GetDevicesResponse> {
89

910
@override
1011
Future<GetDevicesResponse> handle(Sane sane) async {
11-
return GetDevicesResponse(
12-
devices: await sane.getDevices(localOnly: localOnly),
13-
);
12+
final devices = await sane.getDevices(localOnly: localOnly);
13+
setDevices(devices);
14+
return GetDevicesResponse(devices);
1415
}
1516
}
1617

1718
class GetDevicesResponse implements IsolateResponse {
18-
GetDevicesResponse({required this.devices});
19+
GetDevicesResponse(this.devices);
1920

2021
final List<SaneDevice> devices;
2122
}

packages/sane/lib/src/sane.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dart:typed_data';
33

44
import 'package:meta/meta.dart';
55
import 'package:sane/sane.dart';
6-
import 'package:sane/src/impl/sane_dev.dart';
6+
import 'package:sane/src/impl/sane_mock.dart';
77
import 'package:sane/src/impl/sane_native.dart';
88
import 'package:sane/src/impl/sane_sync.dart';
99

@@ -15,7 +15,7 @@ abstract interface class Sane {
1515
/// See also:
1616
///
1717
/// - [Sane.sync]
18-
factory Sane() => NativeSane();
18+
factory Sane([Sane? backingSane]) => NativeSane(backingSane);
1919

2020
/// Instantiates a new synchronous SANE instance.
2121
factory Sane.sync() => SyncSane();

packages/sane/test/sane_singleton_test.dart

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1+
import 'package:logging/logging.dart';
12
import 'package:sane/sane.dart';
23
import 'package:test/test.dart';
34

45
void main() {
56
late Sane sane;
67

8+
setUp(() {
9+
Logger.root.level = Level.ALL;
10+
Logger.root.onRecord.listen((record) {
11+
// ignore: avoid_print
12+
print('${record.level.name}: ${record.time}: ${record.message}');
13+
});
14+
});
15+
716
test('can instantiate', () {
817
sane = Sane();
918
});
@@ -25,7 +34,7 @@ void main() {
2534
});
2635

2736
test('can reinstiate with new instance', () {
28-
final newSane = Sane();
37+
final newSane = Sane(Sane.mock());
2938
expect(sane, isNot(newSane));
3039
sane = newSane;
3140
});

0 commit comments

Comments
 (0)