node-datachannel 0.5.5 → 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.
@@ -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;
package/src/main.cpp CHANGED
@@ -6,6 +6,8 @@
6
6
  #include "media-track-wrapper.h"
7
7
  #include "media-video-wrapper.h"
8
8
  #include "media-audio-wrapper.h"
9
+ #include "web-socket-wrapper.h"
10
+ #include "web-socket-server-wrapper.h"
9
11
 
10
12
  Napi::Object InitAll(Napi::Env env, Napi::Object exports)
11
13
  {
@@ -16,6 +18,8 @@ Napi::Object InitAll(Napi::Env env, Napi::Object exports)
16
18
  AudioWrapper::Init(env, exports);
17
19
  DataChannelWrapper::Init(env, exports);
18
20
  PeerConnectionWrapper::Init(env, exports);
21
+ WebSocketWrapper::Init(env, exports);
22
+ WebSocketServerWrapper::Init(env, exports);
19
23
  return exports;
20
24
  }
21
25
 
@@ -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 track
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
- // Callback Ptrs
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::ResetCallbacksAll()
23
+ void PeerConnectionWrapper::CleanupAll()
24
24
  {
25
- PLOG_DEBUG << "ResetCallbacksAll() called";
25
+ PLOG_DEBUG << "CleanupAll() called";
26
26
  auto copy(instances);
27
27
  for (auto inst : copy)
28
- inst->doResetCallbacks();
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
- doDestroy();
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
- instances.erase(this);
286
+ void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
287
+ {
288
+ PLOG_DEBUG << "close() called";
289
+ doClose();
304
290
  }
305
291
 
306
- void PeerConnectionWrapper::destroy(const Napi::CallbackInfo &info)
292
+ void PeerConnectionWrapper::doCleanup()
307
293
  {
308
- PLOG_DEBUG << "destroy() called";
309
- doDestroy();
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 ResetCallbacksAll();
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 doDestroy();
69
- void doResetCallbacks();
66
+ void doCleanup();
70
67
 
71
68
  std::string mPeerName;
72
69
  std::unique_ptr<rtc::PeerConnection> mRtcPeerConnPtr = nullptr;
@@ -2,6 +2,8 @@
2
2
  #include "peer-connection-wrapper.h"
3
3
  #include "data-channel-wrapper.h"
4
4
  #include "media-track-wrapper.h"
5
+ #include "web-socket-wrapper.h"
6
+ #include "web-socket-server-wrapper.h"
5
7
 
6
8
  #include "plog/Log.h"
7
9
 
@@ -116,13 +118,18 @@ void RtcWrapper::cleanup(const Napi::CallbackInfo &info)
116
118
  PeerConnectionWrapper::CloseAll();
117
119
  DataChannelWrapper::CloseAll();
118
120
  TrackWrapper::CloseAll();
121
+ WebSocketWrapper::CloseAll();
122
+ WebSocketServerWrapper::StopAll();
119
123
 
120
124
  const auto timeout = std::chrono::seconds(10);
121
125
  if (rtc::Cleanup().wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout)
122
126
  throw std::runtime_error("cleanup timeout (possible deadlock)");
123
127
 
124
- // Clear Callbacks
125
- PeerConnectionWrapper::ResetCallbacksAll();
128
+ // Cleanup the instances
129
+ PeerConnectionWrapper::CleanupAll();
130
+ DataChannelWrapper::CleanupAll();
131
+ TrackWrapper::CleanupAll();
132
+ WebSocketWrapper::CleanupAll();
126
133
 
127
134
  if (logCallback)
128
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,
@@ -0,0 +1,265 @@
1
+ #include "web-socket-server-wrapper.h"
2
+
3
+ #include "plog/Log.h"
4
+
5
+ void WebSocketServerWrapper::StopAll()
6
+ {
7
+ PLOG_DEBUG << "StopAll() called";
8
+ auto copy(instances);
9
+ for (auto inst : copy)
10
+ inst->doStop();
11
+ }
12
+
13
+ Napi::FunctionReference WebSocketServerWrapper::constructor;
14
+ std::unordered_set<WebSocketServerWrapper *> WebSocketServerWrapper::instances;
15
+
16
+ Napi::Object WebSocketServerWrapper::Init(Napi::Env env, Napi::Object exports)
17
+ {
18
+ Napi::HandleScope scope(env);
19
+
20
+ Napi::Function func = DefineClass(
21
+ env,
22
+ "WebSocketServer",
23
+ {
24
+ InstanceMethod("stop", &WebSocketServerWrapper::stop),
25
+ InstanceMethod("port", &WebSocketServerWrapper::port),
26
+ InstanceMethod("onClient", &WebSocketServerWrapper::onClient)
27
+ });
28
+
29
+ constructor = Napi::Persistent(func);
30
+ constructor.SuppressDestruct();
31
+
32
+ exports.Set("WebSocketServer", func);
33
+ return exports;
34
+ }
35
+
36
+ WebSocketServerWrapper::WebSocketServerWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<WebSocketServerWrapper>(info)
37
+ {
38
+ PLOG_DEBUG << "Constructor called";
39
+
40
+ Napi::Env env = info.Env();
41
+
42
+ // Create WebSocketServer without config
43
+ if (info.Length() == 0)
44
+ {
45
+ try
46
+ {
47
+ PLOG_DEBUG << "Creating a new WebSocketServer without config";
48
+ mWebSocketServerPtr = std::make_unique<rtc::WebSocketServer>();
49
+ }
50
+ catch (std::exception &ex)
51
+ {
52
+ Napi::Error::New(env, std::string("libdatachannel error while creating WebSocketServer without config: ") + ex.what()).ThrowAsJavaScriptException();
53
+ return;
54
+ }
55
+
56
+ PLOG_DEBUG << "WebSocketServer created without config";
57
+
58
+ instances.insert(this);
59
+ return;
60
+ }
61
+
62
+ // Create WebSocketServer with config
63
+
64
+ Napi::Object config = info[0].As<Napi::Object>();
65
+ rtc::WebSocketServerConfiguration webSocketServerConfig;
66
+
67
+ // Port
68
+ if (config.Has("port"))
69
+ {
70
+ if (!config.Get("port").IsNumber())
71
+ {
72
+ Napi::TypeError::New(info.Env(), "port must be a number").ThrowAsJavaScriptException();
73
+ return;
74
+ }
75
+ webSocketServerConfig.port = config.Get("port").ToNumber().Uint32Value();
76
+ }
77
+
78
+ // Enable TLS
79
+ if (config.Has("enableTls"))
80
+ {
81
+ if (!config.Get("enableTls").IsBoolean())
82
+ {
83
+ Napi::TypeError::New(info.Env(), "enableTls must be boolean").ThrowAsJavaScriptException();
84
+ return;
85
+ }
86
+ webSocketServerConfig.enableTls = config.Get("enableTls").ToBoolean();
87
+ }
88
+
89
+ // Certificate PEM File
90
+ if (config.Has("certificatePemFile"))
91
+ {
92
+ if (!config.Get("certificatePemFile").IsString())
93
+ {
94
+ Napi::TypeError::New(info.Env(), "certificatePemFile must be a string").ThrowAsJavaScriptException();
95
+ return;
96
+ }
97
+ webSocketServerConfig.certificatePemFile = config.Get("certificatePemFile").ToString();
98
+ }
99
+
100
+ // Key PEM File
101
+ if (config.Has("keyPemFile"))
102
+ {
103
+ if (!config.Get("keyPemFile").IsString())
104
+ {
105
+ Napi::TypeError::New(info.Env(), "keyPemFile must be a string").ThrowAsJavaScriptException();
106
+ return;
107
+ }
108
+ webSocketServerConfig.keyPemFile = config.Get("keyPemFile").ToString();
109
+ }
110
+
111
+ // Key PEM Pass
112
+ if (config.Has("keyPemPass"))
113
+ {
114
+ if (!config.Get("keyPemPass").IsString())
115
+ {
116
+ Napi::TypeError::New(info.Env(), "keyPemPass must be a string").ThrowAsJavaScriptException();
117
+ return;
118
+ }
119
+ webSocketServerConfig.keyPemPass = config.Get("keyPemPass").ToString();
120
+ }
121
+
122
+ // Bind Address
123
+ if (config.Has("bindAddress"))
124
+ {
125
+ if (!config.Get("bindAddress").IsString())
126
+ {
127
+ Napi::TypeError::New(info.Env(), "bindAddress must be a string").ThrowAsJavaScriptException();
128
+ return;
129
+ }
130
+ webSocketServerConfig.bindAddress = config.Get("bindAddress").ToString();
131
+ }
132
+
133
+ // Connection Timeout
134
+ if (config.Has("connectionTimeout"))
135
+ {
136
+ if (!config.Get("connectionTimeout").IsNumber())
137
+ {
138
+ Napi::TypeError::New(info.Env(), "connectionTimeout must be a number").ThrowAsJavaScriptException();
139
+ return;
140
+ }
141
+ webSocketServerConfig.connectionTimeout = std::chrono::milliseconds(config.Get("connectionTimeout").ToNumber().Int64Value());
142
+ }
143
+
144
+ // Max Message Size
145
+ if (config.Has("maxMessageSize"))
146
+ {
147
+ if (!config.Get("maxMessageSize").IsNumber())
148
+ {
149
+ Napi::TypeError::New(info.Env(), "maxMessageSize must be a number").ThrowAsJavaScriptException();
150
+ return;
151
+ }
152
+ webSocketServerConfig.maxMessageSize = config.Get("maxMessageSize").ToNumber().Int32Value();
153
+ }
154
+
155
+ // Create WebSocketServer with config
156
+ try
157
+ {
158
+ PLOG_DEBUG << "Creating a new WebSocketServer";
159
+ mWebSocketServerPtr = std::make_unique<rtc::WebSocketServer>(webSocketServerConfig);
160
+ }
161
+ catch (std::exception &ex)
162
+ {
163
+ Napi::Error::New(env, std::string("libdatachannel error while creating WebSocketServer: ") + ex.what()).ThrowAsJavaScriptException();
164
+ return;
165
+ }
166
+
167
+ PLOG_DEBUG << "WebSocketServer created";
168
+ instances.insert(this);
169
+ }
170
+
171
+ WebSocketServerWrapper::~WebSocketServerWrapper()
172
+ {
173
+ PLOG_DEBUG << "Destructor called";
174
+ doStop();
175
+ }
176
+
177
+ void WebSocketServerWrapper::doStop()
178
+ {
179
+ PLOG_DEBUG << "doStop() called";
180
+ if (mWebSocketServerPtr)
181
+ {
182
+ PLOG_DEBUG << "Closing...";
183
+ try
184
+ {
185
+ mWebSocketServerPtr->stop();
186
+ mWebSocketServerPtr.reset();
187
+ }
188
+ catch (std::exception &ex)
189
+ {
190
+ std::cerr << std::string("libWebRtc error while closing WebSocketServer: ") + ex.what() << std::endl;
191
+ return;
192
+ }
193
+ }
194
+
195
+ mOnClientCallback.reset();
196
+
197
+ instances.erase(this);
198
+ }
199
+
200
+ void WebSocketServerWrapper::stop(const Napi::CallbackInfo &info)
201
+ {
202
+ PLOG_DEBUG << "stop() called";
203
+ doStop();
204
+ }
205
+
206
+ Napi::Value WebSocketServerWrapper::port(const Napi::CallbackInfo &info)
207
+ {
208
+ PLOG_DEBUG << "port() called";
209
+ Napi::Env env = info.Env();
210
+
211
+ if (!mWebSocketServerPtr)
212
+ {
213
+ return Napi::Number::New(info.Env(), 0);
214
+ }
215
+
216
+ try
217
+ {
218
+ return Napi::Number::New(info.Env(), mWebSocketServerPtr->port());
219
+ }
220
+ catch (std::exception &ex)
221
+ {
222
+ Napi::Error::New(env, std::string("WebSocketServer error: ") + ex.what()).ThrowAsJavaScriptException();
223
+ return Napi::Number::New(info.Env(), 0);
224
+ }
225
+ }
226
+
227
+ void WebSocketServerWrapper::onClient(const Napi::CallbackInfo &info)
228
+ {
229
+ PLOG_DEBUG << "onClient() called";
230
+ Napi::Env env = info.Env();
231
+ int length = info.Length();
232
+
233
+ if (!mWebSocketServerPtr)
234
+ {
235
+ Napi::Error::New(env, "onClient() called on destroyed WebSocketServer").ThrowAsJavaScriptException();
236
+ return;
237
+ }
238
+
239
+ if (length < 1 || !info[0].IsFunction())
240
+ {
241
+ Napi::TypeError::New(env, "Function expected as onClient calback").ThrowAsJavaScriptException();
242
+ return;
243
+ }
244
+
245
+ // Callback
246
+ mOnClientCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
247
+
248
+ mWebSocketServerPtr->onClient([&](std::shared_ptr<rtc::WebSocket> ws)
249
+ {
250
+ PLOG_DEBUG << "onClient ws received from WebSocketServer";
251
+ if (mOnClientCallback)
252
+ mOnClientCallback->call([this, ws](Napi::Env env, std::vector<napi_value> &args) {
253
+ PLOG_DEBUG << "mOnClientCallback call(1)";
254
+ // Check the WebSocketServer is not stopped
255
+ if(instances.find(this) == instances.end())
256
+ throw ThreadSafeCallback::CancelException();
257
+
258
+ // This will run in main thread and needs to construct the
259
+ // arguments for the call
260
+ std::shared_ptr<rtc::WebSocket> webSocket = ws;
261
+ auto instance = WebSocketWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::WebSocket>>::New(env, nullptr), Napi::External<std::shared_ptr<rtc::WebSocket>>::New(env, &webSocket)});
262
+ args = {instance};
263
+ PLOG_DEBUG << "mOnClientCallback call(2)";
264
+ }); });
265
+ }