1 /** 2 * Реализация упрощенного Rpc протокола 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.simple; 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 SimpleRpcServerProtocol : 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["id"] = UniNode(); 125 UniNode[string] err; 126 err["code"] = UniNode(error.code); 127 err["message"] = UniNode(error.message); 128 if (!error.data.isNull) 129 err["data"] = error.data.get; 130 response["error"] = UniNode(err); 131 return _serializer.serialize(UniNode(response)); 132 } 133 134 135 ubyte[] createResultBody(UniNode* id, UniNode result) 136 { 137 if (id is null) 138 return []; 139 140 UniNode[string] response; 141 response["id"] = *id; 142 response["result"] = result; 143 return _serializer.serialize(UniNode(response)); 144 } 145 } 146 147 148 class SimpleRpcClientProtocol : RpcClientProtocol 149 { 150 private 151 { 152 Serializer _serializer; 153 ClientTransport _transport; 154 } 155 156 157 this() {} 158 159 160 this(Serializer serializer, ClientTransport transport) 161 { 162 initialize(serializer, transport); 163 } 164 165 166 void initialize(Serializer serializer, ClientTransport transport) 167 { 168 _serializer = serializer; 169 _transport = transport; 170 } 171 172 173 UniNode request(string cmd, UniNode params) 174 { 175 UniNode[string] request; 176 request["id"] = UniNode(1); 177 request["method"] = UniNode(cmd); 178 request["params"] = params; 179 180 ubyte[] resData; 181 try 182 { 183 auto reqData = _serializer.serialize(UniNode(request)); 184 resData = _transport.request(reqData); 185 } 186 catch (Exception e) 187 throw new RpcException(ErrorCode.SERVER_ERROR, e.msg); 188 189 if (resData.length <= 0) 190 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Empty response"); 191 192 auto response = _serializer.deserialize(resData); 193 if (response.type != UniNode.Type.object) 194 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Error response"); 195 196 auto responseMap = response.via.map; 197 if (auto error = "error" in responseMap) 198 { 199 int errorCode; 200 string errorMsg; 201 auto errorMap = (*error).via.map; 202 203 if (auto codePtr = "code" in errorMap) 204 errorCode = (*codePtr).get!int; 205 206 if (auto msgPtr = "message" in errorMap) 207 errorMsg = (*msgPtr).get!string; 208 209 if (auto dataPtr = "data" in errorMap) 210 throw new RpcException(errorCode, errorMsg, *dataPtr); 211 else 212 throw new RpcException(errorCode, errorMsg); 213 } 214 else if (auto result = "result" in responseMap) 215 return *result; 216 217 throw new RpcException(ErrorCode.INTERNAL_ERROR, "Not found result"); 218 } 219 }