How to use boost to put a stream into a buffer - c++

I am new to Streams and Buffers implementation and I do not really know how to fix this:
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <thread>
#include <boost/property_tree/json_parser.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
using tcp = boost::asio::ip::tcp;
namespace websocket = boost::beast::websocket;
namespace pt = boost::property_tree;
struct DefaultMessage {
std::string command;
int value;
};
void defaultMessage(DefaultMessage *dm ,pt::ptree *root) {
root->put("command", dm->command);
root->put("value", dm->value);
}
// Echoes back all received WebSocket messages
void do_session(tcp::socket &socket) {
try {
// Construct the stream by moving in the socket
websocket::stream<tcp::socket> ws{std::move(socket)};
// Accept the websocket handshake
ws.accept();
for (;;) {
// Read a message into the buffer
boost::beast::multi_buffer buffer;
ws.read(buffer);
// Make string from buffer
auto s = boost::beast::buffers_to_string(buffer.data());
// Create ptree root
pt::ptree root;
// Create array source from s
boost::iostreams::array_source array_source(&s[0], s.size());
// Create input stream from array source
boost::iostreams::stream<boost::iostreams::array_source> input_stream(array_source);
// Read the json an populate ptree root
pt::read_json(input_stream, root);
// Discard all in buffer
buffer.consume(buffer.size());
// Construct a default message
auto message = DefaultMessage{
root.get<std::string>("command"),
root.get<int>("value")
};
defaultMessage(&message, &root);
// **This won't compile.**
pt::write_json(buffer, root);
// Echo the message back
ws.text(ws.got_text());
ws.write(buffer.data());
}
}
catch (boost::system::system_error const &se) {
// This indicates that the session was closed
if (se.code() != websocket::error::closed) {
std::cerr << "Error: " << se.code().message() << std::endl;
}
}
catch (std::exception const &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
I want to respond with the message struct. So I guess I need to put it back in the buffer. This part is what is do not know how to do.

If efficiency is not your top concern, I'd suggest
std::ostringstream oss;
pt::write_json(oss, root);
to write to a string, and
// Echo the message back
ws.text(ws.got_text());
ws.write(boost::asio::buffer(oss.str()));
to write that buffer out.
Caveats:
this does more allocations than strictly required, probably
Boost PropertyTree is NOT a JSON library

Related

Function which calls a service in gRPC

I have to write a function in c++ which calls shared library which is created from gRPC client which runs the gRPC client and returns the result.
Is there any samples?
Here are Some Examples I hope i would be helpful somehow.
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;
class GreeterClient
{
public:
GreeterClient(std::shared_ptr<Channel> channel): stub_(Greeter::NewStub(channel)) {}
// Assembles the client's payload, sends it and presents the response back from the server.
std::string SayHello(const std::string &user)
{
// Data we are sending to the server.
HelloRequest request;
request.set_name(user);
// Container for the data we expect from the server.
HelloReply reply;
// Context for the client. It could be used to convey extra information to the server and/or tweak certain RPC behaviors.
ClientContext context;
// The actual RPC.
Status status = stub_->SayHello(&context, request, &reply);
// Act upon its status.
if (status.ok())
{
return reply.message();
}
else
{
std::cout << status.error_code() << ": " << status.error_message() <<
std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<Greeter::Stub > stub_;
};
int main(int argc, char **argv)
{
// Instantiate the client. It requires a channel, out of which the actual RPCs are created. This channel models a connection to an endpoint (in this case, localhost at port 50051). We indicate that the channel isn't authenticated (use of InsecureChannelCredentials()).
GreeterClient greeter(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
std::string user("world");
std::string reply = greeter.SayHello(user);
std::cout << "Greeter received: " << reply << std::endl;
return 0;
}
OR
#include <iostream>
#include <string>
#include <dlfcn.h > // for dlopen, dlsym, dlclose
using namespace std;
int main()
{
void *handle; // handle to the library
string(*func)(string); // function pointer
char *error; // error message
handle = dlopen("/home/user/Desktop/grpc_client/libgrpc_client.so", RTLD_NOW); // open the library
if (!handle)
{
fputs(dlerror(), stderr); // print error message
exit(1);
}
func = (string(*)(string)) dlsym(handle, "run_grpc_client"); // get the function pointer
if ((error = dlerror()) != NULL)
{
fputs(error, stderr); // print error message
exit(1);
}
string result = func("hello"); // call the function
cout << result << endl;
dlclose(handle); // close the library
return 0;
}

C++ Unable to decompress messages returning from WebSocket API(Okex) through the inflate algorithm

I am trying to decompress message returning from WebSocket API(Okex). I tried to use zlib to decompress but fails. Please advise how to do so.
The following are websocket class written to connect to okex and returning data from the websocket server.
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef std::shared_ptr<boost::asio::ssl::context> context_ptr;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
using websocketpp::lib::bind;
void on_open(client* c, websocketpp::connection_hdl hdl) {
std::string msg = "{\"op\": \"subscribe\", \"args\": [\"spot/depth5:ETH-USDT\"]}";
c->send(hdl,msg,websocketpp::frame::opcode::text);
c->get_alog().write(websocketpp::log::alevel::app, "Sent Message: "+msg);
}
void websocketClient::on_message(websocketpp::connection_hdl hdl, message_ptr msg) {
std::cout << msg->get_payload().size()<< std::endl;
std::cout << msg->get_payload().data()<< std::endl;
string str = utility::inflationAlgorithm::decompress(msg->get_payload());
}
websocketClient::websocketClient() {
client c;
std::string uri = "wss://real.okex.com:8443/ws/v3";
try {
// Set logging to be pretty verbose (everything except message payloads)
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
// Initialize ASIO
c.init_asio();
c.set_tls_init_handler(bind(&on_tls_init));
// Register our message handler
c.set_open_handler(bind(&on_open, &c,::_1));
c.set_message_handler(bind(&websocketClient::on_message,this,::_1,::_2));
websocketpp::lib::error_code ec;
websocketClient::con = c.get_connection(uri, ec);
if (ec) {
std::cout << "could not create connection because: " << ec.message() << std::endl;
}else {
c.connect(websocketClient::con);
// Start the ASIO io_service run loop
// this will cause a single connection to be made to the server. c.run()
// will exit when this connection is closed.
c.run();
}
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
}
}
The following code are written to decompress the message returning from Okex, but unable to get decompressed string.
#include <sstream>
#include "inflationAlgorithm.h"
using namespace zlibcomplete;
using namespace std;
std::string utility::inflationAlgorithm::decompress(const std::string & str)
{
z_stream zs; // z_stream is zlib's control structure
memset(&zs, 0, sizeof(zs));
if (inflateInit2(&zs, 47) != Z_OK)
throw(std::runtime_error("inflateInit failed while decompressing."));
zs.next_in = (Bytef*)str.data();
zs.avail_in = (uint)str.size();
int ret;
char outbuffer[32768];
std::string outstring;
// get the decompressed bytes blockwise using repeated calls to inflate
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = inflateInit2(&zs, 47);
if (outstring.size() < zs.total_out) {
outstring.append(outbuffer,
zs.total_out - outstring.size());
}
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
std::ostringstream oss;
oss << "Exception during zlib decompression: (" << ret << ") "
<< zs.msg;
throw(std::runtime_error(oss.str()));
}
return outstring;
}

getting VS C2664 on sniffer.h libtins

I'm working on a packet-capturing program.
I started from one of libtins examples on http http://libtins.github.io/examples/http-requests/.
but VS prompts a
C2664
Error C2664 'bool main::::operator ()(Tins::Packet &) const': cannot convert argument 1 from 'Tins::PDU' to 'Tins::Packet &' packetSniff path-to-tins\sniffer.h 681
on the following part of the sniffer.h
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
//here
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
I have already build and run the example from the front page
http://libtins.github.io/
But the following code produces C2664
#define WIN32
#define TINS_STATIC
#define NOMINMAX
#pragma warning(disable : 4996)
#include <string>
#include <iostream>
#include <stdexcept>
#include <boost/regex.hpp>
#include <tins/tcp_ip/stream_follower.h>
#include <tins/sniffer.h>
#include <tins/tins.h>
#include "color.h"
#include <vector>
#include <sstream>
using std::string;
using std::cout;
using std::cerr;
using std::endl;
using std::exception;
using std::vector;
using std::wcout;
using std::stringstream;
using boost::regex;
using boost::match_results;
using Tins::Packet;
using Tins::Sniffer;
using Tins::SnifferConfiguration;
using Tins::TCPIP::Stream;
using Tins::TCPIP::StreamFollower;
using Tins::NetworkInterface;
using termcolor::on_red;
using termcolor::on_green;
using termcolor::reset;
// This example captures and follows TCP streams seen on port 80. It will
// wait until both the client and server send data and then apply a regex
// to both payloads, extrating some information and printing it.
// Don't buffer more than 3kb of data in either request/response
const size_t MAX_PAYLOAD = 3 * 1024;
// The regex to be applied on the request. This will extract the HTTP
// method being used, the request's path and the Host header value.
regex request_regex("([\\w]+) ([^ ]+).+\r\nHost: ([\\d\\w\\.-]+)\r\n");
// The regex to be applied on the response. This finds the response code.
regex response_regex("HTTP/[^ ]+ ([\\d]+)");
void on_server_data(Stream& stream) {
match_results<Stream::payload_type::const_iterator> client_match;
match_results<Stream::payload_type::const_iterator> server_match;
const Stream::payload_type& client_payload = stream.client_payload();
const Stream::payload_type& server_payload = stream.server_payload();
// Run the regexes on client/server payloads
bool valid = regex_search(server_payload.begin(), server_payload.end(),
server_match, response_regex) &&
regex_search(client_payload.begin(), client_payload.end(),
client_match, request_regex);
stringstream ss;
for (char c : server_payload) {
ss << c;
}
cout << on_green << "Server raw payload " <<
ss.str() << reset << endl;
// If we matched both the client and the server regexes
if (valid) {
// Extract all fields
string method = string(client_match[1].first, client_match[1].second);
string url = string(client_match[2].first, client_match[2].second);
string host = string(client_match[3].first, client_match[3].second);
string response_code = string(server_match[1].first, server_match[1].second);
// Now print them
cout << method << " http://" << host << url << " -> " << response_code << endl;
// Once we've seen the first request on this stream, ignore it
stream.ignore_client_data();
stream.ignore_server_data();
}
// Just in case the server returns invalid data, stop at 3kb
if (stream.server_payload().size() > MAX_PAYLOAD) {
stream.ignore_server_data();
}
}
void on_client_data(Stream& stream) {
// Don't hold more than 3kb of data from the client's flow
if (stream.client_payload().size() > MAX_PAYLOAD) {
stream.ignore_client_data();
}
}
void on_new_connection(Stream& stream) {
stream.client_data_callback(&on_client_data);
stream.server_data_callback(&on_server_data);
// Don't automatically cleanup the stream's data, as we'll manage
// the buffer ourselves and let it grow until we see a full request
// and response
stream.auto_cleanup_payloads(false);
}
int main(int argc, char* argv[]) {
// First fetch all network interfaces
vector<NetworkInterface> interfaces = NetworkInterface::all();
// Now iterate them
int i = 0;
for (const NetworkInterface& iface : interfaces) {
// First print the name (GUID)
cout << i++ << ' ' << "Interface name: " << termcolor::on_red << iface.name() <<
termcolor::on_cyan << ' ' << iface.addresses().ip_addr << termcolor::reset;
// Now print the friendly name, a wstring that will contain something like
// "Local Area Connection 2"
wcout << " (" << iface.friendly_name() << ")" << endl;
}
try {
// Construct the sniffer configuration object
SnifferConfiguration config;
// Only capture TCP traffic sent from/to port 80
config.set_filter("tcp port 5000");
// Construct the sniffer we'll use
Sniffer sniffer(interfaces[5].name(), config);
wcout << on_green <<"Starting capture on interface " <<
interfaces[5].friendly_name() << reset << endl;
// Now construct the stream follower
StreamFollower follower;
// We just need to specify the callback to be executed when a new
// stream is captured. In this stream, you should define which callbacks
// will be executed whenever new data is sent on that stream
// (see on_new_connection)
follower.new_stream_callback(&on_new_connection);
// Now start capturing. Every time there's a new packet, call
// follower.process_packet
sniffer.sniff_loop([&](Packet& packet) {
follower.process_packet(packet);
return true;
});
}
catch (exception& ex) {
cerr << "Error: " << ex.what() << endl;
return 1;
}
}
According to the code inside sniffer.h,
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
//here
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
When you uses VS to compile, the macro _MSC_VER is defined by default, and your code will go to the #else branch, so it will call your callback with a PDU object. To avoid that I would suggest you to choose a different compiler or look for their instructions specifically for MSVC.
I finally came across a work around by casting it to Tins::Packet & in sniffer.h
if (!function((Tins::Packet &)*it->pdu())) {
return;
}

read from keyboard using boost async_read and posix::stream_descriptor

I am trying to capture single keyboard inputs in a non blocking way inside a while loop using boost asio async_read. The handler is expected to display the read characters.
My code:
#include <boost/asio/io_service.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/system/error_code.hpp>
#include <iostream>
#include <unistd.h>
#include <termios.h>
using namespace boost::asio;
void read_handler(const boost::system::error_code&, std::size_t)
{
char c;
std::cin>>c;
std::cout << "keyinput=" << c << std::endl;
}
int main()
{
io_service ioservice;
posix::stream_descriptor stream(ioservice, STDIN_FILENO);
char buf[1];
while(1)
{
async_read(stream, buffer(buf,sizeof(buf)), read_handler);
ioservice.run();
}
return 0;
}
My output is not as expected(keyinput=char format):
a
key input
b
c
d
e
Where am I going wrong?
Also the program is very cpu intensive. How to rectify it?
There's an important restriction on async IO with stdin: Strange exception throw - assign: Operation not permitted
Secondly, if you use async_read do not use std::cin at the same time (you will just do two reads). (Do look at async_wait instead).
That aside, you should be able to fix the high CPU load by using async IO properly:
#include <boost/asio.hpp>
#include <iostream>
using namespace boost::asio;
int main()
{
io_service ioservice;
posix::stream_descriptor stream(ioservice, STDIN_FILENO);
char buf[1] = {};
std::function<void(boost::system::error_code, size_t)> read_handler;
read_handler = [&](boost::system::error_code ec, size_t len) {
if (ec) {
std::cerr << "exit with " << ec.message() << std::endl;
} else {
if (len == 1) {
std::cout << "keyinput=" << buf[0] << std::endl;
}
async_read(stream, buffer(buf), read_handler);
}
};
async_read(stream, buffer(buf), read_handler);
ioservice.run();
}
As you can see the while loop has been replaced with a chain of async operations.

Sending a audio buffer using C++ Rest SDK

I recently started to use C++ Rest SDK and I'm trying to send an audio buffer to Watson Speech to Text service and the docs didn't make clear to me how to use or upload a buffer using this lib, I started using a Microsfot sample to upload files(https://msdn.microsoft.com/en-us/library/jj950081.aspx) and then a I tried to modify the code to send a buffer as the examples (https://msdn.microsoft.com/en-us/library/jj950083.aspx), but I for some how doesn't work.
This is my current code:
My current code:
#include <codecvt>
#include <cpprest/containerstream.h>
#include <cpprest/http_client.h>
#include <iostream>
#include <cpprest/producerconsumerstream.h>
#include <cpprest/rawptrstream.h>
#include <cpprest/json.h>
#include "ReqHTTP.h"
#include <sstream>
#include <fstream>
#include <Windows.h>
using namespace std;
using namespace web;
using namespace concurrency;
using namespace concurrency::streams;
using namespace web::http;
using namespace web::http::client;
using namespace utility::conversions;
#pragma comment(lib, "winmm.lib")
pplx::task<void> RequestHTTP::UploadFileToHttpServerAsync(streams::ostream outStream, LPSTR buffer)
{
container_buffer<LPSTR> outAudioBuffer(move(buffer));
return outStream.write(outAudioBuffer, outAudioBuffer.size()).then([](size_t
bytesWritten)
{
try {
http_client_config config;
credentials cred(L"c674021d-5a0f-4ec1-84a4-da6fbd50541c", L"WvYMlztHWCbC");
config.set_credentials(cred);
http_request req(methods::POST);
req.headers().add(L"Transfer-Encoding", L"chunked");
req.headers().add(L"Content-Type", L"audio/wav");
req.set_request_uri(L"speech-to-text/api/v1/recognize?continuous=true&model=pt-BR_BroadbandModel");
req.set_body(bytesWritten);
// Make HTTP request with the file stream as the body.
http_client client(L"https://stream.watsonplatform.net/", config);
//concurrency::streams::producer_consumer_buffer<uint8_t> buf;
//buf.putn_nocopy(&body[0], body.size());
return client.request(req).then([bytesWritten](pplx::task<http_response> previousTask)
{
//buffer.close;
std::wostringstream ss;
try
{
auto response = previousTask.get();
response.extract_json().then([=](json::value js) {
int i = 0;
auto campo = js.at(to_string_t("results"));
while (i < campo.size()) {
auto transc = campo.operator[](i).operator[](to_string_t("alternatives")).operator[](0);
wcout << transc.at(to_string_t("transcript")) << endl;
i++;
}
});
}
catch (const http_exception& e)
{
ss << e.what() << std::endl;
}
std::wcout << ss.str();
});
}
catch (const std::system_error& e)
{
std::wostringstream ss;
ss << e.what() << std::endl;
std::wcout << ss.str();
// Return an empty task.
return pplx::task_from_result();
}
});
}