1 /**
2   Utilties for handling/listening to events through the dscord bot interface.
3 */
4 
5 module dscord.bot.listener;
6 
7 import std.variant,
8        std.string,
9        std.array;
10 
11 import dscord.gateway.events,
12        dscord.types.all,
13        dscord.util.emitter;
14 
15 /**
16   UDA that can be used on a Plugin, informing it that the function will handle
17   all events of type T.
18 
19   Params:
20     T = Event type to listen for
21 */
22 ListenerDef!T Listener(T)() {
23   return ListenerDef!(T)(T.stringof, (event, func) {
24     func(event.get!(T));
25   });
26 }
27 
28 /**
29   Utility struct returned by the UDA.
30 */
31 struct ListenerDef(T) {
32   string clsName;
33   void delegate(Variant, void delegate(T)) func;
34 }
35 
36 /**
37   A ListenerObject represents the configuration/state for a single listener.
38 */
39 class ListenerObject {
40   /** The class name of the event this listener is for */
41   string  clsName;
42 
43   /** EventListener function for this Listener */
44   EventListener  listener;
45 
46   /** Utility variant caller for converting event type */
47   void delegate(Variant v) func;
48 
49   this(string clsName, void delegate(Variant v) func) {
50     this.clsName = clsName;
51     this.func = func;
52   }
53 }
54 
55 /**
56   The Listenable template is a virtual implementation which handles the listener
57   UDAs, storing them within a local "listeners" mapping.
58 */
59 mixin template Listenable() {
60   ListenerObject[]  listeners;
61 
62   void loadListeners(T)() {
63     foreach (mem; __traits(allMembers, T)) {
64       foreach(attr; __traits(getAttributes, __traits(getMember, T, mem))) {
65         static if (__traits(hasMember, attr, "clsName")) {
66           this.registerListener(new ListenerObject(attr.clsName, (v) {
67             attr.func(v, mixin("&(cast(T)this)." ~ mem));
68           }));
69         }
70       }
71     }
72   }
73 
74   /**
75     Registers a listener from a ListenerObject
76   */
77   void registerListener(ListenerObject obj) {
78     this.listeners ~= obj;
79   }
80 }