uws-react-native 0.0.10 → 0.1.0-beta.1

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.
Files changed (78) hide show
  1. package/README.md +108 -3
  2. package/cpp/UwsReactNativeModule.cpp +4 -0
  3. package/cpp/app/HttpResponseObject.h +116 -40
  4. package/cpp/app/RecognizedString.h +20 -14
  5. package/cpp/app/TemplatedAppObject.h +61 -36
  6. package/cpp/app/WebSocketBehaviorImpl.h +269 -11
  7. package/cpp/app/WebSocketObject.h +354 -16
  8. package/cpp/app/WebSocketUserData.h +227 -0
  9. package/lib/commonjs/modules/WebSocketSendStatus.js +22 -0
  10. package/lib/commonjs/modules/WebSocketSendStatus.js.map +1 -0
  11. package/lib/commonjs/modules/index.js +22 -0
  12. package/lib/commonjs/modules/index.js.map +1 -1
  13. package/lib/commonjs/types/WebSocketUserData.js +2 -0
  14. package/lib/commonjs/types/WebSocketUserData.js.map +1 -0
  15. package/lib/module/modules/WebSocketSendStatus.js +18 -0
  16. package/lib/module/modules/WebSocketSendStatus.js.map +1 -0
  17. package/lib/module/modules/index.js +2 -1
  18. package/lib/module/modules/index.js.map +1 -1
  19. package/lib/module/types/WebSocketUserData.js +2 -0
  20. package/lib/module/types/WebSocketUserData.js.map +1 -0
  21. package/lib/typescript/commonjs/modules/WebSocketSendStatus.d.ts +15 -0
  22. package/lib/typescript/commonjs/modules/WebSocketSendStatus.d.ts.map +1 -0
  23. package/lib/typescript/commonjs/modules/index.d.ts +2 -0
  24. package/lib/typescript/commonjs/modules/index.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/types/HttpResponse.d.ts +39 -4
  26. package/lib/typescript/commonjs/types/HttpResponse.d.ts.map +1 -1
  27. package/lib/typescript/commonjs/types/HttpRouterOptions.d.ts +1 -1
  28. package/lib/typescript/commonjs/types/TemplatedApp.d.ts +5 -0
  29. package/lib/typescript/commonjs/types/TemplatedApp.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/types/WebSocket.d.ts +18 -8
  31. package/lib/typescript/commonjs/types/WebSocket.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/types/WebSocketBehavior.d.ts +9 -9
  33. package/lib/typescript/commonjs/types/WebSocketBehavior.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/types/WebSocketUserData.d.ts +9 -0
  35. package/lib/typescript/commonjs/types/WebSocketUserData.d.ts.map +1 -0
  36. package/lib/typescript/commonjs/types/index.d.ts +3 -0
  37. package/lib/typescript/commonjs/types/index.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/types/us_socket_context_t.d.ts +2 -3
  39. package/lib/typescript/commonjs/types/us_socket_context_t.d.ts.map +1 -1
  40. package/lib/typescript/module/index.d.ts +2 -2
  41. package/lib/typescript/module/index.d.ts.map +1 -1
  42. package/lib/typescript/module/modules/App.d.ts +1 -1
  43. package/lib/typescript/module/modules/App.d.ts.map +1 -1
  44. package/lib/typescript/module/modules/WebSocketSendStatus.d.ts +15 -0
  45. package/lib/typescript/module/modules/WebSocketSendStatus.d.ts.map +1 -0
  46. package/lib/typescript/module/modules/getParts.d.ts +1 -1
  47. package/lib/typescript/module/modules/getParts.d.ts.map +1 -1
  48. package/lib/typescript/module/modules/index.d.ts +7 -5
  49. package/lib/typescript/module/modules/index.d.ts.map +1 -1
  50. package/lib/typescript/module/types/HttpRequest.d.ts +1 -1
  51. package/lib/typescript/module/types/HttpRequest.d.ts.map +1 -1
  52. package/lib/typescript/module/types/HttpResponse.d.ts +40 -5
  53. package/lib/typescript/module/types/HttpResponse.d.ts.map +1 -1
  54. package/lib/typescript/module/types/HttpRouterOptions.d.ts +1 -1
  55. package/lib/typescript/module/types/TemplatedApp.d.ts +10 -5
  56. package/lib/typescript/module/types/TemplatedApp.d.ts.map +1 -1
  57. package/lib/typescript/module/types/WebSocket.d.ts +19 -9
  58. package/lib/typescript/module/types/WebSocket.d.ts.map +1 -1
  59. package/lib/typescript/module/types/WebSocketBehavior.d.ts +14 -14
  60. package/lib/typescript/module/types/WebSocketBehavior.d.ts.map +1 -1
  61. package/lib/typescript/module/types/WebSocketUserData.d.ts +9 -0
  62. package/lib/typescript/module/types/WebSocketUserData.d.ts.map +1 -0
  63. package/lib/typescript/module/types/index.d.ts +8 -5
  64. package/lib/typescript/module/types/index.d.ts.map +1 -1
  65. package/lib/typescript/module/types/us_socket_context_t.d.ts +2 -3
  66. package/lib/typescript/module/types/us_socket_context_t.d.ts.map +1 -1
  67. package/lib/typescript/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +4 -3
  69. package/src/modules/WebSocketSendStatus.ts +14 -0
  70. package/src/modules/index.ts +2 -1
  71. package/src/types/HttpResponse.ts +50 -33
  72. package/src/types/HttpRouterOptions.ts +1 -1
  73. package/src/types/TemplatedApp.ts +10 -10
  74. package/src/types/WebSocket.ts +24 -8
  75. package/src/types/WebSocketBehavior.ts +9 -9
  76. package/src/types/WebSocketUserData.ts +28 -0
  77. package/src/types/index.ts +3 -2
  78. package/src/types/us_socket_context_t.ts +2 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # uws-react-native
2
2
 
3
- The port of [**uWebSockets**](https://github.com/uNetworking/uWebSockets) library for React Native. Inspired by the [**uWebSockets.js**](https://github.com/uNetworking/uWebSockets.js) for Node.js and tailored for React Native app.
3
+ The port of [**uWebSockets**](https://github.com/uNetworking/uWebSockets) server library for React Native. Inspired by the [**uWebSockets.js**](https://github.com/uNetworking/uWebSockets.js) for Node.js and tailored for React Native app.
4
4
 
5
5
  - **uWebSockets** is simple, secure & standards compliant web server for the most demanding of applications. See [**uWebSockets**](https://github.com/uNetworking/uWebSockets) for more information
6
6
  - **uws-react-native** is library that allows you to easily use **uWebSockets** in your React Native through new architecture with JSI to the native C++
@@ -9,6 +9,7 @@ The port of [**uWebSockets**](https://github.com/uNetworking/uWebSockets) librar
9
9
 
10
10
  - [Installation](#installation)
11
11
  - [From NPM Registry](#from-npm-registry)
12
+ - [From GitHub Release](#from-github-release)
12
13
  - [From GitHub Packages](#from-github-packages)
13
14
  - [Usage](#usage)
14
15
  - [Compatibility](#compatibility)
@@ -20,7 +21,7 @@ The port of [**uWebSockets**](https://github.com/uNetworking/uWebSockets) librar
20
21
 
21
22
  ## Installation
22
23
 
23
- We provide two registry homes where this library lives which can be used for your project. You can use either it is from NPM registry or GitHub Packages. It has absolutely **no external JavaScript dependencies**
24
+ We provide three registry homes where this library is available for use in your project. You can use either it is from NPM registry, or GitHub Release, or GitHub Packages. It has absolutely **no external JavaScript dependencies**
24
25
 
25
26
  ### From NPM Registry
26
27
 
@@ -39,6 +40,31 @@ pnpm
39
40
  pnpm install uws-react-native
40
41
  ```
41
42
 
43
+ ### From GitHub Release
44
+
45
+ To install this library from GitHub release
46
+
47
+ 1. Go to this project's [GitHub Release](https://github.com/RakaDoank/uws-react-native/releases)
48
+ 2. Find the `uws-react-native-X.X.X.tgz` asset from one of the release versions
49
+ 3. Copy the asset URL or link (Right click at the asset file name in your browser)
50
+
51
+ Finally, do the regular installation with the CLI, but with the asset URL
52
+
53
+ npm
54
+ ```
55
+ npm install https://github.com/.../uws-react-native-X.X.X.tgz
56
+ ```
57
+ yarn
58
+ ```
59
+ yarn add https://github.com/.../uws-react-native-X.X.X.tgz
60
+ ```
61
+ pnpm
62
+ ```
63
+ pnpm install https://github.com/.../uws-react-native-X.X.X.tgz
64
+ ```
65
+
66
+ > You can also do an offline installation by downloading the tarball file first, and do the regular installation with the CLI, but with the local file path.
67
+
42
68
  ### From GitHub Packages
43
69
 
44
70
  First, create your GitHub personal token (classic) with `read:packages` access
@@ -77,10 +103,89 @@ pnpm install @rakadoank/uws-react-native
77
103
  ## Usage
78
104
 
79
105
  Since uws-react-native is a port of uWebSockets library for JavaScript, this library is really similar of how to use the [uWebSockets](https://github.com/uNetworking/uWebSockets) in C++, or the [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js) for Node.js.
80
- You can refer to the [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js) example.
106
+ You can refer to the [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js) example, but **we recommend to create a server in `useEffect`**.
81
107
 
82
108
  This repository does also contain the [server example](https://github.com/RakaDoank/uws-react-native/blob/main/examples/app/src/screens/home/_use-server.ts). You can also refer to it, but it is currently for library development playground rather than proper example.
83
109
 
110
+ A simple server example
111
+
112
+ ```tsx
113
+ import { useEffect } from "react"
114
+ import * as uWS from "uws-react-native"
115
+
116
+ export function Component() {
117
+
118
+ // useEffect is perfect tool for production and even in development mode.
119
+ // In the development mode, any changes below will restart the server automatically because of the useEffect cycle
120
+ useEffect(() => {
121
+ const app = uWS.App()
122
+
123
+ app.get("/data/:foo/:bar", (res, req) => {
124
+ const fooSlug = req.getParameter("foo")
125
+ const barSlug = req.getParameter("bar")
126
+
127
+ res.writeHeader("content-type", "application/json")
128
+ res.end(
129
+ JSON.stringify({
130
+ foo: fooSlug,
131
+ bar: barSlug,
132
+ });
133
+ )
134
+ })
135
+
136
+ app.get("/about", res => {
137
+ res.write("<html><body>")
138
+ res.write("<h2>Hello World</h2>")
139
+ res.end("</body></html>")
140
+ })
141
+
142
+ app.post("/data", (res, req) => {
143
+ let isAborted = false
144
+ res.onAborted(() => {
145
+ isAborted = true
146
+ })
147
+
148
+ res.onFullData(data => {
149
+ const textDecoder = new TextDecoder("utf-8")
150
+ const text = textDecoder.decode(data)
151
+
152
+ try {
153
+ const json = JSON.parse(text)
154
+
155
+ if(!isAborted) {
156
+ // send the json back
157
+ res.writeHeader("content-type", "application/json")
158
+ res.end(
159
+ JSON.stringify(json)
160
+ )
161
+ }
162
+ } catch {
163
+ // not a valid json
164
+ res.end(
165
+ JSON.stringify({
166
+ message: "Something went wrong",
167
+ })
168
+ )
169
+ }
170
+ })
171
+ })
172
+
173
+ app.listen("127.0.0.1", 5000, token => {
174
+ if(token) {
175
+ console.log("Listening at port 5000")
176
+ } else {
177
+ console.log("Failed to listen")
178
+ }
179
+ })
180
+
181
+ return () => {
182
+ app.close()
183
+ }
184
+ }, [])
185
+
186
+ }
187
+ ```
188
+
84
189
  ## Compatibility
85
190
 
86
191
  `uws-react-native` is only compatible for new architecture of React Native.
@@ -87,6 +87,10 @@ facebook::jsi::Object UwsReactNativeModule::getParts(facebook::jsi::Runtime &rt,
87
87
 
88
88
  auto parts = std::vector<facebook::jsi::Object>();
89
89
 
90
+ /// Using jsi Array with zero element and "push" it later
91
+ /// is only supported in React Native >= 0.86
92
+ // auto parts = facebook::jsi::Array(rt, 0);
93
+
90
94
  while(true) {
91
95
  std::optional<std::string_view> optionalPart = mp.getNextPart(headers);
92
96
  if(!optionalPart.has_value()) {
@@ -3,11 +3,38 @@
3
3
  #include <ReactCommon/CallInvoker.h>
4
4
  #include <jsi/Buffer.h>
5
5
  #include <jsi/jsi.h>
6
+ #include <react/bridging/Function.h>
6
7
  #include <utility>
7
- #include "RecognizedString.h"
8
8
  #include "HttpResponseObjectProvider.h"
9
+ #include "RecognizedString.h"
10
+ #include "WebSocketUserData.h"
9
11
  #include "uWebSockets/App.h"
10
12
 
13
+ #ifdef REACT_NATIVE_DEBUG
14
+ namespace {
15
+
16
+ thread_local int insideCorkCallback = 0;
17
+
18
+ void assumeCorked(facebook::jsi::Runtime &rt) {
19
+ if(!insideCorkCallback) {
20
+ auto console = rt.global().getProperty(rt, "console");
21
+ if(!console.isObject()) {
22
+ return;
23
+ }
24
+
25
+ auto warning = console.asObject(rt).getProperty(rt, "warning");
26
+ if(!warning.isObject()) {
27
+ return;
28
+ }
29
+
30
+ auto fn = warning.asObject(rt).asFunction(rt);
31
+ fn.call(rt, "Warning: uWS.HttpResponse writes must be made from within a corked callback. See documentation for uWS.HttpResponse.cork and consult the user manual.");
32
+ }
33
+ }
34
+
35
+ } // namespace
36
+ #endif
37
+
11
38
  namespace uws_react_native {
12
39
 
13
40
  /// Only use this in the JavaScript thread
@@ -41,7 +68,15 @@ public:
41
68
  const facebook::jsi::Value *arguments,
42
69
  size_t count) -> facebook::jsi::Value {
43
70
  provider->res->cork([&rt_1, callback = arguments[0].asObject(rt_1).asFunction(rt_1)]() {
71
+ #ifdef REACT_NATIVE_DEBUG
72
+ insideCorkCallback++;
73
+ #endif
74
+
44
75
  callback.call(rt_1);
76
+
77
+ #ifdef REACT_NATIVE_DEBUG
78
+ insideCorkCallback--;
79
+ #endif
45
80
  });
46
81
 
47
82
  return {rt_1, thisValue};
@@ -65,7 +100,12 @@ public:
65
100
  }
66
101
 
67
102
  auto body = RecognizedString(rt_1, arguments[0]).getStringView();
103
+
104
+ #ifdef REACT_NATIVE_DEBUG
105
+ assumeCorked(rt_1);
106
+ #endif
68
107
  provider->res->end(body);
108
+
69
109
  return {rt_1, thisValue};
70
110
  }));
71
111
 
@@ -103,6 +143,9 @@ public:
103
143
  closeConnection = arguments[1].asBool();
104
144
  }
105
145
 
146
+ #ifdef REACT_NATIVE_DEBUG
147
+ assumeCorked(rt_1);
148
+ #endif
106
149
  provider->res->endWithoutBody(reportedContentLength, closeConnection);
107
150
 
108
151
  return {rt_1, thisValue};
@@ -354,50 +397,71 @@ public:
354
397
  auto fullBodyOrChunk = RecognizedString(rt_1, arguments[0]).getStringView();
355
398
  auto totalSize = arguments[1].asNumber();
356
399
 
400
+ #ifdef REACT_NATIVE_DEBUG
401
+ assumeCorked(rt_1);
402
+ #endif
357
403
  auto tryEndResult = provider->res->tryEnd(fullBodyOrChunk, static_cast<uintmax_t>(totalSize));
358
404
 
359
405
  return facebook::jsi::Array::createWithElements(rt_1, {tryEndResult.first, tryEndResult.second});
360
406
  }));
361
407
 
362
- /// TODO
363
- /// Implement this method later
364
- /// It looks like we need to persist/save the us_socket_context_t from the ws.
365
- // this->setProperty(rt, "upgrade", facebook::jsi::Function::createFromHostFunction(rt,
366
- // facebook::jsi::PropNameID::forUtf8(rt, "upgrade"),
367
- // 5,
368
- // [res](facebook::jsi::Runtime &rt_1,
369
- // const facebook::jsi::Value &thisValue,
370
- // const facebook::jsi::Value *arguments,
371
- // size_t count) -> facebook::jsi::Value {
372
- // if(!arguments ||
373
- // count != 5 ||
374
- // !arguments[0].isString() ||
375
- // !arguments[1].isString() ||
376
- // !arguments[2].isString() ||
377
- // !arguments[3].isString() ||
378
- // !arguments[4].isNumber()) {
379
- // return facebook::jsi::Value::undefined();
380
- // }
381
- //
382
- // auto userData = arguments[0].asString(rt_1).utf8(rt_1);
383
- // auto secWebSocketKey = arguments[1].asString(rt_1).utf8(rt_1);
384
- // auto secWebSocketProtocol = arguments[2].asString(rt_1).utf8(rt_1);
385
- // auto secWebSocketExtensions = arguments[3].asString(rt_1).utf8(rt_1);
386
- // auto context = arguments[4].asNumber();
387
- //
388
- // // TODO give user a warning if this method has been called outside of cork handler
389
- // // assumeCorked()
390
- //
391
- // auto *usSocketContext = reinterpret_cast<us_socket_context_t *>(static_cast<u_long>(context));
392
- //
393
- // res->upgrade(std::string_view(userData),
394
- // std::string_view(secWebSocketKey),
395
- // std::string_view(secWebSocketProtocol),
396
- // std::string_view(secWebSocketExtensions),
397
- // usSocketContext);
398
- //
399
- // return facebook::jsi::Value::undefined();
400
- // }));
408
+ this->setProperty(rt, "upgrade", facebook::jsi::Function::createFromHostFunction(rt,
409
+ facebook::jsi::PropNameID::forUtf8(rt, "upgrade"),
410
+ 5,
411
+ [provider](facebook::jsi::Runtime &rt_1,
412
+ const facebook::jsi::Value &thisValue,
413
+ const facebook::jsi::Value *arguments,
414
+ size_t count) -> facebook::jsi::Value {
415
+ if(!arguments || count != 5 ||
416
+ !arguments[1].isString() ||
417
+ !arguments[2].isString() ||
418
+ !arguments[3].isString() ||
419
+ !arguments[4].isBigInt()) {
420
+ return facebook::jsi::Value::undefined();
421
+ }
422
+
423
+ if(!arguments[0].isObject()) {
424
+ return facebook::jsi::Value::undefined();
425
+ }
426
+
427
+ auto userDataFnObj = arguments[0].asObject(rt_1);
428
+ if(!userDataFnObj.isFunction(rt_1)) {
429
+ return facebook::jsi::Value::undefined();
430
+ }
431
+
432
+ /// We are not supposed to store the user data object inside of singleton member,
433
+ /// such as map, vector, or any else.
434
+ ///
435
+ /// See this manual
436
+ /// https://github.com/uNetworking/uWebSockets/blob/master/misc/READMORE.md#the-appws-route
437
+ ///
438
+ /// Not like uWebSockets.js, there is no equivalent of v8::UniquePersistent in JSI.
439
+ /// So, instead of holding an JS object,
440
+ /// we store user data as facebook::jsi::HostObject.
441
+ /// See WebSocketUserData.h
442
+ auto userDataFn = userDataFnObj.asFunction(rt_1);
443
+ auto userData = std::make_shared<WebSocketUserData>();
444
+ userDataFn.call(rt_1,
445
+ facebook::jsi::Object::createFromHostObject(rt_1, userData));
446
+
447
+ auto secWebSocketKey = arguments[1].asString(rt_1).utf8(rt_1);
448
+ auto secWebSocketProtocol = arguments[2].asString(rt_1).utf8(rt_1);
449
+ auto secWebSocketExtensions = arguments[3].asString(rt_1).utf8(rt_1);
450
+ auto context = arguments[4].asBigInt(rt_1).asUint64(rt_1);
451
+
452
+ auto *usSocketContext = reinterpret_cast<us_socket_context_t *>(context);
453
+
454
+ #ifdef REACT_NATIVE_DEBUG
455
+ assumeCorked(rt_1);
456
+ #endif
457
+ provider->res->upgrade(std::move(userData),
458
+ std::string_view(secWebSocketKey),
459
+ std::string_view(secWebSocketProtocol),
460
+ std::string_view(secWebSocketExtensions),
461
+ usSocketContext);
462
+
463
+ return facebook::jsi::Value::undefined();
464
+ }));
401
465
 
402
466
  this->setProperty(rt,
403
467
  "write",
@@ -409,6 +473,10 @@ public:
409
473
  const facebook::jsi::Value *arguments,
410
474
  size_t count) -> facebook::jsi::Value {
411
475
  auto chunk = RecognizedString(rt_1, arguments[0]).getStringView();
476
+
477
+ #ifdef REACT_NATIVE_DEBUG
478
+ assumeCorked(rt_1);
479
+ #endif
412
480
  return provider->res->write(chunk);
413
481
  }));
414
482
 
@@ -423,6 +491,10 @@ public:
423
491
  size_t count) -> facebook::jsi::Value {
424
492
  auto headerKey = RecognizedString(rt_1, arguments[0]).getStringView();
425
493
  auto headerVal = RecognizedString(rt_1, arguments[1]).getStringView();
494
+
495
+ #ifdef REACT_NATIVE_DEBUG
496
+ assumeCorked(rt_1);
497
+ #endif
426
498
  provider->res->writeHeader(headerKey, headerVal);
427
499
 
428
500
  return {rt_1, thisValue};
@@ -438,6 +510,10 @@ public:
438
510
  const facebook::jsi::Value *arguments,
439
511
  size_t count) -> facebook::jsi::Value {
440
512
  auto status = RecognizedString(rt_1, arguments[0]).getStringView();
513
+
514
+ #ifdef REACT_NATIVE_DEBUG
515
+ assumeCorked(rt_1);
516
+ #endif
441
517
  provider->res->writeStatus(status);
442
518
 
443
519
  return {rt_1, thisValue};
@@ -19,10 +19,17 @@ private:
19
19
 
20
20
  bool valid = false;
21
21
 
22
+ #ifdef REACT_NATIVE_DEBUG
23
+ void check(facebook::jsi::Runtime &rt) const {
24
+ if(!this->valid) {
25
+ throw facebook::jsi::JSError(rt, "The value is not known by RecognizedString which only recognizes string and ArrayBuffer");
26
+ }
27
+ }
28
+ #endif
29
+
22
30
  public:
23
31
  RecognizedString(facebook::jsi::Runtime &rt,
24
- const facebook::jsi::Value &value,
25
- std::optional<bool> withCheck = true) {
32
+ const facebook::jsi::Value &value) {
26
33
  if(value.isString()) {
27
34
  std::function<void (bool ascii, const void *pData, size_t num)> handler = [this](bool ascii, const void *pData, size_t num) {
28
35
  if(ascii) {
@@ -42,19 +49,13 @@ public:
42
49
  }
43
50
  }
44
51
 
45
- if(withCheck.has_value() && withCheck.value()) {
46
- this->check(rt);
47
- }
48
- }
49
-
50
- public:
51
- void check(facebook::jsi::Runtime &rt) const {
52
- if(!this->valid) {
53
- throw facebook::jsi::JSError(rt, "Text and data can only be passed by string or ArrayBuffer");
54
- }
52
+ #ifdef REACT_NATIVE_DEBUG
53
+ this->check(rt);
54
+ #endif
55
55
  }
56
56
 
57
- bool isValid() const {
57
+ // Check if the Value is recognized as string
58
+ [[nodiscard]] bool isValid() const {
58
59
  return this->valid;
59
60
  }
60
61
 
@@ -66,6 +67,11 @@ public:
66
67
  return {this->data, this->length};
67
68
  }
68
69
 
70
+ static bool isValid(facebook::jsi::Runtime &rt,
71
+ const facebook::jsi::Value &value) {
72
+ return value.isString() || (value.isObject() && value.asObject(rt).isArrayBuffer(rt));
73
+ }
74
+
69
75
  };
70
76
 
71
- }
77
+ }
@@ -3,6 +3,7 @@
3
3
  #include <ReactCommon/CallInvoker.h>
4
4
  #include <ReactCommon/SchedulerPriority.h>
5
5
  #include <jsi/jsi.h>
6
+ #include <react/bridging/Function.h>
6
7
  #include "AppRunner.h"
7
8
  #include "HttpRequestObject.h"
8
9
  #include "HttpResponseObject.h"
@@ -88,6 +89,7 @@ private:
88
89
  }
89
90
  }
90
91
 
92
+ // AppRunner thread
91
93
  std::function<void (uWS::HttpResponse<false> *res, uWS::HttpRequest *req)> uwsRouteHandler = [&jsInvoker, disableBodyRead, maxBodySize, asyncCallback = facebook::react::AsyncCallback(rt, std::move(callback), jsInvoker)](uWS::HttpResponse<false> *res, uWS::HttpRequest *req) {
92
94
  // auto httpResponseObject = std::make_shared<HttpResponseObject>(rt,
93
95
  // res,
@@ -99,6 +101,7 @@ private:
99
101
  auto sharedRequest = std::make_shared<uWS::HttpRequest>(*req);
100
102
 
101
103
  asyncCallback.callWithPriority(facebook::react::SchedulerPriority::ImmediatePriority, [httpResponseObjectProvider, sharedRequest, &jsInvoker](facebook::jsi::Runtime &rt_1, facebook::jsi::Function &cb) {
104
+ // React Native JS runtime
102
105
  if(httpResponseObjectProvider && sharedRequest) {
103
106
  cb.call(rt_1,
104
107
  HttpResponseObject(rt_1, httpResponseObjectProvider, jsInvoker),
@@ -248,7 +251,16 @@ public:
248
251
  const facebook::jsi::Value &thisValue,
249
252
  const facebook::jsi::Value *arguments,
250
253
  size_t count) -> facebook::jsi::Value {
251
- auto callback = arguments[0].asObject(rt_1).asFunction(rt_1);
254
+ if(!arguments || !arguments[0].isObject()) {
255
+ return {rt_1, thisValue};
256
+ }
257
+
258
+ auto obj = arguments[0].asObject(rt_1);
259
+ if(!obj.isFunction(rt_1)) {
260
+ return {rt_1, thisValue};
261
+ }
262
+
263
+ auto callback = obj.asFunction(rt_1);
252
264
 
253
265
  appRunner.app.filter([&jsInvoker, asyncCallback = facebook::react::AsyncCallback(rt_1, std::move(callback), jsInvoker)](auto *res, int count) {
254
266
  auto httpResponseObjectProvider = std::make_shared<HttpResponseObjectProvider>(res);
@@ -299,7 +311,7 @@ public:
299
311
  std::optional<int> options = std::nullopt;
300
312
 
301
313
  if(arguments[0].isString()) {
302
- host = RecognizedString(rt_1, arguments[0]).getString();
314
+ host = arguments[0].asString(rt_1).utf8(rt_1);
303
315
  if(arguments[1].isNumber()) {
304
316
  port = arguments[1].asNumber();
305
317
  }
@@ -338,8 +350,12 @@ public:
338
350
  const facebook::jsi::Value &thisValue,
339
351
  const facebook::jsi::Value *arguments,
340
352
  size_t count) -> facebook::jsi::Value {
341
- auto topic = RecognizedString(rt_1, arguments[0]).getStringView();
342
- return static_cast<int>(appRunner.app.numSubscribers(topic));
353
+ auto topic = RecognizedString(rt_1, arguments[0]);
354
+ if(!topic.isValid()) {
355
+ return {rt_1, int(0)};
356
+ }
357
+
358
+ return static_cast<int>(appRunner.app.numSubscribers(topic.getStringView()));
343
359
  }));
344
360
 
345
361
  this->setProperty(rt,
@@ -351,8 +367,15 @@ public:
351
367
  const facebook::jsi::Value &thisValue,
352
368
  const facebook::jsi::Value *arguments,
353
369
  size_t count) -> facebook::jsi::Value {
354
- auto topic = RecognizedString(rt_1, arguments[0]).getStringView();
355
- auto message = RecognizedString(rt_1, arguments[1]).getStringView();
370
+ auto topic = RecognizedString(rt_1, arguments[0]);
371
+ if(!topic.isValid()) {
372
+ return {rt_1, false};
373
+ }
374
+
375
+ auto message = RecognizedString(rt_1, arguments[1]);
376
+ if(!message.isValid()) {
377
+ return {rt_1, false};
378
+ }
356
379
 
357
380
  bool isBinary = false;
358
381
  if(arguments[2].isBool()) {
@@ -364,38 +387,40 @@ public:
364
387
  compress = arguments[3].asBool();
365
388
  }
366
389
 
367
- return appRunner.app.publish(topic,
368
- message,
369
- isBinary ? uWS::OpCode::BINARY : uWS::TEXT,
370
- compress);
390
+ return appRunner.app.publish(topic.getStringView(),
391
+ message.getStringView(),
392
+ isBinary ? uWS::OpCode::BINARY : uWS::TEXT,
393
+ compress);
371
394
  }));
372
395
 
373
- // TODO `WebSocketObject` and `WebSocketBehaviorImpl` are not properly implemented yet
374
- // this->setProperty(rt,
375
- // "ws",
376
- // facebook::jsi::Function::createFromHostFunction(rt,
377
- // facebook::jsi::PropNameID::forUtf8(rt, "ws"),
378
- // 2,
379
- // [&appRunner, &jsInvoker](facebook::jsi::Runtime &rt_1,
380
- // const facebook::jsi::Value &thisValue,
381
- // const facebook::jsi::Value *arguments,
382
- // size_t count) -> facebook::jsi::Value {
383
- //#ifdef REACT_NATIVE_DEBUG
384
- // if(!arguments) {
385
- // throw facebook::jsi::JSError(rt_1, "Expected pattern and WebSocketBehaviour argument");
386
- // }
387
- // if(!arguments[1].isObject()) {
388
- // throw facebook::jsi::JSError(rt_1, "Expected a WebSocketBehaviour object in the second argument");
389
- // }
390
- //#endif
391
- //
392
- // auto pattern = RecognizedString(rt_1, arguments[0]).getString();
393
- // auto behavior = WebSocketBehaviorImpl(rt_1, jsInvoker, arguments[1].asObject(rt_1));
394
- //
395
- // appRunner.app.ws(pattern, std::move(behavior));
396
- //
397
- // return {rt_1, thisValue};
398
- // }));
396
+ this->setProperty(rt,
397
+ "ws",
398
+ facebook::jsi::Function::createFromHostFunction(rt,
399
+ facebook::jsi::PropNameID::forUtf8(rt, "ws"),
400
+ 2,
401
+ [&appRunner, &jsInvoker](facebook::jsi::Runtime &rt_1,
402
+ const facebook::jsi::Value &thisValue,
403
+ const facebook::jsi::Value *arguments,
404
+ size_t count) -> facebook::jsi::Value {
405
+ if(!arguments) {
406
+ return {rt_1, thisValue};
407
+ }
408
+
409
+ auto pattern = RecognizedString(rt_1, arguments[0]);
410
+ if(!pattern.isValid()) {
411
+ return {rt_1, thisValue};
412
+ }
413
+
414
+ if(!arguments[1].isObject()) {
415
+ return {rt_1, thisValue};
416
+ }
417
+
418
+ auto behavior = WebSocketBehaviorImpl(rt_1, jsInvoker, arguments[1].asObject(rt_1));
419
+
420
+ appRunner.app.ws(pattern.getString(), std::move(behavior));
421
+
422
+ return {rt_1, thisValue};
423
+ }));
399
424
 
400
425
  // +++++ ROUTER +++++
401
426