1 module buffer.message;
2 
3 import std.traits;
4 import std.typecons;
5 import std.variant;
6 import std.conv : to;
7 
8 import cryption.rsa;
9 
10 public import buffer.compiler;
11 public import buffer.packet;
12 
13 abstract class Message
14 {
15 public:
16 
17     alias byte    int8;
18     alias ubyte   uint8;
19     alias short   int16;
20     alias ushort  uint16;
21     alias int     int32;
22     alias uint    uint32;
23     alias long    int64;
24     alias ulong   uint64;
25     alias float   float32;
26     alias double  float64;
27     //bool
28     //char
29     //string
30 
31     @property ushort messageId()
32     {
33         return _messageId;
34     }
35 
36     @property TypeInfo_Class messageName()
37     {
38         return _messages[_messageId];
39     }
40 
41     static void settings(ushort magic, CryptType crypt = CryptType.NONE, string key = string.init)
42     {
43         assert(crypt == CryptType.NONE || (crypt != CryptType.NONE && key != string.init),
44                 "Must specify key when specifying the type of CryptType.");
45 
46         _magic = magic;
47         _crypt = crypt;
48         _key   = key;
49 
50         if (_crypt == CryptType.RSA)
51         {
52             _rsaKey = RSA.decodeKey(Message._key);
53 
54             assert(!_rsaKey.isNull, "Rsakey is incorrect.");
55         }
56     }
57 
58     static ubyte[] serialize_without_msginfo(Params...)(string method, Params params)
59     {
60         Variant[] t_params;
61 
62         foreach(p; params)
63         {
64             t_params ~= Variant(p);
65         }
66 
67         return Packet.build(_magic, _crypt, _key, _rsaKey, 0x00, method, t_params);
68     }
69 
70     static void getMessageInfo(ubyte[] buffer, out ushort messageId, out TypeInfo_Class messageName, out string method)
71     {
72         Packet.parseInfo(buffer, messageId, method);
73 
74         if (messageId in _messages)
75         {
76             messageName = _messages[messageId];
77         }
78     }
79 
80     static Variant[] deserialize(ubyte[] buffer, out ushort messageId, out TypeInfo_Class messageName, out string method)
81     {
82         Variant[] ret = Packet.parse(buffer, _magic, _crypt, _key, _rsaKey, messageId, method);
83 
84         if (messageId in _messages)
85         {
86             messageName = _messages[messageId];
87         }
88 
89         return ret;
90     }
91 
92     static T deserialize(T)(ubyte[] buffer) if (BaseTypeTuple!T.length > 0 && is(BaseTypeTuple!T[0] == Message))
93     {
94         string method;
95 
96         return deserialize!T(buffer, method);
97     }
98 
99     static T deserialize(T)(ubyte[] buffer, out string method) if (BaseTypeTuple!T.length > 0 && is(BaseTypeTuple!T[0] == Message))
100     {
101         ushort messageId;
102         TypeInfo_Class messageName;
103         Variant[] params = deserialize(buffer, messageId, messageName, method);
104 
105         if (messageName is null || params == null)
106             return null;
107 
108         T message = new T();
109         if (message.messageId != messageId)
110         {
111             assert(0, "The type T(" ~ T.classinfo.name ~ ") of the incoming template is incorrect. It should be " ~ messageName.name);
112         }
113 
114         foreach (i, type; FieldTypeTuple!(T))
115         {
116             mixin(`
117                 message.` ~ FieldNameTuple!T[i] ~ ` = params[` ~ i.to!string ~ `].get!` ~ type.stringof ~ `;
118             `);
119         }
120 
121         return message;
122     }
123 
124 protected:
125 
126     ubyte[] serialize(T)(T message, string method = string.init) if (BaseTypeTuple!T.length > 0 && is(BaseTypeTuple!T[0] == Message))
127     {
128         assert(message !is null, "The object to serialize cannot be null.");
129 
130         Variant[] params;
131 
132         foreach (i, type; FieldTypeTuple!T)
133         {
134             mixin(`
135                 params ~= Variant(message.` ~ FieldNameTuple!T[i] ~ `);
136             `);
137         }
138 
139         return Packet.build(_magic, _crypt, _key, _rsaKey, message.messageId, method, params);
140     }
141 
142     ushort _messageId;
143     __gshared static TypeInfo_Class[ushort] _messages;
144 
145 private:
146 
147     __gshared static ushort              _magic;
148     __gshared static CryptType           _crypt;
149     __gshared static string              _key;
150     __gshared static Nullable!RSAKeyInfo _rsaKey;
151 }