Making FTP client with socket in Flutter - flutter

i'm making an FTP connection with sockets.
Everything works without TLS but when i start PASV in TLS mode, i can connect to data socket but i can't listen nothing.
Could someone help me to understand where i'm wrong?
This is the code i'm using:
String? pasvIP;
int? pasvPort;
RawSocket rawsock = await RawSocket.connect(ftpHost!, int.parse(port));
StreamSubscription<RawSocketEvent> rwlisten = rawsock.listen((event) {
if (event == RawSocketEvent.read) {
Uint8List? buffer = rawsock.read();
String result = String.fromCharCodes(buffer!);
print(' ${result}');
}
});
rawsock.write(Utf8Codec().encode('AUTH TLS\r\n'));
rawsock = await RawSecureSocket.secure(
rawsock,
onBadCertificate: (certificate) => true,
subscription: rwlisten,
);
rwlisten = rawsock.listen((event) {
if (event == RawSocketEvent.read) {
Uint8List? buffer = rawsock.read();
String result = String.fromCharCodes(buffer!);
print('${result}');
if (result.startsWith('227')) {
final startIndex = result.indexOf('(');
final endIndex = result.indexOf(')');
String ipPasv = result.substring(startIndex + 1, endIndex);
List ipPasvList = ipPasv.split(',');
pasvIP =
'${ipPasvList[0]}.${ipPasvList[1]}.${ipPasvList[2]}.${ipPasvList[3]}';
pasvPort =
(int.parse(ipPasvList[4]) * 256 + int.parse(ipPasvList[5]));
}
}
});
rawsock.write(Utf8Codec().encode('PBSZ 0\r\n'));
rawsock.write(Utf8Codec().encode('PROT P\r\n'));
rawsock.write(Utf8Codec().encode('USER ${username}\r\n'));
rawsock.write(
Utf8Codec().encode('PASS ${activeUser!.decrypt(password!)}\r\n'));
rawsock.write(Utf8Codec().encode('PASV\r\n'));
SecureSocket sockData = await SecureSocket.connect(
pasvIP!,
pasvPort!,
onBadCertificate: (certificate) => true,
);
sockData.listen(
(data) { // <-- NO DATA HERE
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
onError: (error) {
print(error);
sockData.destroy();
},
onDone: () {
print('Server left.');
sockData.destroy();
},
);
rawsock.write(Utf8Codec().encode('LIST\r\n'));
rawsock.write(Utf8Codec().encode('QUIT\r\n'));
Thanks
Marco

Related

flutter_libserialport write OK but read unhandled exception

I'm trying to implement a simple at cmd application.
I modified the flutter_libserialport example.
https://pub.dev/packages/flutter_libserialport
simply,
replace the floatButton action to my own reTest() function
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
// onPressed: initPorts,
onPressed: rwTest,
),
and my rwTest below,
Future<void> rwTest() async {
for (var p in availablePorts) {
if (p == 'COM115') {
print(p);
List<int> d = [65, 84, 13];
Uint8List bytes = Uint8List.fromList(d);
SerialPort port = SerialPort(p);
SerialPortReader reader = SerialPortReader(port, timeout: 10000);
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
port.close();
} on SerialPortError catch (_, err) {
if (port.isOpen) {
port.close();
print('serial port error');
}
}
}
}
}
my device is shown as COM115 so I put the fixed value.
and the "write" operation was success
but when I use "reader.stream.listen()"
SerialPortError occurs as below
flutter: COM115
flutter: 3
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: SerialPortError: ÀÛ¾÷À» ¿Ï·áÇß½À´Ï´Ù., errno = 0
I guess the usage of "listen" was wrong, but I don't know how to fix it.
anyone can help me to fix it?
You just need to remove the port.close() in try{} ... and I think you should also set the timeout = 1,
Also, it is better to set a configuration before using the port
Note: you can just access the port through name, without looping over all the available ports.
Future<void> rwTest() async {
List<int> d = [65, 84, 13];
Uint8List bytes = Uint8List.fromList(d);
SerialPort port = SerialPort('COM115');
// configuration
final configu = SerialPortConfig();
configu.baudRate = 9600;
configu.bits = 8;
configu.parity = 0;
port.config = configu;
SerialPortReader reader = SerialPortReader(port, timeout: 10);
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
} on SerialPortError catch (_, err) {
if (port.isOpen) {
port.close();
print('serial port error');
}
}
}
The serial port need to open as far as the communication is active to send and receive data
Remove the port close method call
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
//port.close(); --> remove this line
}
On exit close the reader stream and then close the port

How can I get multiple messages from dart isolate?

How can I get multiple messages from dart isolate?
I'm trying to create an excel file and want to do some operation on that file in an isolate. Before doing an operation on that file, I want to return an message to main isolate, that excel file is created.
Here is function goes in isolate :
foo(String filePath){
// create excel file
var bytes = File(filePath).readAsBytesSync();
var excel = Excel.decodeBytes(bytes);
//HERE I WANT TO SEND THE MESSAGE THAT CREATING EXCEL FILE IS DONE
// some operatoin on excel file
var result = doSomeOperation(excel);
return result;
}
Main isolate code :
var result = await compute(foo, filePath);
What should I do to get creating file message before the actual result comes?
For excel, I'm using excel: ^2.0.0-null-safety-3 package.
Compute only returns one result. If you want to pass multiple 'events' back to the main isolate then you need to use the full Isolate logic (with sendPort and receivePort).
For example, the following code runs in an isolate, and downloads a file while emitting float values to represent progress, potentially a String to indicate log messages and then a bool to indicate success or failure upon completion.
Future<void> isolateDownload(
DownloadRequest request) async {
final sendPort = request.sendPort;
if (sendPort != null) {
var success = false;
var errorMessage = '';
var url = Uri.parse('a_url_based_on_request');
IOSink? out;
try {
http.StreamedResponse response =
await http.Client().send(http.Request('GET', url));
if (response.statusCode == 200) {
var filePath =
join(request.destinationDirPath, '${request.fileName}.ZIP');
var contentLength = response.contentLength;
var bytesLoadedUpdateInterval = (contentLength ?? 0) / 50;
var bytesLoaded = 0;
var bytesLoadedAtLastUpdate = 0;
out = File(filePath).openWrite();
await response.stream.forEach((chunk) {
out?.add(chunk);
bytesLoaded += chunk.length;
// update if enough bytes have passed since last update
if (contentLength != null &&
bytesLoaded - bytesLoadedAtLastUpdate >
bytesLoadedUpdateInterval) {
sendPort.send(bytesLoaded / contentLength);
bytesLoadedAtLastUpdate = bytesLoaded;
}
});
success = true;
if (contentLength != null) {
sendPort.send(1.0); // send 100% downloaded message
}
} else {
errorMessage =
'Download of ${request.fileName} '
'received response ${response.statusCode} - ${response.reasonPhrase}';
}
} catch (e) {
errorMessage = 'Download of ${request.chartType}:${request.chartName} '
'received error $e';
} finally {
await out?.flush();
await out?.close();
if (errorMessage.isNotEmpty) {
sendPort.send(errorMessage);
}
sendPort.send(success);
}
}
}
The code that spawns the isolate then simply checks for the type of the message passed to it to determine the action.
Future<bool> _downloadInBackground(
DownloadRequest request) async {
var receivePort = ReceivePort();
request.sendPort = receivePort.sendPort;
var isDone = Completer();
var success = false;
receivePort.listen((message) {
if (message is double) {
showUpdate(message);
}
if (message is String) {
log.fine(message); // log error messages
}
if (message is bool) {
success = message; // end with success or failure
receivePort.close();
}
}, onDone: () => isDone.complete()); // wraps up
await Isolate.spawn(isolateDownload, request);
await isDone.future;
return success;
}

how create future function in flutter?

i trying to create post function in flutter
here is my code:
Future<String> makePostRequest() async {
String requestResult;
var body = this.toMapRequest();
String requestUrl = RequestZarinpal.PAYMENT_REQUEST_URL;
String gateWayUrl;
String jsonBody = json.encode(body);
final encoding = Encoding.getByName('utf-8');
Response response = await post(
requestUrl,
headers: headers,
body: jsonBody,
encoding: encoding,
).timeout(const Duration(seconds: 10), onTimeout: () {
throw TimeoutException('The connection has timed out, Please try again!');
});
responseBody = response.body;
var parsedJson = json.decode(responseBody);
var data = parsedJson['data'];
var error = parsedJson['errors'];
if (error.toString() != "[]") {
var errorcode = parsedJson['errors']['code'];
print("$body va $requestUrl va $parsedJson");
requestResult = " شما ارور زیر را دریافت کرده اید \n$error";
} else if (data.toString() != "[]") {
var authority = parsedJson['data']['authority'];
requestResult = "اتوریتی شما با موفقیت ساخته شد و به درگاه متصل می شود";
_request.setAuthority(authority);
print(parsedJson);
String gateWay = RequestZarinpal.PAYMENT_GATEWAY_URL;
gateWayUrl = "$gateWay$authority";
if (await canLaunch(gateWayUrl)) {
await launch(
gateWayUrl,
forceSafariVC: false,
forceWebView: false,
headers: headers,
);
} else {
throw 'Could not launch $requestUrl';
}
print(requestResult);
return requestResult;
}
}
but i got this error:
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.dart(body_might_complete_normally)
what should i do?
With the line if (error.toString() != "[]") you divided your function in 2 possibile outcome.
The positive one, doesn't have a return.
Maybe you should move return requestResult; after the curly bracket, so that the return gets fired regardless.
You are missing the return statement inside the if condition
if (error.toString() != "[]") {
var errorcode = parsedJson['errors']['code'];
print("$body va $requestUrl va $parsedJson");
requestResult = " شما ارور زیر را دریافت کرده اید \n$error";
return requestResult;
}

How to use Dart socket onError as inline function?

I have dart socket that gets very long data. Lucky the third party add '\r\n' end of the data, so I can close when I find last data has '\r\n'.
In weeks I am trying to get long data due server problem. Before I used to waiting endlessly to server closes the connection (sometime took me 10 to 12 min)
Now seems everything works but a small problem. I used to get onError and onDone using void function. But I am using aqueduct so I need to return long data after I receive from server as a response.
In my below full code its keep printing "Server_Error". If I comment below data seems everything works. But my problem is that I need to return error data as well.
onError: () {
print("Server_Error");
},
onDone: () {
_socket.destroy();
},
cancelOnError: true);
If I comment above part I can print the long data.
My question is that, based on my scenario how to use Dart socket onError as inline function?
import 'dart:io';
import 'dart:convert';
import 'dart:typed_data';
Socket _socket;
String _reply;
String _testValue = "";
main() async {
String _queryA = “QueryLongData”;
await Socket.connect("192.168.22.120”, 3000).then((Socket sock) {
_socket = sock;
_socket.write('$_queryA\r\n');
_socket.listen((data) {
final List<int> byteArray = data;
_reply = String.fromCharCodes(byteArray);
int dataLen = _reply.length;
int carriageReturnPosition = dataLen - 2;
int newLinePosition = dataLen - 1;
_testValue = _testValue + _reply;
if (_reply.substring(carriageReturnPosition, newLinePosition) == '\r' &&
_reply.substring(newLinePosition, dataLen) == '\n') {
_socket.close();
print("Data: $_testValue"); // means return data
}
}, onError: () {
print("Server_Error");
},
onDone: () {
_socket.destroy();
},
cancelOnError: true);
}).catchError((e) {
print("Server_Error");
});
if(_socket.done == true) {
print("Exiting...");
exit(0);
}
}
<!-- language: dart -->
String _queryA = "QueryLongData";
Socket.connect("192.168.22.120", 3000).then((Socket sock) {
_socket = sock;
_socket.write("$_queryA\r\n");
_socket.listen((data) {
final List<int> byteArray = data;
_reply = String.fromCharCodes(byteArray);
int dataLen = _reply.length;
int carriageReturnPosition = dataLen - 2;
int newLinePosition = dataLen - 1;
_testValue = _testValue + _reply;
if (_reply.substring(carriageReturnPosition, newLinePosition) == "\r" &&
_reply.substring(newLinePosition, dataLen) == "\n") {
_socket.close();
print("Data: $_testValue"); // means return data
}
}, onError: () => print("Server_Error"),
onDone: () => _socket.destroy(),
cancelOnError: true);
}).catchError((e) => print("Server_Error"));
if( ( await _socket.done enter code here) == true) {
print("Exiting...");
exit(0);
}

Dart HTML Server. How do I have the server refuse more than one client connection?

I'm writing a web application that is to be used by only one client and want to accept only one connection to the server. The LAN will be confined to an aircraft. I'm really new to Dart, HTML etc. How can I refuse multiple connections to the server?
Here's my code fir the HTTP server -
class MicroServer {
var address;
var port;
var httpServer; // global
MicroServer(this.address, this.port) {
final HTTP_ROOT_PATH = Platform.script.resolve('../build/web').toFilePath();
final virDir = new VirtualDirectory(HTTP_ROOT_PATH)
..jailRoot = false
..allowDirectoryListing = true;
HttpServer.bind(address, port)
.then((httpserver) {
httpServer = httpserver;
httpserver.listen((request) {
virDir.serveRequest(request);
});
});
}
}
Dart is single-threaded, so you can safely use check a variable to see if there's a current connection:
bool hasClient = false;
HttpServer.bind(address, port)
.then((httpserver) {
httpServer = httpserver;
httpserver.listen((request) {
if (hasClient) {
sendBusyPage(request);
} else {
hasClient = true;
virDir.serveRequest(request);
hasClient = false;
}
});
});
}
I have found that the code below works so far. I could also have taken advantage of
if(request.session.isNew) // then grab the session.id etc.
but it's just as easy to use the session.id variable since I will use it anyway.
class MicroServer {
var address;
var port;
var httpServer;
var sessionID; // null until first request received
MicroServer(this.address, this.port) {
final HTTP_ROOT_PATH = Platform.script.resolve('../build/web').toFilePath();
final virDir = new VirtualDirectory(HTTP_ROOT_PATH)
..jailRoot = false // process links will work
..followLinks = true
..allowDirectoryListing = true;
HttpServer.bind(address, port)
.then((httpserver) {
httpServer = httpserver;
httpserver.idleTimeout = null;
print("micro server started on ${httpserver.address}:${httpserver.port}");
httpserver.listen((request) {
if(sessionID == null) {
sessionID = request.session.id;
virDir.serveRequest(request);
} else if(sessionID == request.session.id){
virDir.serveRequest(request);
} else {
request.response.writeln('ERROR - Connection is in use.');
request.response.close();
request.session.destroy();
}
});
}).catchError((e) => print(e.toString()));
}
}