running SocketServer as Isolate in dart - sockets

I am trying to control dart script via socket, running within isolate
I came up with some (spoiler warning) not working code:
import "dart:io";
import "dart:convert";
import "dart:isolate";
reader(SendPort sendPort) async {
var serverSocket = await ServerSocket.bind("127.0.0.1", 83);
print('connected');
await for (var socket in serverSocket) {
socket.transform(UTF8.decoder).listen((msg) => sendPort.send(msg));
}
}
main() {
bool start = false;
bool stop = false;
listener (message)
{
print ("message from isolate: $message");
stop = start;
start = true;
}
ReceivePort receive = new ReceivePort();
receive.listen(listener);
Isolate.spawn(reader, receive.sendPort).then((Isolate) => print("Isolate started"));
print("Waiting to start");
while (!start) {}
print("Waiting to stop");
while (!stop) {}
print("Ended");
}
But isolate does not even seem to be launched. Only output of script is "Waiting to start"

This worked for me:
import 'dart:async';
import "dart:io";
import "dart:convert";
import "dart:isolate";
reader(SendPort sendPort) async {
print('isolate started');
var serverSocket = await ServerSocket.bind("127.0.0.1", 8123);
sendPort.send('bound');
await for (var socket in serverSocket) {
socket.transform(UTF8.decoder).listen((msg) {
print('server received $msg');
sendPort.send(msg);
if (msg == 'close') {
socket.close();
serverSocket.close();
}
});
}
}
StreamSubscription subscription;
Isolate isolate;
ReceivePort receive;
main() async {
listener(message) async {
print("message from isolate: $message");
if (message == 'bound') {
final socket = await Socket.connect("127.0.0.1", 8123);
print('client connected');
socket.add('close'.codeUnits);
socket.destroy();
}
if (message == 'close') {
subscription.cancel();
// exits application
}
}
receive = new ReceivePort();
subscription = receive.listen(listener);
isolate = await Isolate.spawn(reader, receive.sendPort);
}

Related

Why exceptions thrown by an awaited async function are not caught by the try catch block?

If you run this in DartPad you'll never catch the exceptions, they are reported as unhandled in the console. Why?
import 'dart:html';
void main() async {
try {
final socket = await wsConnect('wss://127.0.0.1:7654');
print('${socket.readyState}');
} catch (e) {print(e);}
}
Future<WebSocket> wsConnect(String url) async {
final socket = WebSocket(url);
socket.onError.listen((_) => throw Exception('connection error'));
socket.onClose.listen((_) => throw Exception('connection close'));
return socket;
}
This doesn't work either:
import 'dart:html';
void main() async {
try {
final socket = await wsConnect('wss://127.0.0.1:7654', () => throw Exception('some problem'));
print('${socket.readyState}');
} catch (e) {print(e);}
}
Future<WebSocket> wsConnect(String url, void Function() onProblem) async {
final socket = WebSocket(url);
socket.onError.listen((_) => onProblem());
socket.onClose.listen((_) => onProblem());
return socket;
}
Are the stream callbacks being executed on some separate zone, isolate or VM or whatnot and where can I read about it?

How to pass data between isolates in flutter dart

I am buiding an app were I want to run a batch operation in firestore and I want to run it in a different isolate. Here is my code for spawning the isolate:
Future<void> _startAnotherIsolate(String mediaUrl) async {
final isolate = await FlutterIsolate.spawn(isolate1,"hello"); // i need to pass 2 more
arguments
Timer(Duration(seconds: 5), () {
print("Pausing Isolate 1");
isolate.pause();
});
Timer(Duration(seconds: 10), () {
print("Resuming Isolate 1");
isolate.resume();
});
Timer(Duration(seconds: 20), () {
print("Killing Isolate 1");
isolate.kill();
});
}
My code for the isolate:
void isolate1(String data1, String data2) async {
await Firebase.initializeApp();
print("changing profile picture: $phone");
Timer.periodic(Duration(seconds: 1), (timer) => print("Timer Running From Isolate 1"));
var db = FirebaseFirestore.instance;
var batch = db.batch();
FirebaseFirestore.instance.collection("posts").doc(phone).collection("userPosts")
.get().then((querySnapshot) {
for (var document in querySnapshot.docs) {
try {
batch.update(document.reference,{'user_image': mediaUrl});
} on FormatException catch (error) {
// If a document ID is unparsable. Example "lRt931gu83iukSSLwyei" is unparsable.
// print("The document ${error.source} could not be parsed.");
return null;
}
}
return batch.commit();
});
}
I have seen This link and this link but they are not helpful
import 'dart:isolate';
class RequiredArgs {
late final SendPort sendPort;
late int id;
RequiredArgs(this.id, this.sendPort);
}
Future<void> main() async {
ReceivePort receivePort = ReceivePort();
RequiredArgs requiredArgs = RequiredArgs(1122, receivePort.sendPort);
Isolate isolate = await Isolate.spawn(download, requiredArgs);
var resp = await receivePort.first;
print(resp);
}
void download(RequiredArgs requiredArgs) {
final SendPort sendPort = requiredArgs.sendPort;
final id = requiredArgs.id;
print(id);
sendPort.send("yes");
}
We pass the value using the RequiredArgs class. Hope my answer helps.

I'm having trouble connecting to mqtt in flutter?

I'm having trouble connecting to mqtt in flutter. I can't connect. The code I am using is as follows.
import 'package:mqtt_client/mqtt_server_client.dart';
late MqttServerClient client;
// ignore: camel_case_types
class mqttconnect {
Future<MqttServerClient> connect() async {
try {
client =
MqttServerClient.withPort('broker.emqx.io', 'flutter_client', 1883);
client.logging(on: true);
client.onConnected = onConnected;
client.onDisconnected = onDisconnected;
} catch (e) {
print(e.toString());
}
try {
await client.connect();
} catch (e) {
print('Exception: $e');
client.disconnect();
}
return client;
}
void onConnected() {
print('object');
}
void onDisconnected() {}
}
While trying to connect to mqtt, I get an error as above in the console. How can I fix.
import 'dart:convert';
import 'dart:developer';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
late MqttServerClient client;
mqttSubscribe() async {
client = MqttServerClient.withPort("broker.emqx.io", "daly", 1883);
client.keepAlivePeriod = 30;
client.autoReconnect = true;
await client.connect().onError((error, stackTrace) {
log("error -> " + error.toString());
});
client.onConnected = () {
log('MQTT connected');
};
client.onDisconnected = () {
log('MQTT disconnected');
};
client.onSubscribed = (String topic) {
log('MQTT subscribed to $topic');
};
if (client.connectionStatus!.state == MqttConnectionState.connected) {
client.subscribe("battery", MqttQos.atMostOnce);
client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) {
final recMess = c![0].payload as MqttPublishMessage;
final pt = MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
log("message payload => " + pt);
});
}
}
import 'dart:async';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
class MqttService{
MqttService._();
/// Our mqtt client object.
static late MqttClient client;
// for listen from other pages.
// and can close listen mqtt.
static StreamSubscription? mqttListen;
static void initMqtt(){
/// Initialize Mqtt and connect.
client = MqttServerClient(/* Your mqtt host address */)
..logging(on: false)
..port = MqttConstants.mqttPort
..keepAlivePeriod = 20
..onDisconnected = _onDisconnected
..onSubscribed = _onSubscribed
..onConnected = _onConnected
..onUnsubscribed = _onUnsubscribed
..onSubscribeFail = _onSubscribeFail;
/// If the mqtt connection lost
/// MqttBroker publish this message on this topic.
final mqttMsg = MqttConnectMessage()
.withWillMessage('connection-failed')
.withWillTopic('willTopic')
.startClean()
.withWillQos(MqttQos.atLeastOnce)
.withWillTopic('failed');
client.connectionMessage = mqttMsg;
await _connectMqtt();
}
/// Mqtt server connected.
void _onConnected() {
log('Connected');
_listenMqtt();
}
/// Mqtt server disconnected
void _onDisconnected() {
log('Disconnected');
}
/// Mqtt server subscribed
void _onSubscribed(String? topic) {
log('Subscribed topic is : $topic');
}
void _onUnsubscribed(String? topic) {
log('Unsubscribed topic is : $topic');
}
void _onSubscribeFail(String? topic) {
log('Failed subscribe topic : $topic');
}
/// Connection MQTT Server.
Future<void> _connectMqtt() async {
if (client.connectionStatus!.state != MqttConnectionState.connected) {
try {
await client.connect();
} catch (e) {
log('Connection failed' + e.toString());
}
} else {
log('MQTT Server already connected ');
}
}
/// Diconnection MQTT Server.
static Future<void> disconnectMqtt() async {
if (client.connectionStatus!.state == MqttConnectionState.connected) {
try {
client.disconnect();
} catch (e) {
log('Disconnection Failed ' + e.toString());
}
} else {
log('MQTT Server already disconnected ');
}
}
/// Subscribe a topic
static void subscribeTopic(String topic) {
final state = client.connectionStatus?.state;
if (state != null) {
if (state == MqttConnectionState.connected) {
client.subscribe(topic + "/data", MqttQos.atLeastOnce);
}
}
}
/// Publish a message to topic
/// [reatain] means last message save the broker.
static void publish(String topic, String message, {bool retain = true}) {
final builder = MqttClientPayloadBuilder();
builder.addString(message);
client.publishMessage(
topic,
MqttQos.atLeastOnce,
builder.payload!,
retain: retain,
);
builder.clear();
}
static void unSubscribeTopic(String topic) {
final state = client.connectionStatus?.state;
if (state != null) {
if (state == MqttConnectionState.connected) {
client.unsubscribe(topic + "/data");
}
}
}
static void onClose(){
mqttListen?.close();
disconnectMqtt();
}
void _listenMqtt() {
mqttListen = client.updates!.listen((dynamic t) {
MqttPublishMessage recMessage = t[0].payload;
final message =
MqttPublishPayload.bytesToStringAsString(recMessage.payload.message);
/*
Listen subscribe topic.
*/
log(message);
});
}
}
I have created a nice format for MQTT and I wanted to share with you through this question.
Package: mqtt_client

Client only listens to server when sends a message

I'm implementing socket.
Two clients connect to the server with no problem, when client1 sends a message to the server, the server publishes it to every other client (which in this case is client2). but client2 won't get the message unless it sends a message. It seems the listener of the client doesn't work. Obviously, I want client2 to get the message from client1 instantly.
here is my sever code:
import 'dart:io';
import 'dart:typed_data';
void main() async {
// bind the socket server to an address and port
MySocket mySocket = MySocket();
await mySocket.init();
}
class MySocket {
ServerSocket? server;
List<Socket> clients = [];
//initialize the socket
init() async {
server = await ServerSocket.bind("192.168.0.112", 4000);
// listen for client connections to the server
server!.listen((client) {
handleConnection(client);
addClient(client);
});
}
void handleConnection(Socket client) async {
print('Connection from'
' ${client.remoteAddress.address}:${client.remotePort}');
// listen for events from the client
client.listen(
// handle data from the client
(Uint8List data) async {
await Future.delayed(Duration(seconds: 1));
final message = String.fromCharCodes(data);
print(message);
publish(message, client);
},
// handle errors
onError: (error) {
print(error);
client.close();
},
// handle the client closing the connection
onDone: () {
print('Client left');
client.close();
},
);
}
void addClient(Socket client) {
//if client doesn't already exist add it to the list of clients
if (!clients.any((element) =>
'${client.remoteAddress.address}:${client.remotePort}' ==
'${element.remoteAddress.address}:${element.remotePort}')) {
clients.add(client);
}
}
void publish(String message, Socket client) {
//write the message to every client except the author of it
clients.forEach((element) async {
if ('${client.remoteAddress.address}:${client.remotePort}' !=
'${element.remoteAddress.address}:${element.remotePort}') {
element.write(message);
}
});
}
}
here is my client-side code:
import 'dart:io';
import 'dart:typed_data';
void main() async {
//gets the username
String name = '';
while (name.isEmpty) {
print('Enter your name: ');
name = stdin.readLineSync() ?? '';
}
// connect to the socket server
final socket = await Socket.connect("192.168.0.112", 4000);
print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
// listen for responses from the server
socket.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
// handle errors
onError: (error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () {
print('Left server.');
socket.destroy();
},
);
// sending messages to the server
String message = "";
while (message != "exit") {
message = stdin.readLineSync() ?? '';
await sendMessage(socket, name, message);
}
socket.close();
}
Future<void> sendMessage(Socket socket, String name, String message) async {
socket.write('$name: $message');
await Future.delayed(Duration(seconds: 2));
}
Thank you in advance.
The issue is because stdin.readLineSync() in your client blocks the current thread. You can get around this by spawning an isolate to handle that portion of the code, so that it does not block the socket.listen from printing out the responses from the server.
See updated client code below:
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
void main() async {
//gets the username
String name = '';
while (name.isEmpty) {
print('Enter your name: ');
name = stdin.readLineSync() ?? '';
}
// connect to the socket server
final socket = await Socket.connect("192.168.0.112", 4000);
print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
// listen for responses from the server
socket.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
// handle errors
onError: (dynamic error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () {
print('Left server.');
socket.destroy();
},
);
final receive = ReceivePort();
final isolate = await Isolate.spawn(readMessages, receive.sendPort);
await for (final message in receive) {
if (message == 'exit') break;
await sendMessage(socket, name, message as String);
}
socket.close();
}
void readMessages(SendPort port) {
String message = '';
while (message != 'exit') {
message = stdin.readLineSync() ?? '';
port.send(message);
}
Isolate.exit(port);
}
Future<void> sendMessage(Socket socket, String name, String message) async {
socket.write('$name: $message');
await Future<void>.delayed(Duration(seconds: 2));
}

How to post observer from normal class and receive listener to widget?

I'm pretty new to Flutter and experimenting with the SDK. I am working with the flutter application which works with Socket connection. I saw lots of example which communicate with widget to widget. But, I want to add listener from Socket class to widgets. The actual scenario is, I have socket listeners in my socket manager class. Here is the rough code for better idea.
class SocketManager {
static SocketIO socketIO;
static SocketIOManager manager = SocketIOManager();
//Constructor
SocketManager(){
initSocket().then((socketIO){
addListener();
});
}
void addListener(){
socketIO.onConnect((data){
print("connected...");
});
}
}
I want to notify to my widgets when socket connected.
What kind of thing am I looking for to implement this?
Thanks in advance.
here is my class, you can follow to create yours
import 'dart:convert';
import 'package:flutter_app/global.dart';
import 'package:flutter_app/strings.dart';
import 'package:rxdart/subjects.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
IO.Socket kSocket;
class Sockets {
static PublishSubject socket = PublishSubject(sync: true);
static PublishSubject status = PublishSubject(sync: true);
static PublishSubject notify = PublishSubject(sync: true);
static PublishSubject chatCount = PublishSubject(sync: true);
static PublishSubject typing = PublishSubject(sync: true);
static PublishSubject login = PublishSubject(sync: false);
static PublishSubject getInfo = PublishSubject(sync: true);
static PublishSubject alreadyLogin = PublishSubject(sync: false);
static void connectSocket() async {
/* kSocket = await IO.io('${Strings.socket}', <String, dynamic>{
'transports': ['websocket', 'polling'],
});*/
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('userToken');
if (token != null && token != '') {
Map<String, dynamic> parsedToken = Functions.parseJwt(token);
String imza = token?.split('.')[2];
kSocket = await IO.io('${Strings.socket}', <String, dynamic>{
'transports': ['websocket', 'polling'],
'query': 'token=$imza'
});
parsedToken['Tur'] = 2;
kSocket.close();
kSocket.disconnect();
kSocket.open();
try {
kSocket.on('connect', (data) {
print('SOCKET CONNECTED');
kSocket.emit('adduser', parsedToken);
kSocket.on('getmessage', (res) {
print('GETMSG: $res');
chatCount.sink.add(res);
socket.sink.add(res);
});
kSocket.on('bildirim', (res) {
print('[BILDIRIM]: $res');
notify.sink.add(res);
});
kSocket.on('durum', (res) {
status.sink.add(res);
});
kSocket.on('disconnect', (data) {
// print('DISCONNECT: $data');
});
kSocket.on('typing', (res) {
typing.sink.add(res);
});
kSocket.on('login', (res) {
//print('Multi Login');
login.sink.add(res);
});
kSocket.on('getinfo', (res) {
//print('GETINFO: $res');
getInfo.sink.add(res);
});
kSocket.on('alreadylogin', (res) {
//print('ALREADY LOGIN: $res');
alreadyLogin.sink.add(res);
});
});
} catch (e) {
print(e);
}
} else {
print('SOCKET: token yok');
}
}
static void setInfo(Map<String, dynamic> data) {
kSocket.emit('setinfo', [data]);
}
static void setRead(String userid) {
kSocket.emit('setreaded', '$userid');
}
static void isTyping(String username, int status) {
kSocket.emit('istyping', [
{"user": int.parse(username), "durum": status}
]);
}
static void isActive(String userid) {
if (kSocket != null) {
if (kSocket.connected) {
try {
//print('${kSocket.connected}');
kSocket.emit('isactive', '$userid');
} catch (e) {
print(e);
}
}
}
}
static void disconnectSocket() async {
try {
await kSocket.disconnect();
await kSocket.close();
await kSocket.destroy();
print('SOCKET DISCONNECTED');
} catch (e) {
//print(e);
}
}
static void dispose(){
socket.close();
status.close();
//notify.close();
chatCount.close();
typing.close();
login.close();
getInfo.close();
alreadyLogin.close();
}
static void unSubNotify(){
notify.close();
}
}
Answer is here !! Here what I found while surfing on the web. Flutter-NotificationCenter. An IOS type post and receive observer. It is Very helpful to other developers who want to post observer from anywhere and want to receive it to anywhere.