react-native-nitro-net 0.1.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.
Files changed (83) hide show
  1. package/README.md +133 -0
  2. package/android/CMakeLists.txt +29 -0
  3. package/android/OnLoad.cpp +6 -0
  4. package/android/build.gradle +72 -0
  5. package/android/gradle.properties +6 -0
  6. package/android/libs/arm64-v8a/librust_c_net.so +0 -0
  7. package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
  8. package/android/libs/x86/librust_c_net.so +0 -0
  9. package/android/libs/x86_64/librust_c_net.so +0 -0
  10. package/android/src/main/AndroidManifest.xml +3 -0
  11. package/android/src/main/java/com/margelo/nitro/net/NitroNetPackage.java +32 -0
  12. package/cpp/HybridNetDriver.cpp +5 -0
  13. package/cpp/HybridNetDriver.hpp +42 -0
  14. package/cpp/HybridNetServerDriver.cpp +5 -0
  15. package/cpp/HybridNetServerDriver.hpp +114 -0
  16. package/cpp/HybridNetSocketDriver.cpp +6 -0
  17. package/cpp/HybridNetSocketDriver.hpp +132 -0
  18. package/cpp/NetBindings.hpp +68 -0
  19. package/cpp/NetManager.hpp +160 -0
  20. package/ios/Frameworks/RustCNet.xcframework/Info.plist +44 -0
  21. package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/Info.plist +20 -0
  22. package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
  23. package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/Info.plist +20 -0
  24. package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
  25. package/lib/Driver.d.ts +2 -0
  26. package/lib/Driver.js +5 -0
  27. package/lib/Net.nitro.d.ts +85 -0
  28. package/lib/Net.nitro.js +21 -0
  29. package/lib/index.d.ts +162 -0
  30. package/lib/index.js +781 -0
  31. package/nitrogen/generated/.gitattributes +1 -0
  32. package/nitrogen/generated/android/RustCNet+autolinking.cmake +86 -0
  33. package/nitrogen/generated/android/RustCNet+autolinking.gradle +27 -0
  34. package/nitrogen/generated/android/RustCNetOnLoad.cpp +51 -0
  35. package/nitrogen/generated/android/RustCNetOnLoad.hpp +25 -0
  36. package/nitrogen/generated/android/c++/JFunc_void_double_std__shared_ptr_ArrayBuffer_.hpp +77 -0
  37. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +74 -0
  38. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +67 -0
  39. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +99 -0
  40. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +72 -0
  41. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +127 -0
  42. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +79 -0
  43. package/nitrogen/generated/android/c++/JNetConfig.hpp +57 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/Func_void_double_std__shared_ptr_ArrayBuffer_.kt +80 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +65 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +92 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +122 -0
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +38 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/RustCNetOnLoad.kt +35 -0
  50. package/nitrogen/generated/ios/RustCNet+autolinking.rb +60 -0
  51. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +75 -0
  52. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +186 -0
  53. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +60 -0
  54. package/nitrogen/generated/ios/RustCNetAutolinking.mm +35 -0
  55. package/nitrogen/generated/ios/RustCNetAutolinking.swift +12 -0
  56. package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.cpp +11 -0
  57. package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +100 -0
  58. package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.cpp +11 -0
  59. package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +117 -0
  60. package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.cpp +11 -0
  61. package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +163 -0
  62. package/nitrogen/generated/ios/swift/Func_void_double_std__shared_ptr_ArrayBuffer_.swift +47 -0
  63. package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +58 -0
  64. package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +167 -0
  65. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +61 -0
  66. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +217 -0
  67. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +69 -0
  68. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +288 -0
  69. package/nitrogen/generated/ios/swift/NetConfig.swift +36 -0
  70. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +23 -0
  71. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +74 -0
  72. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +29 -0
  73. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +72 -0
  74. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +36 -0
  75. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +78 -0
  76. package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.cpp +32 -0
  77. package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.hpp +74 -0
  78. package/nitrogen/generated/shared/c++/NetConfig.hpp +83 -0
  79. package/package.json +59 -0
  80. package/react-native-nitro-net.podspec +47 -0
  81. package/src/Driver.ts +4 -0
  82. package/src/Net.nitro.ts +85 -0
  83. package/src/index.ts +870 -0
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # react-native-nitro-net
2
+
3
+ Node.js `net` API implementation for React Native using [Nitro Modules](https://github.com/mrousavy/nitro) and Rust.
4
+
5
+ ## Features
6
+
7
+ * 🚀 **High Performance**: Built on top of Rust's `tokio` asynchronous runtime.
8
+ * 🤝 **Node.js Compatible**: Implements the standard `net` API including `Socket` (Duplex stream) and `Server`.
9
+ * ⚡ **Nitro Modules**: Uses JSI for zero-overhead communication between JavaScript and Native code.
10
+ * 🛡️ **Robust & Stable**: Advanced fixes for common networking issues like port reuse, deadlocks, and DNS reliability.
11
+ * 📱 **Cross-Platform**: Supports both iOS and Android.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install react-native-nitro-net
17
+ # or
18
+ yarn add react-native-nitro-net
19
+ ```
20
+
21
+ ### iOS
22
+
23
+ Requires `pod install` to link the native libraries.
24
+
25
+ ```bash
26
+ cd ios && pod install
27
+ ```
28
+
29
+ ## Architecture
30
+
31
+ This library uses a high-performance three-layer architecture:
32
+
33
+ 1. **JavaScript Layer**: Provides the high-level Node.js compatible `net.Socket` (Duplex) and `net.Server` APIs using `readable-stream` and `EventEmitter`.
34
+ 2. **C++ Bridge (Nitro)**: Handles the zero-copy orchestration between JS and Rust using Nitro Hybrid Objects and JSI.
35
+ 3. **Rust Core**: Implements the actual networking logic using the **Tokio** asynchronous runtime, providing memory safety and high concurrency.
36
+
37
+ ## Usage
38
+
39
+ ### Client (Socket)
40
+
41
+ ```typescript
42
+ import net from 'react-native-nitro-net';
43
+
44
+ const client = net.createConnection({ port: 8080, host: '1.1.1.1' }, () => {
45
+ console.log('Connected!');
46
+ client.write('Hello Server!');
47
+ });
48
+
49
+ client.on('data', (data) => {
50
+ console.log('Received:', data.toString());
51
+ });
52
+
53
+ client.on('error', (err) => {
54
+ console.error('Error:', err.message);
55
+ });
56
+ ```
57
+
58
+ ### Server (Dynamic Port Support)
59
+
60
+ The server supports binding to a dynamic port by using `0`.
61
+
62
+ ```typescript
63
+ import net from 'react-native-nitro-net';
64
+
65
+ const server = net.createServer((socket) => {
66
+ socket.write('Echo: ' + socket.read());
67
+ });
68
+
69
+ // Use 0 for dynamic port allocation
70
+ server.listen(0, '127.0.0.1', () => {
71
+ const address = server.address();
72
+ console.log(`Server listening on dynamic port: ${address?.port}`);
73
+ });
74
+ ```
75
+
76
+ ## Stability Improvements
77
+
78
+ We have implemented several critical fixes to ensure production-grade stability:
79
+
80
+ * **Port Reuse (`SO_REUSEPORT`)**: Automatically enabled on Unix/iOS to allow immediate server restarts without the "Address already in use" error.
81
+ * **Anti-Deadlock Logic**: C++ layer uses lock-free callback dispatching to prevent UI freezes during high-frequency events.
82
+ * **DNS Reliability**: Automatically retries all resolved IP addresses if the first one fails to connect.
83
+ * **Resource Management**: Strict protective shutdown logic in Rust to prevent socket and Unix domain socket file leaks.
84
+
85
+ ## API Reference
86
+
87
+ ### `net.Socket`
88
+
89
+ | Property / Method | Description |
90
+ | --- | --- |
91
+ | `connect(options)` | Connect to a remote host/port or Unix path. |
92
+ | `write(data)` | Send data asynchronously. Supports backpressure. |
93
+ | `destroy()` | Immediate closing of the socket and resource cleanup. |
94
+ | `setNoDelay(bool)` | Control Nagle's algorithm. |
95
+ | `setKeepAlive(bool)`| Enable/disable keep-alive. |
96
+ | `address()` | Returns `{ port, family, address }` for the local side. |
97
+
98
+ **Events**: `connect`, `ready`, `data`, `error`, `close`, `timeout`, `lookup`.
99
+
100
+ ### Global APIs
101
+
102
+ | Method | Description |
103
+ | --- | --- |
104
+ | `initWithConfig(options)` | Optional. Initializes the Rust runtime with custom settings (e.g., `workerThreads`). Must be called before any other operation. |
105
+ | `setVerbose(bool)` | Toggle detailed logging for JS, C++, and Rust. |
106
+ | `isIP(string)` | Returns `0`, `4`, or `6`. |
107
+
108
+ ### `net.Server`
109
+
110
+ | Method | Description |
111
+ | --- | --- |
112
+ | `listen(options)` | Start listening. Supports `port: 0` for dynamic allocation. |
113
+ | `close()` | Stops the server from accepting new connections. |
114
+ | `address()` | Returns the bound address (crucial for dynamic ports). |
115
+ | `getConnections(cb)`| Get count of active connections. |
116
+
117
+ **Events**: `listening`, `connection`, `error`, `close`.
118
+
119
+ ## Debugging
120
+
121
+ Enable verbose logging to see the internal data flow across JS, C++, and Rust:
122
+
123
+ ```typescript
124
+ import { setVerbose } from 'react-native-nitro-net';
125
+
126
+ setVerbose(true);
127
+ ```
128
+
129
+ Logs will be visible in your native debugger (Xcode/logcat) and JS console, prefixed with `[NET DEBUG]` or `[NET NATIVE]`.
130
+
131
+ ## License
132
+
133
+ ISC
@@ -0,0 +1,29 @@
1
+ cmake_minimum_required(VERSION 3.9.0)
2
+ project(RustCNet)
3
+
4
+ set(PACKAGE_NAME RustCNet)
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
6
+ set(CMAKE_CXX_STANDARD 20)
7
+
8
+ # Add our custom implementation and JNI adapter
9
+ add_library(${PACKAGE_NAME} SHARED
10
+ ../cpp/HybridNetDriver.cpp
11
+ ../cpp/HybridNetServerDriver.cpp
12
+ ../cpp/HybridNetSocketDriver.cpp
13
+ OnLoad.cpp
14
+ )
15
+
16
+ # Include paths for our headers
17
+ include_directories(
18
+ ${CMAKE_CURRENT_SOURCE_DIR}/../cpp
19
+ )
20
+
21
+ # Include the Nitrogen-generated CMake file
22
+ include(${CMAKE_CURRENT_SOURCE_DIR}/../nitrogen/generated/android/RustCNet+autolinking.cmake)
23
+
24
+ # Link the Rust Net library
25
+ target_link_directories(${PACKAGE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI})
26
+ target_link_libraries(${PACKAGE_NAME}
27
+ rust_c_net
28
+ log # For android logging
29
+ )
@@ -0,0 +1,6 @@
1
+ #include "RustCNetOnLoad.hpp"
2
+ #include <jni.h>
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
5
+ return margelo::nitro::net::initialize(vm);
6
+ }
@@ -0,0 +1,72 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'org.jetbrains.kotlin.android'
3
+
4
+ def reactNativeArchitectures() {
5
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
6
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
7
+ }
8
+
9
+ def getExtOrDefault(name, defaultValue) {
10
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : defaultValue
11
+ }
12
+
13
+ android {
14
+ namespace "com.margelo.nitro.net"
15
+ ndkVersion getExtOrDefault("ndkVersion", "27.1.12297006")
16
+ compileSdkVersion getExtOrDefault('compileSdkVersion', 35)
17
+
18
+ defaultConfig {
19
+ minSdkVersion getExtOrDefault('minSdkVersion', 21)
20
+ targetSdkVersion getExtOrDefault('targetSdkVersion', 35)
21
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "false" // Default to false, app will override if needed
22
+
23
+ externalNativeBuild {
24
+ cmake {
25
+ cppFlags "-fexceptions", "-frtti", "-std=c++20"
26
+ arguments "-DANDROID_STL=c++_shared"
27
+ abiFilters (*reactNativeArchitectures())
28
+ }
29
+ }
30
+ }
31
+
32
+ buildFeatures {
33
+ buildConfig true
34
+ prefab true
35
+ }
36
+
37
+ sourceSets {
38
+ main {
39
+ jniLibs.srcDirs += ['libs']
40
+ }
41
+ }
42
+
43
+ externalNativeBuild {
44
+ cmake {
45
+ path "CMakeLists.txt"
46
+ }
47
+ }
48
+
49
+ buildTypes {
50
+ release {
51
+ minifyEnabled false
52
+ }
53
+ }
54
+
55
+ packagingOptions {
56
+ excludes += [
57
+ "**/libc++_shared.so",
58
+ "**/libjsi.so",
59
+ "**/libreactnativejni.so",
60
+ "**/libreact_nativemodule_core.so",
61
+ "**/libturbomodulejsijni.so"
62
+ ]
63
+ }
64
+ }
65
+
66
+ dependencies {
67
+ implementation "com.facebook.react:react-native:+"
68
+ implementation project(':react-native-nitro-modules')
69
+ }
70
+
71
+ // Apply the Nitrogen-generated Gradle file
72
+ apply from: "../nitrogen/generated/android/RustCNet+autolinking.gradle"
@@ -0,0 +1,6 @@
1
+ reactNativeArchitectures=arm64-v8a,armeabi-v7a,x86,x86_64
2
+ ndkVersion=27.1.12297006
3
+ compileSdkVersion=35
4
+ targetSdkVersion=35
5
+ minSdkVersion=24
6
+ kotlinVersion=1.9.24
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.margelo.nitro.net">
3
+ </manifest>
@@ -0,0 +1,32 @@
1
+ package com.margelo.nitro.net;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.facebook.react.ReactPackage;
5
+ import com.facebook.react.bridge.NativeModule;
6
+ import com.facebook.react.bridge.ReactApplicationContext;
7
+ import com.facebook.react.uimanager.ViewManager;
8
+ import java.util.Collections;
9
+ import java.util.List;
10
+ import android.util.Log;
11
+
12
+ public class NitroNetPackage implements ReactPackage {
13
+ static {
14
+ try {
15
+ System.loadLibrary("RustCNet");
16
+ } catch (Throwable e) {
17
+ Log.e("NitroNetPackage", "Failed to load RustCNet library", e);
18
+ }
19
+ }
20
+
21
+ @NonNull
22
+ @Override
23
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
24
+ return Collections.emptyList();
25
+ }
26
+
27
+ @NonNull
28
+ @Override
29
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
30
+ return Collections.emptyList();
31
+ }
32
+ }
@@ -0,0 +1,5 @@
1
+ #include "HybridNetDriver.hpp"
2
+
3
+ namespace margelo::nitro::net {
4
+ // Inline
5
+ }
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include "../nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp"
4
+ #include "HybridNetServerDriver.hpp"
5
+ #include "HybridNetSocketDriver.hpp"
6
+ #include "NetManager.hpp"
7
+
8
+ namespace margelo {
9
+ namespace nitro {
10
+ namespace net {
11
+
12
+ class HybridNetDriver : public HybridNetDriverSpec {
13
+ public:
14
+ HybridNetDriver() : HybridObject(TAG) {}
15
+
16
+ std::shared_ptr<HybridNetSocketDriverSpec>
17
+ createSocket(const std::optional<std::string> &id) override {
18
+ if (id.has_value()) {
19
+ // Existing socket from server accept
20
+ try {
21
+ uint32_t socketId = static_cast<uint32_t>(std::stoul(id.value()));
22
+ return std::make_shared<HybridNetSocketDriver>(socketId);
23
+ } catch (...) {
24
+ return std::make_shared<HybridNetSocketDriver>();
25
+ }
26
+ }
27
+ return std::make_shared<HybridNetSocketDriver>();
28
+ }
29
+
30
+ std::shared_ptr<HybridNetServerDriverSpec> createServer() override {
31
+ return std::make_shared<HybridNetServerDriver>();
32
+ }
33
+
34
+ void initWithConfig(const NetConfig &config) override {
35
+ uint32_t workerThreads = config.workerThreads.value_or(0);
36
+ NetManager::shared().initWithConfig(workerThreads);
37
+ }
38
+ };
39
+
40
+ } // namespace net
41
+ } // namespace nitro
42
+ } // namespace margelo
@@ -0,0 +1,5 @@
1
+ #include "HybridNetServerDriver.hpp"
2
+
3
+ namespace margelo::nitro::net {
4
+ // Inline implementation
5
+ }
@@ -0,0 +1,114 @@
1
+ #pragma once
2
+
3
+ #include "../nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp"
4
+ #include "NetBindings.hpp"
5
+ #include "NetManager.hpp"
6
+ #include <NitroModules/ArrayBuffer.hpp>
7
+ #include <optional>
8
+ #include <string>
9
+
10
+ namespace margelo {
11
+ namespace nitro {
12
+ namespace net {
13
+
14
+ class HybridNetServerDriver : public HybridNetServerDriverSpec {
15
+ public:
16
+ HybridNetServerDriver() : HybridObject(TAG) {
17
+ _id = net_create_server();
18
+ NetManager::shared().registerHandler(
19
+ _id, [this](int type, const uint8_t *data, size_t len) {
20
+ this->onNativeEvent(type, data, len);
21
+ });
22
+ }
23
+
24
+ ~HybridNetServerDriver() override { destroy(); }
25
+
26
+ // Properties
27
+ std::function<void(double, const std::shared_ptr<ArrayBuffer> &)>
28
+ getOnEvent() override {
29
+ return _onEvent;
30
+ }
31
+ void setOnEvent(
32
+ const std::function<void(double, const std::shared_ptr<ArrayBuffer> &)>
33
+ &onEvent) override {
34
+ _onEvent = onEvent;
35
+ }
36
+
37
+ double getMaxConnections() override { return _maxConnections; }
38
+ void setMaxConnections(double maxConnections) override {
39
+ _maxConnections = maxConnections;
40
+ net_server_set_max_connections(_id, static_cast<int>(maxConnections));
41
+ }
42
+
43
+ // Methods
44
+ void listen(double port, std::optional<double> backlog,
45
+ std::optional<bool> ipv6Only,
46
+ std::optional<bool> reusePort) override {
47
+ net_listen(_id, static_cast<int>(port),
48
+ static_cast<int>(backlog.value_or(128)),
49
+ ipv6Only.value_or(false), reusePort.value_or(false));
50
+ }
51
+
52
+ void listenUnix(const std::string &path,
53
+ std::optional<double> backlog) override {
54
+ net_listen_unix(_id, path.c_str(), static_cast<int>(backlog.value_or(128)));
55
+ }
56
+
57
+ void listenHandle(double fd, std::optional<double> backlog) override {
58
+ net_listen_handle(_id, static_cast<int>(fd),
59
+ static_cast<int>(backlog.value_or(128)));
60
+ }
61
+
62
+ std::string getLocalAddress() override {
63
+ char buf[256];
64
+ size_t len = net_get_server_local_address(_id, buf, sizeof(buf));
65
+ if (len > 0 && len < sizeof(buf)) {
66
+ buf[len] = '\0';
67
+ return std::string(buf);
68
+ }
69
+ return "";
70
+ }
71
+
72
+ void close() override {
73
+ if (_id != 0) {
74
+ net_server_close(_id);
75
+ }
76
+ }
77
+
78
+ private:
79
+ void destroy() {
80
+ if (_id != 0) {
81
+ NetManager::shared().unregisterHandler(_id);
82
+ net_destroy_server(_id);
83
+ _id = 0;
84
+ }
85
+ }
86
+
87
+ void onNativeEvent(int type, const uint8_t *data, size_t len) {
88
+ if (!_onEvent)
89
+ return;
90
+
91
+ std::shared_ptr<ArrayBuffer> ab;
92
+ if (data && len > 0) {
93
+ ab = ArrayBuffer::copy(data, len);
94
+ } else {
95
+ static uint8_t empty = 0;
96
+ ab = ArrayBuffer::copy(&empty, 0);
97
+ }
98
+
99
+ _onEvent(static_cast<double>(type), ab);
100
+
101
+ if (type == 4) { // CLOSE
102
+ LOGI("Server %u received CLOSE event, destroying...", _id);
103
+ destroy();
104
+ }
105
+ }
106
+
107
+ uint32_t _id;
108
+ double _maxConnections = 0;
109
+ std::function<void(double, const std::shared_ptr<ArrayBuffer> &)> _onEvent;
110
+ };
111
+
112
+ } // namespace net
113
+ } // namespace nitro
114
+ } // namespace margelo
@@ -0,0 +1,6 @@
1
+ #include "HybridNetSocketDriver.hpp"
2
+
3
+ namespace margelo::nitro::net {
4
+ // Implementation is inline in header for simplicity, but if needed we can move
5
+ // it here.
6
+ }
@@ -0,0 +1,132 @@
1
+ #pragma once
2
+
3
+ #include "../nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp"
4
+ #include "NetBindings.hpp"
5
+ #include "NetManager.hpp"
6
+ #include <NitroModules/ArrayBuffer.hpp>
7
+ #include <string>
8
+
9
+ namespace margelo {
10
+ namespace nitro {
11
+ namespace net {
12
+
13
+ class HybridNetSocketDriver : public HybridNetSocketDriverSpec {
14
+ public:
15
+ HybridNetSocketDriver() : HybridObject(TAG) {
16
+ _id = net_create_socket();
17
+ NetManager::shared().registerHandler(
18
+ _id, [this](int type, const uint8_t *data, size_t len) {
19
+ this->onNativeEvent(type, data, len);
20
+ });
21
+ }
22
+
23
+ // For server connections (created with existing ID)
24
+ explicit HybridNetSocketDriver(uint32_t id) : HybridObject(TAG), _id(id) {
25
+ NetManager::shared().registerHandler(
26
+ _id, [this](int type, const uint8_t *data, size_t len) {
27
+ this->onNativeEvent(type, data, len);
28
+ });
29
+ }
30
+
31
+ ~HybridNetSocketDriver() override { destroy(); }
32
+
33
+ // Properties
34
+ double getId() override { return static_cast<double>(_id); }
35
+
36
+ std::function<void(double, const std::shared_ptr<ArrayBuffer> &)>
37
+ getOnEvent() override {
38
+ return _onEvent;
39
+ }
40
+ void setOnEvent(
41
+ const std::function<void(double, const std::shared_ptr<ArrayBuffer> &)>
42
+ &onEvent) override {
43
+ _onEvent = onEvent;
44
+ }
45
+
46
+ // Methods
47
+ void connect(const std::string &host, double port) override {
48
+ net_connect(_id, host.c_str(), static_cast<int>(port));
49
+ }
50
+
51
+ void write(const std::shared_ptr<ArrayBuffer> &data) override {
52
+ if (!data)
53
+ return;
54
+ net_write(_id, data->data(), data->size());
55
+ }
56
+
57
+ void destroy() override {
58
+ if (_id != 0) {
59
+ NetManager::shared().unregisterHandler(_id);
60
+ net_destroy_socket(_id);
61
+ _id = 0;
62
+ }
63
+ }
64
+
65
+ void resetAndDestroy() override {
66
+ if (_id != 0) {
67
+ net_socket_reset_and_destroy(_id);
68
+ NetManager::shared().unregisterHandler(_id);
69
+ _id = 0;
70
+ }
71
+ }
72
+
73
+ void setNoDelay(bool enable) override { net_set_nodelay(_id, enable); }
74
+
75
+ void setKeepAlive(bool enable, double delay) override {
76
+ net_set_keepalive(_id, enable, static_cast<uint64_t>(delay));
77
+ }
78
+
79
+ void setTimeout(double timeout) override {
80
+ net_set_timeout(_id, static_cast<uint64_t>(timeout));
81
+ }
82
+
83
+ std::string getLocalAddress() override {
84
+ char buf[256];
85
+ size_t len = net_get_local_address(_id, buf, sizeof(buf));
86
+ if (len > 0 && len < sizeof(buf)) {
87
+ return std::string(buf);
88
+ }
89
+ return "";
90
+ }
91
+
92
+ std::string getRemoteAddress() override {
93
+ char buf[256];
94
+ size_t len = net_get_remote_address(_id, buf, sizeof(buf));
95
+ if (len == 0)
96
+ return "";
97
+ return std::string(buf);
98
+ }
99
+
100
+ void pause() override { net_pause(_id); }
101
+
102
+ void resume() override { net_resume(_id); }
103
+
104
+ void shutdown() override { net_shutdown(_id); }
105
+
106
+ void connectUnix(const std::string &path) override {
107
+ net_connect_unix(_id, path.c_str());
108
+ }
109
+
110
+ private:
111
+ void onNativeEvent(int type, const uint8_t *data, size_t len) {
112
+ if (!_onEvent)
113
+ return;
114
+
115
+ std::shared_ptr<ArrayBuffer> ab;
116
+ if (data && len > 0) {
117
+ ab = ArrayBuffer::copy(data, len);
118
+ } else {
119
+ static uint8_t empty = 0;
120
+ ab = ArrayBuffer::copy(&empty, 0);
121
+ }
122
+
123
+ _onEvent(static_cast<double>(type), ab);
124
+ }
125
+
126
+ uint32_t _id;
127
+ std::function<void(double, const std::shared_ptr<ArrayBuffer> &)> _onEvent;
128
+ };
129
+
130
+ } // namespace net
131
+ } // namespace nitro
132
+ } // namespace margelo
@@ -0,0 +1,68 @@
1
+ #pragma once
2
+
3
+ #include <stddef.h>
4
+ #include <stdint.h>
5
+
6
+ extern "C" {
7
+
8
+ // Callback function type
9
+ typedef void (*NetCallback)(uint32_t id, int event_type, const uint8_t *data,
10
+ size_t len, void *context);
11
+
12
+ // Init
13
+ void net_init(NetCallback callback, void *context);
14
+ /// Initialize with configuration
15
+ /// @param callback Event callback function
16
+ /// @param context User context passed to callback
17
+ /// @param worker_threads Number of worker threads, 0 = use CPU core count
18
+ void net_init_with_config(NetCallback callback, void *context,
19
+ uint32_t worker_threads);
20
+
21
+ // Socket
22
+ uint32_t net_create_socket();
23
+ void net_connect(uint32_t id, const char *host, int port);
24
+ void net_write(uint32_t id, const uint8_t *data, size_t len);
25
+ void net_close(uint32_t id);
26
+ void net_destroy_socket(uint32_t id);
27
+ void net_socket_reset_and_destroy(uint32_t id);
28
+
29
+ // New Options
30
+ void net_set_nodelay(uint32_t id, bool enable);
31
+ void net_set_keepalive(uint32_t id, bool enable, uint64_t delay_ms);
32
+ void net_set_timeout(uint32_t id, uint64_t timeout_ms);
33
+
34
+ // New Address Info
35
+ // Returns length of address string. buf can be null to query length.
36
+ size_t net_get_local_address(uint32_t id, char *buf, size_t len);
37
+ size_t net_get_remote_address(uint32_t id, char *buf, size_t len);
38
+
39
+ // Flow Control
40
+ void net_pause(uint32_t id);
41
+ void net_resume(uint32_t id);
42
+ void net_shutdown(uint32_t id);
43
+
44
+ // IPC
45
+ void net_connect_unix(uint32_t id, const char *path);
46
+ void net_listen_unix(uint32_t id, const char *path, int backlog);
47
+
48
+ // Server
49
+ uint32_t net_create_server();
50
+ void net_listen(uint32_t id, int port, int backlog, bool ipv6_only,
51
+ bool reuse_port);
52
+ void net_server_close(uint32_t id);
53
+ void net_destroy_server(uint32_t id);
54
+ void net_server_set_max_connections(uint32_t id, int max_connections);
55
+ size_t net_get_server_local_address(uint32_t id, char *buf, size_t len);
56
+ /// Listen on an existing file descriptor (handle)
57
+ /// @param id Server ID
58
+ /// @param fd File descriptor of an already-bound TCP listener
59
+ /// @param backlog Listen backlog
60
+ void net_listen_handle(uint32_t id, int fd, int backlog);
61
+
62
+ // Event Types
63
+ #define NET_EVENT_CONNECT 1
64
+ #define NET_EVENT_DATA 2
65
+ #define NET_EVENT_ERROR 3
66
+ #define NET_EVENT_CLOSE 4
67
+ #define NET_EVENT_CONNECTION 6
68
+ }