1 /**
2  * Low level wire protocol for RPC.
3  */
4 module vibe.rpcchannel.protocol;
5 
6 import std.exception : enforceEx;
7 import vibe.data.json;
8 import vibe.core.stream;
9 import vibe.rpcchannel.base;
10 
11 /*
12  * Problem : vibe.d does not really support JSON deserialization from a range
13  * Solution : Always read & buffer a line and use line terminators after every
14  * JSON entity.
15  * 
16  * Request protocol:
17  * 
18  * RequestType   
19  *               |----=call-->CallMessage-->parameters*any
20  * --------------|
21  *               |----=disconnect
22  * 
23  * Reponse protocol:
24  * 
25  * ResponseType  |---=error-->ErrorMessage
26  * --------------|
27  *               |---=result->ResultMessage-->hasResult?any:none
28  *               |
29  *               |---=event-->EventMessage-->parameters*any
30  *               |
31  *               |---=disconnect
32  */
33 
34 /**
35  * Type of message sent to server.
36  */
37 enum RequestType
38 {
39     call, /// call a function
40     disconnect /// disconnect
41 }
42 
43 /**
44  * Message sent to server to call a function.
45  */
46 struct CallMessage
47 {
48     uint id; /// request id
49     string target; /// function target name
50     string mangle; /// function mangle for overloading
51     uint parameters; /// number of parameters following this message
52 }
53 
54 /**
55  * Type of message sent to client.
56  */
57 enum ResponseType
58 {
59     disconnect, /// Disconnect the session
60     error, /// An error occured
61     result, /// A function result is returned
62     event /// A event occured
63 }
64 
65 /**
66  * If an error is being send, type of error.
67  */
68 enum ErrorType
69 {
70     notImplemented, /// calling an unimplemented endpoint
71     parameterMismatch, /// invalid number of parameters or parser error
72     internalError /// called method threw an Exception
73 }
74 
75 /**
76  * Message sent to client as response to a call if an error occured.
77  */
78 struct ErrorMessage
79 {
80     uint id; /// The request id repeated
81     ErrorType type; /// Type of error
82 
83     @optional string message; /// In debug mode only
84     @optional string file; /// In debug mode only
85     @optional uint line; /// In debug mode only
86 }
87 
88 /**
89  * Message sent to client as response to a call if call was sucessfull.
90  */
91 struct ResultMessage
92 {
93     uint id; /// The request id repeated
94     bool hasResult; /// Whether there's a result value after this message
95 }
96 
97 /**
98  * Message sent to client if an event occurs.
99  */
100 struct EventMessage
101 {
102     string target; /// Name of the event
103     uint parameters; /// Number of parameters following this message
104 }
105 
106 /**
107  * Read one line from stream and deserialize the json value.
108  */
109 T deserializeJsonLine(T)(InputStream stream)
110 {
111     import vibe.stream.operations;
112 
113     // TODO: Avoid GC
114     auto line = cast(string) stream.readLine(size_t.max, "\n");
115 
116     enforceEx!RPCException(line.length != 0);
117 
118     static if (!is(T == void))
119         return deserializeJson!T(line);
120 }
121 
122 /**
123  * Serialize the json value and write as one line to stream.
124  */
125 void serializeToJsonLine(T)(OutputStream stream, T value)
126 {
127     auto str = serializeToJsonString(value);
128     stream.write(str);
129     stream.write("\n");
130 }
131 
132 /**
133  * Skip num objects on stream.
134  */
135 void skipParameters(Stream stream, size_t num)
136 {
137     // skip remaining params
138     for (size_t i = 0; i < num; i++)
139     {
140         stream.deserializeJsonLine!void();
141     }
142 }