How to use libmosquitto to make a request and get response using MQTT v5? - c++

I'm trying to use libmosquitto to make a request (publish to a 'test/topic' topic) and I want to get a response based on the client (sender) id. So that means the client will publish to 'test/topic' and it will automatically subscribe 'test/topic/<client_id>'
The server has already subscribed on 'test/topic' and when it becomes the message, it will send a response (publish) to 'test/topic/<client_id>', which the client subscribed to receive that response in the first place.
The challenge here is how do I get the <client_id>, right. I already done this in python and js, where the client will send metadata or properties in the payload, which the server can unpack to get the client_id. However, I'm using C++ now and it's frustrating because I can't figure out how to get these properties.
Here is an example of how to do this in python. I just want to do the same with c++
I'm using the libmosquitto as I mentionned. I don't even have an example to show because I didn't find how to do this. There is literally no example on how to do this with the mosquitto c++ lib (which is confusing since mosquitto is a famous lib I guess).
I hope someone had a similar problem or can post an example for c++ and mosquitto lib. Thanks in advance.

When in doubt, look at the tests:
const char *my_client_id = ...;
mosquitto_property *proplist = NULL;
mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client_id", my_client_id);
mosquitto_publish_v5(mosq, &sent_mid, "test/topic", strlen("message"), "message", 0, false, proplist);
mosquitto_property_free_all(&proplist);
Since you asked in the comments, you can retrieve these properties from published messages by first setting an on_message callback using mosquitto_message_v5_callback_set and the implementing it like so:
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *props) {
std::string topic{message->topic};
if (topic == "test/topic") {
const char *client_id = nullptr;
mosquitto_property_read_string_pair(props, MQTT_PROP_USER_PROPERTY, nullptr, &client_id, false);
if (client_id) {
/* client_id contains a client id. */
}
}

Related

How can i send packages on a Minecraft Client (With Fabricmc) and receive it on a Bukkit Server?

I'm a Chinese secondary school student,so my written English may not very well.
How can i send packages (like some words) on a Minecraft Client (Use a Fabricmc Mod to send) and receive it on the bukkit server on MC Multiplayer?
This is done using what's known as the 'plugin messaging channel'. Take a look at this Fabricmc wiki to read about client networking (messaging). See this Spigot wiki on the plugin server-side messaging channel; ignore that this wiki talks a lot about bungee, it's just because that's a common use case. You can make your own channel.
The code below is copied from said wikis and is very much pseudo-code:
Client
Sending from the client
PacketByteBuf buf = PacketByteBufs.create();
buf.writeBlockPos(target);
ServerPlayNetworking.send((ServerPlayerEntity) user, TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, buf);
Receiving on the client
ClientPlayNetworking.registerGlobalReceiver(TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, (client, handler, buf, responseSender) -> {
client.execute(() -> {
// Everything in this lambda is run on the render thread
ClientBlockHighlighting.highlightBlock(client, target);
});
});
Where you see TutorialNetworkingConstants.HIGHL..., that's the Identifier for the channel.
Server (Spigot/Bukkit)
Sending from the server
player.sendPluginMessage(this, "YourChannelName", out.toByteArray());
Receiving on the server
#Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals("YourChannelName")) {
return;
}
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String data = in.readUTF();
...
Take a thorough read of those tutorials, they should cover all you need to know. Just be sure to unregister your channels on both the client and server.

MQTT Receive Message in C++

I'm trying to receive messages from a published topic in C++. I know in Java it's just client.on('message', (topic, message)). But I couldn't do something like that in a C++ library. How can I do it?
As of now, I've got everything set up and am subscribing to the topic I'm interested in, but I'm stuck on how to fetch the message from there.
MQTTClient client;
void mqtt_subscribe(std::string const &topic) {
if(!mqtt_initialized) {
return;
}
MQTTClient_subscribe(client, topic.c_str(), 1);
}
Your client is connected to nothing, so you have to connect first by calling the Mqtt client constructor of the mosquitopp library witch is the top level cpp interface.

Apache Thrift for just processing, not server

I hope I don't have misunderstood the Thrift concept, but what I see from (example) questions like this, this framework is composed by different modular layers that can be enabled or disabled.
I'm mostly interesed in the "IDL part" of Thrift, so that I can create a common interface between my C++ code and an external Javascript application. I would like to call C++ functions using JS, with Binary data transmission, and I've already used the compiler for this.
But both my C++ (the server) and JS (client) application already exchange data using a C++ Webserver with Websockets support, it is not provided by Thrift.
So I was thinking to setup the following items:
In JS (already done):
TWebSocketTransport to send data to my "Websocket server" (with host ws://xxx.xxx.xxx.xxx)
TBinaryProtocol to encapsulate the data (using this JS implementation)
The compiled Thrift JS library with the correspondent C++ functions to call (done with the JS compiler)
In C++ (partial):
TBinaryProtocol to encode/decode the data
A TProcessor with handler to get the data from the client and process it
For now, the client is already able to sent requests to my websocket server, I see receiving them in binary form and I just need Thrift to:
Decode the input
Call the appropriate C++ function
Encode the output
My webserver will send the response to the client. So no "Thrift server" is needed here. I see there is the TProcessor->process() function, I'm trying to use it when I receive the binary data but it needs an in/out TProtocol. No problem here... but in order to create the TBinaryProtocol I also need a TTransport! If no Thrift server is expected... what Transport should I use?
I tried to set TTransport to NULL in TBinaryProtocol constructor, but once I use it it gives nullptr exception.
Code is something like:
Init:
boost::shared_ptr<MySDKServiceHandler> handler(new MySDKServiceHandler());
thriftCommandProcessor = boost::shared_ptr<TProcessor>(new MySDKServiceProcessor(handler));
thriftInputProtocol = boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(TTransport???));
thriftOutputProtocol = boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(TTransport???));
When data arrives:
this->thriftInputProtocol->writeBinary(input); // exception here
this->thriftCommandProcessor->process(this->thriftInputProtocol, this->thriftOutputProtocol, NULL);
this->thriftOutputProtocol->readBinary(output);
I've managed to do it using the following components:
// create the Processor using my compiled Thrift class (from IDL)
boost::shared_ptr<MySDKServiceHandler> handler(new MySDKServiceHandler());
thriftCommandProcessor = boost::shared_ptr<TProcessor>(new ThriftSDKServiceProcessor(handler));
// Transport is needed, I use the TMemoryBuffer so everything is kept in local memory
boost::shared_ptr<TTransport> transport(new apache::thrift::transport::TMemoryBuffer());
// my client/server data is based on binary protocol. I pass the transport to it
thriftProtocol = boost::shared_ptr<TProtocol>(new TBinaryProtocol(transport, 0, 0, false, false));
/* .... when the message arrives through my webserver */
void parseMessage(const byte* input, const int input_size, byte*& output, int& output_size)
{
// get the transports to write and read Thrift data
boost::shared_ptr<TTransport> iTr = this->thriftProtocol->getInputTransport();
boost::shared_ptr<TTransport> oTr = this->thriftProtocol->getOutputTransport();
// "transmit" my data to Thrift
iTr->write(input, input_size);
iTr->flush();
// make the Thrift work using the Processor
this->thriftCommandProcessor->process(this->thriftProtocol, NULL);
// the output transport (oTr) contains the called procedure result
output = new byte[MAX_SDK_WS_REPLYSIZE];
output_size = oTr->read(output, MAX_SDK_WS_REPLYSIZE);
}
My webserver will send the response to the client. So no "Thrift server" is needed here. I see there is the TProcessor->process() function, I'm trying to use it when I receive the binary data but it needs an in/out TProtocol. No problem here... but in order to create the TBinaryProtocol I also need a TTransport! If no Thrift server is expected... what Transport should I use?
The usual pattern is to store the bits somewhere and use that buffer or data stream as the input, same for the output. For certain languages there is a TStreamTransport available, for C++ the TBufferBase class looks promising to me.

How to send a ConverseRequest message by Converse using C++

I am trying to build an google assistant client by using c++.
I've passed the authentication and created channel;
Then as the doc say: "Send a ConverseRequest message...", and stuck here, since Converse only has one parameter: ClientContext,
How can a ConverseRequest convert to be ClientContext?
my code segment:
ConverseConfig config;
config.set_allocated_audio_in_config(&audio_in_config);
config.set_allocated_audio_out_config(&audio_out_config);
ConverseRequest request;
request.set_allocated_config(&config);
ClientContext context;
//context.AddMetadata(request.GetMetadata());
ConverseResponse *response = stub_->Converse(&context);
Or some correct code sample will be thankful!
Well, C++ sample has offered:
https://github.com/googlesamples/assistant-sdk-cpp

Does libwebsockets offer publish/subscribe?

I want to create a web application where a group of users could receive some data asynchronously whenever the C++ backend have something new. So, ideally, when a new user comes, he'll be added to the subscribers list and whenever the C++ backend has new data for the group, it will publish it to everybody.
libwebsockets seems to be a good library to use with C++. The only problem is that it seems that it's mainly designed on a callback system, so, apparently data is meant to be sent only if the client asks for it.
I found this post with a similar issue but I don't know if this is the best way to do that: How do I send async data via libwebsocket?
Any help will be appreciated.
Thank you.
found it!
libwebsockets lets you broadcast to all connected users to a specific protocol using libwebsocket_callback_on_writable_all_protocol(*protocol) which triggers LWS_CALLBACK_SERVER_WRITEABLE that will be handled by the protocol's callback function and that's where we could send the data.
So, typically, I use my second protocol (the non-http one) whenever I have some data to broadcast in any part of my code with libwebsocket_callback_on_writable_all_protocol(protocols + 1) and in the protocol's callback function
static int callback_linux_shell(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) {
switch (reason) {
...
case LWS_CALLBACK_SERVER_WRITEABLE:
libwebsocket_write(wsi, my_data, my_data_size, LWS_WRITE_TEXT);
break;
...
}
}