Note, I intentially began this discussion as a question, not a statement.
Totally thinking "aloud."

I think it is like gen_server. For gen_server all you need is a
handle_call/3 and handle_cast/2. The real API is inside that.

For example, maybe all that's required for the behaviour is on/1 and we can
make a flexible hook system from that. (Now why would "on" be a meaningful
or useful function name?)

 on({log, Severity, Message}) -> ok
    , io:format("Couch says ~s\n", [Message])
    ;

% Suppose I want a database that stays synced to my config
% (something I personally need at the moment).

on({startup}) -> ok
    , io:format("CouchDB started!\n")
    , init_my_config_db(couch_config:get("*/*")) % Pseudocode
    ;

on({config, Section, Key, Value}) -> ok
    , io:format("Config update: ~s/~s = ~p\n", [Section, Key, Value])
    , update_my_config_db(Section, Key, Value)
    ;

on(Unknown) -> ok
    , io:format("Did you know there is a ~p hook?\n", [element(1, Unknown)])
    .



On Thu, Aug 8, 2013 at 5:42 PM, Jan Lehnardt <j...@apache.org> wrote:

>
> On Aug 8, 2013, at 12:39 , Jason Smith <j...@apache.org> wrote:
>
> > Well, I just googled it. Basically there is a couchdb_plugin.erl which
> > tells Erlang what a behavior looks like. And all that does is define the
> > functions and arity which a couchdb_plugin would have to export.
> >
> > Probably there are some better Erlangers on the list who might chime in.
> It
> > looks like okay bang-for-buck; only not much bang or much buck.
>
> how would this work if a plugin is only interested in handling a single
> hook,
> would it have to implement mock funs for all hooks then?
>
> > On Thu, Aug 8, 2013 at 5:26 PM, Jan Lehnardt <j...@apache.org> wrote:
> >
> >> how would this look in code?
> >>
> >> On Aug 8, 2013, at 12:21 , Jason Smith <j...@apache.org> wrote:
> >>
> >>> Perhaps a custom behaviour to help catch API problems at compile time?
> >>>
> >>>   -behaviour(couchdb_plugin).
> >>>
> >>>
> >>>
> >>> On Thu, Aug 8, 2013 at 3:47 PM, Jan Lehnardt <j...@apache.org> wrote:
> >>>
> >>>> Heya,
> >>>>
> >>>> I’m toying with the idea of moving some of my experimental into
> >>>> bona-fide plugins. One of them is my log_to_db branch that on top of
> >>>> writing log messages to a text file also writes a document to a log
> >>>> database.
> >>>>
> >>>> Conceptually, this is the perfect use of a plugin: the feature is not
> >>>> useful in the general case, because *any* activity creates write load
> >>>> on a single database, but for certain low-volume installations, this
> >>>> might be a useful feature (I wouldn’t have written it, if I hadn’t
> >>>> needed it at some point) so allowing users to enable it as a plugin
> >>>> would be nice.
> >>>>
> >>>> But regardless of whether my plugin is useful, it illustrates an
> >>>> interesting point:
> >>>>
> >>>> A log_to_db plugin would need to register for logging events or, if it
> >>>> doesn’t want to duplicate all the logging-level logic in couch_log, it
> >>>> would need some way of injecting a function call into
> >>>> `couch_log:log().`. We could of course try and find a way where a
> >>>> plugin would be able to provide an API compatible version of a CouchDB
> >>>> module and swap it out for it’s custom one, but that’s hardly a great
> >>>> idea.
> >>>>
> >>>> Other software has the notion of “hooks” (some may call it something
> >>>> else) where at well defined points in the main code base, external
> >>>> functions get called with certain parameters. To make things dynamic,
> >>>> there might be a way for plugins to register to be called by those
> >>>> hooks and the main code then asks the registry whether there are any
> >>>> plugin functions to call.
> >>>>
> >>>> In the log_to_db example, we’d have something like this:
> >>>>
> >>>> couch_log_to_db.erl:
> >>>>
> >>>>   init() ->
> >>>>       couch_hooks:register(couch_log_hook, log_hook_fun/1),
> >>>>       ok.
> >>>>
> >>>>   log_hook_fun(Log) ->
> >>>>       % do the log_to_db magic
> >>>>       ok.
> >>>>
> >>>>
> >>>> couch_hooks.erl:
> >>>>
> >>>>   register(Hook, Fun) ->
> >>>>       % store the Fun with the Hook somewhere
> >>>>       ok.
> >>>>
> >>>>   call(Hook, Args) ->
> >>>>        % retrieve Fun for Hook from somewhere
> >>>>       Fun(Args).
> >>>>
> >>>> couch_log.erl:
> >>>>
> >>>> % in log()
> >>>>
> >>>>   ...
> >>>>   couch_hooks:call(couch_log_hook, Args),
> >>>>   ...
> >>>>
> >>>> The main code would define what the hook name and arguments are and
> the
> >>>> plugin would have to conform. The plugin registry would just manage
> the
> >>>> registration and calling of functions for a hook, but nothing more.
> >>>>
> >>>> * * *
> >>>>
> >>>> This is just my first stab at this not thinking about it too much and
> I
> >>>> likely miss some subtleties in Erlang that make this not work (hot
> code
> >>>> upgrades e.g.).
> >>>>
> >>>>
> >>>> How do you think we should implement a hooks feature in CouchDB?
> >>>>
> >>>>
> >>>> Thanks!
> >>>> Jan
> >>>> --
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>
> >>
>
>

Reply via email to