1 // Written in the D programming language.
2 
3 /**
4  * MessagePack RPC common symbols
5  */
6 module msgpackrpc.common;
7 
8 import msgpack;
9 
10 
11 /**
12  * See: http://wiki.msgpack.org/display/MSGPACK/RPC+specification#RPCspecification-MessagePackRPCProtocolspecification
13  */
14 enum MessageType
15 {
16     request = 0,
17     response = 1,
18     notify = 2
19 }
20 
21 struct Endpoint
22 {
23     ushort port;
24     string address;
25 
26     this(ushort port, string address)
27     {
28         this.port = port;
29         this.address = address;
30     }
31 
32     this(string connectionString)
33     {
34         import std.array;
35         auto splitted = connectionString.split(":");
36         this.address = splitted[0];
37         import std.conv;
38         this.port = splitted[1].to!ushort;
39     }
40 
41 }
42 
43 unittest
44 {
45     auto e = Endpoint("127.0.0.1:18800");
46     assert(e.port = 18800);
47     assert(e.address = "127.0.0.1");
48 }
49 /**
50  * Base exception for RPC error hierarchy
51  */
52 class RPCException : Exception
53 {
54     enum Code = ".RPCError";
55 
56     static void rethrow(ref Value error)
57     {
58         if (error.type == Value.type.array) {
59             auto errCode = error.via.array[0].as!string;
60             auto errMsg = error.via.array[1].as!string;
61 
62             switch (errCode) {
63             case RPCException.Code:
64                 throw new RPCException(errMsg);
65             case TimeoutException.Code:
66                 throw new TimeoutException(errMsg);
67             case TransportException.Code:
68                 throw new TransportException(errMsg);
69             case CallException.Code:
70                 throw new CallException(errMsg);
71             case NoMethodException.Code:
72                 throw new NoMethodException(errMsg);
73             case ArgumentException.Code:
74                 throw new ArgumentException(errMsg);
75             default:
76                 throw new Exception("Unknown code: code = " ~ errCode);
77             }
78         } else {
79             throw new RPCException(error.as!string);
80         }
81     }
82 
83     mixin ExceptionConstructor;
84 }
85 
86 ///
87 class TimeoutException : RPCException
88 {
89     enum Code = ".TimeoutError";
90     mixin ExceptionConstructor;
91 }
92 
93 ///
94 class TransportException : RPCException
95 {
96     enum Code = ".TransportError";
97     mixin ExceptionConstructor;
98 }
99 
100 ///
101 class CallException : RPCException
102 {
103     enum Code = ".NoMethodError";
104     mixin ExceptionConstructor;
105 }
106 
107 ///
108 class NoMethodException : CallException
109 {
110     enum Code = ".CallError.NoMethodError";
111     mixin ExceptionConstructor;
112 }
113 
114 ///
115 class ArgumentException : CallException
116 {
117     enum Code = ".CallError.ArgumentError";
118     mixin ExceptionConstructor;
119 }
120 
121 private:
122 
123 mixin template ExceptionConstructor()
124 {
125     @safe pure nothrow this(string msg)
126     {
127         super(msg);
128     }
129 
130     void toMsgpack(Packer)(ref Packer packer, bool withFieldName = false) const
131     {
132         packer.beginArray(2);
133         packer.pack(Code);
134         packer.pack(msg);
135     }
136 }
137 
138 unittest
139 {
140     import std.typetuple;
141 
142     foreach (E; TypeTuple!(RPCException, TimeoutException, TransportException, CallException, NoMethodException, ArgumentException)) {
143         auto e = new E("hoge");
144         string[] codeAndMsg;
145         unpack(pack(e), codeAndMsg);
146         assert(codeAndMsg[0] == E.Code);
147     }
148 }