Skip to content

Commit

Permalink
refactor: move event handler store to js side to avoid crash on reload
Browse files Browse the repository at this point in the history
  • Loading branch information
hans00 committed Sep 30, 2024
1 parent e66f421 commit caa4822
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 61 deletions.
2 changes: 0 additions & 2 deletions android/cpp-adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "react-native-jsi-udp.h"

std::shared_ptr<jsiudp::UdpManager> manager;
std::map<int, std::shared_ptr<facebook::jsi::Function>> eventHandlers;

extern "C"
JNIEXPORT void JNICALL
Expand All @@ -24,5 +23,4 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_jsiudp_JsiUdpModule_nativeReset(JNIEnv *env, jclass _) {
manager.reset();
eventHandlers.clear();
}
31 changes: 14 additions & 17 deletions cpp/react-native-jsi-udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,10 @@ int setupIface(int fd, struct sockaddr_in6 &addr) {
return 0;
}

UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr<CallInvoker> callInvoker, std::map<int, std::shared_ptr<facebook::jsi::Function>> &eventHandlers): _runtime(jsiRuntime), _callInvoker(callInvoker), _eventHandlers(eventHandlers) {
UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr<CallInvoker> 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));
Expand All @@ -194,6 +193,7 @@ UdpManager::UdpManager(Runtime *jsiRuntime, std::shared_ptr<CallInvoker> callInv
global.setProperty(*_runtime, "dgc_IP_ADD_MEMBERSHIP", static_cast<int>(IP_ADD_MEMBERSHIP));
global.setProperty(*_runtime, "dgc_IP_DROP_MEMBERSHIP", static_cast<int>(IP_DROP_MEMBERSHIP));
global.setProperty(*_runtime, "dgc_IP_TTL", static_cast<int>(IP_TTL));
global.setProperty(*_runtime, "datagram_callbacks", Object(*_runtime));

createWorker();
}
Expand Down Expand Up @@ -309,16 +309,6 @@ JSI_HOST_FUNCTION(UdpManager::create) {
return fd;
}

JSI_HOST_FUNCTION(UdpManager::startWorker) {
auto fd = static_cast<int>(arguments[0].asNumber());
auto handler = arguments[1].asObject(runtime).asFunction(runtime);

_eventHandlers[fd] = std::make_shared<facebook::jsi::Function>(std::move(handler));
emplaceFd(fd);

return Value::undefined();
}

JSI_HOST_FUNCTION(UdpManager::bind) {
auto fd = static_cast<int>(arguments[0].asNumber());
auto type = static_cast<int>(arguments[1].asNumber());
Expand Down Expand Up @@ -354,6 +344,8 @@ JSI_HOST_FUNCTION(UdpManager::bind) {
throw JSError(runtime, error_name(errno));
}

emplaceFd(fd);

return Value::undefined();
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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());
}
});
}
}

Expand Down
8 changes: 1 addition & 7 deletions cpp/react-native-jsi-udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ namespace jsiudp {

class UdpManager {
public:
UdpManager(
facebook::jsi::Runtime *jsiRuntime,
std::shared_ptr<facebook::react::CallInvoker> callInvoker,
std::map<int, std::shared_ptr<facebook::jsi::Function>> &eventHandlers
);
UdpManager(facebook::jsi::Runtime *jsiRuntime, std::shared_ptr<facebook::react::CallInvoker> callInvoker);
~UdpManager();

void closeAll();
Expand All @@ -63,11 +59,9 @@ namespace jsiudp {
std::shared_ptr<facebook::react::CallInvoker> _callInvoker;
std::atomic<bool> _invalidate = false;
std::thread eventThread;
std::map<int, std::shared_ptr<facebook::jsi::Function>> &_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);
Expand Down
3 changes: 1 addition & 2 deletions ios/JsiUdp.mm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ @implementation JsiUdp
RCT_EXPORT_MODULE()

std::shared_ptr<jsiudp::UdpManager> _manager;
std::map<int, std::shared_ptr<facebook::jsi::Function>> _eventHandlers;

- (void)invalidate {
if (_manager) {
Expand All @@ -32,7 +31,7 @@ void installApi(
std::shared_ptr<facebook::react::CallInvoker> callInvoker,
facebook::jsi::Runtime *runtime
) {
_manager = std::make_shared<jsiudp::UdpManager>(runtime, std::move(callInvoker), _eventHandlers);
_manager = std::make_shared<jsiudp::UdpManager>(runtime, std::move(callInvoker));
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
Expand Down
54 changes: 26 additions & 28 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 3 additions & 5 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
};

0 comments on commit caa4822

Please sign in to comment.