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 }