opal-up 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/up_ext/App.h +665 -544
- data/ext/up_ext/AsyncSocket.h +307 -284
- data/ext/up_ext/AsyncSocketData.h +35 -51
- data/ext/up_ext/BloomFilter.h +37 -42
- data/ext/up_ext/ChunkedEncoding.h +174 -175
- data/ext/up_ext/ClientApp.h +20 -23
- data/ext/up_ext/HttpContext.h +476 -381
- data/ext/up_ext/HttpContextData.h +20 -20
- data/ext/up_ext/HttpErrors.h +14 -10
- data/ext/up_ext/HttpParser.h +631 -563
- data/ext/up_ext/HttpResponse.h +526 -460
- data/ext/up_ext/HttpResponseData.h +59 -55
- data/ext/up_ext/HttpRouter.h +328 -310
- data/ext/up_ext/Loop.h +174 -168
- data/ext/up_ext/LoopData.h +60 -67
- data/ext/up_ext/MoveOnlyFunction.h +71 -80
- data/ext/up_ext/PerMessageDeflate.h +218 -198
- data/ext/up_ext/ProxyParser.h +100 -99
- data/ext/up_ext/QueryParser.h +91 -84
- data/ext/up_ext/TopicTree.h +273 -268
- data/ext/up_ext/Utilities.h +25 -25
- data/ext/up_ext/WebSocket.h +376 -310
- data/ext/up_ext/WebSocketContext.h +487 -372
- data/ext/up_ext/WebSocketContextData.h +74 -62
- data/ext/up_ext/WebSocketData.h +53 -46
- data/ext/up_ext/WebSocketExtensions.h +194 -178
- data/ext/up_ext/WebSocketHandshake.h +115 -110
- data/ext/up_ext/WebSocketProtocol.h +441 -398
- data/ext/up_ext/up_ext.c +43 -5
- data/lib/up/ruby/cluster.rb +29 -6
- data/lib/up/version.rb +1 -1
- metadata +2 -2
data/ext/up_ext/Loop.h
CHANGED
@@ -21,184 +21,190 @@
|
|
21
21
|
/* The loop is lazily created per-thread and run with run() */
|
22
22
|
|
23
23
|
#include "LoopData.h"
|
24
|
-
#include "libusockets.h"
|
25
24
|
#include <iostream>
|
25
|
+
#include <libusockets.h>
|
26
26
|
|
27
27
|
namespace uWS {
|
28
28
|
struct Loop {
|
29
29
|
private:
|
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
|
-
|
30
|
+
static void wakeupCb(us_loop_t *loop) {
|
31
|
+
LoopData *loopData = (LoopData *)us_loop_ext(loop);
|
32
|
+
|
33
|
+
/* Swap current deferQueue */
|
34
|
+
loopData->deferMutex.lock();
|
35
|
+
int oldDeferQueue = loopData->currentDeferQueue;
|
36
|
+
loopData->currentDeferQueue = (loopData->currentDeferQueue + 1) % 2;
|
37
|
+
loopData->deferMutex.unlock();
|
38
|
+
|
39
|
+
/* Drain the queue */
|
40
|
+
for (auto &x : loopData->deferQueues[oldDeferQueue]) {
|
41
|
+
x();
|
42
|
+
}
|
43
|
+
loopData->deferQueues[oldDeferQueue].clear();
|
44
|
+
}
|
45
|
+
|
46
|
+
static void preCb(us_loop_t *loop) {
|
47
|
+
LoopData *loopData = (LoopData *)us_loop_ext(loop);
|
48
|
+
|
49
|
+
for (auto &p : loopData->preHandlers) {
|
50
|
+
p.second((Loop *)loop);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
static void postCb(us_loop_t *loop) {
|
55
|
+
LoopData *loopData = (LoopData *)us_loop_ext(loop);
|
56
|
+
|
57
|
+
for (auto &p : loopData->postHandlers) {
|
58
|
+
p.second((Loop *)loop);
|
59
|
+
}
|
60
|
+
|
61
|
+
/* After every event loop iteration, we must not hold the cork buffer */
|
62
|
+
if (loopData->corkedSocket) {
|
63
|
+
std::cerr
|
64
|
+
<< "Error: Cork buffer must not be held across event loop iterations!"
|
65
|
+
<< std::endl;
|
66
|
+
std::terminate();
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
Loop() = delete;
|
71
|
+
~Loop() = default;
|
72
|
+
|
73
|
+
Loop *init() {
|
74
|
+
new (us_loop_ext((us_loop_t *)this)) LoopData;
|
75
|
+
return this;
|
76
|
+
}
|
77
|
+
|
78
|
+
static Loop *create(void *hint) {
|
79
|
+
Loop *loop = ((Loop *)us_create_loop(hint, wakeupCb, preCb, postCb,
|
80
|
+
sizeof(LoopData)))
|
81
|
+
->init();
|
82
|
+
|
83
|
+
/* We also need some timers (should live off the one 4 second timer rather)
|
84
|
+
*/
|
85
|
+
LoopData *loopData = (LoopData *)us_loop_ext((struct us_loop_t *)loop);
|
86
|
+
loopData->dateTimer =
|
87
|
+
us_create_timer((struct us_loop_t *)loop, 1, sizeof(LoopData *));
|
88
|
+
memcpy(us_timer_ext(loopData->dateTimer), &loopData, sizeof(LoopData *));
|
89
|
+
us_timer_set(
|
90
|
+
loopData->dateTimer,
|
91
|
+
[](struct us_timer_t *t) {
|
92
|
+
LoopData *loopData;
|
93
|
+
memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *));
|
94
|
+
loopData->updateDate();
|
95
|
+
},
|
96
|
+
1000, 1000);
|
97
|
+
|
98
|
+
return loop;
|
99
|
+
}
|
100
|
+
|
101
|
+
/* What to do with loops created with existingNativeLoop? */
|
102
|
+
struct LoopCleaner {
|
103
|
+
~LoopCleaner() {
|
104
|
+
if (loop && cleanMe) {
|
105
|
+
loop->free();
|
106
|
+
}
|
107
|
+
}
|
108
|
+
Loop *loop = nullptr;
|
109
|
+
bool cleanMe = false;
|
110
|
+
};
|
111
|
+
|
112
|
+
static LoopCleaner &getLazyLoop() {
|
113
|
+
static thread_local LoopCleaner lazyLoop;
|
114
|
+
return lazyLoop;
|
115
|
+
}
|
107
116
|
|
108
117
|
public:
|
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
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
}
|
118
|
+
/* Lazily initializes a per-thread loop and returns it.
|
119
|
+
* Will automatically free all initialized loops at exit. */
|
120
|
+
static Loop *get(void *existingNativeLoop = nullptr) {
|
121
|
+
if (!getLazyLoop().loop) {
|
122
|
+
/* If we are given a native loop pointer we pass that to uSockets and let
|
123
|
+
* it deal with it */
|
124
|
+
if (existingNativeLoop) {
|
125
|
+
/* Todo: here we want to pass the pointer, not a boolean */
|
126
|
+
getLazyLoop().loop = create(existingNativeLoop);
|
127
|
+
/* We cannot register automatic free here, must be manually done */
|
128
|
+
} else {
|
129
|
+
getLazyLoop().loop = create(nullptr);
|
130
|
+
getLazyLoop().cleanMe = true;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
return getLazyLoop().loop;
|
135
|
+
}
|
136
|
+
|
137
|
+
/* Freeing the default loop should be done once */
|
138
|
+
void free() {
|
139
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
140
|
+
|
141
|
+
/* Stop and free dateTimer first */
|
142
|
+
us_timer_close(loopData->dateTimer);
|
143
|
+
|
144
|
+
loopData->~LoopData();
|
145
|
+
/* uSockets will track whether this loop is owned by us or a borrowed alien
|
146
|
+
* loop */
|
147
|
+
us_loop_free((us_loop_t *)this);
|
148
|
+
|
149
|
+
/* Reset lazyLoop */
|
150
|
+
getLazyLoop().loop = nullptr;
|
151
|
+
}
|
152
|
+
|
153
|
+
void addPostHandler(void *key, MoveOnlyFunction<void(Loop *)> &&handler) {
|
154
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
155
|
+
|
156
|
+
loopData->postHandlers.emplace(key, std::move(handler));
|
157
|
+
}
|
158
|
+
|
159
|
+
/* Bug: what if you remove a handler while iterating them? */
|
160
|
+
void removePostHandler(void *key) {
|
161
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
162
|
+
|
163
|
+
loopData->postHandlers.erase(key);
|
164
|
+
}
|
165
|
+
|
166
|
+
void addPreHandler(void *key, MoveOnlyFunction<void(Loop *)> &&handler) {
|
167
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
168
|
+
|
169
|
+
loopData->preHandlers.emplace(key, std::move(handler));
|
170
|
+
}
|
171
|
+
|
172
|
+
/* Bug: what if you remove a handler while iterating them? */
|
173
|
+
void removePreHandler(void *key) {
|
174
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
175
|
+
|
176
|
+
loopData->preHandlers.erase(key);
|
177
|
+
}
|
178
|
+
|
179
|
+
/* Defer this callback on Loop's thread of execution */
|
180
|
+
void defer(MoveOnlyFunction<void()> &&cb) {
|
181
|
+
LoopData *loopData = (LoopData *)us_loop_ext((us_loop_t *)this);
|
182
|
+
|
183
|
+
// if (std::thread::get_id() == ) // todo: add fast path for same thread id
|
184
|
+
loopData->deferMutex.lock();
|
185
|
+
loopData->deferQueues[loopData->currentDeferQueue].emplace_back(
|
186
|
+
std::move(cb));
|
187
|
+
loopData->deferMutex.unlock();
|
188
|
+
|
189
|
+
us_wakeup_loop((us_loop_t *)this);
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Actively block and run this loop */
|
193
|
+
void run() { us_loop_run((us_loop_t *)this); }
|
194
|
+
|
195
|
+
/* Passively integrate with the underlying default loop */
|
196
|
+
/* Used to seamlessly integrate with third parties such as Node.js */
|
197
|
+
void integrate() { us_loop_integrate((us_loop_t *)this); }
|
198
|
+
|
199
|
+
/* Dynamically change this */
|
200
|
+
void setSilent(bool silent) {
|
201
|
+
((LoopData *)us_loop_ext((us_loop_t *)this))->noMark = silent;
|
202
|
+
}
|
195
203
|
};
|
196
204
|
|
197
205
|
/* Can be called from any thread to run the thread local loop */
|
198
|
-
inline void run() {
|
199
|
-
Loop::get()->run();
|
200
|
-
}
|
206
|
+
inline void run() { Loop::get()->run(); }
|
201
207
|
|
202
|
-
}
|
208
|
+
} // namespace uWS
|
203
209
|
|
204
210
|
#endif // UWS_LOOP_H
|
data/ext/up_ext/LoopData.h
CHANGED
@@ -18,16 +18,16 @@
|
|
18
18
|
#ifndef UWS_LOOPDATA_H
|
19
19
|
#define UWS_LOOPDATA_H
|
20
20
|
|
21
|
-
#include <
|
21
|
+
#include <cstdint>
|
22
|
+
#include <ctime>
|
22
23
|
#include <functional>
|
23
|
-
#include <vector>
|
24
|
-
#include <mutex>
|
25
24
|
#include <map>
|
26
|
-
#include <
|
27
|
-
#include <
|
25
|
+
#include <mutex>
|
26
|
+
#include <thread>
|
27
|
+
#include <vector>
|
28
28
|
|
29
|
-
#include "PerMessageDeflate.h"
|
30
29
|
#include "MoveOnlyFunction.h"
|
30
|
+
#include "PerMessageDeflate.h"
|
31
31
|
|
32
32
|
struct us_timer_t;
|
33
33
|
|
@@ -36,77 +36,70 @@ namespace uWS {
|
|
36
36
|
struct Loop;
|
37
37
|
|
38
38
|
struct alignas(16) LoopData {
|
39
|
-
|
39
|
+
friend struct Loop;
|
40
|
+
|
40
41
|
private:
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
std::mutex deferMutex;
|
43
|
+
int currentDeferQueue = 0;
|
44
|
+
std::vector<MoveOnlyFunction<void()>> deferQueues[2];
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
/* Map from void ptr to handler */
|
47
|
+
std::map<void *, MoveOnlyFunction<void(Loop *)>> postHandlers, preHandlers;
|
47
48
|
|
48
49
|
public:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
delete inflationStream;
|
58
|
-
delete deflationStream;
|
59
|
-
}
|
60
|
-
delete [] corkBuffer;
|
50
|
+
LoopData() { updateDate(); }
|
51
|
+
|
52
|
+
~LoopData() {
|
53
|
+
/* If we have had App.ws called with compression we need to clear this */
|
54
|
+
if (zlibContext) {
|
55
|
+
delete zlibContext;
|
56
|
+
delete inflationStream;
|
57
|
+
delete deflationStream;
|
61
58
|
}
|
59
|
+
delete[] corkBuffer;
|
60
|
+
}
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
void updateDate() {
|
63
|
+
time_t now = time(0);
|
64
|
+
struct tm tstruct = {};
|
66
65
|
#ifdef _WIN32
|
67
|
-
|
68
|
-
|
66
|
+
/* Micro, fucking soft never follows spec. */
|
67
|
+
gmtime_s(&tstruct, &now);
|
69
68
|
#else
|
70
|
-
|
69
|
+
gmtime_r(&now, &tstruct);
|
71
70
|
#endif
|
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
|
-
/* Per message deflate data */
|
103
|
-
ZlibContext *zlibContext = nullptr;
|
104
|
-
InflationStream *inflationStream = nullptr;
|
105
|
-
DeflationStream *deflationStream = nullptr;
|
106
|
-
|
107
|
-
us_timer_t *dateTimer;
|
71
|
+
static const char wday_name[][4] = {"Sun", "Mon", "Tue", "Wed",
|
72
|
+
"Thu", "Fri", "Sat"};
|
73
|
+
static const char mon_name[][4] = {"Jan", "Feb", "Mar", "Apr",
|
74
|
+
"May", "Jun", "Jul", "Aug",
|
75
|
+
"Sep", "Oct", "Nov", "Dec"};
|
76
|
+
snprintf(date, 32, "%.3s, %.2u %.3s %.4u %.2u:%.2u:%.2u GMT",
|
77
|
+
wday_name[tstruct.tm_wday], tstruct.tm_mday % 99,
|
78
|
+
mon_name[tstruct.tm_mon], (1900 + tstruct.tm_year) % 9999,
|
79
|
+
tstruct.tm_hour % 99, tstruct.tm_min % 99, tstruct.tm_sec % 99);
|
80
|
+
}
|
81
|
+
|
82
|
+
char date[32];
|
83
|
+
|
84
|
+
/* Be silent */
|
85
|
+
bool noMark = false;
|
86
|
+
|
87
|
+
/* Good 16k for SSL perf. */
|
88
|
+
static const unsigned int CORK_BUFFER_SIZE = 16 * 1024;
|
89
|
+
|
90
|
+
/* Cork data */
|
91
|
+
char *corkBuffer = new char[CORK_BUFFER_SIZE];
|
92
|
+
unsigned int corkOffset = 0;
|
93
|
+
void *corkedSocket = nullptr;
|
94
|
+
|
95
|
+
/* Per message deflate data */
|
96
|
+
ZlibContext *zlibContext = nullptr;
|
97
|
+
InflationStream *inflationStream = nullptr;
|
98
|
+
DeflationStream *deflationStream = nullptr;
|
99
|
+
|
100
|
+
us_timer_t *dateTimer;
|
108
101
|
};
|
109
102
|
|
110
|
-
}
|
103
|
+
} // namespace uWS
|
111
104
|
|
112
105
|
#endif // UWS_LOOPDATA_H
|