v / vlib / net / jsonrpc / server.v
235 lines · 200 sloc · 5.39 KB · f53920bcec4f43594143c41772b42b6465f1c6a9
Raw
1module jsonrpc
2
3import json
4import strings
5import io
6
7pub struct ServerConfig {
8pub mut:
9 stream io.ReaderWriter
10 handler Handler @[required]
11 interceptors Interceptors
12}
13
14// Server represents a JSONRPC server that sends/receives data
15// from a stream (an io.ReaderWriter) and uses Content-Length framing. :contentReference[oaicite:6]{index=6}
16@[heap]
17pub struct Server {
18mut:
19 stream io.ReaderWriter
20 handler Handler @[required]
21 interceptors Interceptors
22}
23
24// new_server creates new `jsonrpc.Server` with `stream` to read/write,
25// the `jsonrpc.Handler` to handle Requests/Responses and `interceptors`
26pub fn new_server(cfg ServerConfig) Server {
27 return Server{
28 stream: cfg.stream
29 handler: cfg.handler
30 interceptors: cfg.interceptors
31 }
32}
33
34// respond reads bytes from stream, pass them to the `interceptors.encoded_request`,
35// tries to decode into `jsonrpc.Request` and pass to `interceptors.request`
36// and on fail it responds with `jsonrpc.parse_error` after that it calls handlers
37// (batch requests are handled automatically as well as writing batch response)
38// and passes recieved `jsonrpc.Response` into `interceptors.response` and the
39// last step is to encode `jsonrpc.Response`, pass it into `interceptors.encoded_response`
40// and write to stream
41pub fn (mut s Server) respond() ! {
42 mut rw := s.writer()
43 mut rx := []u8{len: 4096}
44 bytes_read := s.stream.read(mut rx) or {
45 if err is io.Eof {
46 return
47 }
48 return err
49 }
50
51 if bytes_read == 0 {
52 return
53 }
54
55 intercept_encoded_request(s.interceptors.encoded_request, rx) or {
56 rw.write_error(response_error(error: err))
57 return err
58 }
59
60 req_str := rx.bytestr()
61
62 mut req_batch := []Request{}
63 match req_str[0].ascii_str() {
64 '[' {
65 req_batch = decode_batch_request(req_str) or {
66 rw.write_error(response_error(error: parse_error))
67 return err
68 }
69 rw.start_batch()
70 }
71 '{' {
72 req := decode_request(req_str) or {
73 rw.write_error(response_error(error: parse_error))
74 return err
75 }
76 req_batch.prepend(req)
77 }
78 else {
79 rw.write_error(response_error(error: parse_error))
80 return parse_error
81 }
82 }
83
84 for rq in req_batch {
85 rw.req_id = rq.id
86
87 intercept_request(s.interceptors.request, &rq) or {
88 rw.write_error(response_error(error: err))
89 return err
90 }
91
92 s.handler(&rq, mut rw)
93 }
94
95 if req_batch.len > 1 {
96 rw.close_batch()
97 }
98}
99
100fn (s &Server) writer() &ResponseWriter {
101 return &ResponseWriter{
102 writer: s.stream
103 sb: strings.new_builder(4096)
104 server: s
105 }
106}
107
108// start `Server` loop to operate on `stream` passed into constructor
109// it calls `Server.respond()` method in loop
110pub fn (mut s Server) start() {
111 for {
112 s.respond() or {
113 if err is io.Eof {
114 return
115 }
116 }
117 }
118}
119
120// Handler is the function called when `jsonrpc.Request` is
121// decoded and `jsonrpc.Response` is required which is written
122// into `jsonrpc.ResponseWriter`. Before returning from Handler
123// either `wr.write()` or `wr.write_error()` must be called
124// or the stream will stuck awaiting writing `jsonrpc.Response`
125pub type Handler = fn (req &Request, mut wr ResponseWriter)
126
127// Router is simple map of method names and their `Handler`s
128pub struct Router {
129mut:
130 methods map[string]Handler
131}
132
133// handle_jsonrpc must be passed into `Server` handler field to operate
134// it simply tries to invoke registered methods and if none valid found
135// writes `jsonrpc.method_not_found` error into `jsonrpc.ResponseWriter`
136pub fn (r Router) handle_jsonrpc(req &Request, mut wr ResponseWriter) {
137 if h := r.methods[req.method] {
138 h(req, mut wr)
139 return
140 }
141
142 wr.write_error(method_not_found)
143}
144
145// register `handler` to operate when `method` found in incoming `jsonrpc.Request`
146pub fn (mut r Router) register(method string, handler Handler) bool {
147 if method in r.methods {
148 return false
149 }
150
151 r.methods[method] = handler
152 return true
153}
154
155pub struct ResponseWriter {
156mut:
157 sb strings.Builder
158 is_batch bool
159 server &Server
160pub mut:
161 req_id string
162 writer io.ReaderWriter
163}
164
165fn (mut rw ResponseWriter) start_batch() {
166 rw.is_batch = true
167 rw.sb.write_string('[')
168}
169
170fn (mut rw ResponseWriter) close_batch() {
171 rw.is_batch = false
172 rw.sb.go_back(2)
173 rw.sb.write_string(']')
174 rw.close()
175}
176
177fn (mut rw ResponseWriter) close() {
178 intercept_encoded_response(rw.server.interceptors.encoded_response, rw.sb)
179 rw.writer.write(rw.sb) or {}
180 rw.sb.go_back_to(0)
181}
182
183// write payload into `jsonrpc.Response.result`.
184// call when need to send data in response
185pub fn (mut rw ResponseWriter) write[T](payload T) {
186 final_resp := Response{
187 id: rw.req_id
188 result: json.encode(payload)
189 }
190
191 intercept_response(rw.server.interceptors.response, final_resp)
192
193 if rw.req_id.len == 0 {
194 return
195 }
196
197 rw.sb.write_string(final_resp.encode())
198
199 if rw.is_batch == true {
200 rw.sb.write_string(', ')
201 return
202 }
203 rw.close()
204}
205
206// write_empty writes `jsonrpc.null` as response
207pub fn (mut rw ResponseWriter) write_empty() {
208 rw.write[Null](null)
209}
210
211// write_error into the `jsonrpc.Response` of current request
212pub fn (mut rw ResponseWriter) write_error(err IError) {
213 mut res_err := err
214 if err !is ResponseError {
215 if err.code() !in error_codes {
216 res_err = response_error(error: unknown_error)
217 } else {
218 res_err = response_error(error: err)
219 }
220 }
221
222 final_resp := Response{
223 id: rw.req_id
224 error: res_err as ResponseError
225 }
226
227 intercept_response(rw.server.interceptors.response, final_resp)
228
229 rw.sb.write_string(final_resp.encode())
230 if rw.is_batch {
231 rw.sb.write_string(', ')
232 return
233 }
234 rw.close()
235}
236