1 /*
2  * MsgTrans - Message Transport Framework for DLang. Based on TCP, WebSocket, UDP transmission protocol.
3  *
4  * Copyright (C) 2019 HuntLabs
5  *
6  * Website: https://www.msgtrans.org
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module msgtrans.executor.AbstractExecutor;
13 
14 import msgtrans.MessageBuffer;
15 import msgtrans.MessageTransport;
16 import msgtrans.channel.TransportSession;
17 import msgtrans.executor.ExecutorInfo;
18 
19 public import msgtrans.executor.Executor;
20 public import msgtrans.executor.MessageId;
21 
22 import hunt.logging.ConsoleLogger;
23 import witchcraft;
24 
25 import std.algorithm;
26 import std.conv;
27 import std.range;
28 import std.variant;
29 
30 /** 
31  * 
32  */
33 class AbstractExecutor(T) : Executor if (is(T == class)) { 
34 
35     this() {
36     }
37 
38     shared static this() {
39 
40         version(HUNT_DEBUG) tracef("Registering %s", T.stringof);
41         Class c = T.metaof;
42         const(Method)[] methods =  c.getMethods();
43         ExecutorInfo[] executors;
44 
45         foreach (const Method method; methods ) {
46             // trace(method.toString());
47             const(Attribute)[] attrs = method.getAttributes!(MessageId)();
48             // tracef("name: %s, MessageId: %s", method.getName(), method.hasAttribute!(MessageId)());
49             foreach(const(Attribute) attr; attrs) {
50                 // trace(attr.toString());
51                 if(!attr.isExpression()) 
52                     continue;
53 
54                 Variant value = attr.get();
55                 // trace(value.type.toString());
56                 MessageId messageId = value.get!(MessageId)();
57                 // trace(messageId.value);
58 
59                 int messageCode = messageId.value;
60                 bool isFound = executors.canFind!((ExecutorInfo a, uint b) => a.messageId() == b)(messageCode);
61                 if(isFound) {
62                     warningf("message code collision: %d in %s", messageCode, c.getFullName());
63                 } else {
64                     // Annoying const
65                     executors ~= cast(ExecutorInfo)ExecutorInfo(messageCode, cast(Class)c, cast(Method)method);
66 
67                 }
68             }
69         }
70 
71         // Register executor for Server
72         const(Attribute)[] attrs = c.getAttributes!(TransportServer)();
73         foreach(const(Attribute) attr; attrs) {
74             // trace(attr.toString());
75             if(!attr.isExpression()) 
76                 continue;
77 
78             Variant value = attr.get();
79             // trace(value.type.toString());
80             TransportServer messageServer = value.get!(TransportServer)();
81             // trace(messageServer.name);
82             Executor.registerExecutors(TransportServer.NAME_PREFIX ~ messageServer.name, executors);
83         }
84 
85 
86         // Register executor for Client
87         attrs = c.getAttributes!(TransportClient)();
88         foreach(const(Attribute) attr; attrs) {
89             // trace(attr.toString());
90             if(!attr.isExpression()) 
91                 continue;
92 
93             Variant value = attr.get();
94             // trace(value.type.toString());
95             TransportClient messageclient = value.get!(TransportClient)();
96             // trace(messageclient.name);
97             Executor.registerExecutors(TransportClient.NAME_PREFIX ~ messageclient.name, executors);
98         }
99 
100     }
101 
102     mixin Witchcraft!T;
103 }