opal-up 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,65 +23,49 @@
23
23
  namespace uWS {
24
24
 
25
25
  struct BackPressure {
26
- std::string buffer;
27
- unsigned int pendingRemoval = 0;
28
- BackPressure(BackPressure &&other) {
29
- buffer = std::move(other.buffer);
30
- pendingRemoval = other.pendingRemoval;
31
- }
32
- BackPressure() = default;
33
- void append(const char *data, size_t length) {
34
- buffer.append(data, length);
35
- }
36
- void erase(unsigned int length) {
37
- pendingRemoval += length;
38
- /* Always erase a minimum of 1/32th the current backpressure */
39
- if (pendingRemoval > (buffer.length() >> 5)) {
40
- buffer.erase(0, pendingRemoval);
41
- pendingRemoval = 0;
42
- }
43
- }
44
- size_t length() {
45
- return buffer.length() - pendingRemoval;
46
- }
47
- void clear() {
48
- pendingRemoval = 0;
49
- buffer.clear();
50
- }
51
- void reserve(size_t length) {
52
- buffer.reserve(length + pendingRemoval);
53
- }
54
- void resize(size_t length) {
55
- buffer.resize(length + pendingRemoval);
56
- }
57
- const char *data() {
58
- return buffer.data() + pendingRemoval;
59
- }
60
- size_t size() {
61
- return length();
62
- }
63
- /* The total length, incuding pending removal */
64
- size_t totalLength() {
65
- return buffer.length();
26
+ std::string buffer;
27
+ unsigned int pendingRemoval = 0;
28
+ BackPressure(BackPressure &&other) {
29
+ buffer = std::move(other.buffer);
30
+ pendingRemoval = other.pendingRemoval;
31
+ }
32
+ BackPressure() = default;
33
+ void append(const char *data, size_t length) { buffer.append(data, length); }
34
+ void erase(unsigned int length) {
35
+ pendingRemoval += length;
36
+ /* Always erase a minimum of 1/32th the current backpressure */
37
+ if (pendingRemoval > (buffer.length() >> 5)) {
38
+ buffer.erase(0, pendingRemoval);
39
+ pendingRemoval = 0;
66
40
  }
41
+ }
42
+ size_t length() { return buffer.length() - pendingRemoval; }
43
+ void clear() {
44
+ pendingRemoval = 0;
45
+ buffer.clear();
46
+ }
47
+ void reserve(size_t length) { buffer.reserve(length + pendingRemoval); }
48
+ void resize(size_t length) { buffer.resize(length + pendingRemoval); }
49
+ const char *data() { return buffer.data() + pendingRemoval; }
50
+ size_t size() { return length(); }
51
+ /* The total length, incuding pending removal */
52
+ size_t totalLength() { return buffer.length(); }
67
53
  };
68
54
 
69
55
  /* Depending on how we want AsyncSocket to function, this will need to change */
70
56
 
71
- template <bool SSL>
72
- struct AsyncSocketData {
73
- /* This will do for now */
74
- BackPressure buffer;
57
+ template <bool SSL> struct AsyncSocketData {
58
+ /* This will do for now */
59
+ BackPressure buffer;
75
60
 
76
- /* Allow move constructing us */
77
- AsyncSocketData(BackPressure &&backpressure) : buffer(std::move(backpressure)) {
78
-
79
- }
61
+ /* Allow move constructing us */
62
+ AsyncSocketData(BackPressure &&backpressure)
63
+ : buffer(std::move(backpressure)) {}
80
64
 
81
- /* Or emppty */
82
- AsyncSocketData() = default;
65
+ /* Or emppty */
66
+ AsyncSocketData() = default;
83
67
  };
84
68
 
85
- }
69
+ } // namespace uWS
86
70
 
87
71
  #endif // UWS_ASYNCSOCKETDATA_H
@@ -21,63 +21,58 @@
21
21
  /* This filter has no false positives or collisions for the standard
22
22
  * and non-standard common request headers */
23
23
 
24
+ #include <bitset>
24
25
  #include <cstdint>
25
26
  #include <string_view>
26
- #include <bitset>
27
27
 
28
28
  namespace uWS {
29
29
 
30
30
  struct BloomFilter {
31
31
  private:
32
- std::bitset<256> filter;
33
- static inline uint32_t perfectHash(uint32_t features) {
34
- return features *= 1843993368;
35
- }
32
+ std::bitset<256> filter;
33
+ static inline uint32_t perfectHash(uint32_t features) {
34
+ return features *= 1843993368;
35
+ }
36
36
 
37
- union ScrambleArea {
38
- unsigned char p[4];
39
- uint32_t val;
40
- };
41
-
42
- ScrambleArea getFeatures(std::string_view key) {
43
- ScrambleArea s;
44
- s.p[0] = reinterpret_cast<const unsigned char&>(key[0]);
45
- s.p[1] = reinterpret_cast<const unsigned char&>(key[key.length() - 1]);
46
- s.p[2] = reinterpret_cast<const unsigned char&>(key[key.length() - 2]);
47
- s.p[3] = reinterpret_cast<const unsigned char&>(key[key.length() >> 1]);
48
- return s;
49
- }
37
+ union ScrambleArea {
38
+ unsigned char p[4];
39
+ uint32_t val;
40
+ };
41
+
42
+ ScrambleArea getFeatures(std::string_view key) {
43
+ ScrambleArea s;
44
+ s.p[0] = reinterpret_cast<const unsigned char &>(key[0]);
45
+ s.p[1] = reinterpret_cast<const unsigned char &>(key[key.length() - 1]);
46
+ s.p[2] = reinterpret_cast<const unsigned char &>(key[key.length() - 2]);
47
+ s.p[3] = reinterpret_cast<const unsigned char &>(key[key.length() >> 1]);
48
+ return s;
49
+ }
50
50
 
51
51
  public:
52
- bool mightHave(std::string_view key) {
53
- if (key.length() < 2) {
54
- return true;
55
- }
56
-
57
- ScrambleArea s = getFeatures(key);
58
- s.val = perfectHash(s.val);
59
- return filter[s.p[0]] &&
60
- filter[s.p[1]] &&
61
- filter[s.p[2]] &&
62
- filter[s.p[3]];
52
+ bool mightHave(std::string_view key) {
53
+ if (key.length() < 2) {
54
+ return true;
63
55
  }
64
56
 
65
- void add(std::string_view key) {
66
- if (key.length() >= 2) {
67
- ScrambleArea s = getFeatures(key);
68
- s.val = perfectHash(s.val);
69
- filter[s.p[0]] = 1;
70
- filter[s.p[1]] = 1;
71
- filter[s.p[2]] = 1;
72
- filter[s.p[3]] = 1;
73
- }
74
- }
57
+ ScrambleArea s = getFeatures(key);
58
+ s.val = perfectHash(s.val);
59
+ return filter[s.p[0]] && filter[s.p[1]] && filter[s.p[2]] && filter[s.p[3]];
60
+ }
75
61
 
76
- void reset() {
77
- filter.reset();
62
+ void add(std::string_view key) {
63
+ if (key.length() >= 2) {
64
+ ScrambleArea s = getFeatures(key);
65
+ s.val = perfectHash(s.val);
66
+ filter[s.p[0]] = 1;
67
+ filter[s.p[1]] = 1;
68
+ filter[s.p[2]] = 1;
69
+ filter[s.p[3]] = 1;
78
70
  }
71
+ }
72
+
73
+ void reset() { filter.reset(); }
79
74
  };
80
75
 
81
- }
76
+ } // namespace uWS
82
77
 
83
78
  #endif // UWS_BLOOMFILTER_H
@@ -20,217 +20,216 @@
20
20
 
21
21
  /* Independent chunked encoding parser, used by HttpParser. */
22
22
 
23
- #include <string>
24
- #include <cstring>
25
- #include <algorithm>
26
- #include <string_view>
27
23
  #include "MoveOnlyFunction.h"
24
+ #include <algorithm>
25
+ #include <cstring>
28
26
  #include <optional>
27
+ #include <string>
28
+ #include <string_view>
29
29
 
30
30
  namespace uWS {
31
31
 
32
- constexpr uint64_t STATE_HAS_SIZE = 1ull << (sizeof(uint64_t) * 8 - 1);//0x80000000;
33
- constexpr uint64_t STATE_IS_CHUNKED = 1ull << (sizeof(uint64_t) * 8 - 2);//0x40000000;
34
- constexpr uint64_t STATE_SIZE_MASK = ~(3ull << (sizeof(uint64_t) * 8 - 2));//0x3FFFFFFF;
35
- constexpr uint64_t STATE_IS_ERROR = ~0ull;//0xFFFFFFFF;
36
- constexpr uint64_t STATE_SIZE_OVERFLOW = 0x0Full << (sizeof(uint64_t) * 8 - 8);//0x0F000000;
32
+ constexpr uint64_t STATE_HAS_SIZE =
33
+ 1ull << (sizeof(uint64_t) * 8 - 1); // 0x80000000;
34
+ constexpr uint64_t STATE_IS_CHUNKED =
35
+ 1ull << (sizeof(uint64_t) * 8 - 2); // 0x40000000;
36
+ constexpr uint64_t STATE_SIZE_MASK =
37
+ ~(3ull << (sizeof(uint64_t) * 8 - 2)); // 0x3FFFFFFF;
38
+ constexpr uint64_t STATE_IS_ERROR = ~0ull; // 0xFFFFFFFF;
39
+ constexpr uint64_t STATE_SIZE_OVERFLOW =
40
+ 0x0Full << (sizeof(uint64_t) * 8 - 8); // 0x0F000000;
41
+
42
+ inline uint64_t chunkSize(uint64_t state) { return state & STATE_SIZE_MASK; }
43
+
44
+ /* Reads hex number until CR or out of data to consume. Updates state. Returns
45
+ * bytes consumed. */
46
+ inline void consumeHexNumber(std::string_view &data, uint64_t &state) {
47
+ /* Consume everything higher than 32 */
48
+ while (data.length() && data.data()[0] > 32) {
49
+
50
+ unsigned char digit = (unsigned char)data.data()[0];
51
+ if (digit >= 'a') {
52
+ digit = (unsigned char)(digit - ('a' - ':'));
53
+ } else if (digit >= 'A') {
54
+ digit = (unsigned char)(digit - ('A' - ':'));
55
+ }
56
+
57
+ unsigned int number = ((unsigned int)digit - (unsigned int)'0');
37
58
 
38
- inline uint64_t chunkSize(uint64_t state) {
39
- return state & STATE_SIZE_MASK;
59
+ if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
60
+ state = STATE_IS_ERROR;
61
+ return;
40
62
  }
41
63
 
42
- /* Reads hex number until CR or out of data to consume. Updates state. Returns bytes consumed. */
43
- inline void consumeHexNumber(std::string_view &data, uint64_t &state) {
44
- /* Consume everything higher than 32 */
45
- while (data.length() && data.data()[0] > 32) {
64
+ // extract state bits
65
+ uint64_t bits = /*state &*/ STATE_IS_CHUNKED;
66
+
67
+ state = (state & STATE_SIZE_MASK) * 16ull + number;
68
+
69
+ state |= bits;
70
+ data.remove_prefix(1);
71
+ }
72
+ /* Consume everything not /n */
73
+ while (data.length() && data.data()[0] != '\n') {
74
+ data.remove_prefix(1);
75
+ }
76
+ /* Now we stand on \n so consume it and enable size */
77
+ if (data.length()) {
78
+ state += 2; // include the two last /r/n
79
+ state |= STATE_HAS_SIZE | STATE_IS_CHUNKED;
80
+ data.remove_prefix(1);
81
+ }
82
+ }
46
83
 
47
- unsigned char digit = (unsigned char)data.data()[0];
48
- if (digit >= 'a') {
49
- digit = (unsigned char) (digit - ('a' - ':'));
50
- } else if (digit >= 'A') {
51
- digit = (unsigned char) (digit - ('A' - ':'));
52
- }
84
+ inline void decChunkSize(uint64_t &state, unsigned int by) {
53
85
 
54
- unsigned int number = ((unsigned int) digit - (unsigned int) '0');
86
+ // unsigned int bits = state & STATE_IS_CHUNKED;
55
87
 
56
- if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
57
- state = STATE_IS_ERROR;
58
- return;
59
- }
88
+ state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);
60
89
 
61
- // extract state bits
62
- uint64_t bits = /*state &*/ STATE_IS_CHUNKED;
90
+ // state |= bits;
91
+ }
63
92
 
64
- state = (state & STATE_SIZE_MASK) * 16ull + number;
93
+ inline bool hasChunkSize(uint64_t state) { return state & STATE_HAS_SIZE; }
65
94
 
66
- state |= bits;
67
- data.remove_prefix(1);
68
- }
69
- /* Consume everything not /n */
70
- while (data.length() && data.data()[0] != '\n') {
71
- data.remove_prefix(1);
72
- }
73
- /* Now we stand on \n so consume it and enable size */
74
- if (data.length()) {
75
- state += 2; // include the two last /r/n
76
- state |= STATE_HAS_SIZE | STATE_IS_CHUNKED;
77
- data.remove_prefix(1);
78
- }
79
- }
95
+ /* Are we in the middle of parsing chunked encoding? */
96
+ inline bool isParsingChunkedEncoding(uint64_t state) {
97
+ return state & ~STATE_SIZE_MASK;
98
+ }
80
99
 
81
- inline void decChunkSize(uint64_t &state, unsigned int by) {
100
+ inline bool isParsingInvalidChunkedEncoding(uint64_t state) {
101
+ return state == STATE_IS_ERROR;
102
+ }
82
103
 
83
- //unsigned int bits = state & STATE_IS_CHUNKED;
104
+ /* Returns next chunk (empty or not), or if all data was consumed, nullopt is
105
+ * returned. */
106
+ static std::optional<std::string_view>
107
+ getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {
84
108
 
85
- state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);
109
+ while (data.length()) {
86
110
 
87
- //state |= bits;
88
- }
111
+ // if in "drop trailer mode", just drop up to what we have as size
112
+ if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) &&
113
+ chunkSize(state)) {
89
114
 
90
- inline bool hasChunkSize(uint64_t state) {
91
- return state & STATE_HAS_SIZE;
92
- }
115
+ // printf("Parsing trailer now\n");
93
116
 
94
- /* Are we in the middle of parsing chunked encoding? */
95
- inline bool isParsingChunkedEncoding(uint64_t state) {
96
- return state & ~STATE_SIZE_MASK;
97
- }
117
+ while (data.length() && chunkSize(state)) {
118
+ data.remove_prefix(1);
119
+ decChunkSize(state, 1);
98
120
 
99
- inline bool isParsingInvalidChunkedEncoding(uint64_t state) {
100
- return state == STATE_IS_ERROR;
101
- }
121
+ if (chunkSize(state) == 0) {
102
122
 
103
- /* Returns next chunk (empty or not), or if all data was consumed, nullopt is returned. */
104
- static std::optional<std::string_view> getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {
105
-
106
- while (data.length()) {
107
-
108
- // if in "drop trailer mode", just drop up to what we have as size
109
- if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) && chunkSize(state)) {
110
-
111
- //printf("Parsing trailer now\n");
112
-
113
- while(data.length() && chunkSize(state)) {
114
- data.remove_prefix(1);
115
- decChunkSize(state, 1);
116
-
117
- if (chunkSize(state) == 0) {
118
-
119
- /* This is an actual place where we need 0 as state */
120
- state = 0;
121
-
122
- /* The parser MUST stop consuming here */
123
- return std::nullopt;
124
- }
125
- }
126
- continue;
127
- }
128
-
129
- if (!hasChunkSize(state)) {
130
- consumeHexNumber(data, state);
131
- if (isParsingInvalidChunkedEncoding(state)) {
132
- return std::nullopt;
133
- }
134
- if (hasChunkSize(state) && chunkSize(state) == 2) {
135
-
136
- //printf("Setting state to trailer-parsing and emitting empty chunk\n");
137
-
138
- // set trailer state and increase size to 4
139
- if (trailer) {
140
- state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
141
- } else {
142
- state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
143
- }
144
-
145
- return std::string_view(nullptr, 0);
146
- }
147
- continue;
148
- }
149
-
150
- // do we have data to emit all?
151
- if (data.length() >= chunkSize(state)) {
152
- // emit all but 2 bytes then reset state to 0 and goto beginning
153
- // not fin
154
- std::string_view emitSoon;
155
- bool shouldEmit = false;
156
- if (chunkSize(state) > 2) {
157
- emitSoon = std::string_view(data.data(), chunkSize(state) - 2);
158
- shouldEmit = true;
159
- }
160
- data.remove_prefix(chunkSize(state));
161
- state = STATE_IS_CHUNKED;
162
- if (shouldEmit) {
163
- return emitSoon;
164
- }
165
- continue;
166
- } else {
167
- /* We will consume all our input data */
168
- std::string_view emitSoon;
169
- if (chunkSize(state) > 2) {
170
- uint64_t maximalAppEmit = chunkSize(state) - 2;
171
- if (data.length() > maximalAppEmit) {
172
- emitSoon = data.substr(0, maximalAppEmit);
173
- } else {
174
- //cb(data);
175
- emitSoon = data;
176
- }
177
- }
178
- decChunkSize(state, (unsigned int) data.length());
179
- state |= STATE_IS_CHUNKED;
180
- // new: decrease data by its size (bug)
181
- data.remove_prefix(data.length()); // ny bug fix för getNextChunk
182
- if (emitSoon.length()) {
183
- return emitSoon;
184
- } else {
185
- return std::nullopt;
186
- }
187
- }
188
- }
123
+ /* This is an actual place where we need 0 as state */
124
+ state = 0;
189
125
 
190
- return std::nullopt;
126
+ /* The parser MUST stop consuming here */
127
+ return std::nullopt;
128
+ }
129
+ }
130
+ continue;
191
131
  }
192
132
 
193
- /* This is really just a wrapper for convenience */
194
- struct ChunkIterator {
133
+ if (!hasChunkSize(state)) {
134
+ consumeHexNumber(data, state);
135
+ if (isParsingInvalidChunkedEncoding(state)) {
136
+ return std::nullopt;
137
+ }
138
+ if (hasChunkSize(state) && chunkSize(state) == 2) {
195
139
 
196
- std::string_view *data;
197
- std::optional<std::string_view> chunk;
198
- uint64_t *state;
199
- bool trailer;
140
+ // printf("Setting state to trailer-parsing and emitting empty
141
+ // chunk\n");
200
142
 
201
- ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) {
202
- chunk = uWS::getNextChunk(*data, *state, trailer);
143
+ // set trailer state and increase size to 4
144
+ if (trailer) {
145
+ state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
146
+ } else {
147
+ state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
203
148
  }
204
149
 
205
- ChunkIterator() {
150
+ return std::string_view(nullptr, 0);
151
+ }
152
+ continue;
153
+ }
206
154
 
155
+ // do we have data to emit all?
156
+ if (data.length() >= chunkSize(state)) {
157
+ // emit all but 2 bytes then reset state to 0 and goto beginning
158
+ // not fin
159
+ std::string_view emitSoon;
160
+ bool shouldEmit = false;
161
+ if (chunkSize(state) > 2) {
162
+ emitSoon = std::string_view(data.data(), chunkSize(state) - 2);
163
+ shouldEmit = true;
164
+ }
165
+ data.remove_prefix(chunkSize(state));
166
+ state = STATE_IS_CHUNKED;
167
+ if (shouldEmit) {
168
+ return emitSoon;
169
+ }
170
+ continue;
171
+ } else {
172
+ /* We will consume all our input data */
173
+ std::string_view emitSoon;
174
+ if (chunkSize(state) > 2) {
175
+ uint64_t maximalAppEmit = chunkSize(state) - 2;
176
+ if (data.length() > maximalAppEmit) {
177
+ emitSoon = data.substr(0, maximalAppEmit);
178
+ } else {
179
+ // cb(data);
180
+ emitSoon = data;
207
181
  }
182
+ }
183
+ decChunkSize(state, (unsigned int)data.length());
184
+ state |= STATE_IS_CHUNKED;
185
+ // new: decrease data by its size (bug)
186
+ data.remove_prefix(data.length()); // ny bug fix för getNextChunk
187
+ if (emitSoon.length()) {
188
+ return emitSoon;
189
+ } else {
190
+ return std::nullopt;
191
+ }
192
+ }
193
+ }
208
194
 
209
- ChunkIterator begin() {
210
- return *this;
211
- }
195
+ return std::nullopt;
196
+ }
212
197
 
213
- ChunkIterator end() {
214
- return ChunkIterator();
215
- }
198
+ /* This is really just a wrapper for convenience */
199
+ struct ChunkIterator {
216
200
 
217
- std::string_view operator*() {
218
- if (!chunk.has_value()) {
219
- std::abort();
220
- }
221
- return chunk.value();
222
- }
201
+ std::string_view *data;
202
+ std::optional<std::string_view> chunk;
203
+ uint64_t *state;
204
+ bool trailer;
223
205
 
224
- bool operator!=(const ChunkIterator &other) const {
225
- return other.chunk.has_value() != chunk.has_value();
226
- }
206
+ ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false)
207
+ : data(data), state(state), trailer(trailer) {
208
+ chunk = uWS::getNextChunk(*data, *state, trailer);
209
+ }
227
210
 
228
- ChunkIterator &operator++() {
229
- chunk = uWS::getNextChunk(*data, *state, trailer);
230
- return *this;
231
- }
211
+ ChunkIterator() {}
232
212
 
233
- };
234
- }
213
+ ChunkIterator begin() { return *this; }
214
+
215
+ ChunkIterator end() { return ChunkIterator(); }
216
+
217
+ std::string_view operator*() {
218
+ if (!chunk.has_value()) {
219
+ std::abort();
220
+ }
221
+ return chunk.value();
222
+ }
223
+
224
+ bool operator!=(const ChunkIterator &other) const {
225
+ return other.chunk.has_value() != chunk.has_value();
226
+ }
227
+
228
+ ChunkIterator &operator++() {
229
+ chunk = uWS::getNextChunk(*data, *state, trailer);
230
+ return *this;
231
+ }
232
+ };
233
+ } // namespace uWS
235
234
 
236
235
  #endif // UWS_CHUNKEDENCODING_H
@@ -4,33 +4,30 @@
4
4
 
5
5
  namespace uWS {
6
6
 
7
- struct WebSocketClientBehavior {
8
- MoveOnlyFunction<void()> open;
9
- MoveOnlyFunction<void()> message;
10
- MoveOnlyFunction<void()> close;
11
- //MoveOnlyFunction<void()> failed;
7
+ struct WebSocketClientBehavior {
8
+ MoveOnlyFunction<void()> open;
9
+ MoveOnlyFunction<void()> message;
10
+ MoveOnlyFunction<void()> close;
11
+ // MoveOnlyFunction<void()> failed;
12
+ };
12
13
 
13
- };
14
+ struct ClientApp {
14
15
 
15
- struct ClientApp {
16
+ WebSocketContext<0, false, int> *webSocketContext;
17
+ // behöver ett nytt http context med minimal klient, som slår om till den
18
+ // riktiga websocketcontext om samma storlek på httpsocket och websocket blir
19
+ // det enkel övergång
16
20
 
17
- WebSocketContext<0, false, int> *webSocketContext;
18
- // behöver ett nytt http context med minimal klient, som slår om till den riktiga websocketcontext
19
- // om samma storlek på httpsocket och websocket blir det enkel övergång
21
+ ClientApp(WebSocketClientBehavior &&behavior) {
22
+ // webSocketContext = WebSocketContext<0, false, int>::create();
23
+ }
20
24
 
21
- ClientApp(WebSocketClientBehavior &&behavior) {
22
- //webSocketContext = WebSocketContext<0, false, int>::create();
23
- }
25
+ ClientApp &&connect(std::string url, std::string protocol = "") {
24
26
 
25
- ClientApp &&connect(std::string url, std::string protocol = "") {
27
+ return std::move(*this);
28
+ }
26
29
 
27
- return std::move(*this);
28
- }
30
+ void run() {}
31
+ };
29
32
 
30
- void run() {
31
-
32
- }
33
-
34
- };
35
-
36
- }
33
+ } // namespace uWS