How to merge aqueduct Future<RequestOrResponse> with dart console app? - sockets

Thanks to Bryan from voidrealms. I was struggling last 2 days (and weeks of resarch) and now I can get big data using dart tcp socket from the old system very fast. The process with dart console app is much faster than the dart Future project.
Now problem to mixing dart console app to aqueduct Future app. In below I put my questions after (********).
If I use Socket.connect("192..... Inside Future the process will be very slow and sometimes returns null response. So, my question is how to merge aqueduct Future with dart console app.
aqueduct.io part
class NtmsApiController extends Controller {
#override
Future<RequestOrResponse> handle(Request request) async {
try {
if (request.path.remainingPath != null) {
_requestValue = request.path.remainingPath;
// (********) In here I need to add below code, how?
}
} else {
_secureResponse = "$_errorData";
}
} catch (e) {
_secureResponse = "$_errorData";
}
return new Response.ok("$_secureResponse")
..contentType = ContentType.json;
}
}
dart console app
import 'dart:io';
import 'dart:async';
Socket socket;
String _response;
String _requestedData;
Stopwatch _stopWatch;
void main() {
_stopWatch = Stopwatch()..start();
_response = "";
_requestedData = "Q77:_:NBRT:_:6785417534\r\n";
Socket.connect("192.168.22.120", 3000).then((Socket sock) {
socket = sock;
socket.write('$_requestedData\r\n');
socket.listen(dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: false);
}).catchError((AsyncError e) {
print("Unable to connect: $e");
});
print("_requestedData: $_requestedData");
}
void dataHandler(data){
_response = new String.fromCharCodes(data).trim();
_printResponse(_response);
}
void errorHandler(error, StackTrace trace){
print(error);
}
void doneHandler(){
socket.destroy();
}
void _printResponse(String _response) {
// approximately I get 500 rows with 20 column data in 250ms
print("$_response ... (${_stopWatch.elapsedMilliseconds} ms)");
_stopWatch..stop();
if(_stopWatch.isRunning == false) {
socket.close();
// (********)return response object to aqueduct Future request_response--- how?
}
}

Related

Rare error when trying to save data "unhandled exception on the current circuit"

I am using VS 2022, Blazor server project. When I trying to save data
async public static Task<bool> updateObject(Firecall obj)
{
Firecall r;
try
{
using (var context = new sptContext())
{
r = context.Firecalls.Where(c => c.Mguid == obj.Mguid).FirstOrDefault();
bool новое = (r == null);
if (новое)
{
r = new Firecall();
}
r.comment = obj.comment;
if (новое)
await context.Firecalls.AddAsync(r);
if (busy)
return false;
try
{
busy = true;
await context.SaveChangesAsync();
}
catch (Exception)
{
return false;
}
finally {
busy = false;
}
}
return true;
}
catch (Exception)
{
return false;
}
}
sometimes I get error:
Sometimes an error occurs, sometimes not. No error in debugger.
How to solve problem?
P.S. Data in each operation is saved as expected. Only after the operation is completed the indicated error message appear
And calling savechanges method from #code block of .razor view:
async private void SaveChanges()
{
bool rez = await firecallRepository.updateObject(_currentFireCall);
}

SpringBoot to Flutter Stream using application/x-ndjson

I am trying to get a Flutter app to process a NDJSON stream properly, but cannot get it to work.
I have a SpringBoot server that the Flutter app requests a stream from.
SpringBoot side:
#GetMapping(value = "/streaming", produces = {
// MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_NDJSON_VALUE
})
public Flux<String> getItemsStream(){
FluxSinkImpl<String> fluxSinkConsumer = new FluxSinkImpl<>();
try {
logger.info("streaming New Stream!");
synchronized (fluxSinkConsumers) {
fluxSinkConsumers.add(fluxSinkConsumer);
}
return Flux.create(fluxSinkConsumer).doOnNext(s -> {
logger.info("streaming doOnNext ["+s+"]");
}).doFinally(signalType -> {
logger.info("streaming Done ["+signalType+"]");
synchronized (fluxSinkConsumers) {
fluxSinkConsumers.remove(fluxSinkConsumer);
}
});
} catch (Exception e) {
logger.error("Failed to register Stream",e);
throw e;
}
}
private synchronized void publishEvent(String jsonStr) {
Set<FluxSinkImpl> fluxSinkConsumersCopy;
synchronized (fluxSinkConsumers) {
fluxSinkConsumersCopy = new HashSet<>(fluxSinkConsumers);
}
fluxSinkConsumersCopy.forEach(fluxSink -> {
try {
logger.info("streaming publishEvent");
fluxSink.publishEvent(jsonStr);
} catch (Throwable t) {
logger.info("streaming Failed to publish");
t.printStackTrace();
synchronized (fluxSinkConsumers) {
fluxSinkConsumers.remove(fluxSink);
}
}
});
}
The flutter side:
void startStreamListener2() async {
try {
final client = new http.Client();
http.Request request = http.Request("GET", Uri.parse(host+'streaming'));
request.headers['Content-type'] = 'application/x-ndjson';
request.headers['Accept'] = 'application/x-ndjson';
Future<http.StreamedResponse> streamedResponseFuture = client.send(request);
Stream<http.StreamedResponse> asStream = streamedResponseFuture.asStream();
print('startStreamListener1 [${host+'streaming'}]');
final StreamController<http.StreamedResponse> controller2 = new StreamController<http.StreamedResponse>();
asStream.asyncMap((event) {
event.stream.listen((value) {
print('startStreamListener4 listen [${utf8.decode(value)}]');
});
});
controller2.stream.listen((http.StreamedResponse event) {
event.stream.listen((value) {
print('startStreamListener3 listen [${utf8.decode(value)}]');
});
});
StreamSubscription<http.StreamedResponse> listen = asStream.listen((http.StreamedResponse event) {
event.stream.listen((value) {
print('startStreamListener2 listen [${utf8.decode(value)}]');
});
});
listen.onDone(() {
print('startStreamListener2 Done');
});
listen.onError((error) {
print('startStreamListener2 Error[$error] runtimeType[${error.runtimeType}]');
if (error is ClientException) {
print('ClientException [${(error as ClientException).message}]');
}
});
} catch (error) {
print('startStreamListener error [$error]');
}
}
When I use a Browser to connect directly to the stream, it works just fine. I see pushed messages as they are generated. The Stream is supposed to be open for a long time with asynchronous messages being pushed towards listeners (Flutter in this case).
Flutter does register, but does not trigger onData on single message. It does register the SpringBoot server restarting.

VertX JUnit 5 MongoDB test does not complete (TimeoutException) or completes too early (testContext.awaitCompletion not working)

Background:
During migration from JUnit4 to JUnit5 using VertX I read the migration guides which explain:
how to use the changed Promise and Future Vertx interfaces
how to VertxTestContext, Vertx auto-injection in Vertx Tests
how to use testContext.awaitCondition(), textContext.completing(), testContext.completeNow() etc.
Having this information in mind I wrote the following test:
Test Code:
import io.vertx.core.Promise;
import io.vertx.core.Future;
#ExtendWith(VertxExtension.class)
class RestApiTest {
#BeforeAll
static void setUpMongoDatabase() throws IOException {
(...)
}
#BeforeEach
void setUp(Vertx vertx, VertxTestContext ctx) {
vertx.deployVerticle(ApiVerticle.class.getName(), options, ctx.completing());
return WebClient.create(vertx);
}
#AfterEach
void tearDown(Vertx vertx, VertxTestContext testContext) {
assertThat(vertx.deploymentIDs().size(), is(equalTo(2)));
}
#AfterAll
static void stopMongoDatabase() {
(...)
}
#Test
void test(Vertx vertx, VertxTestContext testContext) {
Future<Void> insertFuture = insertTestData();
future.setHandler(testContext.completing());
// This ether throws a TimeoutException or does not block until the insert completed
testContext.awaitCompletion(5, TimeUnit.SECONDS);
// assert
mongoClient.findOne(COLLECTION, QUERY, result -> {
if (result.succeeded()) testContext.completeNow();
else testContext.failNow();
});
}
Future<Void> insertTestData() {
Promise<Void> promise = Promise.promise();
Future<Void> future = promise.future();
mongoClient.insert(COLLECTION, QUERY, result -> {
if (result.succeeded()) {
promise.complete();
} else {
promise.fail();
}
});
return future;
}
}
Problem:
testContext.awaitCompletion() ether throws a TimeoutException
or does not block until the async insert completed so that my assert returns successfully
Question:
How can I wait for the async mongo query to complete before I continue with my test?
The problem was that I am using the VertX Promise and Future classes:
those classes only work on a VertX Verticle
my insertTestData() method is not executed on a Verticle
One solution is to use the java.util.concurrent.ReentrantLock and Condition classes instead:
#Test
void test() {
insertTestData(); // This is now synchronous as required
// assert
mongoClient.findOne(COLLECTION, QUERY, result -> {
if (result.succeeded()) testContext.completeNow();
else testContext.failNow();
});
}
void insertTestData() {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
mongoClient.insert(COLLECTION, QUERY, result -> {
if (result.succeeded()) {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
} else {
fail();
}
});
lock.lock();
try {
condition.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
} finally {
lock.unlock();
}
}
}

Handling callbacks in Dart classes

My dart application it's listening to a socket I want to return the socket reply on the command(...) function after it is processed in the dataHandler event.
import 'dart:io';
import 'dart:async';
class TeamSpeak3{
Socket socket;
String command;
String _ip;
int _port;
TeamSpeak3(String ip, int port) {
this._ip = ip;
this._port = port;
}
Future<int> connect() async {
await Socket.connect(_ip, _port)
.then((Socket sock) {
socket = sock;
socket.listen(
dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: false);
}).catchError((AsyncError e) {
print("Connection failed: $e");
exit(1);
});
socket.done;
return 1;
}
void auth(String name, String pass){
socket.write("login $name $pass\n");
}
void send(String cmd){
command = cmd;
socket.write('$cmd\n');
//return reply from dataHandler
}
void dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
//return $reply on the send function
}
void errorHandler(error, StackTrace trace){
print(error);
}
void doneHandler(){
print("Connection termiated!");
socket.destroy();
exit(0);
}
}
First of all, you don't know for sure that the entire response to your send arrives in one packet, so you might not have the entire response.
Let's assume that you do (otherwise you'll have to do more processing in dataHandler to collect the response before delivering it).
The canonical way to allow a callback to be called when something has happened in the future, is to return a Future. You will also need a way to complete that future, so you create a Completer and store it until you need it. Since you can probably do more sends, you need to remember more than one completer. So, all in all, I'd write this as:
Queue<Completer<String>> _queue = Queue();
Future<String> send(String cmd){
socket.writeln(cmd);
var completer = new Completer<String>();
_queue.add(completer);
return completer.future;
}
void _dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
// Add some sanity checking here. Make sure you have the entire response before
// executing the code below.
_queue.removeFirst().complete(reply);
}
(I made _dataHandler private because you probably don't want the user calling send to alse be able to call dataHandler).

Flutter, dart:io - convert Uint8List (from websocket) to a jpeg file I can draw

I've written a simple nodejs ws websocket server that is serving a binary jpeg file when a client connects as follows:
import WebSocket = require("ws");
console.log("Websocket is starting...");
// Setup websocket
const wss = new WebSocket.Server({ port: 8080 });
wss.on("connection", function connection(webSocket) {
console.log("Connected");
webSocket.on("message", function incoming(message) {
console.log("received: %s", message);
});
webSocket.on("error", function error(err) {
console.log(err.error);
});
webSocket.send(binaryJpegFile);
});
There was an error in this code as it sends as text by default so I replaced:
webSocket.send(binaryJpegFile);
with:
webSocket.send(binaryJpegFile, {binary: true});
Now my flutter codes receives the binary jpeg file as a Uint8List using the following code:
WebSocket socket;
void handleWebSocket(data) {
// Listen for incoming data. We expect the data to be a JSON-encoded String.
print("WebSocket data received");
if (data.runtimeType == String) {
print("String received");
String dataString = data;
print(dataString.length);
print(dataString);
} else if (data.runtimeType == Uint8List) {
print("Binary received");
Uint8List binaryIntList = data;
print(binaryIntList.lengthInBytes);
} else {
print("Unknown datatype recieved : " + data.runtimeType.toString());
}
}
connect() async {
if (socket == null) {
socket = await WebSocket.connect('ws://localhost:8080');
socket.listen(handleWebSocket);
}
socket.add('Hello, World!');
}
#override
void initState() {
super.initState();
connect();
}
Can anyone give tips on how to convert Uint8List to a jpeg file I can draw?
First try using Uint8List directly with Image.memory widget.
example:
new Image.memory(binaryIntList);
If that doesn't work as expected.
You can use the image dart package to first decode the bytes to Image object and the encode it to the format you wish.
example:
import 'package:image/image.dart' as I; //So that this does not conflict with the Image widget
then
I.Image _img = I.decodeImage(binaryIntList);
_img = I.encodeJpg(_img);
then use it as
new Image.memory(_img.getBytes());
Hope that helped!
Image.memory(binaryIntList);
Is always useful,good luck