D++ (DPP)
C++ Discord API Bot Library
dpp::event_router_t< T > Class Template Reference

Handles routing of an event to multiple listeners. Multiple listeners may attach to the event_router_t by means of operator(). Passing a lambda into operator() attaches to the event. More...

#include <event_router.h>

Public Member Functions

 event_router_t ()=default
 Construct a new event_router_t object. More...
 
 ~event_router_t ()
 Destructor. Will cancel any coroutine awaiting on events. More...
 
void call (const T &event) const
 Call all attached listeners. Listeners may cancel, by calling the event.cancel method. More...
 
void call (T &&event) const
 Call all attached listeners. Listeners may cancel, by calling the event.cancel method. More...
 
template<typename Predicate >
auto when (Predicate &&pred)
 Obtain an awaitable object that refers to an event with a certain condition. It can be co_await-ed to wait for the next event that satisfies this condition. On resumption the awaiter will be given a reference to the event, saving it in a variable is recommended to avoid variable lifetime issues. More...
 
auto operator co_await () noexcept
 Obtain an awaitable object that refers to any event. It can be co_await-ed to wait for the next event. More...
 
bool empty () const
 Returns true if the container of listeners is empty, i.e. there is nothing listening for this event right now. More...
 
 operator bool () const
 Returns true if any listeners are attached. More...
 
template<typename F >
event_handle operator() (F &&fun)
 Attach a callable to the event, adding a listener. The callable should either be of the form void(const T&) or dpp::task<void>(const T&) (the latter requires DPP_CORO to be defined), where T is the event type for this event router. More...
 
template<typename F >
event_handle attach (F &&fun)
 Attach a callable to the event, adding a listener. The callable should either be of the form void(const T&) or dpp::task<void>(const T&) (the latter requires DPP_CORO to be defined), where T is the event type for this event router. More...
 
bool detach (const event_handle &handle)
 Detach a listener from the event using a previously obtained ID. More...
 

Protected Member Functions

void set_warning_callback (std::function< void(const T &)> warning_function)
 Next handle to be given out by the event router. More...
 
void handle (const T &event) const
 Handle an event. This function should only be used without coro enabled, otherwise use handle_coro. More...
 
dpp::job handle_coro (T event) const
 Handle an event as a coroutine, ensuring the lifetime of the event object. More...
 
void attach_awaiter (detail::event_router::awaitable< T > *awaiter)
 Attach a suspended coroutine to this event router via detail::event_router::awaitable. It will be resumed and detached when an event satisfying its condition completes, or it is cancelled. More...
 
void detach_coro (void *handle)
 Detach an awaiting coroutine handle from this event router. This is mostly called when a detail::event_router::awaitable is cancelled. More...
 
void resume_awaiters (const T &event) const
 Resume any awaiter whose predicate matches this event, or is null. More...
 

Friends

class cluster
 
class detail::event_router::awaitable< T >
 

Detailed Description

template<class T>
class dpp::event_router_t< T >

Handles routing of an event to multiple listeners. Multiple listeners may attach to the event_router_t by means of operator(). Passing a lambda into operator() attaches to the event.

Dispatchers of the event may call the call() method to cause all listeners to receive the event.

The empty() method will return true if there are no listeners attached to the event_router_t (this can be used to save time by not constructing objects that nobody will ever see).

The detach() method removes an existing listener from the event, using the event_handle ID returned by operator().

This class is used by the library to route all websocket events to listening code.

Example:

// Declare an event that takes log_t as its parameter
event_router_t<log_t> my_event;
// Attach a listener to the event
event_handle id = my_event([&](const log_t& cc) {
std::cout << cc.message << "\n";
});
// Construct a log_t and call the event (listeners will receive the log_t object)
log_t lt;
lt.message = "foo";
my_event.call(lt);
// Detach from an event using the handle returned by operator()
my_event.detach(id);
size_t event_handle
A returned event handle for an event which was attached.
Definition: event_router.h:159
Template Parameters
Ttype of single parameter passed to event lambda derived from event_dispatch_t

Constructor & Destructor Documentation

◆ event_router_t()

template<class T >
dpp::event_router_t< T >::event_router_t ( )
default

Construct a new event_router_t object.

◆ ~event_router_t()

template<class T >
dpp::event_router_t< T >::~event_router_t ( )
inline

Destructor. Will cancel any coroutine awaiting on events.

Exceptions
!Cancelling a coroutine will throw a dpp::task_cancelled_exception to it. This will be caught in this destructor, however, make sure no other exceptions are thrown in the coroutine after that or it will terminate.

Member Function Documentation

◆ attach()

template<class T >
template<typename F >
event_handle dpp::event_router_t< T >::attach ( F &&  fun)

Attach a callable to the event, adding a listener. The callable should either be of the form void(const T&) or dpp::task<void>(const T&) (the latter requires DPP_CORO to be defined), where T is the event type for this event router.

Parameters
funCallable to attach to event
Returns
event_handle An event handle unique to this event, used to detach the listener from the event later if necessary.

◆ attach_awaiter()

template<class T >
void dpp::event_router_t< T >::attach_awaiter ( detail::event_router::awaitable< T > *  awaiter)
inlineprotected

Attach a suspended coroutine to this event router via detail::event_router::awaitable. It will be resumed and detached when an event satisfying its condition completes, or it is cancelled.

This is for internal usage only, the user way to do this is to co_await it (which will call this when suspending) This guarantees that the coroutine is indeed suspended and thus can be resumed at any time

Parameters
awaiterAwaiter to attach

◆ call() [1/2]

template<class T >
void dpp::event_router_t< T >::call ( const T &  event) const
inline

Call all attached listeners. Listeners may cancel, by calling the event.cancel method.

Parameters
eventClass to pass as parameter to all listeners.

◆ call() [2/2]

template<class T >
void dpp::event_router_t< T >::call ( T &&  event) const
inline

Call all attached listeners. Listeners may cancel, by calling the event.cancel method.

Parameters
eventClass to pass as parameter to all listeners.

◆ detach()

template<class T >
bool dpp::event_router_t< T >::detach ( const event_handle handle)
inline

Detach a listener from the event using a previously obtained ID.

Warning
You cannot call this within an event handler.
Parameters
handleAn ID obtained from operator()
Return values
trueThe event was successfully detached
falseThe ID is invalid (possibly already detached, or does not exist)

◆ detach_coro()

template<class T >
void dpp::event_router_t< T >::detach_coro ( void *  handle)
inlineprotected

Detach an awaiting coroutine handle from this event router. This is mostly called when a detail::event_router::awaitable is cancelled.

Parameters
handleCoroutine handle to find in the attached coroutines

◆ empty()

template<class T >
bool dpp::event_router_t< T >::empty ( ) const
inline

Returns true if the container of listeners is empty, i.e. there is nothing listening for this event right now.

Return values
trueif there are no listeners
falseif there are some listeners

◆ handle()

template<class T >
void dpp::event_router_t< T >::handle ( const T &  event) const
inlineprotected

Handle an event. This function should only be used without coro enabled, otherwise use handle_coro.

◆ handle_coro()

template<class T >
dpp::job dpp::event_router_t< T >::handle_coro ( event) const
inlineprotected

Handle an event as a coroutine, ensuring the lifetime of the event object.

◆ operator bool()

template<class T >
dpp::event_router_t< T >::operator bool ( ) const
inline

Returns true if any listeners are attached.

This is the boolean opposite of event_router_t::empty().

Return values
trueif listeners are attached
falseif no listeners are attached

◆ operator co_await()

template<class T >
auto dpp::event_router_t< T >::operator co_await ( )
inlinenoexcept

Obtain an awaitable object that refers to any event. It can be co_await-ed to wait for the next event.

Example:

Example:

dpp::task<> my_handler(const dpp::slashcommand_t& event) {
co_await event.co_reply(dpp::message().add_component(dpp::component().add_component().set_label("click me!").set_id("test")));
dpp::button_click_t b = co_await c->on_message_create;
// do something on button click
}
Represents the component object. A component is a clickable button or drop down list within a discord...
Definition: message.h:348
A coroutine task. It starts immediately on construction and can be co_await-ed, making it perfect for...
Definition: task.h:95
constexpr const char b[]
Definition: unicode_emoji.h:5255
Click on button.
Definition: dispatcher.h:703
Represents messages sent and received on Discord.
Definition: message.h:2071
User has issued a slash command.
Definition: dispatcher.h:695

This can be combined with dpp::when_any and other awaitables, for example dpp::cluster::co_sleep to create expiring buttons.

Warning
On resumption the awaiter will be given a reference to the event. This means that variable may become dangling at the next co_await, be careful and save it in a variable if you need to.
Returns
awaitable An awaitable object that can be co_await-ed to await an event matching the condition.

◆ operator()()

template<class T >
template<typename F >
event_handle dpp::event_router_t< T >::operator() ( F &&  fun)

Attach a callable to the event, adding a listener. The callable should either be of the form void(const T&) or dpp::task<void>(const T&) (the latter requires DPP_CORO to be defined), where T is the event type for this event router.

This has the exact same behavior as using attach.

See also
attach
Parameters
funCallable to attach to event
Returns
event_handle An event handle unique to this event, used to detach the listener from the event later if necessary.

◆ resume_awaiters()

template<class T >
void dpp::event_router_t< T >::resume_awaiters ( const T &  event) const
inlineprotected

Resume any awaiter whose predicate matches this event, or is null.

Parameters
eventEvent to compare and pass to accepting awaiters

If state == none (was never awaited), do nothing If state == waiting, prevent resumption, resume on our end If state == resuming || cancelling, ignore

Technically only cancelling || waiting should be possible here We do this by trying to exchange "waiting" with "resuming". If that returns false, this is presumed to be "cancelling"

◆ set_warning_callback()

template<class T >
void dpp::event_router_t< T >::set_warning_callback ( std::function< void(const T &)>  warning_function)
inlineprotected

Next handle to be given out by the event router.

Set the warning callback object used to check that this event is capable of running properly

Parameters
warning_functionA checking function to call

◆ when()

template<class T >
template<typename Predicate >
auto dpp::event_router_t< T >::when ( Predicate &&  pred)
inline

Obtain an awaitable object that refers to an event with a certain condition. It can be co_await-ed to wait for the next event that satisfies this condition. On resumption the awaiter will be given a reference to the event, saving it in a variable is recommended to avoid variable lifetime issues.

Example:

dpp::task<> my_handler(const dpp::slashcommand_t& event) {
co_await event.co_reply(dpp::message().add_component(dpp::component().add_component().set_label("click me!").set_id("test")));
dpp::button_click_t b = co_await c->on_button_click.with([](const dpp::button_click_t &event){ return event.custom_id == "test"; });
// do something on button click
}

This can be combined with dpp::when_any and other awaitables, for example dpp::cluster::co_sleep to create expiring buttons.

Warning
On resumption the awaiter will be given a reference to the event. This means that variable may become dangling at the next co_await, be careful and save it in a variable if you need to.
Parameters
predPredicate to check the event against. This should be a callable of the form bool(const T&) where T is the event type, returning true if the event is to match.
Returns
awaitable An awaitable object that can be co_await-ed to await an event matching the condition.

Friends And Related Function Documentation

◆ cluster

template<class T >
friend class cluster
friend

◆ detail::event_router::awaitable< T >

template<class T >
friend class detail::event_router::awaitable< T >
friend
D++ Library version 10.0.34D++ Library version 10.0.33D++ Library version 10.0.32D++ Library version 10.0.31D++ Library version 10.0.30D++ Library version 10.0.29D++ Library version 10.0.28D++ Library version 10.0.27D++ Library version 10.0.26D++ Library version 10.0.25D++ Library version 10.0.24D++ Library version 10.0.23D++ Library version 10.0.22D++ Library version 10.0.21D++ Library version 10.0.20D++ Library version 10.0.19D++ Library version 10.0.18D++ Library version 10.0.17D++ Library version 10.0.16D++ Library version 10.0.15D++ Library version 10.0.14D++ Library version 10.0.13D++ Library version 10.0.12D++ Library version 10.0.11D++ Library version 10.0.10D++ Library version 10.0.9D++ Library version 10.0.8D++ Library version 10.0.7D++ Library version 10.0.6D++ Library version 10.0.5D++ Library version 10.0.4D++ Library version 10.0.3D++ Library version 10.0.2D++ Library version 10.0.1D++ Library version 10.0.0D++ Library version 9.0.19D++ Library version 9.0.18D++ Library version 9.0.17D++ Library version 9.0.16D++ Library version 9.0.15D++ Library version 9.0.14D++ Library version 9.0.13D++ Library version 9.0.12D++ Library version 9.0.11D++ Library version 9.0.10D++ Library version 9.0.9D++ Library version 9.0.8D++ Library version 9.0.7D++ Library version 9.0.6D++ Library version 9.0.5D++ Library version 9.0.4D++ Library version 9.0.3D++ Library version 9.0.2D++ Library version 9.0.1D++ Library version 9.0.0D++ Library version 1.0.2D++ Library version 1.0.1D++ Library version 1.0.0