i am using the proxygen for making a simple web server. i am restricted to use proxygen.I am using proxygen default echo server example i want to print the header values whenever a request is sent to the server. below is the code that i think i should modify.but what exactly i am unsure of.:
#include "customHandler.h"
#include <iostream>
#include <proxygen/httpserver/RequestHandler.h>
#include <proxygen/httpserver/ResponseBuilder.h>
#include <proxygen/lib/http/HTTPMessage.h>
#include <proxygen/lib/http/HTTPMethod.h>
using namespace std;
using namespace proxygen;
namespace EchoService {
EchoHandler::EchoHandler(EchoStats* stats): stats_(stats) {
}
void EchoHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept {
//------------------HERE TO MODIFY I THINK-------------------//
}
void EchoHandler::onBody(std::unique_ptr<folly::IOBuf> body) noexcept {
if (body_) {
body_->prependChain(std::move(body));
} else {
body_ = std::move(body);
}
}
/*
.header("Request-Number",
//this sets the request number
folly::to<std::string>(stats_->getRequestCount()),"test-b")*/
void EchoHandler::onEOM() noexcept {
ResponseBuilder(downstream_)
.status(200, "OK")
//Response is set Here...........ex-> .body(std::move("some Response object"))
.body(std::move(body_))
.sendWithEOM();
}
void EchoHandler::onUpgrade(UpgradeProtocol protocol) noexcept {
// handler doesn't support upgrades
}
void EchoHandler::requestComplete() noexcept {
delete this;
}
void EchoHandler::onError(ProxygenError err) noexcept {
delete this;
}
}
correct me if i am wrong.
Try this:
void EchoHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept
{
HTTPHeaders head = headers->getHeaders();
head.forEach([&] (const string& header, const string& val) {
cout << header << ": " << val<<endl;
});
}
Related
I've been looking for some time now, how to implement graphql-subscriptions in c++ without libgraphqlparser, CAFFQL or cppgraphqlgen which are the recommended libraries for graphql implementations.
Currently i am using curl for queries and mutations, which is working so far, but this wont work for subscriptions. In javascript Apollo uses a Websocket for this purpose. Is it possible to use a websocket in c++ to do something similar?
EDIT
The GraphhQL server I am currently connecting to is a 1:1 copy of this tutorial: https://www.howtographql.com/graphql-js/0-introduction/
Here is my implementation:
TestClient.hpp:
#include <string>
#include <list>
#include <curlpp/Easy.hpp>
#include "jsoncpp/json/reader.h"
class TestClient {
public:
TestClient();
virtual ~TestClient();
void login();
void subscribe();
protected:
std::string sendRequest(const std::list<std::string> &header, const std::string &graphQL);
std::string loadFile(std::string filePath);
private:
curlpp::Easy *m_request = new curlpp::Easy();
Json::Reader m_reader;
std::string m_token = "";
std::string m_grapqlLogin;
std::string m_grapqlSubscribe;
const std::string m_URL = "http://localhost:4000/graphiql";
const std::string m_headerContentType = "Content-Type: application/json";
const std::string m_headerToken = "Authorization:Bearer ";
};
TestClient.cpp:
#include "TestClient.hpp"
#include <boost/log/trivial.hpp>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Exception.hpp>
#include <fstream>
#include <exception>
#include <regex>
using namespace std;
using namespace curlpp;
TestClient::TestClient()
{
m_grapqlLogin = loadFile("./data/login.graphql");
m_grapqlSubscribe = loadFile("./data/subscribe.graphql");
}
void TestClient::login()
{
list<string> header = { m_headerContentType };
Json::Value json;
string result = sendRequest(header, m_grapqlLogin);
if(m_reader.parse(result, json, false))
{
if(json["errors"] == Json::nullValue)
{
cout << json.toStyledString() << endl;
m_token = json["data"]["login"]["token"].asString();
}
}
}
void TestClient::subscribe()
{
string headerToken = m_headerToken + m_token;
std::list<string> header = { m_headerContentType, headerToken };
Json::Value json;
string result = sendRequest(header, m_grapqlSubscribe);
if(m_reader.parse(result, json, false))
{
if(json["errors"] == Json::nullValue)
{
cout << json.toStyledString() << endl;
}
}
}
string TestClient::sendRequest(const std::list<string> &header, const string &graphQL)
{
stringstream result;
m_request->reset();
m_request->setOpt<Options::Url>(m_URL);
m_request->setOpt<Options::Post>(true);
m_request->setOpt<Options::HttpHeader>(header);
m_request->setOpt<Options::PostFields>(graphQL);
m_request->setOpt<Options::PostFieldSize>(graphQL.size());
m_request->setOpt<Options::WriteStream>(&result);
m_request->perform();
return result.str();
}
The output of this code is:
{
"data" : {
"login" : {
"token" : "a long token",
"user" : {
"email" : "alice#prisma.io",
"links" : [
{some links}
]
}
}
},
"errors" : null
}
{
"data" : {
"newLink" : null
},
"errors" : null
}
Now I don't know how to use curlpp together with subscricptions. Has someone an idea? Thank you very much.
For some reason I cannot use the "getNotify()" function attached to the "Broker" object. I added a comment to the line that is not working(in "Publisher" class). As an error I get "Error; pointer to incomplete class type is not allowed" Please help
the "Broker" class is implemented with Singleton-Pattern
Broker.h class:
#ifndef DEF_Broker
#define DEF_Broker
#include <iostream>
#include "classes.h"
using namespace std;
class Broker : Publisher
{
static Broker *instance;
Broker();
public:
static Broker* getInstance()
{
if(!instance)
{
instance = new Broker();
}
return instance;
}
void getNotify()
{
for(auto sub : SubscriberList)
{
if(t.msg == "Hello World")
{
SubCount++;
cout << SubCount << " - ";
sub->update(t.msg);
}
else if(t.msg == "Ping")
{
cout << "Ping" << endl;
sub->update("Pong");
}
}
}
};
Broker *Broker::instance = 0; // Null, because instance will be initialized on demand.
Broker::Broker(){}; // Private constructor so that no objects can be created.
#endif
classes.h :
#ifndef DEF_classes
#define DEF_classes
#include <iostream>
#include <list>
using namespace std;
class Broker;
class Subscriber
{
public:
void update(string msg)
{
cout << msg << endl;
}
};
class Topic
{
public:
string msg;
Topic(){};
Topic(string msg)
{
this->msg = msg;
}
};
class Publisher
{
protected:
list<Subscriber*> SubscriberList;
static int SubCount;
public:
Topic t;
Broker *broker;// = broker->getInstance();
Publisher(){}
Publisher(Topic t)
{
this->t = t;
};
void AddSub(Subscriber *sub)
{
SubscriberList.push_back(sub);
}
void notify(string msg)
{
broker->getNotify(); // this not working
}
};
int Publisher::SubCount = 0; // Initialize static member SubCount
#endif
Normally you would need to include broker.h in classes.h, however, this would create a circular dependency.
Therefore, implement the functions of Publisher in a .cpp file and include broker.h in that file. The forward declaration in classes.h (class broker;) needs to remain.
One possible way to solve this would be to create different files(headers and source files) for different classes. I have done this for you in this case so that you can take this example as a reference(starting point) for your future purposes/programs. Below are all the files:
Borker.h
#ifndef DEF_Broker
#define DEF_Broker
#include <iostream>
#include "Publisher.h"
class Broker : Publisher
{
static Broker *instance;
Broker();
public:
static Broker* getInstance()
{
if(!instance)
{
instance = new Broker();
}
return instance;
}
void getNotify();
};
#endif
Broker.cpp
#include "Broker.h"
#include "Subscriber.h"
Broker *Broker::instance = 0; // Null, because instance will be initialized on demand.
void Broker::getNotify()
{
for(auto sub : SubscriberList)
{
if(t.msg == "Hello World")
{
SubCount++;
std::cout << SubCount << " - ";
sub->update(t.msg);
}
else if(t.msg == "Ping")
{
std::cout << "Ping" << std::endl;
sub->update("Pong");
}
}
}
Broker::Broker()
{
}; // Private constructor so that no objects can be created.
Topic.h
#ifndef TOPIC_H
#define TOPIC_H
#include <iostream>
#include <list>
#include <string>
class Topic
{
public:
std::string msg;
Topic(){}
Topic(std::string msg);
};
#endif
Topic.cpp
#include "Topic.h"
Topic::Topic(std::string msg)
{
this->msg = msg;
}
Publisher.h
#ifndef PUBLISHER_H
#define PUBLISHER_H
#include <list>
#include "Topic.h"
class Broker;//needed for Borker *broker
class Subscriber;//needed for Subscriber*
class Publisher
{
protected:
std::list<Subscriber*> SubscriberList;
static int SubCount;
public:
Topic t;
Broker *broker;// = broker->getInstance();
Publisher(){}
Publisher(Topic t)
{
this->t = t;
};
void AddSub(Subscriber *sub);
void notify(std::string msg);
};
#endif
Publisher.cpp
#include "Publisher.h"
#include "Broker.h"//needed for broker->getNotify()
int Publisher::SubCount = 0; // Initialize static member SubCount
void Publisher::notify(std::string msg)
{
broker->getNotify(); // this not working
}
void Publisher::AddSub(Subscriber *sub)
{
SubscriberList.push_back(sub);
}
Subscriber.h
#ifndef SUBSCRIBER_H
#define SUBSCRIBER_H
#include <string>
class Subscriber
{
public:
void update(std::string msg);
};
#endif
Subscriber.cpp
#include "Subscriber.h"
#include <iostream>
void Subscriber::update(std::string msg)
{
std::cout << msg << std::endl;
}
The program compiles successfully as can be seen here.
#Ben #AnnopRana thanxs guys.
I got inspired from ur answers and i got the following solution
broker.h
#ifndef DEF_Broker
#define DEF_Broker
#include <iostream>
#include "classes.h"
using namespace std;
class Broker
{
static Broker *instance;
Broker();
public:
Publisher pub;
static Broker* getInstance()
{
if(!instance)
{
instance = new Broker();
}
return instance;
}
void getNotify()
{
for(auto sub : pub.SubscriberList)
{
if(pub.t.msg == "Hello World")
{
pub.SubCount++;
cout << pub.SubCount << " - ";
sub->Subscriber::update(pub.t.msg);
}
else if(pub.t.msg == "Ping")
{
cout << "Ping" << endl;
sub->Subscriber::update("Pong");
}
else
{
cout << "no such as topic" << endl;
}
}
}
};
Broker *Broker::instance = 0; // Null, because instance will be initialized on demand.
Broker::Broker(){}; // Private constructor so that no objects can be created.
#endif
classes.h
#ifndef DEF_classes
#define DEF_classes
#include <iostream>
#include <list>
using namespace std;
class Broker;
class Subscriber
{
public:
void update(string msg)
{
cout << msg << endl;
}
};
class Topic
{
public:
string msg;
Topic(){};
Topic(string msg)
{
this->msg = msg;
}
};
class Publisher
{
public:
list<Subscriber*> SubscriberList;
static int SubCount;
Topic t;
Publisher(){}
Publisher(Topic t)
{
this->t = t;
};
void AddSub(Subscriber *sub);
void notify(Broker *b);
};
#endif
publisher.cpp
#include "classes.h"
#include "Broker.h"//needed for broker->getNotify()
using namespace std;
int Publisher::SubCount = 0; // Initialize static member SubCount
void Publisher::notify(Broker *b)
{
b->getNotify();
}
void Publisher::AddSub(Subscriber *sub)
{
SubscriberList.push_back(sub);
}
Is it possible to redirect stdout (NOT cout!) to a stream (ostream) (NOT to a file!)
Why? I am integrating a python interpreter in my application and want to capture print() calls from python code.
I am able to redirect cout this way by using rdbuf() but printf() or print() from python is not redirected since it goes to stdout and not cout
On Linux, you can simply temporarily redirect STDOUT to a temporary file for the duration of the python script.
At the end of the python call you can read the contents of the temporary file and then dump the file.
I'm pretty sure Windows will have a similar mechanism.
Here's a first go with an attempt at some RAII to clean up all the handles.
#include <unistd.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <iostream>
void simulate_python_script() {
std::printf("Written to STDOUT I think");
}
struct auto_fd {
auto_fd(int fd)
: fd_(fd) {}
~auto_fd() {
if (fd_ != -1)
::close(fd_);
}
auto_fd(auto_fd const&) = delete;
auto_fd& operator=(auto_fd const&) = delete;
operator int() const {
return fd_;
}
int fd_;
};
struct file_closer
{
void operator()(FILE* p) const noexcept
{
::fclose(p);
}
};
using auto_fp = std::unique_ptr<FILE, file_closer>;
auto make_auto_fp(FILE* fp)
{
return auto_fp(fp, file_closer());
}
struct push_fd {
push_fd(int target, int new_fd)
: saved_(::dup(target)), target_(target) {
::dup2(new_fd, target);
}
~push_fd() {
if (saved_ != -1) {
::dup2(saved_, target_);
::close(saved_);
}
}
int saved_, target_;
};
int main() {
using namespace std::literals;
auto tempfp = make_auto_fp(::tmpfile());
auto tempfd = auto_fd(::fileno(tempfp.get()));
// redirect STDOUT to the temp file with RAII
{
push_fd fd_save(1, tempfd);
simulate_python_script();
}
// now read the file which Python thought was STDOUT
char buf[256];
while (auto count = ::read(tempfd, buf, 256)) {
if (count < 0) break; // error condition
std::cout.write(buf, count);
}
std::cout << std::endl;
}
The following source will not compile using MSVC 12.
IMCThreadMngr.cpp
#include "IMCThreadMngr.h"
CIMCThreadMngr::CIMCThreadMngr() : mService(),
mWork(mService)
{}
CIMCThreadMngr::~CIMCThreadMngr() {};
void CIMCThreadMngr::StopManager()
{
std::cout << "Manager ceasing" << std::endl;
mService.stop();
mServicethread.join();
std::cout << "Manager ceased" << std::endl;
}
void CIMCThreadMngr::StartManager()
{
mServicethread = boost::thread(boost::bind(&boost::asio::io_service::run, &mService));
}
void CIMCThreadMngr::RegisterThread(const std::string& name, int timeout)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
ThreadObject ob = ThreadObject(mService);
ob.name_ = name;
if (timeout > 0) {
ob.timeout_ = timeout;
}
else {
ob.timeout_ = 2000;
}
mThreadGroup.push_back(ob);
}
void CIMCThreadMngr::UnRegisterThread(const std::string& name)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
mThreadGroup.erase(obref);
}
}
void CIMCThreadMngr::ThreadCheckIn(const std::string& name){
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
obref->timer_.cancel();
obref->timer_.expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_.async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
}
bool CIMCThreadMngr::FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob){
for (ob = mThreadGroup.begin(); ob != mThreadGroup.end(); ob++) {
if ((ob->name_.compare(name) == 0)) {
return true;
}
}
return false;
}
void CIMCThreadMngr::TimeoutElapsed(const boost::system::error_code& e, const std::string& name){
boost::mutex::scoped_lock lock(mGroupMutex);
if (e != boost::asio::error::operation_aborted)
{
std::cout << "Thread " << name << " did has not responded" << std::endl; // Timer was not cancelled, take necessary action.
ThreadCheckIn(name);
}
}
IMCThreadMngr.h
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/mutex.hpp>
#include <vector>
class CIMCThreadMngr {
public:
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
boost::asio::deadline_timer timer_;
ThreadObject(boost::asio::io_service& service) : timer_(service)
{
timer_.expires_from_now(boost::posix_time::millisec(3000));
}
};
public:
CIMCThreadMngr();
~CIMCThreadMngr();
void StopManager();
void StartManager();
void RegisterThread(const std::string& name, int timeout);
void UnRegisterThread(const std::string& name);
void ThreadCheckIn(const std::string& name);
bool FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob);
void TimeoutElapsed(const boost::system::error_code& e, const std::string& name);
void TimeoutElapsed( );
private:
boost::asio::io_service mService;
boost::asio::io_service::work mWork;
boost::thread mServicethread;
std::vector<ThreadObject> mThreadGroup;
boost::mutex mGroupMutex;
};
The compiler issue I am running into is as follows
f:\boost\boost_1_57_0\boost\asio\basic_deadline_timer.hpp(510): error C2248: 'boost::asio::basic_io_object<TimerService,false>::operator =' : cannot access private member declared in class 'boost::asio::basic_io_object<TimerService,false>'
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
f:\boost\boost_1_57_0\boost\asio\basic_io_object.hpp(164) : see declaration of 'boost::asio::basic_io_object<TimerService,false>::operator ='
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
This diagnostic occurred in the compiler generated function 'boost::asio::basic_deadline_timer<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>,boost::asio::deadline_timer_service<Time,TimeTraits>> &boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>>::operator =(const boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>> &)'
with
[
Time=boost::posix_time::ptime, TimeTraits=boost::asio::time_traits<boost::posix_time::ptime>
]
Hopefully the issue is something fairly straight forward, though I can't find an obvious difference between my code above, and the boost examples of deadline_timer.
boost::asio::deadline_timer is neither copyable nor moveable (nor copy-assignable nor move-assignable). As a result, neither is CIMCThreadMgr::ThreadObject, which means that you cannot have a std::vector<ThreadObject>.
A simple way around this problem is to hold the deadline_timer in a shared_ptr, as in
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
// HERE
std::shared_ptr<boost::asio::deadline_timer> timer_;
ThreadObject(boost::asio::io_service& service)
// Also HERE
: timer_(std::make_shared<boost::asio::deadline_timer>(service))
{
// -> instead of . now.
timer_->expires_from_now(boost::posix_time::millisec(3000));
}
};
If you go this route, you'll also have to replace . with -> where timer_ is being used:
if (FindThreadObject(name, obref)){
// vv-- HERE
obref->timer_->cancel();
obref->timer_->expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_->async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
It is probably possible to use a std::unique_ptr, but that may require larger changes to your code than replacing . with -> in a few places (because ThreadObject would only be moveable but not copyable).
I really want to see how can those two thread functions RunThread1() & RunThread1() can run in parallel. That RunThread2() is blocked everytime RunThread1() executes or vice a versa.
I do not want to wait until future finishes hence I am using std::async along with std::move
I am using scoped_lock but I don't see that is a problem here.
I am designing an asynchronous response processing engine, one thread inserts data while another thread reads it from other end.
Any suggestions where that problem might be? Any suggestions on overall design.
#include <windows.h>
#include <string>
#include <iostream>
#include <vector>
#include <deque>
#include <chrono>
#include <thread>
#include <future>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
using namespace std;
using namespace boost;
template<typename R>
bool Is_future_ready(std::future<R> const& f)
{
return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
std::vector<std::future<void>> pending_futures;
class A
{
private:
boost::thread* myFunc1Thread;
boost::thread* myFunc2Thread;
public:
A()
{
myFunc1Thread = nullptr;
myFunc2Thread = nullptr;
}
void RunThreads();
void RunThread1();
void RunThread2();
void PopulateResponses(vector<string> responses);
void PopulateResponse(string response);
struct Record
{
char response[128];
Record(const char* response)
{
memset(this->response,0,sizeof(this->response));
strcpy(this->response, response);
}
~Record()
{
}
Record& operator= (const Record& cmd)
{
if(this == &cmd) // Same object?
{
return *this;
}
memset(this->response,0,sizeof(this->response));
strcpy(this->response, cmd.response);
return *this;
}
};
typedef deque<Record> RecordsQueue;
};
boost::mutex ResponseMutex;
A::RecordsQueue Records;
void A::RunThreads()
{
myFunc1Thread = new boost::thread(boost::bind(&A::RunThread1, this));
HANDLE threadHandle1 = myFunc1Thread->native_handle();
SetThreadPriority(threadHandle1, THREAD_PRIORITY_NORMAL);
myFunc2Thread = new boost::thread(boost::bind(&A::RunThread2, this));
HANDLE threadHandle2 = myFunc2Thread->native_handle();
SetThreadPriority(threadHandle2, THREAD_PRIORITY_NORMAL);
myFunc1Thread->join();
myFunc2Thread->join();
}
void A::PopulateResponse(string response)
{
Records.push_back(Record(response.c_str()));
}
void A::PopulateResponses(vector<string> responses)
{
boost::mutex::scoped_lock lock(ResponseMutex);
std::for_each(responses.begin(), responses.end(), bind1st(mem_fun(&A::PopulateResponse), this));
}
void A::RunThread1()
{
int i = 0;
while(true)
{
vector<string> responses;
responses.push_back(to_string(i));
cout<< "Added: " << to_string(i) << endl;
i++;
pending_futures.erase(std::remove_if( pending_futures.begin(), pending_futures.end(), Is_future_ready<void>), pending_futures.end());
auto f = std::async (std::launch::async, &A::PopulateResponses, this, responses);
pending_futures.push_back(std::move(f));
}
}
void A::RunThread2()
{
while(true)
{
boost::mutex::scoped_lock lock(ResponseMutex);
if(!Records.empty())
{
Record res = Records.front();
cout<< "Processed: " << res.response << endl;
//some lengthy processing...., let's use sleep() to depict that
boost::this_thread::sleep(boost::posix_time::seconds(1));
Records.pop_front();
}
}
}
int main()
{
A a;
a.RunThreads();
}
You're adding futures in a tight loop:
void RunThread1() {
while(true)
{
// ...
auto f = std::async (std::launch::async, &A::PopulateResponses, this, responses);
pending_futures.push_back(std::move(f));
}
}
No wonder nothing can keep up with it. The other threads are doing all the locking (thread 1 has no blocking operations, though Is_future_ready might force a thread yield, I'm not sure).
Add a sleep somewhere in the loop and you'll find that things are working as expected.
boost::this_thread::sleep_for(boost::chrono::seconds(1));
Keep in mind that this is still brittle: it depends on timings to be correct. To be more generally robust, use a proper message/task queue and block the pushing side when the queue is full.