Multiple websockets in QML - c++

I understand that it's probably a trivial question but maybe someone knows how to handle multiple websocket clients in server-qml. I did not understand from the official documentation of Qt as NOT using the C++ function or webchannel to do it. Is it possible?
I have a websocket client and server in the program. If I connect from js code to html page(from the simplechat example) how do I send a socket inside the QML app and back. How to handle the name of each socket on the server and send to it the desired text. I would appreciate any help.
My current code.
WebSocketServer {
id: server
listen: true
port:1234
onClientConnected: {
webSocket.onTextMessageReceived.connect(function(message) {
appendMessage(qsTr("Server received message: %1").arg(message));
webSocket.sendTextMessage(qsTr("Hello Client!"));
// how to get a list of sockets and an instance of a particular connected socket
});
}
onErrorStringChanged: {
appendMessage(qsTr("Server error: %1").arg(errorString));
}
}
WebSocket {
id: socket
url: server.url
active:true
onTextMessageReceived: appendMessage(qsTr("Client received message: %1").arg(message))
onStatusChanged: {
if (socket.status == WebSocket.Error) {
appendMessage(qsTr("Client error: %1").arg(socket.errorString));
} else if (socket.status == WebSocket.Closed) {
appendMessage(qsTr("Client socket closed."));
}
}
}
The problem is that there is a page with the following code something like a chat client
var wsUri = "ws://localhost:1234";
var websocket = null;
function initWebSocket() {
try {
if (typeof MozWebSocket == 'function')
WebSocket = MozWebSocket;
if ( websocket && websocket.readyState == 1 )
websocket.close();
websocket = new WebSocket( wsUri );
websocket.onopen = function (evt) {
debug("CONNECTED");
};
websocket.onclose = function (evt) {
debug("DISCONNECTED");
};
websocket.onmessage = function (evt) {
console.log( "Message received :", evt.data );
debug( evt.data );
};
websocket.onerror = function (evt) {
debug('ERROR: ' + evt.data);
};
} catch (exception) {
debug('ERROR: ' + exception);
}
}
Its websocket creates client and connects to the server described. When a client connects from a js script, it can send a message to the server and take QML will be displayed in the hearth of the page. When a new client socket inside QML application connects to the server and sents to the alias in the message QML server and can receive messages from the server. But how to do so from the socket in the application message reached the customer at the js and back. To do this, probably it is necessary to the server as a defined desired socket, take the instance
webSocket.sendTextMessage(qsTr("Hello Client!"));
of the socket it is

Related

Accessing AWS WebSocket using VertX HttpClient

I have created an API Gateway with a Web Socket on AWS. I would like to connect to it using the HttpClient provided by VertX. I am using the following code for the client verticle:
public class WebSocketClient extends AbstractVerticle {
// application address replaced by [address]
protected final String host = "[address].execute-api.us-east-1.amazonaws.com";
protected final String path = "/dev";
protected final int port = 80;
protected final String webSocketAddress = "wss://[address].execute-api.us-east-1.amazonaws.com/dev";
#Override
public void start() throws Exception {
startClient(this.vertx);
}
protected void startClient(Vertx vertx) {
HttpClient client = vertx.createHttpClient();
client.webSocket(port, host, path, asyncWebSocket -> {
if (asyncWebSocket.succeeded()) {
WebSocket socket = asyncWebSocket.result();
System.out.println("Successfully connected. Node closing.");
socket.close().onFailure(throwable -> {
throwable.printStackTrace();
});
} else {
asyncWebSocket.cause().printStackTrace();
}
});
}
}
The same code works when I am testing it with a VertX server running on the localhost, so I assume that it is a question of the correct WebSocketConnectionOptions.
When I try to connect to the AWS socket using the HttpClient verticle, I get a "connection refused" error. Connecting to it using wscat works without problems.
Thanks a lot for your help.
This question is dealing with basically the same problem. I will post the solution here just to document a straight-forward way to use AWS ApiGateway Websockets with VertX.
So, the goal is to implement a VertX WebClient connected to a deployed AWS Api WebSocket Gateway which can be reached under the WsUri "wss://[address].execute-api.us-east-1.amazonaws.com/dev" (you will have to replace [address] by the address of your ApiGateway Websocket).
Here the code to set up the WebClient, connect to the Websocket, print out a success message, and then disconnect again:
public class WebSocketClient extends AbstractVerticle {
protected final String webSocketUrl = "wss://[address].execute-api.us-east-1.amazonaws.com/dev"
protected final String host = "[address].execute-api.us-east-1.amazonaws.com";
protected final String path = "/dev";
protected final int sslPort = 443;
#Override
public void start() throws Exception {
startClient(this.vertx);
}
protected void startClient(Vertx vertx) {
HttpClient client = vertx
.createHttpClient(new
HttpClientOptions().setDefaultHost(host).setDefaultPort(sslPort).setSsl(true));
// connect to the web socket
client.webSocket(path, asyncWebSocket -> {
if (asyncWebSocket.succeeded()) {
// executed on a successful connection
WebSocket socket = asyncWebSocket.result(); // use this for further communication
System.out.println("Successfully connected. Closing the socket.");
// Closing the socket
socket.close().onFailure(throwable -> {
throwable.printStackTrace();
});
} else {
// executed if the connection attempt fails
asyncWebSocket.cause().printStackTrace();
}
});
}
You can use the following class to run the example:
public class PlayWebSocket {
public static void main(String[] args) throws URISyntaxException{
Vertx vertx = Vertx.vertx();
WebSocketClient clientVerticle = new WebSocketClient();
vertx.deployVerticle(clientVerticle);
}
}
On the Java side, this should print the message about the successful connection and the closing of the socket. On the AWS side, the $connect and the $disconnect methods of the ApiGateway should be called. You can check this in the logs of your handler function(s) using CloudWatch.

REST API access: JS and Python code does the job, but Qt/C++ can't. Why?

I am writing a client to work with a python server working in a local network. I think the server's code is irrelevant to show here because it's working as expected (tested with clients written in JavaScript and Python ... and Postman).
Problem: client written in Qt/C++ is not working as expected. Response body is always empty.
Server.
For my particular request, the server responds with Error code 500 and a body in format: { "message" : "error reason" }.
Wireshark. I used this tool to be sure about number of request and check response bodies. In all the cases, responses had expected bodies.
Qt/C++ client.
Qt client is written in a simple, very standard Qt way:
manager = new QNetworkAccessManager();
QObject::connect(manager, &QNetworkAccessManager::finished,
[](QNetworkReply *reply)
{
QByteArray response = reply->readAll();
qDebug() << "Response body:" << response;
if (reply->error())
qDebug() << "System error msg:" << reply->errorString();
else
qDebug() << "Success!";
});
qDebug() << "Sending IrsInit request:";
QString initApi = "http://192.168.101.127:1122/api/v1/replay/initReplay";
QUrl url = QUrl(initApi);
QNetworkRequest request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
QJsonObject bodyObj
{
{ "game_id", "5c0768177fb8217354de84d0" },
{ "objects", QJsonArray{
QJsonObject{ {"id", "5c0768207fb8217354de84d1"}, {"name", "Demon"} }
}
}
};
QJsonDocument *doc = new QJsonDocument(bodyObj);
qDebug() << "url:" << url.toString() << "\nbody:" << doc->toJson();
manager->post(request, doc->toJson());
Here is the output:
Sending IrsInit request:
url: "http://192.168.101.127:1122/api/v1/replay/initReplay"
body: "{"game_id": "5c0768177fb8217354de84d0", "objects": [{"id":"5c0768207fb8217354de84d1","name": "Demon"}]}"
Response body: ""
System error msg: "Connection closed" // error code is QNetworkReply::RemoteHostClosedError
Here, the output shows that one request has been sent and response body is empty (and response code also note 500 I think). However, Wireshark shows totally different thing for this request:
Server IP - *.*.*.127
Client IP - *.*.*.128
As I checked with the server, sending one request from this client causing the server to receive not only one, but different number of requests (from 1 to 4). In this example case, the server shows 4 requests have been received, respectively. Moreover, in Wireshark, all the responses have expected bodies.
I don't know why this is happening: Qt shows that it sent one request, but Wireshark and the server say 4 requests were sent. Long hours of debugging did not give any hint. I would appreciate any suggestions (solutions, debugging, directions)!
JavaScript client.
var xhr = new XMLHttpRequest();
var url = "http://192.168.101.127:1122/api/v1/replay/initReplay";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log('Status 200');
console.log('Response\n');
var json = JSON.parse(xhr.responseText);
console.log(json);
}
if (xhr.status === 500) {
console.log('Status 500');
console.log('Response\n');
var json = JSON.parse(xhr.responseText);
console.log(json);
}
};
var data = JSON.stringify({"game_id":"5c0768177fb8217354de84d0","objects":[{"id":"5c0768207fb8217354de84d1","name":"Demon"}]});
xhr.send(data);
Output:
I don't know why it printed three times but server received (always correctly) one request. And Wireshark proves this:
Python client.
import sys
import requests
post_fields = {
"game_id":"5c0768177fb8217354de84d0",
"objects":[
{
"id":"5c0768207fb8217354de84d1",
"name":"Demon"
}
]
}
link = 'http://192.168.101.127:1122/api/v1/replay/initReplay'
s = requests.Session()
resp = s.post(link,data=post_fields)
print(resp)
print(resp.content)
Output:
Python client worked ideally. Wireshark output:

NodeJS / iOS - How to get a returned value from a binary after calling it with HTTP POST

I have an iOS app (Objective C) and this app call some C++ binaries using NodeJs.
So far, I have been able to execute remotely my C++ program from a clicked button on my app using HTTP POST with the library AFNetworking 3.
iOS App --> Button clicked --> HTTP POST --> Node JS call --> C++ program call (this latter return true or false)
Now, I would like to get the value (True or False) returned by my program. How can I do that ?
I have already used the GET method to get a file on my server but I don't know if it's appropriate to use it for this case i.e get the returned result of my program.
Do you have an idea how can I achieve this ?
Thank
To be able to retrieve the value returned by your C++ program, you need first to retrieve the returned result from NodeJS.
Assuming you are using ExpressJS as your HTTP server, you should implement your endpoint with something like:
var execFile = require('child_process').execFile;
var express = require('express');
var app = express();
app.post('/endpoint', function (req, res) {
const child = execFile('my_exe', (error, stdout, stderr) => {
if (error) {
res.status(500).send('False')
} else {
if (stdout === 'True') {
res.status(200).send('True')
} else {
res.status(500).send('False')
}
}
});
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
If the call succeeded, the server will respond True with the status 200 and if it fails, it will return Falsewith a status False.
Now, in your call to the server from the iOS application, you can use Alamofire like:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"POST" URLString:#"someURL" parameters:#{} error:nil];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
/* Network error*/
NSLog(#"Error: %#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
switch (httpResponse.statusCode) {
case 200:
NSLog(#"Success")
/* Code in case of success == Server returned True */
default:
/* Code in case of no success == Server returned False */
NSLog(#"Error");
}
}
}];
[dataTask resume];

Activemq concurrency fail in Apache camel route

Trying to send multiple requests at same instant to camel activemq route, one request is serviced and the other request is not serviced and sent back as it is. The Jms messages are set with JMScorrelationId too before sending like below
textMessage.setJMSCorrelationID(UUID.randomUUID().toString());
below is my activemq route
from("activemq:queue:TEST_QUEUE?disableReplyTo=true")
.setExchangePattern(ExchangePattern.InOut)
.process(new Processor() {
public void process(Exchange e) throws Exception {
log.info("Request : "
+ MessageHelper.extractBodyAsString(e.getIn()));
/*Processing Logic*/
}
})
.beanRef("testBean","postDetails")
.inOnly("activemq:queue:TEST_QUEUE");
Multiple (Test for 2 requests) requests sent to the above route concurrently not serviced except one. The servicemix.log shows all recieved requests. But only one is serviced.
Below is the code what is sending request deployed in jboss 6.1 as part of web application.
public Message receive(String message, String queueName) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"tcp://localhost:61616");
String userName = "smx";
String password = "smx";
Connection connection;
Message response =null;
try {
connection = connectionFactory.createConnection(userName, password);
connection.start();
((ActiveMQConnectionFactory) connectionFactory)
.setDispatchAsync(false);
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue destination = session.createQueue(queueName);
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage textMessage = session.createTextMessage(message);
Queue tempQueue = session.createQueue(queueName);
textMessage.setJMSReplyTo(tempQueue);
producer.send(textMessage);
MessageConsumer consumer = session.createConsumer(tempQueue);
response = consumer.receive();
response.acknowledge();
session.close();
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
return response;
}
Is there some or the other parameter im missing?? please suggest.
Camel will auto send back a reply if the JMS message has a JMSReplyTo header, so your route should just be
from("activemq:queue:TEST_QUEUE")
.process(new Processor() {
public void process(Exchange e) throws Exception {
log.info("Request : "
+ MessageHelper.extractBodyAsString(e.getIn()));
/*Processing Logic*/
}
})
.beanRef("testBean","postDetails");
At the end of the route (eg after calling testBean) then the content of the message body is used as the reply message, that are sent back to the queue named defined in the JMSReplyTo header.

Chat application using CFWebsocket

How can we develop a facebook like chat application using cfwebsocket. There is no description about how to send an user entered message to the server and how to send that message to a particular client from the server.
<script type="text/javascript">
function mymessagehandler(aevent, atoken)
{
console.log(aevent);
console.log(atoken);
var message = aevent.msg;
var txt=document.getElementById("myDiv");
txt.innerHTML = txt.innerHTML + message +"<br>";
}
</script>
<cfwebsocket name="mycfwebsocketobject" onmessage="mymessagehandler" subscribeto="stocks" >
<cfdiv id="myDiv"></cfdiv>
The above code just prints ok in the display. I am not sure how to pass my message inside the stocks object. Can anyone help on this? Thanks in advance
This is the stocks application that I am using
this.wschannels = [ {name="stocks", cfclistener="myChannelListener" }];
This is what I have did to make my chat application work
This is the chat application
<cfwebsocket name="ChatSocket" onOpen="openHandler" onMessage="msgHandler" onError="errHandler">
This is the script
function openHandler(){
//Subscribe to the channel, pass in headers for filtering later
ChatSocket.subscribe('chatChannel',{name: 'TheUserName', UserID: 'TheUserID', AccountID: 'AnUniqueID' });
}
// function to send the message. we can call this when the user clicks on send message
function publish(userID){
var msg = {
AccountID: "AnUniqueID",
publisher: userID,
id: userID,
message: document.getElementById("Name").value + " : " + document.getElementById("message").value
};
//When including headers, the "selector" is where you will filter who it goes to.
var headers = {
AccountID: "AnUniqueID",
publisher: userID,
id: userID
};
// we can save the chat history by an ajax call here
ChatSocket.publish('chatChannel',msg, headers);
}
// this is the receiving function
function msgHandler(message){
// if condition to display the message to the user who are sending and receiving
if(message.data !== undefined && message.data.message !== undefined && (message.data.id == '#session.userID#' || message.data.publisher == '#session.userID#')) {
var data = message.data.message;
console.log(data);
//showing the message
var txt=document.getElementById("myDiv");
txt.innerHTML+= data + "<br>";
}
}
function errHandler(err){
console.log('err');
console.log(err);
}