diff --git a/module/Library/Discord/Cluster.cpp b/module/Library/Discord/Cluster.cpp index 5d82b5b5..20f38131 100644 --- a/module/Library/Discord/Cluster.cpp +++ b/module/Library/Discord/Cluster.cpp @@ -15,6 +15,7 @@ DpCluster::DpCluster(DpClusterOptions & o) : Base(), mQueue(4096) , mC(std::make_unique< dpp::cluster >(o.mToken, o.mIntents, o.mShards, o.mClusterID, o.mMaxClusters, o.mCompressed, o.mPolicy, o.mRequestThreads, o.mRequestThreadsRaw)) , mSqEvents(), mEvents(), mEventsHandle() + , mCCList(), mCCResults(std::make_shared< CCResultQueue >(4096)) { // Make sure all event handles are not valid mEventsHandle.fill(0); @@ -83,6 +84,31 @@ void DpCluster::Process(bool force) p->Cleanup(); } } + CCResultItem cc_item; + // Retrieve each command completion result individually and process it + for (size_t count = mCCResults->size_approx(), n = 0; n <= count; ++n) + { + // Try to get a result from the queue + if (mCCResults->try_dequeue(cc_item)) + { + CCResult & r = *cc_item; + // Get the script callback + Function & cb = *(r.first); + // Is there still a valid callback to invoke? + if (!cb.IsNull()) + { + // Don't abort everything down the line for an error caused by a script callback + try { + cb.Execute(LightObj(SqTypeIdentity< DpCommandConfirmation >{}, cb.GetVM(), std::move(r.second))); + } catch (const std::exception & e) { + LogErr("Squirrel exception caught in discord command completion event"); + LogSInf("Message: %s", e.what()); + } + } + // Release the callback from the list + mCCList.erase(r.first); + } + } } // ------------------------------------------------------------------------------------------------ @@ -122,6 +148,7 @@ void Register_Discord_Cluster(HSQUIRRELVM vm, Table & ns) .Func(_SC("Stop"), &DpCluster::Stop) .Func(_SC("EnableEvent"), &DpCluster::EnableEvent) .Func(_SC("DisableEvent"), &DpCluster::DisableEvent) + .CbFunc(_SC("CurrentUserGetGuilds"), &DpCluster::CurrentUserGetGuilds) ); } diff --git a/module/Library/Discord/Cluster.hpp b/module/Library/Discord/Cluster.hpp index ba49104d..44b81fa1 100644 --- a/module/Library/Discord/Cluster.hpp +++ b/module/Library/Discord/Cluster.hpp @@ -333,6 +333,64 @@ private: void OnStageInstanceCreate(const dpp::stage_instance_create_t & ev); void OnStageInstanceUpdate(const dpp::stage_instance_update_t & ev); void OnStageInstanceDelete(const dpp::stage_instance_delete_t & ev); + +public: + + // List type for command completion callbacks. + using CCList = std::list< Function >; + /* -------------------------------------------------------------------------------------------- + * List of command completion callbacks. + */ + CCList mCCList{}; + + /* -------------------------------------------------------------------------------------------- + * Queue of iterators pointing to results of completed commands and their associated result. + */ + using CCResult = std::pair< CCList::iterator, DpCommandConfirmation::Ptr >; + using CCResultItem = std::unique_ptr< CCResult >; + using CCResultQueue = moodycamel::ConcurrentQueue< CCResultItem >; + + /* -------------------------------------------------------------------------------------------- + * Command completion links queue. + */ + std::shared_ptr< CCResultQueue > mCCResults{}; + + /* -------------------------------------------------------------------------------------------- + * Maintains an iterator to the script callback associated with a completed command result. + */ + struct CCLink + { + // Iterator to the element where the state can be found. + CCList::iterator mItr{}; + // Reference to the queue of iterators pointing to completed commands. + std::shared_ptr< CCResultQueue > mQueue{}; + /* ---------------------------------------------------------------------------------------- + * Base constructor. + */ + CCLink(CCList::iterator && itr, std::shared_ptr< CCResultQueue > & q) + : mItr(std::forward< CCList::iterator >(itr)), mQueue(q) + { } + // Copy/Move constructors. + CCLink(const CCLink &) = default; + CCLink(CCLink &&) noexcept = default; + // Copy/Move assignment operators. + CCLink & operator = (const CCLink &) = default; + CCLink & operator = (CCLink &&) noexcept = default; + // Function call operator. Marks the linked callback as ready to invoke with obtained result. + void operator () (const dpp::confirmation_callback_t & cc) const + { + mQueue->enqueue(std::make_unique< CCResult >(std::move(mItr), std::make_unique< dpp::confirmation_callback_t >(cc.http_info))); + } + }; + + /* -------------------------------------------------------------------------------------------- + * Get current (bot) user guilds. + * https://discord.com/developers/docs/resources/user#get-current-user-guilds + */ + void CurrentUserGetGuilds(Function & cb) + { + Valid("get message").current_user_get_guilds(CCLink(mCCList.emplace(mCCList.cend(), std::move(cb)), mCCResults)); + } }; } // Namespace:: SqMod