forked from ates/netspire-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetspire_hooks.erl
103 lines (91 loc) · 2.71 KB
/
netspire_hooks.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
-module(netspire_hooks).
%% API
-export([start/0, add/3, add/4, delete/3, delete/4, delete_all/1,
run/2, run_fold/3]).
-include("netspire.hrl").
start() ->
ets:new(hooks, [named_table, public]).
add(Hook, Module, Fun) ->
add(Hook, Module, Fun, 100).
add(Hook, Module, Fun, Seq) ->
case ets:lookup(hooks, Hook) of
[{_, Ls}] ->
El = {Seq, Module, Fun},
case lists:member(El, Ls) of
true ->
ok;
false ->
NewLs = lists:merge(Ls, [El]),
ets:insert(hooks, {Hook, NewLs})
end;
[] ->
NewLs = [{Seq, Module, Fun}],
ets:insert(hooks, {Hook, NewLs})
end.
delete(Hook, Module, Fun) ->
delete(Hook, Module, Fun, 100).
delete(Hook, Module, Fun, Seq) ->
case ets:lookup(hooks, Hook) of
[{_, Ls}] ->
NewLs = lists:delete({Seq, Module, Fun}, Ls),
ets:insert(hooks, {Hook, NewLs});
[] ->
ok
end.
delete_all(Module) ->
do_delete_all(ets:first(hooks), Module).
run(Hook, Args) ->
case ets:lookup(hooks, Hook) of
[{_, Ls}] ->
do_run(Ls, Hook, Args);
[] ->
ok
end.
run_fold(Hook, Val, Args) ->
case ets:lookup(hooks, Hook) of
[{_, Ls}] ->
do_run_fold(Ls, Hook, Val, Args);
[] ->
Val
end.
%%
%% Internal API
%%
do_run([], _Hook, _Args) -> ok;
do_run([{_Seq, Module, Fun} | Ls], Hook, Args) ->
try apply(Module, Fun, Args) of
stop ->
ok;
_ ->
do_run(Ls, Hook, Args)
catch
_:Reason ->
?ERROR_MSG("Error while running hook ~p ~p"
" with args: ~p due to ~p~n", [Hook, {Module, Fun}, Args, Reason]),
do_run(Ls, Hook, Args)
end.
do_run_fold([], _Hook, Value, _Args) -> Value;
do_run_fold([{_Seq, Module, Fun} | Ls], Hook, Value, Args) ->
try apply(Module, Fun, [Value | Args]) of
stop ->
stop;
{stop, NewValue} ->
NewValue;
NewValue ->
do_run_fold(Ls, Hook, NewValue, Args)
catch
_:Reason ->
?ERROR_MSG("Error while running hook ~p ~p"
" with args: ~p due to ~p~n", [Hook, {Module, Fun}, Args, Reason]),
do_run_fold(Ls, Hook, Value, Args)
end.
do_delete_all('$end_of_table', _Module) -> ok;
do_delete_all(Hook, Module) ->
case ets:lookup(hooks, Hook) of
[{_, Ls}] ->
NewLs = [{_Seq, M, _Fun} || {_Seq, M, _Fun} <- Ls, M =/= Module],
ets:insert(hooks, {Hook, NewLs});
[] -> ok
end,
Next = ets:next(hooks, Hook),
do_delete_all(Next, Module).