forked from jojojames/PhxSocketCPP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEasySocket.cpp
156 lines (135 loc) · 4.76 KB
/
EasySocket.cpp
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "EasySocket.h"
#include "SocketDelegate.h"
#include <iostream>
#include <thread>
// Make sure to implement this constructor if you take out the
// Base class constructor call.
// Otherwise, it'll throw `symbol not found` exceptions when compiling.
EasySocket::EasySocket(const std::string& url, SocketDelegate* delegate)
: WebSocket(url, delegate)
, receiveQueue(1) {
this->state = SocketClosed;
}
void EasySocket::open() {
easywsclient::WebSocket::pointer socket
= easywsclient::WebSocket::from_url(this->url);
if (!socket) {
this->state = SocketClosed;
std::thread errorThread([this]() {
SocketDelegate* d = this->delegate;
if (d) {
d->webSocketDidError(this, "");
}
});
errorThread.detach();
this->socket = nullptr;
return;
}
this->socket = socket;
std::thread worker([this]() {
easywsclient::WebSocket::pointer ws = this->socket;
// This worker thread will continue to loop as long as the Websocket
// is connected. Once we get a CLOSED message, this will be set to
// false and the loop (and thread) will be exited.
bool shouldContinueLoop = true;
// We use this flag to track if we've triggered the webSocketDidOpen
// yet. The first time we encounter CONNECTED while looping, trigger
// the callback and then set this to true so we only do it once.
bool triggeredWebsocketJoinedCallback = false;
using std::placeholders::_1;
std::function<void(std::string)> callable
= std::bind(&EasySocket::handleMessage, this, _1);
while (shouldContinueLoop) {
switch (ws->getReadyState()) {
case easywsclient::WebSocket::CLOSED: {
this->state = SocketClosed;
std::thread closeThread([this]() {
SocketDelegate* d = this->delegate;
if (d) {
d->webSocketDidClose(this, 0, "", true);
}
});
closeThread.detach();
// We got a CLOSED so the loop should stop.
shouldContinueLoop = false;
break;
}
case easywsclient::WebSocket::CLOSING: {
this->state = SocketClosing;
std::lock_guard<std::mutex> guard(this->socketMutex);
ws->poll();
ws->dispatch(callable);
break;
}
case easywsclient::WebSocket::CONNECTING: {
this->state = SocketConnecting;
std::lock_guard<std::mutex> guard(this->socketMutex);
ws->poll();
ws->dispatch(callable);
break;
}
case easywsclient::WebSocket::OPEN: {
this->state = SocketOpen;
if (!triggeredWebsocketJoinedCallback) {
triggeredWebsocketJoinedCallback = true;
this->getSocketState();
SocketDelegate* d = this->delegate;
if (d) {
d->webSocketDidOpen(this);
}
}
std::lock_guard<std::mutex> guard(this->socketMutex);
ws->poll();
ws->dispatch(callable);
break;
}
default: { break; }
}
}
this->state = SocketClosed;
this->socket = nullptr;
});
worker.detach();
}
void EasySocket::close() {
this->state = SocketClosed;
// Was already closed or never opened.
if (!this->socket) {
return;
}
this->socket->close();
}
void EasySocket::send(const std::string& message) {
std::thread thread([this, message]() {
std::lock_guard<std::mutex> guard(this->socketMutex);
// Grab a copy of the pointer in case it gets NULLed out.
easywsclient::WebSocket::pointer sock = this->socket;
if (sock && this->state == SocketOpen) {
sock->send(message);
}
});
thread.detach();
}
void EasySocket::handleMessage(const std::string& message) {
// std::cout << message << std::endl;
this->receiveQueue.enqueue([this, message]() {
SocketDelegate* d = this->delegate;
if (d) {
d->webSocketDidReceive(this, message);
}
});
}
SocketState EasySocket::getSocketState() {
// easywsclient's State code is seemingly unreliable.
// So we manage it ourselves.
return this->state;
}
void EasySocket::setDelegate(SocketDelegate* delegate) {
this->delegate = delegate;
}
SocketDelegate* EasySocket::getDelegate() {
return this->delegate;
}
void EasySocket::setURL(const std::string& url) {
this->url = url;
}