@@ -620,7 +620,7 @@ httplib::Headers table_to_headers(const sol::table& headers) {
620
620
return http_headers;
621
621
}
622
622
623
- void TLuaEngine::StateThreadData::Lua_HttpCallCallback (httplib::Result& response, sol::function cb ) {
623
+ void TLuaEngine::StateThreadData::Lua_HttpCallCallback (httplib::Result& response, std::shared_ptr< sol::reference> cb_ref ) {
624
624
auto args = std::vector<TLuaArgTypes>();
625
625
if (response) {
626
626
args.push_back (sol::nil);
@@ -636,25 +636,27 @@ void TLuaEngine::StateThreadData::Lua_HttpCallCallback(httplib::Result& response
636
636
auto err = response.error ();
637
637
args.push_back (httplib::to_string (err));
638
638
}
639
- auto res = this ->EnqueueFunctionCall (cb , args);
639
+ auto res = this ->EnqueueFunctionCall (cb_ref , args);
640
640
641
641
// This doesn't seem strictly necessary, and will make threads in the http pool wait until the lua callbacks are executed
642
642
res->WaitUntilReady ();
643
643
}
644
644
645
- sol::table TLuaEngine::StateThreadData::Lua_HttpGet (std::string host, std::string path, sol::table headers, sol::function cb) {
645
+ void TLuaEngine::StateThreadData::Lua_HttpGet (const std::string& host, const std::string& path, const sol::table& headers, const sol::function& cb) {
646
646
auto http_headers = table_to_headers (headers);
647
- boost::asio::post (this ->mEngine ->http_pool , [this , host, path, http_headers, cb]() {
647
+ // This method and Lua_HttpPost create a sol::reference to save the callback function in the lua registry, and then
648
+ // wrap it in a shared_ptr because passing any sol object by-value involves accessing the lua state. It is NOT safe
649
+ // to derefence this pointer inside the http thread pool
650
+ auto cb_ref = std::make_shared<sol::reference>(cb);
651
+ boost::asio::post (this ->mEngine ->http_pool , [this , host, path, http_headers, cb_ref]() {
648
652
auto client = httplib::Client (host);
649
653
client.set_follow_location (true );
650
654
auto response = client.Get (path, http_headers);
651
- this ->Lua_HttpCallCallback (response, cb );
655
+ this ->Lua_HttpCallCallback (response, cb_ref );
652
656
});
653
-
654
- return sol::table ();
655
657
}
656
658
657
- sol::table TLuaEngine::StateThreadData::Lua_HttpPost (std::string host, std::string path, sol::table body, sol::table headers, sol::function cb) {
659
+ void TLuaEngine::StateThreadData::Lua_HttpPost (const std::string& host, const std::string& path, const sol::table& body, const sol::table& headers, const sol::function& cb) {
658
660
auto http_headers = table_to_headers (headers);
659
661
httplib::Params params;
660
662
for (const auto & pair : body) {
@@ -664,15 +666,13 @@ sol::table TLuaEngine::StateThreadData::Lua_HttpPost(std::string host, std::stri
664
666
beammp_lua_error (" Http:Get: Expected string-string pairs for headers, got something else, ignoring that header" );
665
667
}
666
668
}
667
-
668
- boost::asio::post (this ->mEngine ->http_pool , [this , host, path, http_headers, cb , params]() {
669
+ auto cb_ref = std::make_shared<sol::reference>(cb);
670
+ boost::asio::post (this ->mEngine ->http_pool , [this , host, path, http_headers, cb_ref , params]() {
669
671
auto client = httplib::Client (host);
670
672
client.set_follow_location (true );
671
673
auto response = client.Post (path, http_headers, params);
672
- this ->Lua_HttpCallCallback (response, cb );
674
+ this ->Lua_HttpCallCallback (response, cb_ref );
673
675
});
674
-
675
- return sol::table ();
676
676
}
677
677
678
678
sol::table TLuaEngine::StateThreadData::Lua_HttpCreateConnection (const std::string& host, uint16_t port) {
@@ -897,18 +897,18 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
897
897
return Lua_HttpCreateConnection (host, port);
898
898
});
899
899
HttpTable.set_function (" Get" , sol::overload (
900
- [this ](std::string url, std::string path, sol::function cb) {
900
+ [this ](const std::string& url, const std::string& path, const sol::function& cb) {
901
901
return Lua_HttpGet (url, path, this ->mStateView .create_table (), cb);
902
902
},
903
- [this ](std::string url, std::string path, sol::table headers, sol::function cb) {
903
+ [this ](const std::string& url, const std::string& path, const sol::table& headers, const sol::function& cb) {
904
904
return Lua_HttpGet (url, path, headers, cb);
905
905
}
906
906
));
907
907
HttpTable.set_function (" Post" , sol::overload (
908
- [this ](std::string url, std::string path, sol::table body, sol::function cb) {
908
+ [this ](const std::string& url, const std::string& path, const sol::table& body, const sol::function& cb) {
909
909
return Lua_HttpPost (url, path, body, this ->mStateView .create_table (), cb);
910
910
},
911
- [this ](std::string url, std::string path, sol::table body, sol::table headers, sol::function cb) {
911
+ [this ](const std::string& url, const std::string& path, const sol::table& body, const sol::table& headers, const sol::function& cb) {
912
912
return Lua_HttpPost (url, path, body, headers, cb);
913
913
}
914
914
));
@@ -956,6 +956,8 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueScript(const TLu
956
956
957
957
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFromCustomEvent (const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args, const std::string& EventName, CallStrategy Strategy) {
958
958
// TODO: Document all this
959
+ // mStateFunctionQueue needs to be locked here. Calls modifying mStateFunctionQueue from other threads can invalidate this iterator mid-execution
960
+ std::unique_lock Lock (mStateFunctionQueueMutex );
959
961
decltype (mStateFunctionQueue )::iterator Iter = mStateFunctionQueue .end ();
960
962
if (Strategy == CallStrategy::BestEffort) {
961
963
Iter = std::find_if (mStateFunctionQueue .begin (), mStateFunctionQueue .end (),
@@ -967,8 +969,7 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFrom
967
969
auto Result = std::make_shared<TLuaResult>();
968
970
Result->StateId = mStateId ;
969
971
Result->Function = FunctionName;
970
- std::unique_lock Lock (mStateFunctionQueueMutex );
971
- mStateFunctionQueue .push_back ({ FunctionName, Result, Args, EventName, sol::nil });
972
+ mStateFunctionQueue .push_back ({ FunctionName, Result, Args, EventName, NULL });
972
973
mStateFunctionQueueCond .notify_all ();
973
974
return Result;
974
975
} else {
@@ -981,17 +982,17 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall(con
981
982
Result->StateId = mStateId ;
982
983
Result->Function = FunctionName;
983
984
std::unique_lock Lock (mStateFunctionQueueMutex );
984
- mStateFunctionQueue .push_back ({ FunctionName, Result, Args, " " , sol::nil });
985
+ mStateFunctionQueue .push_back ({ FunctionName, Result, Args, " " , NULL });
985
986
mStateFunctionQueueCond .notify_all ();
986
987
return Result;
987
988
}
988
989
989
- std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall (sol::function function , const std::vector<TLuaArgTypes>& Args) {
990
+ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall (std::shared_ptr< sol::reference> FunctionRef , const std::vector<TLuaArgTypes>& Args) {
990
991
auto Result = std::make_shared<TLuaResult>();
991
992
Result->StateId = mStateId ;
992
993
Result->Function = " anonymous" ;
993
994
std::unique_lock Lock (mStateFunctionQueueMutex );
994
- mStateFunctionQueue .push_back ({ " anonymous" , Result, Args, " " , function });
995
+ mStateFunctionQueue .push_back ({ " anonymous" , Result, Args, " " , FunctionRef });
995
996
mStateFunctionQueueCond .notify_all ();
996
997
return Result;
997
998
}
@@ -1063,8 +1064,9 @@ void TLuaEngine::StateThreadData::operator()() {
1063
1064
// TODO: Use TheQueuedFunction.EventName for errors, warnings, etc
1064
1065
Result->StateId = mStateId ;
1065
1066
sol::state_view StateView (mState );
1066
- auto Fn = TheQueuedFunction.Function != sol::nil ? TheQueuedFunction.Function : StateView[FnName];
1067
- if (Fn.valid () && Fn.get_type () == sol::type::function) {
1067
+ auto FnRef = TheQueuedFunction.FunctionRef ? *TheQueuedFunction.FunctionRef : StateView[FnName];
1068
+ if (FnRef.valid () && FnRef.get_type () == sol::type::function) {
1069
+ sol::function Fn = FnRef;
1068
1070
std::vector<sol::object> LuaArgs;
1069
1071
for (const auto & Arg : Args) {
1070
1072
if (Arg.valueless_by_exception ()) {
0 commit comments