1 module dscord.util.emitter; 2 3 import vibe.core.concurrency, 4 vibe.core.core; 5 6 import std.stdio, 7 std.algorithm, 8 std.array, 9 std.variant, 10 std.datetime, 11 core.time; 12 13 import dscord.util.errors; 14 15 class EmitterStop : Exception { mixin ExceptionMixin; } 16 17 interface BoundEmitter { 18 void call(string, Variant); 19 } 20 21 class BaseEventListener : BoundEmitter { 22 string name; 23 Emitter e; 24 25 void unbind() { 26 this.e.listeners[this.name] = this.e.listeners[this.name].filter!( 27 (li) => li != this).array; 28 } 29 30 void call(string name, Variant arg) { 31 32 } 33 } 34 35 class EventListener : BaseEventListener { 36 void delegate(Variant arg) func; 37 38 this(Emitter e, string name, void delegate(Variant) f) { 39 this.e = e; 40 this.name = name; 41 this.func = f; 42 } 43 44 override void call(string name, Variant arg) { 45 this.func(arg); 46 } 47 } 48 49 class AllEventListener : BaseEventListener { 50 void delegate(string, Variant) func; 51 52 this(Emitter e, void delegate(string, Variant) f) { 53 this.e = e; 54 this.func = f; 55 } 56 57 override void call(string name, Variant arg) { 58 this.func(name, arg); 59 } 60 } 61 62 class Emitter { 63 BoundEmitter[][string] listeners; 64 65 EventListener on(string event, void delegate() f) { 66 auto li = new EventListener(this, event, (arg) { 67 try { f(); } catch (EmitterStop) { return; } 68 }); 69 70 this.listeners[event] ~= li; 71 return li; 72 } 73 74 EventListener listen(T)(void delegate(T) f) { 75 auto li = new EventListener(this, T.stringof, (arg) { 76 try { f(arg.get!T); } catch (EmitterStop) { return; } 77 }); 78 79 this.listeners[T.stringof] ~= li; 80 return li; 81 } 82 83 EventListener listenRaw(string event, void delegate(Variant) f) { 84 auto li = new EventListener(this, event, f); 85 this.listeners[event] ~= li; 86 return li; 87 } 88 89 AllEventListener listenAll(void delegate(string, Variant) f) { 90 auto li = new AllEventListener(this, f); 91 this.listeners[""] ~= li; 92 return li; 93 } 94 95 void emit(T)(T obj) { 96 this.emitByName!T(T.stringof, obj, false); 97 this.emitByName!T(T.stringof, obj, true); 98 } 99 100 void emitByName(T)(string name, T obj, bool all) { 101 if (!((all ? "" : name) in this.listeners)) { 102 return; 103 } 104 105 auto v = Variant(obj); 106 107 foreach (func; this.listeners[all ? "" : name]) { 108 runTask(&func.call, name, v); 109 } 110 } 111 }