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-24
8  */
9 
10 module dango.service.controller;
11 
12 public
13 {
14     import std.meta : Alias;
15     import std.traits : isCallable, getUDAs;
16     import std.functional : toDelegate;
17 
18     import proped : Properties;
19 
20     import dango.system.traits;
21     import dango.service.dispatcher;
22     import dango.service.serializer;
23     import dango.service.protocol;
24 }
25 
26 
27 /**
28  * Аннотация контроллера
29  */
30 struct RpcController
31 {
32     string prefix;
33 }
34 
35 
36 /**
37  * Аннотация метода
38  */
39 struct RpcHandler
40 {
41     string method;
42 }
43 
44 
45 /**
46  * Интерфейс контроллера
47  */
48 interface Controller
49 {
50     /**
51      * Инициализация контроллера
52      * Params:
53      *
54      * config = Конфигурация контроллера
55      */
56     void initialize(Serializer serializer, Properties config);
57 
58 
59     /**
60      * Возвращает активность контроллера
61      */
62     bool enabled() @property;
63 
64 
65     /**
66      * Регистрация обработчиков в диспетчер
67      * Params:
68      * dispatcher = Диспетчер
69      */
70     void register(Dispatcher dispatcher);
71 }
72 
73 
74 /**
75   * Базовый класс для контроллеров
76   * Params:
77   * P = Тип потомка
78   */
79 abstract class BaseController(P) : P, Controller
80 {
81     private
82     {
83         Serializer _serializer;
84         bool _enabled;
85     }
86 
87 
88     final void initialize(Serializer serializer, Properties config)
89     {
90         _enabled = config.getOrElse!bool("enabled", false);
91         _serializer = serializer;
92         doInitialize(config);
93     }
94 
95 
96     bool enabled() @property
97     {
98         return _enabled;
99     }
100 
101 
102     void register(Dispatcher dispatcher)
103     {
104         registerControllerHandlers!(P)(cast(P)this, dispatcher);
105     }
106 
107 protected:
108 
109     void doInitialize(Properties config) {}
110 
111 
112     void enforceRpc(V)(V value, int code, string message,
113             string file = __FILE__, size_t line = __LINE__)
114     {
115         if (!!value)
116             return;
117 
118         RpcError!UniNode error;
119         error.code = code;
120         error.message = message;
121         throw new RpcException(error);
122     }
123 
124 
125     void enforceRpcData(V, T)(V value, int code, string message, T data,
126             string file = __FILE__, size_t line = __LINE__)
127     {
128         if (!!value)
129             return;
130 
131         RpcError!UniNode error;
132         error.code = code;
133         error.message = message;
134         error.data = marshalObject!T(data);
135 
136         throw new RpcException(error);
137     }
138 }
139 
140 
141 
142 void registerControllerHandlers(C)(C controller, Dispatcher dispatcher)
143 {
144     string getFullMethod(string method)
145     {
146         enum udas = getUDAs!(C, RpcController);
147         static if (udas.length > 0)
148         {
149             string prefix = udas[0].prefix;
150             if (prefix.length > 0)
151                 return prefix ~ "." ~ method;
152             else
153                 return method;
154         }
155         else
156             return method;
157     }
158 
159     foreach (string fName; __traits(allMembers, C))
160     {
161         static if(IsPublicMember!(C, fName))
162         {
163             alias member = Alias!(__traits(getMember, C, fName));
164             static if (isCallable!member)
165             {
166                 foreach (attr; __traits(getAttributes, member))
167                 {
168                     static if (is(typeof(attr) == RpcHandler))
169                     {
170                         auto HDL = dispatcher.generateHandler!(
171                                 __traits(getMember, controller, fName))(
172                                 &__traits(getMember, controller, fName));
173                         dispatcher.registerHandler(getFullMethod(attr.method), HDL);
174                     }
175                 }
176             }
177         }
178     }
179 }