diff --git a/android/cpp-adapter.cpp b/android/cpp-adapter.cpp index 2eaef74..1d1efdb 100644 --- a/android/cpp-adapter.cpp +++ b/android/cpp-adapter.cpp @@ -5,7 +5,6 @@ #include "react-native-jsi-udp.h" std::shared_ptr manager; -std::map> eventHandlers; extern "C" JNIEXPORT void JNICALL @@ -24,5 +23,4 @@ extern "C" JNIEXPORT void JNICALL Java_com_jsiudp_JsiUdpModule_nativeReset(JNIEnv *env, jclass _) { manager.reset(); - eventHandlers.clear(); } \ No newline at end of file diff --git a/cpp/react-native-jsi-udp.cpp b/cpp/react-native-jsi-udp.cpp index 7351e35..0a087ba 100644 --- a/cpp/react-native-jsi-udp.cpp +++ b/cpp/react-native-jsi-udp.cpp @@ -168,11 +168,10 @@ int setupIface(int fd, struct sockaddr_in6 &addr) { return 0; } -UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr callInvoker, std::map> &eventHandlers): _runtime(jsiRuntime), _callInvoker(callInvoker), _eventHandlers(eventHandlers) { +UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr callInvoker): _runtime(jsiRuntime), _callInvoker(callInvoker) { eventThread = std::thread(&UdpManager::receiveEvent, this); EXPOSE_FN(*_runtime, datagram_create, 1, BIND_METHOD(UdpManager::create)); - EXPOSE_FN(*_runtime, datagram_startWorker, 2, BIND_METHOD(UdpManager::startWorker)); EXPOSE_FN(*_runtime, datagram_bind, 4, BIND_METHOD(UdpManager::bind)); EXPOSE_FN(*_runtime, datagram_send, 5, BIND_METHOD(UdpManager::send)); EXPOSE_FN(*_runtime, datagram_close, 1, BIND_METHOD(UdpManager::close)); @@ -194,6 +193,7 @@ UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr callInv global.setProperty(*_runtime, "dgc_IP_ADD_MEMBERSHIP", static_cast(IP_ADD_MEMBERSHIP)); global.setProperty(*_runtime, "dgc_IP_DROP_MEMBERSHIP", static_cast(IP_DROP_MEMBERSHIP)); global.setProperty(*_runtime, "dgc_IP_TTL", static_cast(IP_TTL)); + global.setProperty(*_runtime, "datagram_callbacks", Object(*_runtime)); createWorker(); } @@ -309,16 +309,6 @@ JSI_HOST_FUNCTION(UdpManager::create) { return fd; } -JSI_HOST_FUNCTION(UdpManager::startWorker) { - auto fd = static_cast(arguments[0].asNumber()); - auto handler = arguments[1].asObject(runtime).asFunction(runtime); - - _eventHandlers[fd] = std::make_shared(std::move(handler)); - emplaceFd(fd); - - return Value::undefined(); -} - JSI_HOST_FUNCTION(UdpManager::bind) { auto fd = static_cast(arguments[0].asNumber()); auto type = static_cast(arguments[1].asNumber()); @@ -354,6 +344,8 @@ JSI_HOST_FUNCTION(UdpManager::bind) { throw JSError(runtime, error_name(errno)); } + emplaceFd(fd); + return Value::undefined(); } @@ -571,8 +563,11 @@ void UdpManager::receiveEvent() { auto event = events.front(); events.pop(); lock.unlock(); - if (_eventHandlers.count(event.fd) > 0) { - runOnJS([this, event = std::move(event)]() { + runOnJS([this, event = std::move(event)]() { + try { + auto callback = _runtime->global() + .getPropertyAsObject(*_runtime, "datagram_callbacks") + .getPropertyAsFunction(*_runtime, std::to_string(event.fd).c_str()); auto eventObj = Object(*_runtime); eventObj.setProperty( *_runtime, @@ -616,9 +611,11 @@ void UdpManager::receiveEvent() { .getObject(*_runtime); eventObj.setProperty(*_runtime, "error", errorObj); } - _eventHandlers[event.fd]->call(*_runtime, eventObj); - }); - } + callback.call(*_runtime, eventObj); + } catch (const std::exception &e) { + LOGW("Error in receiveEvent: %s", e.what()); + } + }); } } diff --git a/cpp/react-native-jsi-udp.h b/cpp/react-native-jsi-udp.h index a614f60..bfa02ac 100644 --- a/cpp/react-native-jsi-udp.h +++ b/cpp/react-native-jsi-udp.h @@ -49,11 +49,7 @@ namespace jsiudp { class UdpManager { public: - UdpManager( - facebook::jsi::Runtime *jsiRuntime, - std::shared_ptr callInvoker, - std::map> &eventHandlers - ); + UdpManager(facebook::jsi::Runtime *jsiRuntime, std::shared_ptr callInvoker); ~UdpManager(); void closeAll(); @@ -63,11 +59,9 @@ namespace jsiudp { std::shared_ptr _callInvoker; std::atomic _invalidate = false; std::thread eventThread; - std::map> &_eventHandlers; JSI_HOST_FUNCTION(create); JSI_HOST_FUNCTION(send); - JSI_HOST_FUNCTION(startWorker); JSI_HOST_FUNCTION(bind); JSI_HOST_FUNCTION(setOpt); JSI_HOST_FUNCTION(getOpt); diff --git a/ios/JsiUdp.mm b/ios/JsiUdp.mm index a43a7d7..805149a 100644 --- a/ios/JsiUdp.mm +++ b/ios/JsiUdp.mm @@ -12,7 +12,6 @@ @implementation JsiUdp RCT_EXPORT_MODULE() std::shared_ptr _manager; -std::map> _eventHandlers; - (void)invalidate { if (_manager) { @@ -32,7 +31,7 @@ void installApi( std::shared_ptr callInvoker, facebook::jsi::Runtime *runtime ) { - _manager = std::make_shared(runtime, std::move(callInvoker), _eventHandlers); + _manager = std::make_shared(runtime, std::move(callInvoker)); } RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) diff --git a/src/index.tsx b/src/index.tsx index a17ade4..f82a4e6 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -50,6 +50,31 @@ export class Socket extends EventEmitter { this.reuseAddr = options.reuseAddr ?? false; this.reusePort = options.reusePort ?? false; this._fd = datagram_create(this.type); + datagram_callbacks[String(this._fd)] = ({ + type, + family, + address: remoteAddr, + port: remotePort, + data, + error, + }) => { + switch (type) { + case 'error': + this.emit('error', error); + break; + case 'close': + this.state = State.CLOSED; + this.emit('close'); + break; + case 'message': + this.emit('message', Buffer.from(data!), { + address: remoteAddr, + port: remotePort, + family, + }); + break; + } + }; if (callback) this.on('message', callback); } @@ -78,34 +103,6 @@ export class Socket extends EventEmitter { ); datagram_bind(this._fd, this.type, address ?? defaultAddr, port ?? 0); this.state = State.BOUND; - datagram_startWorker( - this._fd, - ({ - type, - family, - address: remoteAddr, - port: remotePort, - data, - error, - }) => { - switch (type) { - case 'error': - this.emit('error', error); - break; - case 'close': - this.state = State.CLOSED; - this.emit('close'); - break; - case 'message': - this.emit('message', Buffer.from(data!), { - address: remoteAddr, - port: remotePort, - family, - }); - break; - } - } - ); this.emit('listening'); } catch (e) { if (callback) callback(e); @@ -141,6 +138,7 @@ export class Socket extends EventEmitter { if (this.state === State.CLOSED) { return; } + delete datagram_callbacks[String(this._fd)]; if (callback) this.once('close', callback!); datagram_close(this._fd); } diff --git a/src/types.d.ts b/src/types.d.ts index 57e7f6f..5d82776 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -9,11 +9,6 @@ declare interface datagram_event { error?: Error; } -declare function datagram_startWorker( - fd: number, - listener: (event: datagram_event) => void -): void; - declare function datagram_bind( fd: number, type: 4 | 6, @@ -67,3 +62,6 @@ declare var dgc_IP_MULTICAST_LOOP: number; declare var dgc_IP_ADD_MEMBERSHIP: number; declare var dgc_IP_DROP_MEMBERSHIP: number; declare var dgc_IP_TTL: number; +declare var datagram_callbacks: { + [key: string]: (event: datagram_event) => void; +};