0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-09 11:31:11 +01:00
construct/include/ircd/m/hook.h

183 lines
3.5 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// 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<class data = void> struct hook;
template<class data = void> struct site;
template<> struct hook<void>;
template<> struct site<void>;
}
namespace ircd::m
{
template<class data = void> using hookfn = m::hook::hook<data>;
}
struct ircd::m::hook::base
:instance_list<base>
{
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<site>
{
json::strung _feature;
json::object feature;
size_t count {0};
std::unique_ptr<struct maps> maps;
std::set<base *> 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<bool (base &)> &);
protected:
site(const json::members &);
site(site &&) = delete;
site(const site &) = delete;
virtual ~site() noexcept;
};
template<>
struct ircd::m::hook::hook<void>
final
:base
{
std::function<void (const m::event &)> function;
public:
hook(const json::members &feature, decltype(function) function);
hook(decltype(function) function, const json::members &feature);
};
template<>
struct ircd::m::hook::site<void>
final
:base::site
{
void call(hook<void> &, const event &);
public:
void operator()(const event &);
site(const json::members &feature);
};
template<class data>
struct ircd::m::hook::hook
:base
{
std::function<void (const m::event &, data)> 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<class data>
struct ircd::m::hook::site
:base::site
{
void call(hook<data> &hfn, const event &event, data d);
public:
void operator()(const event &event, data d);
site(const json::members &feature)
:base::site{feature}
{}
};
template<class data>
void
ircd::m::hook::site<data>::operator()(const event &event,
data d)
{
match(event, [this, &event, &d]
(base &base)
{
call(dynamic_cast<hook<data> &>(base), event, d);
return true;
});
}
template<class data>
void
ircd::m::hook::site<data>::call(hook<data> &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
{
"Unhandled hookfn(%p) %s error :%s",
&hfn,
string_view{hfn.feature},
e.what()
};
}