-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathwebsocket_session.cpp
More file actions
129 lines (114 loc) · 3.36 KB
/
Copy pathwebsocket_session.cpp
File metadata and controls
129 lines (114 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <boost/asio/dispatch.hpp>
#include <boost/beast/http/dynamic_body.hpp>
#include <boost/asio/strand.hpp>
#include <qcoreapplication.h>
#include <qeventloop.h>
#include <qthreadpool.h>
#include "framework.h"
#include "websocket_session.h"
namespace shelllet {
std::mutex mutex;
}
shelllet::inspect::WebsocketSession::WebsocketSession(shelllet::inspect::Receiver* receiver, boost::asio::ip::tcp::socket&& socket)
: receiver_(receiver)
, ws_(std::move(socket))
{
receiver_->callback = [this](auto& message) {
std::lock_guard<std::mutex> lock_guard(mutex);
messages_.emplace_front(message);
};
}
shelllet::inspect::WebsocketSession::~WebsocketSession()
{
receiver_->callback = {};
LOG_TRACE("inspect") << "# ~websocket_session." << std::endl;
}
//void shelllet::inspect::WebsocketSession::customEvent(QEvent* event)
//{
// if (auto* e = dynamic_cast<ReadEvent*>(event)) {
// doRead();
// }
// else if (auto* e = dynamic_cast<WriteEvent*>(event)) {
// doWrite(messages_.back());
// messages_.pop_back();
// }
//}
void shelllet::inspect::WebsocketSession::onAccept(boost::beast::error_code ec)
{
if (ec) {
LOG_ERROR("inspect") << "# accept error: " << ec.message() << std::endl;
return;
}
class Runnable : public QRunnable {
public:
Runnable(const std::shared_ptr<WebsocketSession>& session) :self_(session) {
}
void run() override {
self_->thread_ = QThread::currentThread();
while (true) {
if (QThread::currentThread()->isInterruptionRequested()) {
break;
}
if (self_->messages_.empty()) {
self_->doRead();
}
else {
std::lock_guard<std::mutex> lock_guard(mutex);
self_->doWrite(self_->messages_.back());
self_->messages_.pop_back();
}
QCoreApplication::processEvents();
std::this_thread::sleep_for(10ms);
}
QCoreApplication::postEvent(self_->receiver_, new DisconnectEvent);
LOG_INFO("inspect") << "# message runnable exit." << std::endl;
}
private:
std::shared_ptr<WebsocketSession> self_;
};
QThreadPool::globalInstance()->start(new Runnable(shared_from_this()));
}
void shelllet::inspect::WebsocketSession::doRead()
{
if (is_read_ok_) {
is_read_ok_ = false;
ws_.async_read(buffer_, boost::beast::bind_front_handler(&WebsocketSession::onRead, shared_from_this()));
}
}
void shelllet::inspect::WebsocketSession::onRead(boost::beast::error_code ec, std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if (ec == boost::beast::websocket::error::closed) {
if (thread_) {
thread_->requestInterruption();
}
return;
}
if (ec) {
LOG_ERROR("inspect") << "# read error: " << ec.message() << std::endl;
if (thread_) {
thread_->requestInterruption();
}
return;
}
std::string message = boost::beast::buffers_to_string(buffer_.cdata());
QCoreApplication::postEvent(receiver_, new MessageInEvent(message));
is_read_ok_ = true;
buffer_.consume(buffer_.size());
LOG_TRACE("inspct") << "# incoming: " << message << std::endl;
}
void shelllet::inspect::WebsocketSession::doWrite(const std::string& message)
{
ws_.text(true);
boost::beast::error_code ec;
std::size_t size = ws_.write(boost::asio::buffer(message), ec);
if (ec) {
LOG_ERROR("inspect") << "# write error: " << ec.message() << std::endl;
if (thread_) {
thread_->requestInterruption();
}
return;
}
assert(size == message.length());
LOG_TRACE("inspct") << "# outgoing: " << message << std::endl;
}