1 /**
2  * Общий модуль для протоколов
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.core;
11 
12 public
13 {
14     import std.typecons : Nullable;
15 
16     import proped : Properties;
17 
18     import dango.service.serializer : Serializer, UniNode;
19     import dango.service.dispatcher : Dispatcher;
20     import dango.service.transport : ClientTransport;
21 }
22 
23 
24 /**
25  * Интерфейс серверного Rpc протокола
26  */
27 interface RpcServerProtocol
28 {
29     /**
30      * Инициализация протокола
31      * Params:
32      * dispatcher = Диспетчер вызовов
33      * serializer = Сериализатор
34      * config = Конфигурация протокола
35      */
36     void initialize(Dispatcher dispatcher, Serializer serializer, Properties config);
37 
38     /**
39      * Метод-обработик входящейго запроса
40      * Params:
41      * data = Бинарные данные
42      * Return: Ответ в бинарном виде
43      */
44     ubyte[] handle(ubyte[] data);
45 }
46 
47 
48 /**
49  * Интерфейс клиентского Rpc протокола
50  */
51 interface RpcClientProtocol
52 {
53     /**
54      * Инициализация клиентского протокола
55      * Params:
56      * serializer = Сериализатор
57      * config = Конфигурация протокола
58      */
59     void initialize(Serializer serializer, ClientTransport transport);
60 
61     /**
62      * Отправляет запрос удаленной команды
63      * Params:
64      * cmd = Команда
65      * params = Параметры
66      * Return: Результат выполнения удаленной команды (result)
67      */
68     UniNode request(string cmd, UniNode params);
69 }
70 
71 
72 /**
73  * Сообщение об ошибке
74  */
75 struct RpcError(T)
76 {
77     int code;
78     string message;
79     Nullable!T data;
80 }
81 
82 
83 /**
84  * Создает новое сообщение об ошибке по коду
85  * Params:
86  * code = Код ошибки
87  */
88 RpcError!T createEmptyErrorByCode(T = ubyte)(int code)
89 {
90     RpcError!T result;
91     result.code = code;
92     switch (code)
93     {
94         case -32700:
95             result.message = "Parse error";
96             break;
97         case -32600:
98             result.message = "Invalid Request";
99             break;
100         case -32601:
101             result.message = "Method not found";
102             break;
103         case -32602:
104             result.message = "Invalid params";
105             break;
106         case -32603:
107             result.message = "Internal error";
108             break;
109         default:
110             result.message = "Server error";
111             break;
112     }
113     return result;
114 }
115 
116 
117 /**
118  * Создает новое сообщение об ошибке по коду с доп. данными
119  * Params:
120  * code = Код ошибки
121  * data = Доп. данные
122  */
123 RpcError!T createErrorByCode(T)(int code, T data)
124 {
125     auto ret = createEmptyErrorByCode!T(code);
126     ret.data = Nullable!T(data);
127     return ret;
128 }
129 
130 
131 /**
132  * Предопределенные коды ошибок
133  */
134 enum ErrorCode
135 {
136     PARSE_ERROR = -32700,
137     INVALID_REQUEST = -32600,
138     METHOD_NOT_FOUND = -32601,
139     INVALID_PARAMS = -32602,
140     INTERNAL_ERROR = -32603,
141     SERVER_ERROR = -32000
142 }
143 
144 
145 /**
146  * Ошибка Rpc
147  */
148 class RpcException : Exception
149 {
150     private RpcError!UniNode _error;
151 
152     this(int code, string message, string file = __FILE__,
153             size_t line = __LINE__, Throwable next = null)
154     {
155         _error.code = code;
156         _error.message = message;
157         super(message, file, line, next);
158     }
159 
160 
161     this(int code, string message, UniNode data, string file = __FILE__,
162             size_t line = __LINE__, Throwable next = null)
163     {
164         _error.data = data;
165         this(code, message, file, line, next);
166     }
167 
168 
169     this(RpcError!UniNode error, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
170     {
171         _error = error;
172         super(error.message, file, line, next);
173     }
174 
175 
176     RpcError!UniNode error() @property nothrow
177     {
178         return _error;
179     }
180 }