-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparthanonsWebSocket.h
More file actions
183 lines (169 loc) · 6.15 KB
/
parthanonsWebSocket.h
File metadata and controls
183 lines (169 loc) · 6.15 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
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#ifndef PARTHANONSQWEBSOCKET_H
#define PARTHANONSQWEBSOCKET_H
#include <QObject>
#include <QQuickItem>
#include <QWidget>
#include <QtWebSockets/QWebSocket>
#include <QtGui>
// Created by Daimon Sewell - Daimonsewell@gmail.com
class ParthanonsQWebSocket : public QObject
{
Q_OBJECT
Q_PROPERTY(QString URL READ getUrl WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QString Connected READ isConnected NOTIFY connectionChanged)
public:
explicit CustomWebSocket(QObject *parent = nullptr): QObject(parent) {
qDebug() << "WebSocket client";
connect(&socket, &QWebSocket::connected, this, &ParthanonsQWebSocket::handleConnect);
connect(&socket, &QWebSocket::disconnected, this, &ParthanonsQWebSocket::handleDisconnect);
connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
[=](QAbstractSocket::SocketError error){
qDebug() << "Connection died because: " << error;
this->retryConnect(error);
});
connect(&socket, &QWebSocket::textMessageReceived, this, &ParthanonsQWebSocket::handleMessageReceived);
connect(timer, &QTimer::timeout, this, &ParthanonsQWebSocket::updateSendQueue);
timer->start(retryDelay);
}
signals:
void connectionEstablished();
void disconnect();
void error();
void messageReceived(QString event, QString message);
void urlChanged();
void connectionChanged();
public slots:
//C++
// Q_INVOKABLE void getData(QJSValue value) {
// if (value.isCallable()) {
// QJSValueList args;
// args << QJSValue("Hello, world!");
// value.call(args);
// }
// }
//QML
// action.getData(function (data){console.log(data)});
bool isConnected() {
return bisConnected;
}
void setUrl(QString url) {
this->DisconnectFromServer();
this->connectTo(url);
}
void connectTo(QString url) {
this->URL = url;
socket.open(QUrl(this->URL));
}
void retryConnect(QAbstractSocket::SocketError error) {
qDebug() << error;
handleDisconnect();
}
void DisconnectFromServer() {
socket.close();
}
void handleDisconnect() {
bisConnected = false;
emit disconnect();
emit connectionChanged();
socket.close();
socket.open(QUrl(this->URL));
}
void handleConnect() {
bisConnected = true;
emit connectionEstablished();
emit connectionChanged();
}
void handleMessageReceived(QString message) {
qDebug() << "CPP: [<-]" << message;
QString event = message.mid(0,message.indexOf(";"));
QString msg = message.right(message.length() - message.indexOf(";") - 1);
if (messageHandlers.contains(event)) {
QList<QJSValue> functions = ((QList<QJSValue>)messageHandlers.value(event));
for (QJSValue function: functions) {
QJSValueList args;
args << QJSValue(msg);
function.call(args);
}
}
emit messageReceived(event, msg);
}
void on(QString callString, QJSValue function) {
if (!messageHandlers.contains(callString)) {
QList<QJSValue> tmp = {};
messageHandlers.insert(callString,tmp);
}
QList<QJSValue> handlers = messageHandlers.value(callString);
handlers.push_back(function);
messageHandlers.insert(callString, handlers);
}
void send(QString endpoint, QString data, QJSValue onComplete) {
qDebug() << "CPP: [->]" << endpoint;
if (bisConnected) {
qint64 bytesSent = socket.sendTextMessage(endpoint + ";" + data);
} else {
events += 1;
QString key = QString::number(events);
outBoundEvent.insert(key, endpoint);
outBoundData.insert(key, data);
outBoundOnCompleteFunctions.insert(key, onComplete);
outBoundRetryCounters.insert(key, 0);
}
}
void updateSendQueue() {
if(outBoundData.size() > 0)
qDebug() << "C++: Retrying [->] queue.length =" << outBoundData.size();
QMapIterator<QString, QString> i(outBoundEvent);
while (i.hasNext()) {
i.next();
QString key = i.key();
QString endpoint = outBoundEvent.value(key);
QString data = outBoundData.value(key);
QJSValue onComplete = outBoundOnCompleteFunctions.value(key);
qDebug() << "C++: [->]: " << endpoint << "";
int retryCount = outBoundRetryCounters.value(key);
outBoundRetryCounters.insert( key, retryCount + 1);
bool didFail = false;
if (bisConnected) {
qint64 bytesSent = socket.sendTextMessage(endpoint + ";" + data);
} else {
didFail = true;
}
// if (bytesSent != data.toUtf8().size()) didFail = true;
// qDebug() << "Cpp -> Success?: " << !didFail;
if ((!didFail) || retryCount >= retryLimit) {
if (retryCount >= retryLimit){
qDebug() << "C++: [-> Timed out]";
}
if (onComplete.isCallable()) {
QJSValueList args;
args << QJSValue((didFail)? "Failed":"Success");
isFailing = !didFail;
onComplete.call(args);
}
outBoundEvent.remove(key);
outBoundData.remove(key);
outBoundRetryCounters.remove(key);
outBoundOnCompleteFunctions.remove(key);
break;
}
}
}
private:
QTimer *timer = new QTimer();
const int retryLimit = 5;
const int retryDelay = 3000;
QWebSocket socket;
bool isFailing = false;
volatile bool bisConnected = false;
QMap<QString, QList<QJSValue>> messageHandlers;
long events = 0;
QMap<QString, QString> outBoundEvent;
QMap<QString, QString> outBoundData;
QMap<QString, QJSValue> outBoundOnCompleteFunctions;
QMap<QString, int> outBoundRetryCounters;
QString URL;
QString getUrl() {
return URL;
}
};
#endif // PARTHANONSQWEBSOCKET_H