X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=include%2Fevent.h;h=baa24d7d08798b9f5c9a370dac3bae2af1f64510;hb=2ba32afa9a9aca7c82966b66bda16c3c3dbfbba5;hp=c9bad7d045f81423bb3d24f030fe3f72e46e59c2;hpb=ae6967b8b30ebc956e3158127ecba5d01dc09204;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/include/event.h b/include/event.h index c9bad7d04..baa24d7d0 100644 --- a/include/event.h +++ b/include/event.h @@ -1,7 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2015 Attila Molnar + * Copyright (C) 2018-2020 Sadie Powell + * Copyright (C) 2015, 2018 Attila Molnar * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -19,6 +20,8 @@ #pragma once +#include "base.h" + namespace Events { class ModuleEventListener; @@ -34,7 +37,17 @@ namespace Events class Events::ModuleEventProvider : public ServiceProvider, private dynamic_reference_base::CaptureHook { public: - typedef std::vector SubscriberList; + struct Comp + { + bool operator()(ModuleEventListener* lhs, ModuleEventListener* rhs) const; + }; + + struct ElementComp + { + bool operator()(ModuleEventListener* lhs, ModuleEventListener* rhs) const; + }; + + typedef insp::flat_multiset SubscriberList; /** Constructor * @param mod Module providing the event(s) @@ -47,12 +60,31 @@ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_refe prov.SetCaptureHook(this); } + /** Retrieves the module which created this listener. */ + const Module* GetModule() const { return prov.creator; } + /** Get list of objects subscribed to this event * @return List of subscribed objects */ const SubscriberList& GetSubscribers() const { return prov->subscribers; } - friend class ModuleEventListener; + /** Subscribes a listener to this event. + * @param subscriber The listener to subscribe. + */ + void Subscribe(ModuleEventListener* subscriber) + { + subscribers.insert(subscriber); + OnSubscribe(subscriber); + } + + /** Unsubscribes a listener from this event. + * @param subscriber The listener to unsubscribe. + */ + void Unsubscribe(ModuleEventListener* subscriber) + { + subscribers.erase(subscriber); + OnUnsubscribe(subscriber); + } private: void OnCapture() CXX11_OVERRIDE @@ -62,6 +94,16 @@ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_refe subscribers.clear(); } + /** Called when a listener subscribes to this event. + * @param subscriber The listener which subscribed. + */ + virtual void OnSubscribe(ModuleEventListener* subscriber) { } + + /** Called when a listener unsubscribes from this event. + * @param subscriber The listener which unsubscribed. + */ + virtual void OnUnsubscribe(ModuleEventListener* subscriber) { } + /** Reference to the active provider for this event. In case multiple event providers * exist for the same event, only one of them contains the list of subscribers. * To handle the case when we are not the ones with the list, we get it from the provider @@ -84,20 +126,26 @@ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook */ dynamic_reference_nocheck prov; + const unsigned int eventpriority; + /** Called by the dynref when the event provider becomes available */ void OnCapture() CXX11_OVERRIDE { - prov->subscribers.push_back(this); + prov->Subscribe(this); } public: + static const unsigned int DefaultPriority = 100; + /** Constructor * @param mod Module subscribing * @param eventid Identifier of the event to subscribe to + * @param eventprio The priority to give this event listener */ - ModuleEventListener(Module* mod, const std::string& eventid) + ModuleEventListener(Module* mod, const std::string& eventid, unsigned int eventprio = DefaultPriority) : prov(mod, eventid) + , eventpriority(eventprio) { prov.SetCaptureHook(this); // If the dynamic_reference resolved at construction our capture handler wasn't called @@ -108,21 +156,46 @@ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook ~ModuleEventListener() { if (prov) - stdalgo::erase(prov->subscribers, this); + prov->Unsubscribe(this); } + + /** Retrieves the module which created this listener. */ + const Module* GetModule() const { return prov.creator; } + + /** Retrieves the priority of this event. */ + unsigned int GetPriority() const { return eventpriority; } }; +inline bool Events::ModuleEventProvider::Comp::operator()(Events::ModuleEventListener* lhs, Events::ModuleEventListener* rhs) const +{ + return (lhs->GetPriority() < rhs->GetPriority()); +} + +inline bool Events::ModuleEventProvider::ElementComp::operator()(Events::ModuleEventListener* lhs, Events::ModuleEventListener* rhs) const +{ + if (lhs->GetPriority() < rhs->GetPriority()) + return true; + if (lhs->GetPriority() > rhs->GetPriority()) + return false; + return std::less()(lhs, rhs); +} + /** * Run the given hook provided by a module * * FOREACH_MOD_CUSTOM(accountevprov, AccountEventListener, OnAccountChange, MOD_RESULT, (user, newaccount)) */ #define FOREACH_MOD_CUSTOM(prov, listenerclass, func, params) do { \ - const Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ - for (Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ + if (!(prov).GetModule() || !(prov).GetModule()->dying) \ { \ - listenerclass* _t = static_cast(*_i); \ - _t->func params ; \ + const ::Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ + for (::Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ + { \ + listenerclass* _t = static_cast(*_i); \ + const Module* _m = _t->GetModule(); \ + if (_m && !_m->dying) \ + _t->func params ; \ + } \ } \ } while (0); @@ -135,12 +208,18 @@ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook */ #define FIRST_MOD_RESULT_CUSTOM(prov, listenerclass, func, result, params) do { \ result = MOD_RES_PASSTHRU; \ - const Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ - for (Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ + if (!(prov).GetModule() || !(prov).GetModule()->dying) \ { \ - listenerclass* _t = static_cast(*_i); \ - result = _t->func params ; \ - if (result != MOD_RES_PASSTHRU) \ - break; \ + const ::Events::ModuleEventProvider::SubscriberList& _handlers = (prov).GetSubscribers(); \ + for (::Events::ModuleEventProvider::SubscriberList::const_iterator _i = _handlers.begin(); _i != _handlers.end(); ++_i) \ + { \ + listenerclass* _t = static_cast(*_i); \ + const Module* _m = _t->GetModule(); \ + if (!_m || _m->dying) \ + continue; \ + result = _t->func params ; \ + if (result != MOD_RES_PASSTHRU) \ + break; \ + } \ } \ } while (0);