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