Modify drogon_ctl

This commit is contained in:
antao 2018-08-22 14:27:45 +08:00
parent 17e15d282b
commit aa8170ff18
12 changed files with 335 additions and 82 deletions

View File

@ -27,7 +27,9 @@ std::string create::detail()
"drogon_ctl create controller [-s] [-n <namespace>] <class_name> //"
"create HttpSimpleController source files\n"
"drogon_ctl create controller -a <[namespace::]class_name> //"
"create HttpApiController source files\n";
"create HttpApiController source files\n"
"drogon_ctl create controller -w [-n <namespace>] <class_name> //"
"create WebSocketController source files\n";
}
void create::handleCommand(std::vector<std::string> &parameters)

View File

@ -39,6 +39,12 @@ void create_controller::handleCommand(std::vector<std::string> &parameters)
parameters.erase(iter);
break;
}
else if(*iter=="-w"||*iter=="--websocket")
{
type=WebSocket;
parameters.erase(iter);
break;
}
else if(*iter=="-n"||*iter=="--namespace")
{
if(type==Simple)
@ -87,6 +93,37 @@ void create_controller::handleCommand(std::vector<std::string> &parameters)
}
createSimpleController(parameters,namespaceName);
}
else if(type==WebSocket)
{
std::string namespaceName;
for(auto iter=parameters.begin();iter!=parameters.end();iter++)
{
if((*iter)[0]=='-')
{
if(*iter=="-n"||*iter=="--namespace")
{
iter=parameters.erase(iter);
if(iter!=parameters.end())
{
namespaceName=*iter;
iter=parameters.erase(iter);
break;
}
else
{
std::cout<<"please enter namespace"<<std::endl;
return;
}
}else
{
std::cout<<ARGS_ERROR_STR<<std::endl;
return;
}
}
}
createSimpleController(parameters,namespaceName);
}
else
createApiController(parameters);
}
@ -118,15 +155,59 @@ void create_controller::createSimpleController(const std::string &ctlName,const
newSimpleControllerHeaderFile(oHeadFile,ctlName,namespaceName);
newSimpleControllerSourceFile(oSourceFile,ctlName,namespaceName);
}
void create_controller::createWebsockController(std::vector<std::string> &ctlNames,const std::string &namespaceName)
{
for(auto iter=ctlNames.begin();iter!=ctlNames.end();iter++)
{
if ((*iter)[0] == '-')
{
std::cout<<ARGS_ERROR_STR<<std::endl;
return;
}
}
for(auto ctlName:ctlNames)
{
createWebsockController(ctlName,namespaceName);
}
}
void create_controller::createWebsockController(const std::string &ctlName,const std::string &namespaceName)
{
std::cout<<"create websocket controller:"<<namespaceName<<(namespaceName==""?"":"::")<<ctlName<<std::endl;
std::string headFileName=ctlName+".h";
std::string sourceFilename=ctlName+".cc";
std::ofstream oHeadFile(headFileName.c_str(),std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(),std::ofstream::out);
if(!oHeadFile||!oSourceFile)
return;
newWebsockControllerHeaderFile(oHeadFile,ctlName,namespaceName);
newWebsockControllerSourceFile(oSourceFile,ctlName,namespaceName);
}
void create_controller::newSimpleControllerHeaderFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName)
{
file<<"#pragma once\n";
file<<"#include <drogon/HttpSimpleController.h>\n";
file<<"using namespace drogon;\n";
std::string indent="";
if(namespaceName!="") {
file << "namespace " << namespaceName << "{\n";
indent=" ";
auto namespace_name=namespaceName;
if(namespace_name!="") {
auto pos=namespace_name.find("::");
while(pos!=std::string::npos)
{
auto namespaceI=namespace_name.substr(0,pos);
namespace_name=namespace_name.substr(pos+2);
file<<indent<<"namespace "<<namespaceI<<"\n";
file<<indent<<"{\n";
indent.append(" ");
pos=namespace_name.find("::");
}
if(!namespace_name.empty())
{
file<<indent<<"namespace "<<namespace_name<<"\n";
file<<indent<<"{\n";
indent.append(" ");
}
}
file<<indent<<"class "<<ctlName<<":public drogon::HttpSimpleController<"<<ctlName<<">\n";
file<<indent<<"{\n";
@ -139,8 +220,12 @@ void create_controller::newSimpleControllerHeaderFile(std::ofstream &file,const
file<<indent<<" //PATH_ADD(\"/path\",\"filter1\",\"filter2\",...);\n";
file<<indent<<" PATH_LIST_END\n";
file<<indent<<"};\n";
if(namespaceName!="")
file<<"}\n";
if(indent=="")
return;
do {
indent.resize(indent.length()-4);
file<<indent<<"}\n";
} while(indent!="");
}
void create_controller::newSimpleControllerSourceFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName)
{
@ -152,6 +237,70 @@ void create_controller::newSimpleControllerSourceFile(std::ofstream &file,const
file<<" //write your application logic here\n";
file<<"}";
}
void create_controller::newWebsockControllerHeaderFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName)
{
file<<"#pragma once\n";
file<<"#include <drogon/HttpWebsocketController.h>\n";
file<<"using namespace drogon;\n";
std::string indent="";
auto namespace_name=namespaceName;
if(namespace_name!="") {
auto pos=namespace_name.find("::");
while(pos!=std::string::npos)
{
auto namespaceI=namespace_name.substr(0,pos);
namespace_name=namespace_name.substr(pos+2);
file<<indent<<"namespace "<<namespaceI<<"\n";
file<<indent<<"{\n";
indent.append(" ");
pos=namespace_name.find("::");
}
if(!namespace_name.empty())
{
file<<indent<<"namespace "<<namespace_name<<"\n";
file<<indent<<"{\n";
indent.append(" ");
}
}
file<<indent<<"class "<<ctlName<<":public drogon::HttpWebsocketController<"<<ctlName<<">\n";
file<<indent<<"{\n";
file<<indent<<"public:\n";
//TestController(){}
// virtual void handleNewMessage(const WebSocketConnectionPtr&,
// trantor::MsgBuffer*)=0;
// //on new connection or after disconnect
// virtual void handleConnection(const WebSocketConnectionPtr&)=0;
file<<indent<<" virtual void handleNewMessage(const WebSocketConnectionPtr&,\n";
file<<indent<<" trantor::MsgBuffer*)override;\n";
file<<indent<<" virtual void handleConnection(const WebSocketConnectionPtr&)override;\n";
file<<indent<<" WS_PATH_LIST_BEGIN\n";
file<<indent<<" //list path definations here;\n";
file<<indent<<" //WS_PATH_ADD(\"/path\");\n";
file<<indent<<" WS_PATH_LIST_END\n";
file<<indent<<"};\n";
if(indent=="")
return;
do {
indent.resize(indent.length()-4);
file<<indent<<"}\n";
} while(indent!="");
}
void create_controller::newWebsockControllerSourceFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName)
{
file<<"#include \""<<ctlName<<".h\"\n";
if(namespaceName!="")
file<<"using namespace "<<namespaceName<<";\n";
file<<"void "<<ctlName<<"::handleNewMessage(const WebSocketConnectionPtr& wsConnPtr,trantor::MsgBuffer* buffer)\n";
file<<"{\n";
file<<" //write your application logic here\n";
file<<"}";
file<<"void "<<ctlName<<"::handleConnection(const WebSocketConnectionPtr& wsConnPtr)\n";
file<<"{\n";
file<<" //write your application logic here\n";
file<<"}";
}
void create_controller::createApiController(std::vector<std::string> &apiClasses)
{
for(auto iter=apiClasses.begin();iter!=apiClasses.end();iter++)

View File

@ -27,14 +27,21 @@ namespace drogon_ctl
protected:
enum ControllerType{
Simple=0,
API
API,
WebSocket
};
void createSimpleController(std::vector<std::string> &ctlNames,const std::string &namespaceName="");
void createSimpleController(const std::string &ctlName,const std::string &namespaceName="");
void createWebsockController(std::vector<std::string> &ctlNames,const std::string &namespaceName="");
void createWebsockController(const std::string &ctlName,const std::string &namespaceName="");
void createApiController(std::vector<std::string> &apiClasses);
void createApiController(const std::string &className);
void newSimpleControllerHeaderFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName="");
void newSimpleControllerSourceFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName="");
void newWebsockControllerHeaderFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName="");
void newWebsockControllerSourceFile(std::ofstream &file,const std::string &ctlName,const std::string &namespaceName="");
void newApiControllerHeaderFile(std::ofstream &file,const std::string &className);
void newApiControllerSourceFile(std::ofstream &file,const std::string &className,const std::string &filename);

View File

@ -20,7 +20,7 @@
#include <string>
#include <memory>
namespace drogon{
class WebSocketConnection:public trantor::NonCopyable
class WebSocketConnection
{
public:
WebSocketConnection()= default;

View File

@ -16,6 +16,7 @@
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/WebSocketConnection.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/TcpConnection.h>
#include <string>
@ -38,8 +39,11 @@ namespace drogon
class WebSocketControllerBase:public virtual DrObjectBase
{
public:
virtual void handleNewMessage(const TcpConnectionPtr&,
MsgBuffer*)=0;
//on new data received
virtual void handleNewMessage(const WebSocketConnectionPtr&,
trantor::MsgBuffer*)=0;
//on new connection or after disconnect
virtual void handleConnection(const WebSocketConnectionPtr&)=0;
virtual ~WebSocketControllerBase(){}
};

View File

@ -15,8 +15,8 @@
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpClientImpl.h"
#include "WebSockectConnectionImpl.h"
#include <drogon/utils/Utilities.h>
#include <drogon/WebSocketController.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpRequest.h>
@ -69,7 +69,11 @@ namespace drogon
private:
std::vector<std::tuple<std::string,uint16_t,bool>> _listeners;
void onAsyncRequest(const HttpRequestPtr& req,const std::function<void (HttpResponse &)> & callback);
void onNewWebsockRequest(const HttpRequestPtr& req,const std::function<void (HttpResponse &)> & callback);
void onNewWebsockRequest(const HttpRequestPtr& req,
const std::function<void (HttpResponse &)> & callback,
const WebSocketConnectionPtr &wsConnPtr);
void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr,trantor::MsgBuffer *buffer);
void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr);
void readSendFile(const std::string& filePath,const HttpRequestPtr& req, HttpResponse* resp);
void addApiPath(const std::string &path,
const HttpApiBinderBasePtr &binder,
@ -349,8 +353,9 @@ void HttpAppFrameworkImpl::run()
}
serverPtr->setIoLoopNum(_threadNum);
serverPtr->setHttpAsyncCallback(std::bind(&HttpAppFrameworkImpl::onAsyncRequest,this,_1,_2));
serverPtr->setNewWebsocketCallback(std::bind(&HttpAppFrameworkImpl::onNewWebsockRequest,this,_1,_2));
serverPtr->setNewWebsocketCallback(std::bind(&HttpAppFrameworkImpl::onNewWebsockRequest,this,_1,_2,_3));
serverPtr->setWebsocketMessageCallback(std::bind(&HttpAppFrameworkImpl::onWebsockMessage,this,_1,_2));
serverPtr->setDisconnectWebsocketCallback(std::bind(&HttpAppFrameworkImpl::onWebsockDisconnect,this,_1));
serverPtr->start();
servers.push_back(serverPtr);
#endif
@ -416,32 +421,69 @@ void HttpAppFrameworkImpl::doFilters(const std::vector<std::string> &filters,
}
doFilterChain(filterPtrs,req,callback,needSetJsessionid,session_id,missCallback);
}
void HttpAppFrameworkImpl::onNewWebsockRequest(const HttpRequestPtr& req,const std::function<void (HttpResponse &)> & callback)
void HttpAppFrameworkImpl::onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr)
{
auto wsConnImplPtr=std::dynamic_pointer_cast<WebSocketConnectionImpl>(wsConnPtr);
assert(wsConnImplPtr);
auto ctrl=wsConnImplPtr->controller();
if(ctrl)
{
ctrl->handleConnection(wsConnPtr);
wsConnImplPtr->setController(WebSocketControllerBasePtr());
}
}
void HttpAppFrameworkImpl::onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr,
trantor::MsgBuffer *buffer)
{
auto wsConnImplPtr=std::dynamic_pointer_cast<WebSocketConnectionImpl>(wsConnPtr);
assert(wsConnImplPtr);
auto ctrl=wsConnImplPtr->controller();
if(ctrl)
ctrl->handleNewMessage(wsConnPtr,buffer);
}
void HttpAppFrameworkImpl::onNewWebsockRequest(const HttpRequestPtr& req,
const std::function<void (HttpResponse &)> & callback,
const WebSocketConnectionPtr &wsConnPtr)
{
// magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
// sha1 = hashlib.sha1()
// sha1.update(ws_key + magic)
// return base64.b64encode(sha1.digest())
std::string wsKey=req->getHeader("Sec-WebSocket-Key");
if(!wsKey.empty())
{
// magic="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
unsigned char accKey[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()), wsKey.length(), accKey);
auto base64Key=base64_encode(accKey,SHA_DIGEST_LENGTH);
auto resp=HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k101,"Switching Protocols");
resp->addHeader("Upgrade","websocket");
resp->addHeader("Connection","Upgrade");
resp->addHeader("Sec-WebSocket-Accept",base64Key);
callback(*resp);
} else{
HttpResponseImpl resp;
resp.setStatusCode(HttpResponse::k404NotFound);
resp.setCloseConnection(true);
callback(resp);
WebSocketControllerBasePtr ctrlPtr;
{
std::string pathLower(req->path());
std::transform(pathLower.begin(),pathLower.end(),pathLower.begin(),tolower);
std::lock_guard<std::mutex> guard(_websockCtrlMutex);
if(_websockCtrlMap.find(pathLower)!=_websockCtrlMap.end())
{
ctrlPtr=_websockCtrlMap[pathLower];
}
}
if(ctrlPtr)
{
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
unsigned char accKey[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()), wsKey.length(), accKey);
auto base64Key=base64_encode(accKey,SHA_DIGEST_LENGTH);
auto resp=HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k101,"Switching Protocols");
resp->addHeader("Upgrade","websocket");
resp->addHeader("Connection","Upgrade");
resp->addHeader("Sec-WebSocket-Accept",base64Key);
callback(*resp);
auto wsConnImplPtr=std::dynamic_pointer_cast<WebSocketConnectionImpl>(wsConnPtr);
assert(wsConnImplPtr);
wsConnImplPtr->setController(ctrlPtr);
ctrlPtr->handleConnection(wsConnPtr);
return;
}
}
HttpResponseImpl resp;
resp.setStatusCode(HttpResponse::k404NotFound);
resp.setCloseConnection(true);
callback(resp);
}
void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestPtr& req,const std::function<void (HttpResponse &)> & callback)
{

View File

@ -29,6 +29,7 @@
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include <trantor/utils/MsgBuffer.h>
#include <drogon/WebSocketConnection.h>
using namespace trantor;
namespace drogon
@ -132,13 +133,13 @@ namespace drogon
}
return false;
}
bool isWebsock()
WebSocketConnectionPtr webSocketConn()
{
return _isWebsock;
return _websockConnPtr;
}
void setIsWebsock(bool val)
void setWebsockConnection(const WebSocketConnectionPtr &conn)
{
_isWebsock=val;
_websockConnPtr=conn;
}
private:
bool processRequestLine(const char *begin, const char *end);
@ -150,7 +151,7 @@ namespace drogon
HttpResponseParseState res_state_;
HttpResponseImpl response_;
bool _firstRequest=true;
bool _isWebsock=false;
WebSocketConnectionPtr _websockConnPtr;
};
}

View File

@ -193,13 +193,17 @@ void HttpResponseImpl::appendToBuffer(MsgBuffer* output) const
output->append("\r\n");
snprintf(buf, sizeof buf, "Content-Length: %lu\r\n", _body.size());
output->append(buf);
if (_closeConnection) {
output->append("Connection: close\r\n");
} else {
if(_headers.find("Connection")==_headers.end())
{
if (_closeConnection) {
output->append("Connection: close\r\n");
} else {
output->append("Connection: Keep-Alive\r\n");
output->append("Connection: Keep-Alive\r\n");
}
}
for (auto it = _headers.begin();
it != _headers.end();
++it) {

View File

@ -43,6 +43,16 @@ static void defaultHttpAsyncCallback(const HttpRequestPtr&,const std::function<v
callback(resp);
}
static void defaultWebSockAsyncCallback(const HttpRequestPtr&,
const std::function<void( HttpResponse& resp)> & callback,
const WebSocketConnectionPtr& wsConnPtr)
{
HttpResponseImpl resp;
resp.setStatusCode(HttpResponse::k404NotFound);
resp.setCloseConnection(true);
callback(resp);
}
@ -51,7 +61,7 @@ HttpServer::HttpServer(EventLoop* loop,
const std::string& name)
: server_(loop, listenAddr, name.c_str()),
httpAsyncCallback_(defaultHttpAsyncCallback),
newWebsocketCallback_(defaultHttpAsyncCallback)
newWebsocketCallback_(defaultWebSockAsyncCallback)
{
server_.setConnectionCallback(
std::bind(&HttpServer::onConnection, this, _1));
@ -81,9 +91,9 @@ void HttpServer::onConnection(const TcpConnectionPtr& conn)
HttpContext* context = any_cast<HttpContext>(conn->getMutableContext());
// LOG_INFO << "###:" << string(buf->peek(), buf->readableBytes());
if(context->isWebsock())
if(context->webSocketConn())
{
//TODO websock disconnect !
disconnectWebsocketCallback_(context->webSocketConn());
}
conn->setContext(std::string("None"));
}
@ -95,10 +105,10 @@ void HttpServer::onMessage(const TcpConnectionPtr& conn,
HttpContext* context = any_cast<HttpContext>(conn->getMutableContext());
// LOG_INFO << "###:" << string(buf->peek(), buf->readableBytes());
if(context->isWebsock())
if(context->webSocketConn())
{
//websocket payload,we shouldn't parse it
//TODO websock message callback;
webSocketMessageCallback_(context->webSocketConn(),buf);
return;
}
if (!context->parseRequest(buf)) {
@ -113,16 +123,17 @@ void HttpServer::onMessage(const TcpConnectionPtr& conn,
context->requestImpl()->setReceiveDate(trantor::Date::date());
if(context->firstReq()&&isWebSocket(conn,context->request()))
{
auto wsConn=std::make_shared<WebSocketConnectionImpl>(conn);
newWebsocketCallback_(context->request(),[=](HttpResponse &resp) mutable
{
if(resp.statusCode()==HttpResponse::k101)
{
context->setIsWebsock(true);
context->setWebsockConnection(wsConn);
}
MsgBuffer buffer;
((HttpResponseImpl &)resp).appendToBuffer(&buffer);
conn->send(buffer.peek(),buffer.readableBytes());
});
},wsConn);
}
else
onRequest(conn, context->request());

View File

@ -15,6 +15,7 @@
#pragma once
#include "WebSockectConnectionImpl.h"
#include <drogon/config.h>
#include <trantor/net/TcpServer.h>
#include <trantor/utils/NonCopyable.h>
@ -34,6 +35,15 @@ namespace drogon
public:
typedef std::function< void (const HttpRequestPtr&,const std::function<void (HttpResponse &)>&)> HttpAsyncCallback;
typedef std::function< void (const HttpRequestPtr&,
const std::function<void (HttpResponse &)>&,
const WebSocketConnectionPtr &)>
WebSocketNewAsyncCallback;
typedef std::function< void (const WebSocketConnectionPtr &)>
WebSocketDisconnetCallback;
typedef std::function< void (const WebSocketConnectionPtr &,trantor::MsgBuffer *)>
WebSocketMessageCallback;
HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const std::string& name);
@ -46,10 +56,18 @@ namespace drogon
{
httpAsyncCallback_= cb;
}
void setNewWebsocketCallback(const HttpAsyncCallback& cb)
void setNewWebsocketCallback(const WebSocketNewAsyncCallback& cb)
{
newWebsocketCallback_=cb;
}
void setDisconnectWebsocketCallback(const WebSocketDisconnetCallback& cb)
{
disconnectWebsocketCallback_=cb;
}
void setWebsocketMessageCallback(const WebSocketMessageCallback& cb)
{
webSocketMessageCallback_=cb;
}
void setIoLoopNum(int numThreads)
{
server_.setIoLoopNum(numThreads);
@ -71,8 +89,9 @@ namespace drogon
bool isWebSocket(const TcpConnectionPtr& conn, const HttpRequestPtr& req);
trantor::TcpServer server_;
HttpAsyncCallback httpAsyncCallback_;
HttpAsyncCallback newWebsocketCallback_;
WebSocketNewAsyncCallback newWebsocketCallback_;
WebSocketDisconnetCallback disconnectWebsocketCallback_;
WebSocketMessageCallback webSocketMessageCallback_;
};

View File

@ -1,34 +1,6 @@
#include <drogon/WebSocketConnection.h>
#include "WebSockectConnectionImpl.h"
#include <trantor/net/TcpConnection.h>
namespace drogon{
class WebSocketConnectionImpl:public WebSocketConnection
{
public:
WebSocketConnectionImpl(const trantor::TcpConnectionPtr &conn);
virtual void send(const char *msg,uint64_t len) override;
virtual void send(const std::string &msg) override;
virtual const trantor::InetAddress& localAddr() const override;
virtual const trantor::InetAddress& peerAddr() const override;
virtual bool connected() const override;
virtual bool disconnected() const override;
virtual void shutdown() override;//close write
virtual void forceClose() override;//close
virtual void setContext(const any& context) override;
virtual const any& getContext() const override;
virtual any* getMutableContext() override;
private:
std::weak_ptr<trantor::TcpConnection> _tcpConn;
trantor::InetAddress _localAddr;
trantor::InetAddress _peerAddr;
any _context;
};
}
using namespace drogon;
WebSocketConnectionImpl::WebSocketConnectionImpl(const trantor::TcpConnectionPtr &conn):
_tcpConn(conn),

View File

@ -0,0 +1,42 @@
#pragma once
#include <drogon/WebSocketConnection.h>
#include <drogon/WebSocketController.h>
namespace drogon{
class WebSocketConnectionImpl:public WebSocketConnection
{
public:
WebSocketConnectionImpl(const trantor::TcpConnectionPtr &conn);
virtual void send(const char *msg,uint64_t len) override;
virtual void send(const std::string &msg) override;
virtual const trantor::InetAddress& localAddr() const override;
virtual const trantor::InetAddress& peerAddr() const override;
virtual bool connected() const override;
virtual bool disconnected() const override;
virtual void shutdown() override;//close write
virtual void forceClose() override;//close
virtual void setContext(const any& context) override;
virtual const any& getContext() const override;
virtual any* getMutableContext() override;
void setController(const WebSocketControllerBasePtr &ctrl)
{
_ctrlPtr=ctrl;
}
WebSocketControllerBasePtr controller()
{
return _ctrlPtr;
}
private:
std::weak_ptr<trantor::TcpConnection> _tcpConn;
trantor::InetAddress _localAddr;
trantor::InetAddress _peerAddr;
WebSocketControllerBasePtr _ctrlPtr;
any _context;
};
}