// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_M_HOOK_H namespace ircd::m::hook { IRCD_EXCEPTION(ircd::error, error) struct base; struct maps; template struct hook; template struct site; template<> struct hook; template<> struct site; } namespace ircd::m { template using hookfn = m::hook::hook; } struct ircd::m::hook::base :instance_list { struct site; json::strung _feature; json::object feature; m::event matching; bool registered {false}; size_t matchers {0}; size_t calls {0}; size_t calling {0}; string_view site_name() const; site *find_site() const; protected: base(const json::members &); base(base &&) = delete; base(const base &) = delete; virtual ~base() noexcept; }; struct ircd::m::hook::base::site :instance_list { json::strung _feature; json::object feature; size_t count {0}; std::unique_ptr maps; std::set hooks; size_t matchers {0}; bool exceptions {true}; size_t calls {0}; size_t calling {0}; friend class base; string_view name() const; bool add(base &); bool del(base &); void match(const event &, const std::function &); protected: site(const json::members &); site(site &&) = delete; site(const site &) = delete; virtual ~site() noexcept; }; template<> struct ircd::m::hook::hook final :base { std::function function; public: hook(const json::members &feature, decltype(function) function); hook(decltype(function) function, const json::members &feature); }; template<> struct ircd::m::hook::site final :base::site { void call(hook &, const event &); public: void operator()(const event &); site(const json::members &feature); }; template struct ircd::m::hook::hook :base { std::function function; public: hook(const json::members &feature, decltype(function) function) :base{feature} ,function{std::move(function)} {} hook(decltype(function) function, const json::members &feature) :base{feature} ,function{std::move(function)} {} }; template struct ircd::m::hook::site :base::site { void call(hook &hfn, const event &event, data d); public: void operator()(const event &event, data d); site(const json::members &feature) :base::site{feature} {} }; template void ircd::m::hook::site::operator()(const event &event, data d) { match(event, [this, &event, &d] (base &base) { call(dynamic_cast &>(base), event, d); return true; }); } template void ircd::m::hook::site::call(hook &hfn, const event &event, data d) try { // stats for site ++calls; const scope_count site_calling { calling }; // stats for hook ++hfn.calls; const scope_count hook_calling { hfn.calling }; // call hook hfn.function(event, d); } catch(const std::exception &e) { if(exceptions) throw; log::critical { log, "Unhandled hookfn(%p) %s error :%s", &hfn, string_view{hfn.feature}, e.what() }; }