node-datachannel 0.6.0 → 0.7.0
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/CMakeLists.txt +1 -1
- package/jest.config.cjs +7 -0
- package/lib/index.cjs +142 -0
- package/lib/index.d.ts +0 -1
- package/package.json +13 -5
- package/polyfill/RTCPeerConnection.js +0 -1
- package/polyfill/polyfill.cjs +1069 -0
- package/src/data-channel-wrapper.cpp +15 -1
- package/src/data-channel-wrapper.h +5 -1
- package/src/media-track-wrapper.cpp +25 -5
- package/src/media-track-wrapper.h +7 -3
- package/src/peer-connection-wrapper.cpp +21 -27
- package/src/peer-connection-wrapper.h +2 -5
- package/src/rtc-wrapper.cpp +5 -2
- package/src/thread-safe-callback.cpp +6 -2
- package/src/thread-safe-callback.h +3 -1
- package/src/web-socket-wrapper.cpp +16 -3
- package/src/web-socket-wrapper.h +6 -2
- package/test/jest-tests/basic.test.js +37 -0
- package/test/jest-tests/multiple-run.test.js +73 -0
- package/test/jest-tests/p2p.test.js +99 -0
- package/test/jest-tests/streams.test.js +48 -0
- package/test/jest-tests/websocket.test.js +69 -0
- package/test/test.js +0 -252
|
@@ -13,6 +13,14 @@ void DataChannelWrapper::CloseAll()
|
|
|
13
13
|
inst->doClose();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
void DataChannelWrapper::CleanupAll()
|
|
17
|
+
{
|
|
18
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
19
|
+
auto copy(instances);
|
|
20
|
+
for (auto inst : copy)
|
|
21
|
+
inst->doCleanup();
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
Napi::Object DataChannelWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
17
25
|
{
|
|
18
26
|
Napi::HandleScope scope(env);
|
|
@@ -78,11 +86,15 @@ void DataChannelWrapper::doClose()
|
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
mOnOpenCallback.reset();
|
|
81
|
-
mOnClosedCallback.reset();
|
|
82
89
|
mOnErrorCallback.reset();
|
|
83
90
|
mOnBufferedAmountLowCallback.reset();
|
|
84
91
|
mOnMessageCallback.reset();
|
|
92
|
+
}
|
|
85
93
|
|
|
94
|
+
void DataChannelWrapper::doCleanup()
|
|
95
|
+
{
|
|
96
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
97
|
+
mOnClosedCallback.reset();
|
|
86
98
|
instances.erase(this);
|
|
87
99
|
}
|
|
88
100
|
|
|
@@ -350,6 +362,8 @@ void DataChannelWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
350
362
|
// This will run in main thread and needs to construct the
|
|
351
363
|
// arguments for the call
|
|
352
364
|
args = {};
|
|
365
|
+
},[this]{
|
|
366
|
+
doCleanup();
|
|
353
367
|
}); });
|
|
354
368
|
}
|
|
355
369
|
|
|
@@ -42,10 +42,14 @@ public:
|
|
|
42
42
|
// Close all existing DataChannels
|
|
43
43
|
static void CloseAll();
|
|
44
44
|
|
|
45
|
+
// Reset all Callbacks for existing DataChannels
|
|
46
|
+
static void CleanupAll();
|
|
47
|
+
|
|
45
48
|
private:
|
|
46
|
-
static std::unordered_set<DataChannelWrapper*> instances;
|
|
49
|
+
static std::unordered_set<DataChannelWrapper *> instances;
|
|
47
50
|
|
|
48
51
|
void doClose();
|
|
52
|
+
void doCleanup();
|
|
49
53
|
|
|
50
54
|
std::string mLabel;
|
|
51
55
|
std::shared_ptr<rtc::DataChannel> mDataChannelPtr = nullptr;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
#include "media-direction.h"
|
|
3
3
|
#include "media-rtcpreceivingsession-wrapper.h"
|
|
4
4
|
|
|
5
|
+
#include "plog/Log.h"
|
|
6
|
+
|
|
5
7
|
Napi::FunctionReference TrackWrapper::constructor;
|
|
6
8
|
std::unordered_set<TrackWrapper *> TrackWrapper::instances;
|
|
7
9
|
|
|
@@ -12,6 +14,14 @@ void TrackWrapper::CloseAll()
|
|
|
12
14
|
inst->doClose();
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
void TrackWrapper::CleanupAll()
|
|
18
|
+
{
|
|
19
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
20
|
+
auto copy(instances);
|
|
21
|
+
for (auto inst : copy)
|
|
22
|
+
inst->doCleanup();
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
16
26
|
{
|
|
17
27
|
Napi::HandleScope scope(env);
|
|
@@ -73,10 +83,14 @@ void TrackWrapper::doClose()
|
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
mOnOpenCallback.reset();
|
|
76
|
-
mOnClosedCallback.reset();
|
|
77
86
|
mOnErrorCallback.reset();
|
|
78
87
|
mOnMessageCallback.reset();
|
|
88
|
+
}
|
|
79
89
|
|
|
90
|
+
void TrackWrapper::doCleanup()
|
|
91
|
+
{
|
|
92
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
93
|
+
mOnClosedCallback.reset();
|
|
80
94
|
instances.erase(this);
|
|
81
95
|
}
|
|
82
96
|
|
|
@@ -276,7 +290,8 @@ void TrackWrapper::onOpen(const Napi::CallbackInfo &info)
|
|
|
276
290
|
// Callback
|
|
277
291
|
mOnOpenCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
278
292
|
|
|
279
|
-
mTrackPtr->onOpen([&]()
|
|
293
|
+
mTrackPtr->onOpen([&]()
|
|
294
|
+
{
|
|
280
295
|
if (mOnOpenCallback)
|
|
281
296
|
mOnOpenCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
282
297
|
// Check the track is not closed
|
|
@@ -309,7 +324,8 @@ void TrackWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
309
324
|
// Callback
|
|
310
325
|
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
311
326
|
|
|
312
|
-
mTrackPtr->onClosed([&]()
|
|
327
|
+
mTrackPtr->onClosed([&]()
|
|
328
|
+
{
|
|
313
329
|
if (mOnClosedCallback)
|
|
314
330
|
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
315
331
|
// Do not check if the data channel has been closed here
|
|
@@ -317,6 +333,8 @@ void TrackWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
317
333
|
// This will run in main thread and needs to construct the
|
|
318
334
|
// arguments for the call
|
|
319
335
|
args = {};
|
|
336
|
+
},[this]{
|
|
337
|
+
doCleanup();
|
|
320
338
|
}); });
|
|
321
339
|
}
|
|
322
340
|
|
|
@@ -340,7 +358,8 @@ void TrackWrapper::onError(const Napi::CallbackInfo &info)
|
|
|
340
358
|
// Callback
|
|
341
359
|
mOnErrorCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
342
360
|
|
|
343
|
-
mTrackPtr->onError([&](const std::string &error)
|
|
361
|
+
mTrackPtr->onError([&](const std::string &error)
|
|
362
|
+
{
|
|
344
363
|
if (mOnErrorCallback)
|
|
345
364
|
mOnErrorCallback->call([this, error](Napi::Env env, std::vector<napi_value> &args) {
|
|
346
365
|
// Check the track is not closed
|
|
@@ -373,7 +392,8 @@ void TrackWrapper::onMessage(const Napi::CallbackInfo &info)
|
|
|
373
392
|
// Callback
|
|
374
393
|
mOnMessageCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
375
394
|
|
|
376
|
-
mTrackPtr->onMessage([&](std::variant<rtc::binary, std::string> message)
|
|
395
|
+
mTrackPtr->onMessage([&](std::variant<rtc::binary, std::string> message)
|
|
396
|
+
{
|
|
377
397
|
if (mOnMessageCallback)
|
|
378
398
|
mOnMessageCallback->call([this, message = std::move(message)](Napi::Env env, std::vector<napi_value> &args) {
|
|
379
399
|
// Check the track is not closed
|
|
@@ -39,21 +39,25 @@ public:
|
|
|
39
39
|
void onError(const Napi::CallbackInfo &info);
|
|
40
40
|
void onMessage(const Napi::CallbackInfo &info);
|
|
41
41
|
|
|
42
|
-
// Close all existing
|
|
42
|
+
// Close all existing tracks
|
|
43
43
|
static void CloseAll();
|
|
44
44
|
|
|
45
|
+
// Reset all Callbacks for existing tracks
|
|
46
|
+
static void CleanupAll();
|
|
47
|
+
|
|
45
48
|
private:
|
|
46
49
|
static std::unordered_set<TrackWrapper *> instances;
|
|
47
50
|
|
|
48
51
|
void doClose();
|
|
52
|
+
void doCleanup();
|
|
49
53
|
|
|
50
54
|
std::shared_ptr<rtc::Track> mTrackPtr = nullptr;
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
// Callback Ptrs
|
|
53
57
|
std::unique_ptr<ThreadSafeCallback> mOnOpenCallback = nullptr;
|
|
54
58
|
std::unique_ptr<ThreadSafeCallback> mOnClosedCallback = nullptr;
|
|
55
59
|
std::unique_ptr<ThreadSafeCallback> mOnErrorCallback = nullptr;
|
|
56
60
|
std::unique_ptr<ThreadSafeCallback> mOnMessageCallback = nullptr;
|
|
57
61
|
};
|
|
58
62
|
|
|
59
|
-
#endif // MEDIA_TRACK_WRAPPER_H
|
|
63
|
+
#endif // MEDIA_TRACK_WRAPPER_H
|
|
@@ -20,12 +20,12 @@ void PeerConnectionWrapper::CloseAll()
|
|
|
20
20
|
inst->doClose();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
void PeerConnectionWrapper::
|
|
23
|
+
void PeerConnectionWrapper::CleanupAll()
|
|
24
24
|
{
|
|
25
|
-
PLOG_DEBUG << "
|
|
25
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
26
26
|
auto copy(instances);
|
|
27
27
|
for (auto inst : copy)
|
|
28
|
-
inst->
|
|
28
|
+
inst->doCleanup();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
Napi::Object PeerConnectionWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
@@ -37,7 +37,6 @@ Napi::Object PeerConnectionWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
37
37
|
"PeerConnection",
|
|
38
38
|
{
|
|
39
39
|
InstanceMethod("close", &PeerConnectionWrapper::close),
|
|
40
|
-
InstanceMethod("destroy", &PeerConnectionWrapper::destroy),
|
|
41
40
|
InstanceMethod("setLocalDescription", &PeerConnectionWrapper::setLocalDescription),
|
|
42
41
|
InstanceMethod("setRemoteDescription", &PeerConnectionWrapper::setRemoteDescription),
|
|
43
42
|
InstanceMethod("localDescription", &PeerConnectionWrapper::localDescription),
|
|
@@ -253,7 +252,8 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
253
252
|
PeerConnectionWrapper::~PeerConnectionWrapper()
|
|
254
253
|
{
|
|
255
254
|
PLOG_DEBUG << "Destructor called";
|
|
256
|
-
|
|
255
|
+
doCleanup();
|
|
256
|
+
doClose();
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
void PeerConnectionWrapper::doClose()
|
|
@@ -273,40 +273,27 @@ void PeerConnectionWrapper::doClose()
|
|
|
273
273
|
return;
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
|
|
279
|
-
{
|
|
280
|
-
PLOG_DEBUG << "close() called";
|
|
281
|
-
doClose();
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
void PeerConnectionWrapper::doDestroy()
|
|
285
|
-
{
|
|
286
|
-
PLOG_DEBUG << "doDestroy() called";
|
|
287
|
-
doClose();
|
|
288
|
-
doResetCallbacks();
|
|
289
|
-
}
|
|
290
276
|
|
|
291
|
-
void PeerConnectionWrapper::doResetCallbacks()
|
|
292
|
-
{
|
|
293
|
-
PLOG_DEBUG << "doResetCallbacks() called";
|
|
294
277
|
mOnLocalDescriptionCallback.reset();
|
|
295
278
|
mOnLocalCandidateCallback.reset();
|
|
296
|
-
mOnStateChangeCallback.reset();
|
|
297
279
|
mOnIceStateChangeCallback.reset();
|
|
298
280
|
mOnSignalingStateChangeCallback.reset();
|
|
299
281
|
mOnGatheringStateChangeCallback.reset();
|
|
300
282
|
mOnDataChannelCallback.reset();
|
|
301
283
|
mOnTrackCallback.reset();
|
|
284
|
+
}
|
|
302
285
|
|
|
303
|
-
|
|
286
|
+
void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
|
|
287
|
+
{
|
|
288
|
+
PLOG_DEBUG << "close() called";
|
|
289
|
+
doClose();
|
|
304
290
|
}
|
|
305
291
|
|
|
306
|
-
void PeerConnectionWrapper::
|
|
292
|
+
void PeerConnectionWrapper::doCleanup()
|
|
307
293
|
{
|
|
308
|
-
PLOG_DEBUG << "
|
|
309
|
-
|
|
294
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
295
|
+
mOnStateChangeCallback.reset();
|
|
296
|
+
instances.erase(this);
|
|
310
297
|
}
|
|
311
298
|
|
|
312
299
|
void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
|
|
@@ -738,6 +725,13 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
|
|
|
738
725
|
stream << state;
|
|
739
726
|
args = {Napi::String::New(env, stream.str())};
|
|
740
727
|
PLOG_DEBUG << "mOnStateChangeCallback call(2)";
|
|
728
|
+
},[this,state](){
|
|
729
|
+
PLOG_DEBUG << "mOnStateChangeCallback cleanup";
|
|
730
|
+
// Special case for closed state, we need to reset all callbacks
|
|
731
|
+
if(state == rtc::PeerConnection::State::Closed)
|
|
732
|
+
{
|
|
733
|
+
doCleanup();
|
|
734
|
+
}
|
|
741
735
|
}); });
|
|
742
736
|
}
|
|
743
737
|
|
|
@@ -19,8 +19,6 @@ public:
|
|
|
19
19
|
PeerConnectionWrapper(const Napi::CallbackInfo &info);
|
|
20
20
|
~PeerConnectionWrapper();
|
|
21
21
|
|
|
22
|
-
void destroy(const Napi::CallbackInfo &info);
|
|
23
|
-
|
|
24
22
|
// Functions
|
|
25
23
|
void close(const Napi::CallbackInfo &info);
|
|
26
24
|
void setLocalDescription(const Napi::CallbackInfo &info);
|
|
@@ -58,15 +56,14 @@ public:
|
|
|
58
56
|
static void CloseAll();
|
|
59
57
|
|
|
60
58
|
// Reset all Callbacks for existing Peer Connections
|
|
61
|
-
static void
|
|
59
|
+
static void CleanupAll();
|
|
62
60
|
|
|
63
61
|
private:
|
|
64
62
|
static Napi::FunctionReference constructor;
|
|
65
63
|
static std::unordered_set<PeerConnectionWrapper *> instances;
|
|
66
64
|
|
|
67
65
|
void doClose();
|
|
68
|
-
void
|
|
69
|
-
void doResetCallbacks();
|
|
66
|
+
void doCleanup();
|
|
70
67
|
|
|
71
68
|
std::string mPeerName;
|
|
72
69
|
std::unique_ptr<rtc::PeerConnection> mRtcPeerConnPtr = nullptr;
|
package/src/rtc-wrapper.cpp
CHANGED
|
@@ -125,8 +125,11 @@ void RtcWrapper::cleanup(const Napi::CallbackInfo &info)
|
|
|
125
125
|
if (rtc::Cleanup().wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout)
|
|
126
126
|
throw std::runtime_error("cleanup timeout (possible deadlock)");
|
|
127
127
|
|
|
128
|
-
//
|
|
129
|
-
PeerConnectionWrapper::
|
|
128
|
+
// Cleanup the instances
|
|
129
|
+
PeerConnectionWrapper::CleanupAll();
|
|
130
|
+
DataChannelWrapper::CleanupAll();
|
|
131
|
+
TrackWrapper::CleanupAll();
|
|
132
|
+
WebSocketWrapper::CleanupAll();
|
|
130
133
|
|
|
131
134
|
if (logCallback)
|
|
132
135
|
logCallback.reset();
|
|
@@ -26,9 +26,9 @@ ThreadSafeCallback::~ThreadSafeCallback()
|
|
|
26
26
|
tsfn.Abort();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
void ThreadSafeCallback::call(arg_func_t argFunc)
|
|
29
|
+
void ThreadSafeCallback::call(arg_func_t argFunc, cleanup_func_t cleanupFunc)
|
|
30
30
|
{
|
|
31
|
-
CallbackData *data = new CallbackData{std::move(argFunc)};
|
|
31
|
+
CallbackData *data = new CallbackData{std::move(argFunc), std::move(cleanupFunc)};
|
|
32
32
|
if (tsfn.BlockingCall(data) != napi_ok)
|
|
33
33
|
{
|
|
34
34
|
delete data;
|
|
@@ -47,6 +47,7 @@ void ThreadSafeCallback::callbackFunc(Napi::Env env,
|
|
|
47
47
|
|
|
48
48
|
arg_vector_t args;
|
|
49
49
|
arg_func_t argFunc(std::move(data->argFunc));
|
|
50
|
+
cleanup_func_t cleanup(std::move(data->cleanupFunc));
|
|
50
51
|
delete data;
|
|
51
52
|
|
|
52
53
|
try
|
|
@@ -59,5 +60,8 @@ void ThreadSafeCallback::callbackFunc(Napi::Env env,
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
if (env && callback)
|
|
63
|
+
{
|
|
62
64
|
callback.Call(context->Value(), args);
|
|
65
|
+
cleanup();
|
|
66
|
+
}
|
|
63
67
|
}
|
|
@@ -11,6 +11,7 @@ class ThreadSafeCallback
|
|
|
11
11
|
public:
|
|
12
12
|
using arg_vector_t = std::vector<napi_value>;
|
|
13
13
|
using arg_func_t = std::function<void(napi_env, arg_vector_t &)>;
|
|
14
|
+
using cleanup_func_t = std::function<void()>;
|
|
14
15
|
|
|
15
16
|
ThreadSafeCallback(Napi::Function callback);
|
|
16
17
|
~ThreadSafeCallback();
|
|
@@ -21,7 +22,7 @@ public:
|
|
|
21
22
|
ThreadSafeCallback &operator=(const ThreadSafeCallback &) = delete;
|
|
22
23
|
ThreadSafeCallback &operator=(ThreadSafeCallback &&) = delete;
|
|
23
24
|
|
|
24
|
-
void call(arg_func_t argFunc);
|
|
25
|
+
void call(arg_func_t argFunc, cleanup_func_t cleanupFunc = []() {});
|
|
25
26
|
|
|
26
27
|
class CancelException : public std::exception
|
|
27
28
|
{
|
|
@@ -32,6 +33,7 @@ private:
|
|
|
32
33
|
struct CallbackData
|
|
33
34
|
{
|
|
34
35
|
arg_func_t argFunc;
|
|
36
|
+
cleanup_func_t cleanupFunc;
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
static void callbackFunc(Napi::Env env,
|
|
@@ -13,6 +13,14 @@ void WebSocketWrapper::CloseAll()
|
|
|
13
13
|
inst->doClose();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
void WebSocketWrapper::CleanupAll()
|
|
17
|
+
{
|
|
18
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
19
|
+
auto copy(instances);
|
|
20
|
+
for (auto inst : copy)
|
|
21
|
+
inst->doCleanup();
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
Napi::Object WebSocketWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
17
25
|
{
|
|
18
26
|
Napi::HandleScope scope(env);
|
|
@@ -255,11 +263,15 @@ void WebSocketWrapper::doClose()
|
|
|
255
263
|
}
|
|
256
264
|
|
|
257
265
|
mOnOpenCallback.reset();
|
|
258
|
-
mOnClosedCallback.reset();
|
|
259
266
|
mOnErrorCallback.reset();
|
|
260
267
|
mOnBufferedAmountLowCallback.reset();
|
|
261
268
|
mOnMessageCallback.reset();
|
|
269
|
+
}
|
|
262
270
|
|
|
271
|
+
void WebSocketWrapper::doCleanup()
|
|
272
|
+
{
|
|
273
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
274
|
+
mOnClosedCallback.reset();
|
|
263
275
|
instances.erase(this);
|
|
264
276
|
}
|
|
265
277
|
|
|
@@ -488,8 +500,7 @@ void WebSocketWrapper::onOpen(const Napi::CallbackInfo &info)
|
|
|
488
500
|
// This will run in main thread and needs to construct the
|
|
489
501
|
// arguments for the call
|
|
490
502
|
args = {};
|
|
491
|
-
PLOG_DEBUG << "mOnOpenCallback call(2)"; });
|
|
492
|
-
});
|
|
503
|
+
PLOG_DEBUG << "mOnOpenCallback call(2)"; }); });
|
|
493
504
|
}
|
|
494
505
|
|
|
495
506
|
void WebSocketWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
@@ -524,6 +535,8 @@ void WebSocketWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
524
535
|
// This will run in main thread and needs to construct the
|
|
525
536
|
// arguments for the call
|
|
526
537
|
args = {};
|
|
538
|
+
},[this]{
|
|
539
|
+
doCleanup();
|
|
527
540
|
}); });
|
|
528
541
|
}
|
|
529
542
|
|
package/src/web-socket-wrapper.h
CHANGED
|
@@ -22,7 +22,7 @@ public:
|
|
|
22
22
|
|
|
23
23
|
// Functions
|
|
24
24
|
void open(const Napi::CallbackInfo &info);
|
|
25
|
-
void close(const Napi::CallbackInfo &info);
|
|
25
|
+
void close(const Napi::CallbackInfo &info);
|
|
26
26
|
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
27
27
|
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
28
28
|
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
@@ -40,10 +40,14 @@ public:
|
|
|
40
40
|
// Close all existing WebSockets
|
|
41
41
|
static void CloseAll();
|
|
42
42
|
|
|
43
|
+
// Reset all Callbacks for existing WebSockets
|
|
44
|
+
static void CleanupAll();
|
|
45
|
+
|
|
43
46
|
private:
|
|
44
|
-
static std::unordered_set<WebSocketWrapper*> instances;
|
|
47
|
+
static std::unordered_set<WebSocketWrapper *> instances;
|
|
45
48
|
|
|
46
49
|
void doClose();
|
|
50
|
+
void doCleanup();
|
|
47
51
|
|
|
48
52
|
std::shared_ptr<rtc::WebSocket> mWebSocketPtr = nullptr;
|
|
49
53
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as nodeDataChannel from '../../lib';
|
|
2
|
+
|
|
3
|
+
describe('Module Definition', () => {
|
|
4
|
+
test('Module Defined', () => {
|
|
5
|
+
expect(nodeDataChannel).toBeDefined();
|
|
6
|
+
expect(nodeDataChannel.initLogger).toBeDefined();
|
|
7
|
+
expect(nodeDataChannel.PeerConnection).toBeDefined();
|
|
8
|
+
expect(typeof nodeDataChannel.PeerConnection).toBe('function');
|
|
9
|
+
expect(nodeDataChannel.DataChannel).toBeDefined();
|
|
10
|
+
expect(typeof nodeDataChannel.DataChannel).toBe('function');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('PeerConnection Classes', () => {
|
|
15
|
+
test('Create PeerConnection', () => {
|
|
16
|
+
let peer = new nodeDataChannel.PeerConnection('Peer', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
17
|
+
expect(peer).toBeDefined();
|
|
18
|
+
expect(peer.onStateChange).toBeDefined();
|
|
19
|
+
expect(peer.createDataChannel).toBeDefined();
|
|
20
|
+
|
|
21
|
+
peer.close();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('Create Data Channel', () => {
|
|
25
|
+
let peer = new nodeDataChannel.PeerConnection('Peer', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
26
|
+
let dc = peer.createDataChannel('test', { protocol: 'test-protocol' });
|
|
27
|
+
expect(dc).toBeDefined();
|
|
28
|
+
expect(dc.getId()).toBeDefined();
|
|
29
|
+
expect(dc.getProtocol()).toBe('test-protocol');
|
|
30
|
+
expect(dc.getLabel()).toBe('test');
|
|
31
|
+
expect(dc.onOpen).toBeDefined();
|
|
32
|
+
expect(dc.onMessage).toBeDefined();
|
|
33
|
+
|
|
34
|
+
dc.close();
|
|
35
|
+
peer.close();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import * as nodeDataChannel from '../../lib';
|
|
3
|
+
|
|
4
|
+
describe('P2P', () => {
|
|
5
|
+
// Default is 5000 ms but we need more
|
|
6
|
+
jest.setTimeout(12000);
|
|
7
|
+
|
|
8
|
+
test.each(Array(100).fill(0))('P2P Test-%p', (i) => {
|
|
9
|
+
return new Promise((done) => {
|
|
10
|
+
let peer1 = new nodeDataChannel.PeerConnection('Peer1', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
11
|
+
let peer2 = new nodeDataChannel.PeerConnection('Peer2', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
12
|
+
let dc1 = null;
|
|
13
|
+
let dc2 = null;
|
|
14
|
+
|
|
15
|
+
// Mocks
|
|
16
|
+
const p1DCMessageMock = jest.fn();
|
|
17
|
+
const p2DCMessageMock = jest.fn();
|
|
18
|
+
|
|
19
|
+
// Set Callbacks
|
|
20
|
+
peer1.onStateChange(() => {
|
|
21
|
+
/** */
|
|
22
|
+
});
|
|
23
|
+
peer1.onGatheringStateChange(() => {
|
|
24
|
+
/** */
|
|
25
|
+
});
|
|
26
|
+
peer1.onLocalDescription((sdp, type) => {
|
|
27
|
+
peer2.setRemoteDescription(sdp, type);
|
|
28
|
+
});
|
|
29
|
+
peer1.onLocalCandidate((candidate, mid) => {
|
|
30
|
+
peer2.addRemoteCandidate(candidate, mid);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Set Callbacks
|
|
34
|
+
peer2.onStateChange(() => {
|
|
35
|
+
/** */
|
|
36
|
+
});
|
|
37
|
+
peer2.onGatheringStateChange(() => {
|
|
38
|
+
/** */
|
|
39
|
+
});
|
|
40
|
+
peer2.onLocalDescription((sdp, type) => {
|
|
41
|
+
peer1.setRemoteDescription(sdp, type);
|
|
42
|
+
});
|
|
43
|
+
peer2.onLocalCandidate((candidate, mid) => {
|
|
44
|
+
peer1.addRemoteCandidate(candidate, mid);
|
|
45
|
+
});
|
|
46
|
+
peer2.onDataChannel((dc) => {
|
|
47
|
+
dc2 = dc;
|
|
48
|
+
dc2.onMessage((msg) => {
|
|
49
|
+
p2DCMessageMock(msg);
|
|
50
|
+
dc2.sendMessage('Hello From Peer2');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
dc1 = peer1.createDataChannel('test-p2p');
|
|
55
|
+
dc1.onOpen(() => {
|
|
56
|
+
dc1.sendMessage('Hello From Peer1');
|
|
57
|
+
});
|
|
58
|
+
dc1.onMessage((msg) => {
|
|
59
|
+
p1DCMessageMock(msg);
|
|
60
|
+
peer1.close();
|
|
61
|
+
peer2.close();
|
|
62
|
+
|
|
63
|
+
// DataChannel
|
|
64
|
+
expect(p1DCMessageMock.mock.calls.length).toBe(1);
|
|
65
|
+
expect(p1DCMessageMock.mock.calls[0][0]).toEqual('Hello From Peer2');
|
|
66
|
+
expect(p2DCMessageMock.mock.calls.length).toBe(1);
|
|
67
|
+
expect(p2DCMessageMock.mock.calls[0][0]).toEqual('Hello From Peer1');
|
|
68
|
+
|
|
69
|
+
done();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import * as nodeDataChannel from '../../lib';
|
|
3
|
+
|
|
4
|
+
describe('P2P', () => {
|
|
5
|
+
// Default is 5000 ms but we need more
|
|
6
|
+
jest.setTimeout(30000);
|
|
7
|
+
|
|
8
|
+
test('P2P Test', () => {
|
|
9
|
+
return new Promise((done) => {
|
|
10
|
+
let peer1 = new nodeDataChannel.PeerConnection('Peer1', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
11
|
+
let peer2 = new nodeDataChannel.PeerConnection('Peer2', { iceServers: ['stun:stun.l.google.com:19302'] });
|
|
12
|
+
let dc1 = null;
|
|
13
|
+
let dc2 = null;
|
|
14
|
+
|
|
15
|
+
// Mocks
|
|
16
|
+
const p1StateMock = jest.fn();
|
|
17
|
+
const p1GatheringStateMock = jest.fn();
|
|
18
|
+
const p2StateMock = jest.fn();
|
|
19
|
+
const p2GatheringStateMock = jest.fn();
|
|
20
|
+
const p1SDPMock = jest.fn();
|
|
21
|
+
const p1CandidateMock = jest.fn();
|
|
22
|
+
const p2SDPMock = jest.fn();
|
|
23
|
+
const p2CandidateMock = jest.fn();
|
|
24
|
+
|
|
25
|
+
const p1DCMock = jest.fn();
|
|
26
|
+
const p1DCMessageMock = jest.fn();
|
|
27
|
+
const p2DCMock = jest.fn();
|
|
28
|
+
const p2DCMessageMock = jest.fn();
|
|
29
|
+
|
|
30
|
+
// Set Callbacks
|
|
31
|
+
peer1.onStateChange(p1StateMock);
|
|
32
|
+
peer1.onGatheringStateChange(p1GatheringStateMock);
|
|
33
|
+
peer1.onLocalDescription((sdp, type) => {
|
|
34
|
+
p1SDPMock();
|
|
35
|
+
peer2.setRemoteDescription(sdp, type);
|
|
36
|
+
});
|
|
37
|
+
peer1.onLocalCandidate((candidate, mid) => {
|
|
38
|
+
p1CandidateMock();
|
|
39
|
+
peer2.addRemoteCandidate(candidate, mid);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Set Callbacks
|
|
43
|
+
peer2.onStateChange(p2StateMock);
|
|
44
|
+
peer2.onGatheringStateChange(p2GatheringStateMock);
|
|
45
|
+
peer2.onLocalDescription((sdp, type) => {
|
|
46
|
+
p2SDPMock();
|
|
47
|
+
peer1.setRemoteDescription(sdp, type);
|
|
48
|
+
});
|
|
49
|
+
peer2.onLocalCandidate((candidate, mid) => {
|
|
50
|
+
p2CandidateMock();
|
|
51
|
+
peer1.addRemoteCandidate(candidate, mid);
|
|
52
|
+
});
|
|
53
|
+
peer2.onDataChannel((dc) => {
|
|
54
|
+
p2DCMock();
|
|
55
|
+
dc2 = dc;
|
|
56
|
+
dc2.onMessage((msg) => {
|
|
57
|
+
p2DCMessageMock(msg);
|
|
58
|
+
dc2.sendMessage('Hello From Peer2');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
dc1 = peer1.createDataChannel('test-p2p');
|
|
63
|
+
dc1.onOpen(() => {
|
|
64
|
+
p1DCMock();
|
|
65
|
+
dc1.sendMessage('Hello From Peer1');
|
|
66
|
+
});
|
|
67
|
+
dc1.onMessage((msg) => {
|
|
68
|
+
p1DCMessageMock(msg);
|
|
69
|
+
peer1.close();
|
|
70
|
+
peer2.close();
|
|
71
|
+
|
|
72
|
+
// State Callbacks
|
|
73
|
+
expect(p1StateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
74
|
+
expect(p1GatheringStateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
75
|
+
expect(p2StateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
76
|
+
expect(p2GatheringStateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
77
|
+
|
|
78
|
+
// SDP
|
|
79
|
+
expect(p1SDPMock.mock.calls.length).toBe(1);
|
|
80
|
+
expect(p2SDPMock.mock.calls.length).toBe(1);
|
|
81
|
+
|
|
82
|
+
// Candidates
|
|
83
|
+
expect(p1CandidateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
84
|
+
expect(p2CandidateMock.mock.calls.length).toBeGreaterThanOrEqual(1);
|
|
85
|
+
|
|
86
|
+
// DataChannel
|
|
87
|
+
expect(p1DCMock.mock.calls.length).toBe(1);
|
|
88
|
+
expect(p1DCMessageMock.mock.calls.length).toBe(1);
|
|
89
|
+
expect(p1DCMessageMock.mock.calls[0][0]).toEqual('Hello From Peer2');
|
|
90
|
+
expect(p2DCMock.mock.calls.length).toBe(1);
|
|
91
|
+
|
|
92
|
+
expect(p2DCMessageMock.mock.calls.length).toBe(1);
|
|
93
|
+
expect(p2DCMessageMock.mock.calls[0][0]).toEqual('Hello From Peer1');
|
|
94
|
+
|
|
95
|
+
done();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|