1 /** 2 * Реализация Rpc протокола JsonRpc 2.0 3 * 4 * Copyright: (c) 2015-2017, Milofon Project. 5 * License: Subject to the terms of the BSD license, as written in the included LICENSE.txt file. 6 * Author: <m.galanin@milofon.org> Maksim Galanin 7 * Date: 2018-01-28 8 */ 9 10 module dango.service.protocol.jsonrpc; 11 12 private 13 { 14 import std..string : strip; 15 16 import vibe.core.log; 17 18 import dango.service.protocol.core; 19 import dango.service.serializer.core; 20 import dango.service.transport.core; 21 } 22 23 24 25 class JsonRpcServerProtocol : RpcServerProtocol 26 { 27 private 28 { 29 Dispatcher _dispatcher; 30 Serializer _serializer; 31 } 32 33 34 void initialize(Dispatcher dispatcher, Serializer serializer, Properties config) 35 { 36 _dispatcher = dispatcher; 37 _serializer = serializer; 38 } 39 40 41 ubyte[] handle(ubyte[] data) 42 { 43 UniNode uniReq; 44 try 45 uniReq = _serializer.deserialize(data); 46 catch (Exception e) 47 { 48 logInfo("Error deserialize: (%s)", e.msg); 49 return createErrorBody(createErrorByCode( 50 ErrorCode.PARSE_ERROR, e.msg)); 51 } 52 53 string method; 54 UniNode* id; 55 UniNode params; 56 57 if (uniReq.type != UniNode.Type.object) 58 return createErrorBody(createEmptyErrorByCode( 59 ErrorCode.PARSE_ERROR)); 60 61 UniNode[string] uniReqMap = uniReq.via.map; 62 try 63 { 64 auto vMethod = "method" in uniReqMap; 65 if (!vMethod || !(vMethod.type == UniNode.Type.text 66 || vMethod.type == UniNode.Type.raw)) 67 { 68 logInfo("Not found method"); 69 return createErrorBody(createErrorByCode!string( 70 ErrorCode.INVALID_REQUEST, 71 "Parameter method is invalid")); 72 } 73 74 method = (*vMethod).get!string.strip; 75 id = "id" in uniReqMap; 76 params = UniNode.emptyObject(); 77 if (auto pv = "params" in uniReqMap) 78 params = *pv; 79 } 80 catch (Exception e) 81 { 82 logInfo("Error extract meta info: (%s)", e.msg); 83 return createErrorBody(createErrorByCode( 84 ErrorCode.SERVER_ERROR, e.msg)); 85 } 86 87 if (_dispatcher.existst(method)) 88 { 89 try 90 { 91 UniNode uniRes = _dispatcher.handler(method, params); 92 return createResultBody(id, uniRes); 93 } 94 catch (RpcException e) 95 return createErrorBody(e.error); 96 catch (Exception e) 97 { 98 logInfo("Error execute handler: (%s)", e.msg); 99 return createErrorBody(createErrorByCode( 100 ErrorCode.SERVER_ERROR, e.msg)); 101 } 102 } 103 else 104 return createErrorBody(createEmptyErrorByCode( 105 ErrorCode.METHOD_NOT_FOUND)); 106 } 107 108 private: 109 110 ubyte[] createErrorBody(T)(RpcError!T error) 111 { 112 RpcError!UniNode uniError; 113 uniError.code = error.code; 114 uniError.message = error.message; 115 if (!error.data.isNull) 116 uniError.data = marshalObject!T(error.data); 117 return createErrorBody(uniError); 118 } 119 120 121 ubyte[] createErrorBody(RpcError!UniNode error) 122 { 123 UniNode[string] response; 124 response["jsonrpc"] = UniNode("2.0"); 125 response["id"] = UniNode(); 126 UniNode[string] err; 127 err["code"] = UniNode(error.code); 128 err["message"] = UniNode(error.message); 129 if (!error.data.isNull) 130 err["data"] = error.data.get; 131 response["error"] = UniNode(err); 132 return _serializer.serialize(UniNode(response)); 133 } 134 135 136 ubyte[] createResultBody(UniNode* id, UniNode result) 137 { 138 if (id is null) 139 return []; 140 141 UniNode[string] response; 142 response["jsonrpc"] = UniNode("2.0"); 143 response["id"] = *id; 144 response["result"] = result; 145 return _serializer.serialize(UniNode(response)); 146 } 147 } 148 149 150 151 class JsonRpcClientProtocol : RpcClientProtocol 152 { 153 private 154 { 155 Serializer _serializer; 156 ClientTransport _transport; 157 } 158 159 160 this() {} 161 162 163 this(Serializer serializer, ClientTransport transport) 164 { 165 initialize(serializer, transport); 166 } 167 168 169 void initialize(Serializer serializer, ClientTransport transport) 170 { 171 _serializer = serializer; 172 _transport = transport; 173 } 174 175 176 UniNode request(string cmd, UniNode params) 177 { 178 UniNode[string] request; 179 request["jsonrpc"] = UniNode("2.0"); 180 request["id"] = UniNode(2.0); 181 request["method"] = UniNode(cmd); 182 request["params"] = params; 183 184 ubyte[] resData; 185 try 186 { 187 auto reqData = _serializer.serialize(UniNode(request)); 188 resData = _transport.request(reqData); 189 } 190 catch (Exception e) 191 throw new RpcException(ErrorCode.SERVER_ERROR, e.msg); 192 193 if (resData.length <= 0) 194 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Empty response"); 195 196 auto response = _serializer.deserialize(resData); 197 if (response.type != UniNode.Type.object) 198 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Error response"); 199 200 auto responseMap = response.via.map; 201 if (auto error = "error" in responseMap) 202 { 203 int errorCode; 204 string errorMsg; 205 auto errorMap = (*error).via.map; 206 207 if (auto codePtr = "code" in errorMap) 208 errorCode = (*codePtr).get!int; 209 210 if (auto msgPtr = "message" in errorMap) 211 errorMsg = (*msgPtr).get!string; 212 213 if (auto dataPtr = "data" in errorMap) 214 throw new RpcException(errorCode, errorMsg, *dataPtr); 215 else 216 throw new RpcException(errorCode, errorMsg); 217 } 218 else if (auto result = "result" in responseMap) 219 return *result; 220 221 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Not found result"); 222 } 223 }