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  */
34 class AbstractExecutor(T) : Executor if (is(T == class)) { 
35 
36     this() {
37     }
38 
39     shared static this() {
40 
41         version(HUNT_DEBUG) tracef("Registering %s", T.stringof);
42         Class c = T.metaof;
43         const(Method)[] methods =  c.getMethods();
44         ExecutorInfo[] executors;
45 
46         foreach (const Method method; methods ) {
47             // trace(method.toString());
48             const(Attribute)[] attrs = method.getAttributes!(MessageId)();
49             // tracef("name: %s, MessageId: %s", method.getName(), method.hasAttribute!(MessageId)());
50             foreach(const(Attribute) attr; attrs) {
51                 // trace(attr.toString());
52                 if(!attr.isExpression()) 
53                     continue;
54 
55                 Variant value = attr.get();
56                 // trace(value.type.toString());
57                 MessageId messageId = value.get!(MessageId)();
58                 // trace(messageId.value);
59 
60                 int messageCode = messageId.value;
61                 bool isFound = executors.canFind!((ExecutorInfo a, uint b) => a.messageId() == b)(messageCode);
62                 if(isFound) {
63                     warningf("message code collision: %d in %s", messageCode, c.getFullName());
64                 } else {
65                     // Annoying const
66                     executors ~= cast(ExecutorInfo)ExecutorInfo(messageCode, cast(Class)c, cast(Method)method);
67 
68                 }
69             }
70         }
71 
72         // Register executor for Server
73         const(Attribute)[] attrs = c.getAttributes!(TransportServer)();
74         foreach(const(Attribute) attr; attrs) {
75             // trace(attr.toString());
76             if(!attr.isExpression()) 
77                 continue;
78 
79             Variant value = attr.get();
80             // trace(value.type.toString());
81             TransportServer messageServer = value.get!(TransportServer)();
82             // trace(messageServer.name);
83             Executor.registerExecutors(TransportServer.NAME_PREFIX ~ messageServer.name, executors);
84         }
85 
86 
87         // Register executor for Client
88         attrs = c.getAttributes!(TransportClient)();
89         foreach(const(Attribute) attr; attrs) {
90             // trace(attr.toString());
91             if(!attr.isExpression()) 
92                 continue;
93 
94             Variant value = attr.get();
95             // trace(value.type.toString());
96             TransportClient messageclient = value.get!(TransportClient)();
97             // trace(messageclient.name);
98             Executor.registerExecutors(TransportClient.NAME_PREFIX ~ messageclient.name, executors);
99         }
100 
101     }
102 
103     mixin Witchcraft!T;
104 }