Dart Isolate SendPort and ReceivePort sending 100times vice versa - dart

My main works, but in my foo I would like to send data to main. Here's my code where I want to pass data between foo and main 100 times. How can I achieve that?
import 'dart:isolate';
import 'dart:async';
void foo(SendPort sendPort) async {
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((dataSend){
print('foo received : ${dataSend}');
print('');
});
}
void main() async {
int temp = 0;
ReceivePort receivePort = new ReceivePort();
Isolate.spawn(foo,receivePort.sendPort);
receivePort.listen((dataSend) {
print('I received : ${dataSend}');
dataSend.send(temp+1);
});
}

I am really confused about what you want to achieve but is it something like this?
import 'dart:isolate';
import 'dart:async';
void foo(SendPort sendPort) async {
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((dataSend) {
print('foo received : ${dataSend}');
sendPort.send(receivePort.sendPort);
});
}
void main() async {
int temp = 0;
ReceivePort receivePort = new ReceivePort();
Isolate.spawn(foo, receivePort.sendPort);
receivePort.listen((dataSend) {
print('I received : ${dataSend}');
if (++temp < 100) {
dataSend.send(temp);
} else {
receivePort.close();
}
});
}

Related

How to break the loop for a stream in dart?

I known the listen can be abort by StreamSubscription. But for some reason, I can not call listen for the File.openRead(). How can I abort the read operation stream?
import 'dart:io';
import 'dart:async';
class Reader {
Stream<int> progess(File file) async* {
var sum = 0;
var fs = file.openRead();
await for (var d in fs) {
// consume d
sum += d.length;
yield sum;
}
}
void cancel() {
// How to abort the above loop without using StreamSubscription returned by listen().
}
}
void main() async {
var reader = Reader();
var file = File.new("a.txt");
reader.progess(file).listen((p) => print("$p"));
// How to cancel it without
Future.delayed(Duration(seconds: 1), () { reader.cancel()});
}
You cannot cancel the stream subscription without calling cancel on the stream subscription.
You might be able to interrupt the stream producer in some other way, using a "side channel" to ask it to stop producing values. That's not a stream cancel, more like a premature stream close.
Example:
class Reader {
bool _cancelled = false;
Stream<int> progess(File file) async* {
var sum = 0;
var fs = file.openRead();
await for (var d in fs) {
// consume d
sum += d.length;
if (_cancelled) return; // <---
yield sum;
}
}
void cancel() {
_cancelled = true;
}
}
Another option is to create a general stream wrapper which can interrupt the stream. Maybe something like
import"dart:async";
class CancelableStream<T> extends Stream<T> {
final Stream<T> _source;
final Set<_CancelableStreamSubscription<T>> _subscriptions = {};
CancelableStream(Stream<T> source) : _source = source;
#override
StreamSubscription<T> listen(
onData, {onError, onDone, cancelOnError}) {
var sub = _source.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
var canSub = _CancelableStreamSubscription<T>(sub, this, cancelOnError ?? false);
_subscriptions.add(canSub);
return canSub;
}
void cancelAll() {
while (_subscriptions.isNotEmpty) {
_subscriptions.first.cancel();
}
}
}
class _CancelableStreamSubscription<T> implements StreamSubscription<T> {
final bool _cancelOnError;
final StreamSubscription<T> _source;
final CancelableStream<T> _owner;
_CancelableStreamSubscription(
this._source, this._owner, this._cancelOnError);
#override
Future<void> cancel() {
_owner._subscriptions.remove(this);
return _source.cancel();
}
#override
void onData(f) => _source.onData(f);
#override
void onError(f) {
if (!_cancelOnError) {
_source.onError(f);
} else {
_source.onError((Object e, StackTrace s) {
_owner._subscriptions.remove(this);
if (f is void Function(Object, StackTrace)) {
f(e, s);
} else {
f?.call(e);
}
});
}
}
#override
bool get isPaused => _source.isPaused;
#override
void onDone(f) => _source.onDone(() {
_owner._subscriptions.remove(this);
f?.call();
});
#override
void pause([resumeFuture]) => _source.pause(resumeFuture);
#override
void resume() => _source.resume;
#override
Future<E> asFuture<E>([E? value]) => _source.asFuture(value);
}
You can then use it like:
void main() async {
Stream<int> foo() async* {
yield 1;
yield 2;
yield 3;
yield 4;
}
var s = CancelableStream<int>(foo());
await for (var x in s) {
print(x);
if (x == 2) s.cancelAll();
}
}

How to mock http request in flutter integration test?

I'm trying to do so using Mockito, this is my test:
import 'package:http/http.dart' as http;
import 'package:utgard/globals.dart' as globals;
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
class MockClient extends Mock implements http.Client {}
void main() {
group('Login flow', () {
final SerializableFinder loginContinuePasswordButton =
find.byValueKey('login_continue_password_button');
FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null) {
//await driver.close();
}
});
test('login with correct password', () async {
final client = MockClient();
when(client.post('http://wwww.google.com'))
.thenAnswer((_) async => http.Response('{"title": "Test"}', 200));
globals.httpClient = client;
await driver.enterText('000000');
await driver.tap(loginContinuePasswordButton);
});
});
}
And this is my http request code:
Future<Map<String, dynamic>> post({
RequestType requestType,
Map<String, dynamic> body,
}) async {
final http.Response response =
await globals.httpClient.post('http://wwww.google.com');
print(response);
final Map<String, dynamic> finalResponse = buildResponse(response);
_managerErrors(finalResponse);
return finalResponse;
}
And here I have the global:
library utgard.globals;
import 'package:http/http.dart' as http;
http.Client httpClient = http.Client();
However I continue to receive http errors, that indicates to me that the http wasn't replaced by the mock.
The solution I found was to define the mock in test_driver/app.dart and call the runApp function after that:
import 'package:flutter/widgets.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:utgard/business/config/globals.dart';
import 'package:utgard/main.dart' as app;
class MockClient extends Mock implements http.Client {}
void main() {
enableFlutterDriverExtension();
final MockClient client = MockClient();
// make your mocks here
httpClient = client;
runApp(app.MyApp());
}
Instead of
when(client.post('http://wwww.google.com'))
.thenAnswer((_) async => http.Response('{"title": "Test"}', 200));
try any and then assert it later
when(
mockHttpClient.send(any),
).thenAnswer((_) async => http.Response('{"title": "Test"}', 200));
// ...
final String capt = verify(client.send(captureAny)).captured;
expect(capt, 'http://wwww.google.com');
There's a small chance the call param is not exactly what you mock, so go with any is safer.
We don't see the code you're testing, but it's unlikely that it is going to make this request :
client.post('http://wwww.google.com')
It is anyway a good practice to use mock json files, and you don't want to change the request anytime those mock files change.
I recommend you to use Mocktail instead of Mockito.
That way, you can simulate any call with any :
// Simulate any GET :
mockHttpClient.get(any()))
// Simulate any POST :
mockHttpClient.post(any()))
Here's the complete solution :
class MockClient extends Mock implements http.Client {}
class FakeUri extends Fake implements Uri {}
void main() {
setUp(() {
registerFallbackValue(FakeUri()); // Required by Mocktail
});
tearDown(() {});
MockHttpClient mockHttpClient = MockHttpClient();
group('Login flow', () {
test('login with correct password', () async {
when(() => mockHttpClient.get(any())).thenAnswer(((_) async {
return Response(mockWeatherResponse, 200);
}));
// Call the functions you need to test here
}
}
}

MQTT acknowledgement

If I am using QOS type 1 means the broker will continue to send the message to the subscriber until it gets an acknowledgment. How can i set or return ack ? Please anyone shed some light on this.
This is my source code:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.Vector;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.Callback;
import org.fusesource.mqtt.client.CallbackConnection;
import org.fusesource.mqtt.client.Listener;
import org.fusesource.mqtt.client.MQTT;
import org.fusesource.mqtt.client.QoS;
import org.fusesource.mqtt.client.Topic;
import com.adventnet.management.log.Log;
import com.adventnet.nms.util.NmsLogMgr;
public class DefaultMqttListener implements IMqttListener,Runnable{
long count = 0;
long start = System.currentTimeMillis();
private HashMap serverDetailsHash;
public DefaultMqttListener(HashMap serverProp)
{
this.serverDetailsHash = serverProp;
}
CallbackConnection myconnection;
#Override
public void init() {
MQTT mqtt = new MQTT();
String user = env("APOLLO_USER", (String)serverDetailsHash.get("userName")); //No I18N
String password = env("APOLLO_PASSWORD", (String)serverDetailsHash.get("password")); //No I18N
String host = env("APOLLO_HOST", (String)serverDetailsHash.get("hostName")); //No I18N
int port = Integer.parseInt(env("APOLLO_PORT", (String)serverDetailsHash.get("port")));
try {
mqtt.setHost(host, port);
mqtt.setUserName(user);
mqtt.setPassword(password);
final CallbackConnection connection = mqtt.callbackConnection();
myconnection = connection;
connection.listener(new org.fusesource.mqtt.client.Listener() {
public void onConnected() {
}
public void onDisconnected() {
}
public void onFailure(Throwable value) {
value.printStackTrace();
System.exit(-2);
}
public void onPublish(UTF8Buffer topic, Buffer msg, Runnable ack) {
long time = System.currentTimeMillis();
callback( topic, msg, ack,connection,time);
}
});
connection.connect(new Callback<Void>() {
#Override
public void onSuccess(Void value) {
NmsLogMgr.M2MERR.log("MQTT Listener connected in ::::", Log.SUMMARY);
ArrayList getTopics = (ArrayList)serverDetailsHash.get("Topics");
for(int i=0;i<getTopics.size();i++)
{
HashMap getTopic = (HashMap)getTopics.get(i);
String topicName = (String) getTopic.get("topicName");
String qosType = (String) getTopic.get("qosType");
Topic[] topic = {new Topic(topicName, getQosType(qosType))};
connection.subscribe(topic, new Callback<byte[]>() {
public void onSuccess(byte[] qoses) {
}
public void onFailure(Throwable value) {
value.printStackTrace();
System.exit(-2);
}
});
}
//Topic[] topics = {new Topic("adminTest", QoS.AT_LEAST_ONCE),new Topic("adminTest1", QoS.AT_LEAST_ONCE)};
}
#Override
public void onFailure(Throwable value) {
value.printStackTrace();
System.exit(-2);
}
});
// Wait forever..
synchronized (Listener.class) {
while(true){
Listener.class.wait();}
}
} catch (URISyntaxException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static String env(String key, String defaultValue) {
String rc = System.getenv(key);
if( rc== null ){
return defaultValue;}
return rc;
}
#Override
public void callback(UTF8Buffer topic, Buffer msg, Runnable ack, CallbackConnection connection, long time) {
// TODO Auto-generated method stub
try {
String Message = msg.utf8().toString();
MQTTMessage mqttMsg = new MQTTMessage();
mqttMsg.setMQTTMessage(Message);
mqttMsg.setTime(time);
mqttMsg.setTopic(topic);
mqttMsg.sethostName((String) serverDetailsHash.get("hostName"));
MQTTCacheManager.mgr.addToCache(mqttMsg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void close() {
// TODO Auto-generated method stub
NmsLogMgr.M2MERR.log("myconnection closed", Log.SUMMARY);
myconnection.disconnect(new Callback<Void>() {
#Override
public void onSuccess(Void value) {
System.exit(0);
}
#Override
public void onFailure(Throwable value) {
value.printStackTrace();
System.exit(-2);
}
});
}
#Override
public void run() {
this.init();
// TODO Auto-generated method stub
}
public QoS getQosType(String name)
{
Properties qosContainer = new Properties();
qosContainer.put("0", QoS.AT_MOST_ONCE);
qosContainer.put("1", QoS.AT_LEAST_ONCE);
qosContainer.put("2", QoS.EXACTLY_ONCE);
QoS qosName = (QoS) qosContainer.get(name);
return qosName;
}
}
You don't send the acknowledgement in your code at all, it should all be handled by the MQTT library you are using.
The QOS ack's packets are between the publisher and the broker and then separately between the broker and any subscribers.
I didn't use the Java library but you need to subscribe to the topic specifying the QoS level 1 (to have at least one delivery) or QoS level 2 (to have exactly once delivery). In these cases, the underlying library sends the ACK packets to the broker.

which is better approach while getting data from server and display on list?

Hi can you please tell me which is a better approach while getting data from server and displaying on a list?
package mypackage;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import net.rim.device.api.io.IOUtilities;
import net.rim.device.api.ui.component.Dialog;
public class ConnectJson extends Thread {
private String url;
public String response;
private String myinterface = ";deviceside=true";
private JsonObserver observer;
public void run() {
HttpConnection conn = null;
InputStream in = null;
int code;
try {
conn = (HttpConnection) Connector.open(this.url + this.myinterface, Connector.READ);
conn.setRequestMethod(HttpConnection.GET);
code = conn.getResponseCode();
System.out.println("naveen-------------------------");
if (code == HttpConnection.HTTP_OK) {
in = conn.openInputStream();
byte[] buffer = IOUtilities.streamToBytes(in);
this.response = new String(buffer,"UTF-8");
if (observer != null) {
observer.onResponseReceived(this.response);
}
if (in != null){
in.close();
}
if (conn != null){
conn.close();
}
}
} catch (Exception e) {
Dialog.inform(e.toString());
}
}
public String jsonResult(String url){
this.url = url;
this.start();
// this.run();
return response;
}
public void setObserver(JsonObserver o) {
this.observer = o;
}
}
package mypackage;
import java.util.Vector;
import xjson.me.JSONArray;
import xjson.me.JSONException;
import xjson.me.JSONObject;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
/**
* A class extending the MainScreen class, which provides default standard
* behavior for BlackBerry GUI applications.
*/
public final class MyScreen extends MainScreen implements JsonObserver
{
/**
* Creates a new MyScreen object
*/
public MyScreen()
{
ConnectJson connectJson = new ConnectJson();
System.out.println("------------------");
connectJson.setObserver(this);
connectJson.jsonResult("http://musicbrainz.org/ws/2/release/59211ea4-ffd2-4ad9-9a4e-941d3148024a?inc=artist-credits+labels+discids+recordings&fmt=json");
System.out.println("---------bbbbb---------");
}
public void onResponseReceived(String response) {
System.out.println("000000000000000000000000000000000"+response);
// TODO: create or update your ListField here!!!
}
}
package mypackage;
public interface JsonObserver {
public void onResponseReceived(String response);
}
Well, first of all, this will not work:
public String jsonResult(String url){
this.url = url;
this.start();
return response;
}
Calling start() will cause run() to be called on a background thread (that's good). However, immediately after you start the background thread, you return the response member variable. That won't work, because the run() method hasn't had time to actually assign the response variable.
What you need to do is assign the response variable at the end of the run() method, and then notify the UI on the main/UI thread, to let it update the user interface. Something like this:
if (code == HttpConnection.HTTP_OK) {
in = conn.openInputStream();
byte[] buffer = IOUtilities.streamToBytes(in);
this.response = new String(buffer,"UTF-8");
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// this code is run on the main/UI thread
if (observer != null) {
observer.onResponseReceived(this.response);
}
}
});
where you add a new observer interface
public interface JsonObserver {
public void onResponseReceived(String response);
}
and then you can let your MainScreen implement that interface:
public class MyScreen extends MainScreen implements JsonObserver {
public MyScreen()
{
connectJson.setObserver(this);
// start the json request
connectJson.jsonResult("http://musicbrainz.org/ws/2/release/59211ea4-ffd2-4ad9-9a4e-941d3148024a?inc=artist-credits+labels+d...");
}
public void onResponseReceived(String response) {
System.out.println("000000000000000000000000000000000"+response);
// TODO: create or update your ListField here!!!
}
Of course, you'll need a new member and method in the ConnectJson class, too:
private JsonObserver observer;
public void setObserver(JsonObserver o) {
observer = o;
}
Note: it also might be better, for thread safety, to change your response member variable to a simple local final variable. I can't know all the ways that you plan on using it, but if it's just a way to hold onto the JSON response, you probably don't need a member variable. Try this instead (inside of run()):
final String response = new String(buffer,"UTF-8");
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
observer.onResponseReceived(response);

Dart Isolates As Workers

Edited to make the question more clear.
I am trying to work with Isolates (or Web Workers) in Dart. The only ways I can find to communicate between the main and isolate threads are send and call & then from the main thread. But that's a nice way for the main thread to pass some data to the isolate.
What's if I want the isolate to be the one who generates information? Like a game engine that does all the physics in a worker and then sends an updated world information to the main thread? In JavaScript you can send data at any time. Is there an efficient way in Dart? Or do I still have to wait for the main thread to call me and then pass it to it?
P.S. I wonder, does call & then block the thread until reply is done or not?
As of Dart 1.0, you can use isolates like this:
import 'dart:isolate';
import 'dart:async';
void doStuff(SendPort sendPort) {
print('hi from inside isolate');
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((msg) {
print('Received in isolate: [$msg]');
sendPort.send('ECHO: $msg');
});
}
void main() {
SendPort sendPort;
ReceivePort receive = new ReceivePort();
receive.listen((msg) {
if (sendPort == null) {
sendPort = msg;
} else {
print('From isolate: $msg');
}
});
int counter = 0;
Isolate.spawn(doStuff, receive.sendPort).then((isolate) {
new Timer.periodic(const Duration(seconds:1), (t) {
sendPort.send('Count is ${counter++}');
});
});
}
WARNING: this code only works on very old versions of Dart. It does not work on Dart 1.0 or later.
As you mention to post messages to a isolate you need to have a handle on it's sendport.
#import('dart:isolate');
main() {
SendPort sendPort = spawnFunction(doWork);
sendPort.call("hey 1").then((String res) => print("result was: [$res]"));
sendPort.call("hey 2").then((String res) => print("result was: [$res]"));
}
doWork() {
port.receive((msg, reply) {
msg = "msg $msg";
reply.send(msg);
});
}
however since the Dart main thread is itself an isolate you can send data to it by using the global port function:
#import('dart:isolate');
#import('dart:io');
main() {
port.receive((data, reply) {
// in here you can access objects created in the main thread
print("handle [${data['text']}] for index ${data['index']}");
});
SendPort workPort = spawnFunction(doWork);
workPort.send("msg", port.toSendPort());
}
doWork() {
port.receive((msg, reply) {
int i = 0;
new Timer.repeating(1000, (Timer timer) {
i++;
var data = {
"text": "$msg $i",
"index": i
};
print("sending $data");
reply.send(data);
});
});
}
Note there are certain limits about what can be send back and forth between isolates and also currently isolates act differently in JS and on the VM. The current limitations are well described here.
Here is an example where parent creates two isolates and then two isolates also talk to each other along with the parent process.
Parent Code:
import 'dart:isolate';
import 'dart:html';
import 'dart:async';
main() {
querySelector('#output').text = 'Your Dart app is running.';
int counter = 0;
// Parent - Child 1
SendPort csendPort1;
ReceivePort receivePort1 = new ReceivePort();
// Parent - Child 2
SendPort csendPort2;
ReceivePort receivePort2 = new ReceivePort();
// Child1 - Child2
SendPort csendPort11;
SendPort csendPort12;
// Child 1
receivePort1.listen((msg) {
if (csendPort1 == null) {
csendPort1 = msg;
} else if (csendPort11 == null) {
csendPort11 = msg;
} else {
print('$msg');`enter code here`
}
});
bool child1 = false;
Isolate.spawnUri(Uri.parse('child.dart'), [], receivePort1.sendPort).then((isolate) {
print('Child 1 isolate spawned');
new Timer.periodic(const Duration(milliseconds: 500), (t) {
if (csendPort11 != null && csendPort12 != null && child1 == false) {
child1 = true;
csendPort12.send(csendPort11);
} else {
csendPort1.send('Parent-Child1: ${counter++}');
}
});
});
// Child 2
receivePort2.listen((msg) {
if (csendPort2 == null) {
csendPort2 = msg;
} else if (csendPort12 == null) {
csendPort12 = msg;
} else {
print('$msg');
}
});
bool child2 = false;
Isolate.spawnUri(Uri.parse('child.dart'), [], receivePort2.sendPort).then((isolate) {
print('Child 2 isolate spawned');
new Timer.periodic(const Duration(milliseconds: 500), (t) {
if (csendPort11 != null && csendPort12 != null && child2 == false) {
child2 = true;
csendPort11.send(csendPort12);
} else {
csendPort2.send('Parent-Child2: ${counter++}');
}
});
});
}
Child Code:
import 'dart:isolate';
import 'dart:async';
int pcounter = 0;
int ccounter = 0;
SendPort csendPort;
void handleTimeout() {
csendPort.send("${ccounter++}");
}
main(List<String> args, SendPort psendPort) {
// Parent Comm
ReceivePort creceivePort1 = new ReceivePort();
psendPort.send(creceivePort1.sendPort);
creceivePort1.listen((msg) {
psendPort.send('Child-Parent: ${pcounter++} - ${msg}');
});
// Child-Child Comm
ReceivePort creceivePort2 = new ReceivePort();
psendPort.send(creceivePort2.sendPort);
creceivePort2.listen((msg) {
if (csendPort == null) {
csendPort = msg;
csendPort.send("${ccounter++}");
} else {
print("Child-Child: $msg");
var duration = const Duration(milliseconds: 2000);
new Timer(duration, handleTimeout);
}
});
}
HTML Code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="scaffolded-by" content="https://github.com/google/stagehand">
<title>WebIsolateTest</title>
<link rel="stylesheet" href="styles.css">
<script defer src="main.dart" type="application/dart"></script>
<script defer src="packages/browser/dart.js"></script>
</head>
<body>
<div id="output"></div>
</body>
</html>
You can now use the MessageBox class to communicate the other way around. This code sends a message from the Isolate code as soon as it receives the Sink end of the MessageBox. Main thread receives the messages sent from the Isolate and prints it on the console of Dartium. Once you receive the Sink you can launch your game logic and send updates using the sink object received.
import 'dart:html';
import 'dart:isolate';
void main() {
IsolateSink isolateSink = streamSpawnFunction(myIsolateEntryPoint);
MessageBox isolateMessageBox = new MessageBox();
isolateSink.add(isolateMessageBox.sink);
isolateMessageBox.stream.listen((String data) {
print(data);
});
}
void myIsolateEntryPoint() {
stream.listen((IsolateSink messageBoxSink) {
messageBoxSink.add("Test");
});
}

Resources