2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com>
6 * This file is part of InspIRCd. InspIRCd is free software: you can
7 * redistribute it and/or modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation, version 2.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 class ModuleEventListener;
25 class ModuleEventProvider;
28 /** Provider of one or more cross-module events.
29 * Modules who wish to provide events for other modules create instances of this class and use
30 * one of the macros below to fire the event, passing the instance of the event provider class
32 * Event providers are identified using a unique identifier string.
34 class Events::ModuleEventProvider : public ServiceProvider, private dynamic_reference_base::CaptureHook
37 typedef std::vector<ModuleEventListener*> SubscriberList;
40 * @param mod Module providing the event(s)
41 * @param eventid Identifier of the event or event group provided, must be unique
43 ModuleEventProvider(Module* mod, const std::string& eventid)
44 : ServiceProvider(mod, eventid, SERVICE_DATA)
47 prov.SetCaptureHook(this);
50 /** Get list of objects subscribed to this event
51 * @return List of subscribed objects
53 const SubscriberList& GetSubscribers() const { return prov->subscribers; }
55 friend class ModuleEventListener;
58 void OnCapture() CXX11_OVERRIDE
60 // If someone else holds the list from now on, clear mine. See below for more info.
65 /** Reference to the active provider for this event. In case multiple event providers
66 * exist for the same event, only one of them contains the list of subscribers.
67 * To handle the case when we are not the ones with the list, we get it from the provider
68 * where the dynref points to.
70 dynamic_reference_nocheck<ModuleEventProvider> prov;
72 /** List of objects subscribed to the event(s) provided by us, or empty if multiple providers
73 * exist with the same name and we are not the ones holding the list.
75 SubscriberList subscribers;
78 /** Base class for abstract classes describing cross-module events.
79 * Subscribers should NOT inherit directly from this class.
81 class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook
83 /** Reference to the provider, can be NULL if none of the provider modules are loaded
85 dynamic_reference_nocheck<ModuleEventProvider> prov;
87 /** Called by the dynref when the event provider becomes available
89 void OnCapture() CXX11_OVERRIDE
91 prov->subscribers.push_back(this);
96 * @param mod Module subscribing
97 * @param eventid Identifier of the event to subscribe to
99 ModuleEventListener(Module* mod, const std::string& eventid)
102 prov.SetCaptureHook(this);
103 // If the dynamic_reference resolved at construction our capture handler wasn't called
105 ModuleEventListener::OnCapture();
108 ~ModuleEventListener()
111 stdalgo::erase(prov->subscribers, this);
116 * Run the given hook provided by a module
118 * FOREACH_MOD_CUSTOM(accountevprov, AccountEventListener, OnAccountChange, MOD_RESULT, (user, newaccount))
120 #define FOREACH_MOD_CUSTOM(prov, listenerclass, func, params) do { \
121 const Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \
122 for (Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \
124 listenerclass* _t = static_cast<listenerclass*>(*_i); \
130 * Run the given hook provided by a module until some module returns MOD_RES_ALLOW or MOD_RES_DENY.
131 * If no module does that, result is set to MOD_RES_PASSTHRU.
133 * Example: ModResult MOD_RESULT;
134 * FIRST_MOD_RESULT_CUSTOM(httpevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (request));
136 #define FIRST_MOD_RESULT_CUSTOM(prov, listenerclass, func, result, params) do { \
137 result = MOD_RES_PASSTHRU; \
138 const Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \
139 for (Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \
141 listenerclass* _t = static_cast<listenerclass*>(*_i); \
142 result = _t->func params ; \
143 if (result != MOD_RES_PASSTHRU) \