opal-up 0.0.3 → 0.0.5

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