To use ArangoDB from C++ I'm leveraging httplib to interact with the database's http interface. Example queries like those found in the docs are straight-forward using curl:
curl --user root:test123 --data #- -X POST --dump - http://localhost:8529/_db/Getting-Started/_api/cursor <<EOF
{ "query" : "FOR u IN Airports LIMIT 2 RETURN u", "count" : true, "batchSize" : 2 }
EOF
I'm having difficulty translating the above to C++ code using httplib. As mentioned in the docs the "query" is part of the request body so my best attempt is:
#include "httplib.h"
#include <iostream>
int main()
{
httplib::Client cli("localhost", 8529);
cli.set_basic_auth("root", "test123");
httplib::Params params;
params.emplace(
"query",
"FOR u IN Airports LIMIT 2 RETURN u");
auto res = cli.Post(
"/_db/Getting-Started/_api/cursor", params);
std::cout << res->status << std::endl;
std::cout << res->body << std::endl;
}
The above program succeeds with connection and authentication, but the result is:
400
{"code":400,"error":true,"errorMessage":"VPackError error: Expecting digit","errorNum":600}
How can I properly translate the curl command to httplib code?
Related
Can anyone tell me the answer, I have been unable to eat for a few days, thank you for being my benefactor
I'm using the mysql-connector-c++ 8.0 to mysql 8.0.x
I want to connect to a remote cloud database. After trying countless times, I have encountered great difficulties. Is there something wrong with my code? I am a newbie to msyql
The strange thing is that mysql - h xxx - root - p can be executed on the linux command
line, but it fails in c++ alone, and the error is always one:
CDK Error: Connection attempt to the server was aborted. Timeout of 10000 milliseconds was exceeded
#include <iostream>
#include <string>
#include <list>
#include <cstdlib>
#include <mysqlx/xdevapi.h>
using namespace mysqlx;
int main() {
try {
Session sess(SessionOption::USER, "root",
SessionOption::PWD, "123456",
SessionOption::HOST, "172.29.207.112",
//SessionOption::HOST, "rm-bp1qp1x588kzb49rf.mysql.rds.aliyuncs.com",
SessionOption::PORT, 33060,
SessionOption::DB, "demo");
auto result = sess.sql("select * from person").execute();
for (auto row : result.fetchAll()) {
std::cout << row[0] << " " << row[1] << "\n";
}
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
}
I finally know the answer. The reason is that the cloud database provider does not support 33060 of X Protocol. Currently, Alibaba Cloud does not support it. I learned this from the intelligent problem robot, but it is not mentioned in the document. Alibaba Cloud should update documentation! !
This is a purely aesthetic issue.
I have written a CLI program in C++ and use boost::program_options to pasrse its args.
Per default, boost names all meta variables arg. I'd like to change that.
Here's the code:
#include <iostream>
using std::cerr;
using std::cout;
#include <optional>
using std::optional;
#include <string>
using std::string;
#include <boost/program_options.hpp>
using boost::program_options::unknown_option;
#include "Net.h"
#include "GameServer.h"
using proto::GameServer;
namespace args = boost::program_options;
static auto parseArgs(int argc, const char *argv[])
{
args::options_description desc("Command line options");
desc.add_options()
("help,h", "Show this page")
("address,a", args::value<string>()->default_value(net::Defaults::HOST), "IP address to listen on")
("port,p", args::value<unsigned short>()->default_value(net::Defaults::PORT), "Port to listen on")
;
optional<args::variables_map> result;
args::variables_map varMap;
try {
args::store(args::parse_command_line(argc, argv, desc), varMap);
} catch (unknown_option const &error) {
cerr << "Invalid option: " << error.get_option_name() << "\n";
cerr << desc << "\n";
return result;
}
args::notify(varMap);
if (varMap.count("help")) {
cout << desc << "\n";
return result;
}
return result = varMap;
}
int main(int argc, const char *argv[])
{
auto parsedArgs = parseArgs(argc, argv);
if (!parsedArgs.has_value())
return 1;
auto args = parsedArgs.value();
auto address = args.at("address").as<string>();
auto port = args.at("port").as<unsigned short>();
GameServer server(address, port);
server.listen();
}
And the output generated by the help page:
Command line options:
-h [ --help ] Show this page
-a [ --address ] arg (=127.0.0.1) IP address to listen on
-p [ --port ] arg (=9000) Port to listen on
I'd like to rename arg for -a to ip_address and for -p to portnum respectively.
#prehistoricpenguin's answer brought me onto the right track. In boost, the typed_value class has a method value_name() to set the argument name, which works analogous to setting the defaults, i.e. it modifies the value object and returns it for subsequent operations:
static auto parseArgs(int argc, const char *argv[])
{
options_description desc("Command line options");
desc.add_options()
("help,h", "Show this page")
("address,a", value<string>()->default_value(HOST)->value_name("ip_address"),
"IP address to connect to")
("port,p", value<unsigned short>()->default_value(PORT)->value_name("portnum"),
"Port to connect to");
return parseArgDesc(argc, argv, desc);
}
Resulting in:
Command line options:
-h [ --help ] Show this page
-a [ --address ] ip_address (=127.0.0.1)
IP address to connect to
-p [ --port ] portnum (=9000) Port to connect to
Seems it's an undocumented part of boost::program_options, I have a quick look at the implementation of boost::program_options and find there is a global variable which is used to control the behavior, so we come up with one line code hack:
args::arg = "i_am_not_arg";
Modify a global variable is not an elegant way, but I haven't found any usable APIs to do it, you may do more research and try to find a better solution(Don't forget to notify me here!)
Insert this line in some place of your code, then we get the output for --help command line:
->./a.out --help
Command line options:
-h [ --help ] Show this page
-a [ --address ] i_am_not_arg (=1234) IP address to listen on
-p [ --port ] i_am_not_arg (=42) Port to listen on
Suggestions for asking question on SO:
provide a minimal, reproducible program. Your code doesn't compile on my machine, because you used variables from files that are not provided.
Online demo
I'm building an embedded python application in C++, using boost::python. The embedded environment exports part of itself as a module, in other words the python code that runs in the environment won't run in a standard python env as the embedded module can't be imported.
One of the features that would be really helpful for debugging would be a debug shell, where I can break out and manually input standard python expressions to inspect/modify the current state. The problem I have is that I don't/can't know in advance whether it's an eval (e.g. "2+2") or an exec (e.g. "a=2+2"). If I exec("2+2") I don't get the result, and if I eval("a=2+2") I get a syntax error. (Coming from a C background I don't quite understand why this distinction exists). Trying eval first, then exec if it fails, seems like a very dubious solution not least because of side effects.
As far as I can see boost::python simply replicates python's eval/exec functions, so this problem is more at the python level, but the answer I'm hoping to get is how to do it at the C++ (ideally boost) level. Is there some horrendously complicated regex that could be used to differentiate exec-able from eval-able code? For now I'm just going with the ugly solution of making the user decide with a prefix on the expression.
Here's an MCVE with a TODO at the point where I need to choose between eval and exec (obv. requires python-dev and boost_python libs)
// g++ $(python3-config --cflags) so.cpp -fPIC -lboost_python3 $(python3-config --ldflags)
#include <boost/python.hpp>
#include <string>
#include <iostream>
namespace py = boost::python;
std::string pyobject_to_string(PyObject* obj)
{
PyObject* repr = PyObject_Str(obj);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);
Py_XDECREF(repr);
Py_XDECREF(str);
return std::string(bytes);
}
int main(int argc, const char** argv)
{
// Init python env
Py_Initialize();
if (argc < 2)
{
return 1;
}
try
{
// TODO decide, based on argv[1], which needs to be called, this:
py::object res = py::eval(argv[1]);
std::cout << pyobject_to_string(res.ptr()) << std::endl;
// or this:
py::exec(argv[1]);
// or something else entirely...?
}
catch(py::error_already_set&)
{
if (PyErr_Occurred())
{
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
std::string message = pyobject_to_string(type) + ":" + pyobject_to_string(value);
//PyErr_Restore(type, value, traceback);
std::cerr << message << std::endl;
}
else
{
std::cerr << "unknown error" << std::endl;
return 1;
}
}
}
Example output is:
$ ./a.out 2+2
4
$ ./a.out a=2+2
<class 'SyntaxError'>:('invalid syntax', ('<string>', 1, 2, 'a=2+2'))
Many thanks in advance
I'm doing some code where i need to do a GET request and manipulate the info received. For this i'm using C++ REST SDK (codename "Casablanca") for the request
This is my code
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
using namespace utility;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace concurrency::streams;
//This method i saw on the Microsoft documentation
pplx::task<void> HTTPStreamingAsync()
{
http_client client(L"http://localhost:10000/Something"); //The api is running at the moment
// Make the request and asynchronously process the response.
return client.request(methods::GET).then([](http_response response)
{
// Print the status code.
std::wostringstream ss;
ss << L"Server returned returned status code " << response.status_code() << L'.' << std::endl;
std::wcout << ss.str();
// TODO: Perform actions here reading from the response stream.
auto bodyStream = response.body();
// In this example, we print the length of the response to the console.
ss.str(std::wstring());
ss << L"Content length is " << response.headers().content_length() << L" bytes." << std::endl;
std::wcout << ss.str();
});
}
void main(int argc, char **argv)
{
HTTPStreamingAsync().wait();
//...
}
And when i use debug i get error on the following line:
return client.request(methods::GET).then([](http_response response)
With debug i see that variable "client" has content, but i still receive this error:
Image with the Error Message
I google it the error, and most of the people say that it is error on the code (trying to access some parts of the memory)...
Any ideas?
This issue can happen when the cpprestsdk DLL is build with Multi-Threaded DLL /MD and the calling library is build with Multi-Threaded /MT. Since the cpprestsdk does not offer a configuration for a .lib file, you are forced to use /MD. At least that is best to my knowledge, as I haven't been able to compile cpprestsdk.lib out of the box without a bunch of linker errors.
I am trying to unzip a file from a network stream using POCO C++ library on Ubuntu Linux, but decompressing fails with "Illegal state" exception. HTTPResponse status and reason are 302 Moved Temporarily. At the same time i can download and unzip the link with a browser. What should i do with HTTPClientSession when HTTPResponse is in such state?
...
HTTPResponse res;
std::istream& rs = h_ses.receiveResponse (res);
if (res.getStatus () != HTTPResponse::HTTP_OK) {
poco_error (logger, "http response status: " + std::to_string (res.getStatus ()) + " " + res.getReason ());
}
if (!rs) {
poco_error (logger, "responese stream is in bad state: " + std::to_string (rs.rdstate()));
}
Decompress dec (rs, target_dir_.native ());
poco_debug (logger, "Unzipping: " + dl + " ...");
dec.EError += Poco::Delegate<Addon_Loader, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &Addon_Loader::on_decompress_error);
dec.decompressAllFiles ();
...
You can do it with HTTPStreamFactory; here's a full example:
#include "Poco/URI.h"
#include "Poco/URIStreamOpener.h"
#include "Poco/Net/HTTPStreamFactory.h"
#include "Poco/StreamCopier.h"
#include <iostream>
#include <memory>
using namespace Poco;
using namespace Poco::Net;
int main()
{
URIStreamOpener opener;
opener.registerStreamFactory("http", new HTTPStreamFactory);
URI uri("http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F");
std::auto_ptr<std::istream> pStr(opener.open(uri));
StreamCopier::copyStream(*pStr.get(), std::cout);
return 0;
}
If you have to use HTTPClientSession, look at how HTTPStreamFactory does it.
In the 302 response, there should be a header field which points out the new location. You simply have to follow that link instead.
See e.g. this link, or this Wikipedia page, and of course the actual HTTP 1.1 RFC.