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 }