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.
- package/README.md +133 -0
- package/android/CMakeLists.txt +29 -0
- package/android/OnLoad.cpp +6 -0
- package/android/build.gradle +72 -0
- package/android/gradle.properties +6 -0
- package/android/libs/arm64-v8a/librust_c_net.so +0 -0
- package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
- package/android/libs/x86/librust_c_net.so +0 -0
- package/android/libs/x86_64/librust_c_net.so +0 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/margelo/nitro/net/NitroNetPackage.java +32 -0
- package/cpp/HybridNetDriver.cpp +5 -0
- package/cpp/HybridNetDriver.hpp +42 -0
- package/cpp/HybridNetServerDriver.cpp +5 -0
- package/cpp/HybridNetServerDriver.hpp +114 -0
- package/cpp/HybridNetSocketDriver.cpp +6 -0
- package/cpp/HybridNetSocketDriver.hpp +132 -0
- package/cpp/NetBindings.hpp +68 -0
- package/cpp/NetManager.hpp +160 -0
- package/ios/Frameworks/RustCNet.xcframework/Info.plist +44 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/Info.plist +20 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/Info.plist +20 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
- package/lib/Driver.d.ts +2 -0
- package/lib/Driver.js +5 -0
- package/lib/Net.nitro.d.ts +85 -0
- package/lib/Net.nitro.js +21 -0
- package/lib/index.d.ts +162 -0
- package/lib/index.js +781 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/RustCNet+autolinking.cmake +86 -0
- package/nitrogen/generated/android/RustCNet+autolinking.gradle +27 -0
- package/nitrogen/generated/android/RustCNetOnLoad.cpp +51 -0
- package/nitrogen/generated/android/RustCNetOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JFunc_void_double_std__shared_ptr_ArrayBuffer_.hpp +77 -0
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +74 -0
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +67 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +99 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +72 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +127 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +79 -0
- package/nitrogen/generated/android/c++/JNetConfig.hpp +57 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/Func_void_double_std__shared_ptr_ArrayBuffer_.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +92 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +122 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/RustCNetOnLoad.kt +35 -0
- package/nitrogen/generated/ios/RustCNet+autolinking.rb +60 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +75 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +186 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +60 -0
- package/nitrogen/generated/ios/RustCNetAutolinking.mm +35 -0
- package/nitrogen/generated/ios/RustCNetAutolinking.swift +12 -0
- package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +100 -0
- package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +117 -0
- package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +163 -0
- package/nitrogen/generated/ios/swift/Func_void_double_std__shared_ptr_ArrayBuffer_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +58 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +167 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +61 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +217 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +69 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +288 -0
- package/nitrogen/generated/ios/swift/NetConfig.swift +36 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +74 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +29 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +36 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +78 -0
- package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.cpp +32 -0
- package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.hpp +74 -0
- package/nitrogen/generated/shared/c++/NetConfig.hpp +83 -0
- package/package.json +59 -0
- package/react-native-nitro-net.podspec +47 -0
- package/src/Driver.ts +4 -0
- package/src/Net.nitro.ts +85 -0
- 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,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"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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,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,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,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
|
+
}
|