diff --git a/client/src/CV8Resource.cpp b/client/src/CV8Resource.cpp index 288c69a2..ec5d151a 100644 --- a/client/src/CV8Resource.cpp +++ b/client/src/CV8Resource.cpp @@ -220,7 +220,10 @@ bool CV8ResourceImpl::Stop() requiresMap.clear(); remoteHandlers.clear(); + rpcHandlers.clear(); + remoteRPCHandlers.clear(); + awaitableRPCHandlers.clear(); isPreloading = true; @@ -363,24 +366,8 @@ void CV8ResourceImpl::HandleServerRPC(alt::CScriptRPCEvent* ev) if(returnValue->IsPromise()) { - v8::Local promise = returnValue.As(); - while(true) - { - v8::Promise::PromiseState state = promise->State(); - if(state == v8::Promise::PromiseState::kPending) - { - CV8ScriptRuntime::Instance().OnTick(); - // Run event loop - OnTick(); - } - else if(state == v8::Promise::PromiseState::kFulfilled) - { - returnValue = promise->Result(); - break; - } - else if(state == v8::Promise::PromiseState::kRejected) - break; - } + awaitableRPCHandlers.push_back({ ev->GetAnswerID(), v8::Global(isolate, returnValue.As()) }); + return; } // Retrieve returned error message when an error was returned diff --git a/server/src/CNodeResourceImpl.cpp b/server/src/CNodeResourceImpl.cpp index 32825b06..130d367c 100644 --- a/server/src/CNodeResourceImpl.cpp +++ b/server/src/CNodeResourceImpl.cpp @@ -118,6 +118,7 @@ bool CNodeResourceImpl::Stop() rpcHandlers.clear(); remoteRPCHandlers.clear(); + awaitableRPCHandlers.clear(); return true; } @@ -162,6 +163,12 @@ void CNodeResourceImpl::OnEvent(const alt::CEvent* e) auto player = ev->GetTarget(); remoteRPCHandlers.erase(player); + + for (auto it = awaitableRPCHandlers.rbegin(); it != awaitableRPCHandlers.rend(); ++it) + { + if (player == it->Player) + awaitableRPCHandlers.erase(std::next(it).base()); + } } V8Helpers::EventHandler* handler = V8Helpers::EventHandler::Get(e); @@ -288,26 +295,10 @@ void CNodeResourceImpl::HandleClientRpcEvent(alt::CScriptRPCEvent* ev) else returnValue = v8::Undefined(isolate); - if(returnValue->IsPromise()) + if (returnValue->IsPromise()) { - v8::Local promise = returnValue.As(); - while(true) - { - v8::Promise::PromiseState state = promise->State(); - if(state == v8::Promise::PromiseState::kPending) - { - CNodeScriptRuntime::Instance().OnTick(); - // Run event loop - OnTick(); - } - else if(state == v8::Promise::PromiseState::kFulfilled) - { - returnValue = promise->Result(); - break; - } - else if(state == v8::Promise::PromiseState::kRejected) - break; - } + awaitableRPCHandlers.push_back({ ev->GetTarget(), ev->GetAnswerID(), v8::Global(isolate, returnValue.As()) }); + return; } // Retrieve returned error message when an error was returned diff --git a/shared/V8ResourceImpl.cpp b/shared/V8ResourceImpl.cpp index ea54422b..6991befc 100644 --- a/shared/V8ResourceImpl.cpp +++ b/shared/V8ResourceImpl.cpp @@ -130,6 +130,44 @@ void V8ResourceImpl::OnTick() else ++it; } + + for (auto it = awaitableRPCHandlers.rbegin(); it != awaitableRPCHandlers.rend(); ++it) + { + if (!it->Promise.Get(isolate)->IsPromise()) + { + awaitableRPCHandlers.erase(std::next(it).base()); + continue; + } + + v8::Promise::PromiseState state = it->Promise.Get(isolate)->State(); + if (state == v8::Promise::PromiseState::kFulfilled) + { + v8::Local returnValue = it->Promise.Get(isolate)->Result(); + + // Retrieve returned error message when an error was returned + std::string errorMessage; + if (returnValue->IsNativeError()) { + v8::Local exception = returnValue.As(); + + v8::String::Utf8Value messageValue(isolate, exception->ToString(isolate->GetCurrentContext()).ToLocalChecked()); + errorMessage = *messageValue; + + // Strip exception prefix + if (size_t colonPos = errorMessage.find(':'); colonPos != std::string::npos) { + errorMessage = errorMessage.substr(colonPos + 2); + } + } + +#ifdef ALT_SERVER_API + alt::ICore::Instance().TriggerClientRPCAnswer(it->Player, it->AnswerId, V8Helpers::V8ToMValue(returnValue), errorMessage); +#else + alt::ICore::Instance().TriggerServerRPCAnswer(it->AnswerId, V8Helpers::V8ToMValue(returnValue), errorMessage); +#endif + } + + if (state == v8::Promise::PromiseState::kFulfilled || state == v8::Promise::PromiseState::kRejected) + awaitableRPCHandlers.erase(std::next(it).base()); + } } void V8ResourceImpl::BindEntity(v8::Local val, alt::IBaseObject* handle) diff --git a/shared/V8ResourceImpl.h b/shared/V8ResourceImpl.h index 0372b533..86902087 100644 --- a/shared/V8ResourceImpl.h +++ b/shared/V8ResourceImpl.h @@ -313,6 +313,16 @@ class V8ResourceImpl : public alt::IResource::Impl return static_cast(ctx->GetAlignedPointerFromEmbedderData(1)); } + struct AwaitableRPCHandler + { +#ifdef ALT_SERVER_API + alt::IPlayer* Player; +#endif + + uint16_t AnswerId; + v8::Global Promise; + }; + #ifdef ALT_SERVER_API // Vehicle passengers static inline std::unordered_map> vehiclePassengers{}; @@ -326,9 +336,12 @@ class V8ResourceImpl : public alt::IResource::Impl // rpcs static inline std::unordered_map> rpcHandlers{}; static inline std::unordered_map> remoteRPCHandlers{}; + static inline std::vector awaitableRPCHandlers{}; + #else static inline std::unordered_map> remoteRPCHandlers{}; static inline std::unordered_map> rpcHandlers{}; + static inline std::vector awaitableRPCHandlers{}; #endif protected: