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.application;
11 
12 public
13 {
14     import proped : Properties;
15     import poodinis : DependencyContainer;
16 }
17 
18 private
19 {
20     import std.format : fmt = format;
21 
22     import dango.system.application;
23     import dango.system.container : resolveByName;
24     import dango.system.properties : getOrEnforce, getNameOrEnforce;
25     import dango.system.exception : configEnforce;
26 
27     import dango.service.transport;
28     import dango.service.serializer;
29     import dango.service.protocol;
30     import dango.service.dispatcher;
31     import dango.service.controller;
32 }
33 
34 
35 abstract class ServiceApplication : DaemonApplication
36 {
37     private ServerTransport[] _transports;
38 
39 
40     this(string name, string release)
41     {
42         super(name, release);
43     }
44 
45 
46     override final void initDependencies(shared(DependencyContainer) container, Properties config)
47     {
48         container.registerContext!TransportContext;
49         container.registerContext!SerializerContext;
50         container.registerContext!ProtocolContext;
51 
52         initServiceDependencies(container, config);
53     }
54 
55 
56     this(string name, SemVer release)
57     {
58         super(name, release);
59     }
60 
61 
62     override void initializeDaemon(Properties config)
63     {
64         initializeService(config);
65 
66         auto sConfgs = config.getOrEnforce!Properties("service",
67                 "Not found service configurations");
68 
69         foreach (Properties servConf; sConfgs.getArray())
70         {
71             if (servConf.getOrElse("enabled", false))
72             {
73                 Properties trConf = servConf.getOrEnforce!Properties("transport",
74                         "Not defined transport config");
75                 Properties serConf = servConf.getOrEnforce!Properties("serializer",
76                         "Not defined serializer config");
77                 Properties protoConf = servConf.getOrEnforce!Properties("protocol",
78                         "Not defined protocol config");
79 
80                 string serviceName = servConf.getOrEnforce!string("name",
81                         "Not defined service name");
82                 string serializerName = getNameOrEnforce(serConf,
83                         "Not defined serializer name");
84                 string protoName = getNameOrEnforce(protoConf,
85                         "Not defined protocol name");
86                 string transportName = getNameOrEnforce(trConf,
87                         "Not defined transport name");
88 
89                 Serializer serializer = container.resolveByName!Serializer(serializerName);
90                 serializer.initialize(serConf);
91                 configEnforce(serializer !is null,
92                         "Serializer '%s' not register".fmt(serializerName));
93 
94                 Dispatcher dispatcher = new Dispatcher();
95 
96                 RpcServerProtocol protocol = container.resolveByName!RpcServerProtocol(protoName);
97                 configEnforce(protocol !is null,
98                         "Protocol '%s' not register".fmt(protoName));
99                 protocol.initialize(dispatcher, serializer, protoConf);
100 
101                 ServerTransport tr = container.resolveByName!ServerTransport(transportName);
102                 configEnforce(tr !is null,
103                         "Transport '%s' not register".fmt(transportName));
104 
105                 foreach (Properties ctrConf; servConf.getArray("controller"))
106                 {
107                     string ctrName = getNameOrEnforce(ctrConf,
108                         "Not defined controller name");
109 
110                     Controller ctrl = container.resolveByName!Controller(ctrName);
111                     configEnforce(ctrl !is null, "Controller '%s' not register".fmt(ctrName));
112 
113                     ctrl.initialize(serializer, ctrConf);
114                     if (ctrl.enabled)
115                     {
116                         ctrl.register(dispatcher);
117                         logInfo("Register '%s' controller", ctrName);
118                     }
119                 }
120 
121                 tr.listen(protocol, trConf);
122                 _transports ~= tr;
123             }
124         }
125     }
126 
127 
128     override int finalizeDaemon(int exitCode)
129     {
130         foreach (ServerTransport tr; _transports)
131             tr.shutdown();
132         return finalizeService(exitCode);
133     }
134 
135 protected:
136 
137     /**
138      * Регистрация зависимостей сервиса
139      * Params:
140      * container = DI контейнер
141      * config = Общая конфигурация приложения
142      */
143     void initServiceDependencies(shared(DependencyContainer) container, Properties config);
144 
145 
146     /**
147      * Инициализация сервиса
148      * Params:
149      * config = Общая конфигурация приложения
150      */
151     void initializeService(Properties config);
152 
153 
154     /**
155      * Завершение работы сервиса
156      * Params:
157      * exitCode = Код возврата
158      */
159     int finalizeService(int exitCode);
160 }