Description
I got the following error message when I tried to send a protobuf message to an isolate:
Unhandled exception:
Invalid argument(s): Illegal argument in isolate message : (object is a closure - Function '<anonymous closure>':.)
#0 _SendPortImpl._sendInternal (dart:isolate/runtime/libisolate_patch.dart:218:70)
#1 _SendPortImpl.send (dart:isolate/runtime/libisolate_patch.dart:202:5)
#2 sendReceive (file:///Users/tim/Desktop/DART/messages/bin/printer.dart:40:8)
#3 main (file:///Users/tim/Desktop/DART/messages/bin/printer.dart:54:3)
<asynchronous suspension>
#4 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:287:32)
#5 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
This surprised me because I had previously been able to send other message representations. Looking more closely, I found that the error only occurred for my messages with repeated
fields, and looking into the representation of FieldInfo
I think I see why: because this field and the ones following it store functions for various special cases, including repeated fields.
Here is my test program:
import 'dart:async';
import 'dart:isolate';
import 'package:printer/src/generated/sample.pb.dart';
// Runs in a separate thread.
void printer(SendPort listener) async {
// create receive port and send it to the listener
var receivePort = new ReceivePort();
listener.send(receivePort.sendPort);
// listen on receive port for things to print
await for (var msg in receivePort) {
print('>> [${msg[0]}] (${msg[0].runtimeType})');
var replyPort = msg[1];
replyPort.send(null);
}
}
/// sends a message on a port,
/// receives the response,
/// and returns a future for the message that was received
Future sendReceive(SendPort port, msg) {
var response = new ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
main(List<String> args) async {
// Start the printer and wait for it to reply with its SendPort.
var receivePort = new ReceivePort();
Isolate.spawn(printer, receivePort.sendPort);
var p = await receivePort.first;
// Send some things
sendReceive(p, 123);
sendReceive(p, "hello");
sendReceive(p, Kiosk());
sendReceive(p, SetSignIdForKioskIdsRequest());
}
My protos are in sample.proto
:
syntax = "proto3";
package sample;
// Describes a hardware device that can display signs.
message Kiosk {
int32 id = 1; // unique id
string name = 2; // name of device hardware
ScreenSize size = 3; // screen size
}
// Represents the size of a screen in pixels.
message ScreenSize {
int32 width = 1; // screen width
int32 height = 2; // screen height
}
message SetSignIdForKioskIdsRequest {
repeated int32 kiosk_ids = 1;
int32 sign_id = 2;
}
When I remove the repeated
keyword from the kiosks_ids
field in my proto, my test program runs successfully:
dart bin/printer.dart
>> [123] (int)
>> [hello] (String)
>> [] (Kiosk)
>> [] (SetSignIdForKioskIdsRequest)
I'm new to Dart, so I'm not sure that sending structs into isolates is a good practice (due to possible efficiency problems), but it seems bad for this to work for some protobuf messages and not others.