c++ - How to wait for WebSocket response in PNaCl -
i'm implementing "wait websocket response before continuation" mechanism on pnacl plugin through pp::websocketapi in ppapi. following simplified version stores replied data global std::string, while function myecho() sends string through websocket , polling until global string changes. driver web page same in websocket example in nacl sdk.
#include <string> #include "ppapi/cpp/instance.h" #include "ppapi/cpp/module.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_array_buffer.h" #include "ppapi/utility/websocket/websocket_api.h" class mywebsocketreceivelistener { public: virtual void onwebsocketdatareceived(const std::string& data) = 0; }; class mywebsocketapi : protected pp::websocketapi { public: mywebsocketapi(pp::instance* ppinstance, mywebsocketreceivelistener* recvlistener) : pp::websocketapi(ppinstance), m_onreceivelistener(recvlistener), m_ppinstance(ppinstance) {} virtual ~mywebsocketapi() {} bool isconnected() { return pp::websocketapi::getreadystate() == pp_websocketreadystate_open; } void open(const std::string& url) { pp::websocketapi::connect(url, null, 0); } void close() { pp::websocketapi::close(pp_websocketstatuscode_normal_closure, "bye"); } void senddata(const std::string& data) { pp::websocketapi::send(data); } protected: virtual void websocketdidopen() { m_ppinstance->postmessage("connected"); } virtual void websocketdidclose(bool wasclean, uint16_t code, const pp::var& reason) {} virtual void handlewebsocketmessage(const pp::var& message) { if (message.is_array_buffer()) { pp::vararraybuffer vararybuf(message); char *data = static_cast<char*>(vararybuf.map()); std::string datastr(data, data + vararybuf.bytelength()); vararybuf.unmap(); m_onreceivelistener->onwebsocketdatareceived(datastr); } else { // string m_onreceivelistener->onwebsocketdatareceived(message.asstring()); } } virtual void handlewebsocketerror() {} private: mywebsocketapi(const mywebsocketapi&); mywebsocketapi& operator=(const mywebsocketapi&); mywebsocketreceivelistener* const m_onreceivelistener; pp::instance * const m_ppinstance; }; static std::string g_returnval; class myppplugininstance : public pp::instance, public mywebsocketreceivelistener { public: explicit myppplugininstance(pp_instance instance) : pp::instance(instance), rpcwebsocket_(this, this) {} virtual ~myppplugininstance() {} virtual void handlemessage(const pp::var& var_message); virtual void onwebsocketdatareceived(const std::string& data) { g_returnval = data; } private: bool isconnected() { return rpcwebsocket_.isconnected(); } void open(const std::string& url) { rpcwebsocket_.open(url); postmessage(pp::var("connecting...")); } void close() { if (!isconnected()) return; rpcwebsocket_.close(); } mywebsocketapi rpcwebsocket_; }; std::string myecho(pp::instance* inst, mywebsocketapi& ws, const std::string& in) { ws.senddata(in); while (g_returnval.empty()) { usleep(1000 * 1000); // 1 sec inst->postmessage("waiting response..."); } return g_returnval; } void myppplugininstance::handlemessage(const pp::var& var_message) { if (!var_message.is_string()) return; std::string message = var_message.asstring(); // message must contain command character followed ';' , // arguments "x;arguments". if (message.length() < 2 || message[1] != ';') return; switch (message[0]) { case 'o': // command 'o' requests open specified url. // url passed argument "o;url". open(message.substr(2)); break; case 'c': // command 'c' requests close without argument "c;" close(); break; case 'b': case 't': postmessage(std::string("calling remote echo ") + message.substr(2)); std::string ret(myecho(this, rpcwebsocket_, message.substr(2))); postmessage(ret); break; } } // creates myppplugininstance objects when invoked. class mypppluginmodule : public pp::module { public: mypppluginmodule() : pp::module() {} virtual ~mypppluginmodule() {} virtual pp::instance* createinstance(pp_instance instance) { return new myppplugininstance(instance); } }; // implement required pp::createmodule function creates our specific // kind of module. namespace pp { module* createmodule() { return new mypppluginmodule(); } } // namespace pp however, approach didn't work. after connecting echo test server ws://echo.websocket.org , send "hello", get
connecting... connected calling remote echo hello waiting response... waiting response... waiting response... waiting response... waiting response... (never replies)
i used hand-crafted websocket server test, , message sent server successfully. , in addition usleep() polling in attached snippet, i've tried use pthread_cond_wait() , pthread_cond_signal() wait , notify received message.
what should "wait pp::websocketapi receive data" correctly?
the function myecho() blocks myppplugininstance::handlemessage() , somehow in turn blocks receiving websocket.
i added pp::simplethread new data member of class myppplugininstance , dispatch myecho() thread through pp::simplethread::message_loop().postwork(). works smoothly.
Comments
Post a Comment