guardia-messenger/node_modules/expo-modules-core/common/cpp/EventEmitter.cpp
DESKTOP-TKLFCPRython f29f525c77 refactor: 101.79.17.164 → zioinfo.co.kr 전체 도메인 변환 + Manager UI 배포
- 37개 파일 IP → zioinfo.co.kr 치환 (소스/매뉴얼/설정/하네스)
- Manager DrConsole/NetworkConsole/CsapConsole 빌드 + /var/www/manager/ 배포
- 테스트: Manager HTTP 200, ITSM 신규 API 7개 전체 200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:09:17 +09:00

300 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "JSIUtils.h"
#include "EventEmitter.h"
#include "LazyObject.h"
namespace expo::EventEmitter {
#pragma mark - Listeners
void Listeners::add(jsi::Runtime &runtime, std::string eventName, const jsi::Function &listener) noexcept {
listenersMap[eventName].emplace_back(runtime, listener);
}
void Listeners::remove(jsi::Runtime &runtime, std::string eventName, const jsi::Function &listener) noexcept {
if (!listenersMap.contains(eventName)) {
return;
}
jsi::Value listenerValue(runtime, listener);
listenersMap[eventName].remove_if([&](const jsi::Value &item) {
return jsi::Value::strictEquals(runtime, listenerValue, item);
});
}
void Listeners::removeAll(std::string eventName) noexcept {
if (listenersMap.contains(eventName)) {
listenersMap[eventName].clear();
}
}
void Listeners::clear() noexcept {
listenersMap.clear();
}
size_t Listeners::listenersCount(std::string eventName) noexcept {
if (!listenersMap.contains(eventName)) {
return 0;
}
return listenersMap[eventName].size();
}
void Listeners::call(jsi::Runtime &runtime, std::string eventName, const jsi::Object &thisObject, const jsi::Value *args, size_t count) noexcept {
if (!listenersMap.contains(eventName)) {
return;
}
ListenersList &listenersList = listenersMap[eventName];
size_t listSize = listenersList.size();
if (listSize == 0) {
// Nothing to call.
return;
}
if (listSize == 1) {
// The most common scenario just call the only listener.
listenersList
.front()
.asObject(runtime)
.asFunction(runtime)
.callWithThis(runtime, thisObject, args, count);
return;
}
// When there are more than one listener, we copy the list to a vector as the list may be modified during the loop.
std::vector<jsi::Function> listenersVector;
listenersVector.reserve(listSize);
// Copy listeners to vector already as jsi::Function so we don't additionally copy jsi::Value
for (const jsi::Value &listener : listenersList) {
listenersVector.push_back(listener.asObject(runtime).asFunction(runtime));
}
// Call listeners from the vector. The list can be modified by the listeners but it will not affect this loop,
// i.e. newly added listeners will not be called and removed listeners will be called one last time.
// This is compliant with the EventEmitter in Node.js
for (const jsi::Function &listener : listenersVector) {
listener.callWithThis(runtime, thisObject, args, count);
}
}
#pragma mark - NativeState
NativeState::NativeState() : jsi::NativeState() {}
NativeState::~NativeState() {
listeners.clear();
}
NativeState::Shared NativeState::get(jsi::Runtime &runtime, const jsi::Object &object, bool createIfMissing) {
if (object.hasNativeState<NativeState>(runtime)) {
return object.getNativeState<NativeState>(runtime);
}
if (createIfMissing) {
NativeState::Shared state = std::make_shared<NativeState>();
object.setNativeState(runtime, state);
return state;
}
return nullptr;
}
#pragma mark - Utils
void callObservingFunction(jsi::Runtime &runtime, const jsi::Object &object, const char* functionName, std::string eventName) {
jsi::Value fnValue = object.getProperty(runtime, functionName);
if (!fnValue.isObject()) {
// Skip it if there is no observing function.
return;
}
fnValue
.getObject(runtime)
.asFunction(runtime)
.callWithThis(runtime, object, {
jsi::Value(runtime, jsi::String::createFromUtf8(runtime, eventName))
});
}
void addListener(jsi::Runtime &runtime, const jsi::Object &emitter, const std::string &eventName, const jsi::Function &listener) {
if (NativeState::Shared state = NativeState::get(runtime, emitter, true)) {
state->listeners.add(runtime, eventName, listener);
if (state->listeners.listenersCount(eventName) == 1) {
callObservingFunction(runtime, emitter, "startObserving", eventName);
}
}
}
void removeListener(jsi::Runtime &runtime, const jsi::Object &emitter, const std::string &eventName, const jsi::Function &listener) {
if (NativeState::Shared state = NativeState::get(runtime, emitter, false)) {
size_t listenersCountBefore = state->listeners.listenersCount(eventName);
state->listeners.remove(runtime, eventName, listener);
if (listenersCountBefore >= 1 && state->listeners.listenersCount(eventName) == 0) {
callObservingFunction(runtime, emitter, "stopObserving", eventName);
}
}
}
void removeAllListeners(jsi::Runtime &runtime, const jsi::Object &emitter, const std::string &eventName) {
if (NativeState::Shared state = NativeState::get(runtime, emitter, false)) {
size_t listenersCountBefore = state->listeners.listenersCount(eventName);
state->listeners.removeAll(eventName);
if (listenersCountBefore >= 1) {
callObservingFunction(runtime, emitter, "stopObserving", eventName);
}
}
}
void emitEvent(jsi::Runtime &runtime, const jsi::Object &emitter, const std::string &eventName, const jsi::Value *args, size_t count) {
if (NativeState::Shared state = NativeState::get(runtime, emitter, false)) {
state->listeners.call(runtime, eventName, emitter, args, count);
}
}
size_t getListenerCount(jsi::Runtime &runtime, const jsi::Object &emitter, const std::string &eventName) {
if (NativeState::Shared state = NativeState::get(runtime, emitter, false)) {
return state->listeners.listenersCount(eventName);
}
return 0;
}
jsi::Value createEventSubscription(jsi::Runtime &runtime, const std::string &eventName, const jsi::Object &emitter, const jsi::Function &listener) {
jsi::Object subscription(runtime);
jsi::PropNameID removeProp = jsi::PropNameID::forAscii(runtime, "remove", 6);
std::shared_ptr<jsi::Value> emitterValue = std::make_shared<jsi::Value>(runtime, emitter);
std::shared_ptr<jsi::Value> listenerValue = std::make_shared<jsi::Value>(runtime, listener);
jsi::HostFunctionType removeSubscription = [eventName, emitterValue, listenerValue](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
jsi::Object emitter = emitterValue->getObject(runtime);
jsi::Function listener = listenerValue->getObject(runtime).getFunction(runtime);
removeListener(runtime, emitter, eventName, listener);
return jsi::Value::undefined();
};
subscription.setProperty(runtime, removeProp, jsi::Function::createFromHostFunction(runtime, removeProp, 0, removeSubscription));
return jsi::Value(runtime, subscription);
}
#pragma mark - Public API
void emitEvent(jsi::Runtime &runtime, jsi::Object &emitter, const std::string &eventName, const std::vector<jsi::Value> &arguments) {
emitEvent(runtime, emitter, eventName, arguments.data(), arguments.size());
}
jsi::Function getClass(jsi::Runtime &runtime) {
return common::getCoreObject(runtime)
.getPropertyAsFunction(runtime, "EventEmitter");
}
void installClass(jsi::Runtime &runtime) {
jsi::Function eventEmitterClass = common::createClass(runtime, "EventEmitter", [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
// To provide backwards compatibility with the old EventEmitter where the native module object was passed as an argument.
// We're checking if the argument is already an instance of the new emitter and if so, just return it without unnecessarily wrapping it.
if (count > 0) {
jsi::Object firstArg = args[0].asObject(runtime);
jsi::Function constructor = thisValue.asObject(runtime).getPropertyAsFunction(runtime, "constructor");
if (firstArg.instanceOf(runtime, constructor)) {
return jsi::Value(runtime, args[0]);
}
}
return jsi::Value(runtime, thisValue);
});
jsi::Object prototype = eventEmitterClass.getPropertyAsObject(runtime, "prototype");
jsi::HostFunctionType addListenerHost = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::string eventName = args[0].asString(runtime).utf8(runtime);
jsi::Function listener = args[1].asObject(runtime).asFunction(runtime);
jsi::Object thisObject = thisValue.getObject(runtime);
// `this` might be an object that is representing a host object, in which case it's not possible to get the native state.
// For native modules we need to unwrap it to get the object used under the hood by `LazyObject` host object.
const jsi::Object &emitter = LazyObject::unwrapObjectIfNecessary(runtime, thisObject);
addListener(runtime, emitter, eventName, listener);
return createEventSubscription(runtime, eventName, emitter, listener);
};
jsi::HostFunctionType removeListenerHost = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::string eventName = args[0].asString(runtime).utf8(runtime);
jsi::Function listener = args[1].asObject(runtime).asFunction(runtime);
jsi::Object thisObject = thisValue.getObject(runtime);
// Unwrap `this` object if it's a lazy object (e.g. native module).
const jsi::Object &emitter = LazyObject::unwrapObjectIfNecessary(runtime, thisObject);
removeListener(runtime, emitter, eventName, listener);
return jsi::Value::undefined();
};
jsi::HostFunctionType removeAllListenersHost = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::string eventName = args[0].asString(runtime).utf8(runtime);
jsi::Object thisObject = thisValue.getObject(runtime);
// Unwrap `this` object if it's a lazy object (e.g. native module).
const jsi::Object &emitter = LazyObject::unwrapObjectIfNecessary(runtime, thisObject);
removeAllListeners(runtime, emitter, eventName);
return jsi::Value::undefined();
};
jsi::HostFunctionType emit = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::string eventName = args[0].asString(runtime).utf8(runtime);
jsi::Object thisObject = thisValue.getObject(runtime);
// Unwrap `this` object if it's a lazy object (e.g. native module).
const jsi::Object &emitter = LazyObject::unwrapObjectIfNecessary(runtime, thisObject);
// Make a new pointer that skips the first argument which is the event name.
const jsi::Value *eventArgs = count > 1 ? &args[1] : nullptr;
emitEvent(runtime, emitter, eventName, eventArgs, count - 1);
return jsi::Value::undefined();
};
jsi::HostFunctionType listenerCountHost = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::string eventName = args[0].asString(runtime).utf8(runtime);
jsi::Object thisObject = thisValue.getObject(runtime);
// Unwrap `this` object if it's a lazy object (e.g. native module).
const jsi::Object &emitter = LazyObject::unwrapObjectIfNecessary(runtime, thisObject);
return jsi::Value((int)getListenerCount(runtime, emitter, eventName));
};
// Added for compatibility with the old EventEmitter API.
jsi::HostFunctionType removeSubscriptionHost = [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
jsi::Object subscription = args[0].asObject(runtime);
subscription.getProperty(runtime, "remove")
.asObject(runtime)
.asFunction(runtime)
.callWithThis(runtime, subscription, {});
return jsi::Value::undefined();
};
jsi::PropNameID addListenerProp = jsi::PropNameID::forAscii(runtime, "addListener", 11);
jsi::PropNameID removeListenerProp = jsi::PropNameID::forAscii(runtime, "removeListener", 14);
jsi::PropNameID removeAllListenersProp = jsi::PropNameID::forAscii(runtime, "removeAllListeners", 18);
jsi::PropNameID emitProp = jsi::PropNameID::forAscii(runtime, "emit", 4);
jsi::PropNameID listenerCountProp = jsi::PropNameID::forAscii(runtime, "listenerCount", 13);
jsi::PropNameID removeSubscriptionProp = jsi::PropNameID::forAscii(runtime, "removeSubscription", 18);
prototype.setProperty(runtime, addListenerProp, jsi::Function::createFromHostFunction(runtime, addListenerProp, 2, addListenerHost));
prototype.setProperty(runtime, removeListenerProp, jsi::Function::createFromHostFunction(runtime, removeListenerProp, 2, removeListenerHost));
prototype.setProperty(runtime, removeAllListenersProp, jsi::Function::createFromHostFunction(runtime, removeAllListenersProp, 1, removeAllListenersHost));
prototype.setProperty(runtime, emitProp, jsi::Function::createFromHostFunction(runtime, emitProp, 2, emit));
prototype.setProperty(runtime, listenerCountProp, jsi::Function::createFromHostFunction(runtime, listenerCountProp, 1, listenerCountHost));
prototype.setProperty(runtime, removeSubscriptionProp, jsi::Function::createFromHostFunction(runtime, removeSubscriptionProp, 1, removeSubscriptionHost));
common::getCoreObject(runtime)
.setProperty(runtime, "EventEmitter", eventEmitterClass);
}
} // namespace expo::EventEmitter