blob: 5aba4c169006fada57944f9fabeebecb576c9222 [file] [log] [blame]
Jake Farrellb95b0ff2012-03-22 21:49:10 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19module thrift.server.simple;
20
21import std.variant : Variant;
22import thrift.base;
23import thrift.protocol.base;
24import thrift.protocol.processor;
25import thrift.server.base;
26import thrift.server.transport.base;
27import thrift.transport.base;
28import thrift.util.cancellation;
29
30/**
31 * The most basic server.
32 *
33 * It is single-threaded and after it accepts a connections, it processes
34 * requests on it until it closes, then waiting for the next connection.
35 *
36 * It is not so much of use in production than it is for writing unittests, or
37 * as an example on how to provide a custom TServer implementation.
38 */
39class TSimpleServer : TServer {
40 ///
41 this(
42 TProcessor processor,
43 TServerTransport serverTransport,
44 TTransportFactory transportFactory,
45 TProtocolFactory protocolFactory
46 ) {
47 super(processor, serverTransport, transportFactory, protocolFactory);
48 }
49
50 ///
51 this(
52 TProcessorFactory processorFactory,
53 TServerTransport serverTransport,
54 TTransportFactory transportFactory,
55 TProtocolFactory protocolFactory
56 ) {
57 super(processorFactory, serverTransport, transportFactory, protocolFactory);
58 }
59
60 ///
61 this(
62 TProcessor processor,
63 TServerTransport serverTransport,
64 TTransportFactory inputTransportFactory,
65 TTransportFactory outputTransportFactory,
66 TProtocolFactory inputProtocolFactory,
67 TProtocolFactory outputProtocolFactory
68 ) {
69 super(processor, serverTransport, inputTransportFactory,
70 outputTransportFactory, inputProtocolFactory, outputProtocolFactory);
71 }
72
73 this(
74 TProcessorFactory processorFactory,
75 TServerTransport serverTransport,
76 TTransportFactory inputTransportFactory,
77 TTransportFactory outputTransportFactory,
78 TProtocolFactory inputProtocolFactory,
79 TProtocolFactory outputProtocolFactory
80 ) {
81 super(processorFactory, serverTransport, inputTransportFactory,
82 outputTransportFactory, inputProtocolFactory, outputProtocolFactory);
83 }
84
85 override void serve(TCancellation cancellation = null) {
86 serverTransport_.listen();
87
88 if (eventHandler) eventHandler.preServe();
89
90 while (true) {
91 TTransport client;
92 TTransport inputTransport;
93 TTransport outputTransport;
94 TProtocol inputProtocol;
95 TProtocol outputProtocol;
96
97 try {
98 client = serverTransport_.accept(cancellation);
99 scope(failure) client.close();
100
101 inputTransport = inputTransportFactory_.getTransport(client);
102 scope(failure) inputTransport.close();
103
104 outputTransport = outputTransportFactory_.getTransport(client);
105 scope(failure) outputTransport.close();
106
107 inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
108 outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
109 } catch (TCancelledException tcx) {
110 break;
111 } catch (TTransportException ttx) {
112 logError("TServerTransport failed on accept: %s", ttx);
113 continue;
114 } catch (TException tx) {
115 logError("Caught TException on accept: %s", tx);
116 continue;
117 }
118
119 auto info = TConnectionInfo(inputProtocol, outputProtocol, client);
120 auto processor = processorFactory_.getProcessor(info);
121
122 Variant connectionContext;
123 if (eventHandler) {
124 connectionContext =
125 eventHandler.createContext(inputProtocol, outputProtocol);
126 }
127
128 try {
129 while (true) {
130 if (eventHandler) {
131 eventHandler.preProcess(connectionContext, client);
132 }
133
134 if (!processor.process(inputProtocol, outputProtocol,
135 connectionContext) || !inputProtocol.transport.peek()
136 ) {
137 // Something went fundamentlly wrong or there is nothing more to
138 // process, close the connection.
139 break;
140 }
141 }
142 } catch (TTransportException ttx) {
James E. King III641b1392018-03-03 12:00:05 -0500143 if (ttx.type() != TTransportException.Type.END_OF_FILE) {
144 logError("Client died unexpectedly: %s", ttx);
145 }
Jake Farrellb95b0ff2012-03-22 21:49:10 +0000146 } catch (Exception e) {
147 logError("Uncaught exception: %s", e);
148 }
149
150 if (eventHandler) {
151 eventHandler.deleteContext(connectionContext, inputProtocol,
152 outputProtocol);
153 }
154
155 try {
156 inputTransport.close();
157 } catch (TTransportException ttx) {
158 logError("Input close failed: %s", ttx);
159 }
160 try {
161 outputTransport.close();
162 } catch (TTransportException ttx) {
163 logError("Output close failed: %s", ttx);
164 }
165 try {
166 client.close();
167 } catch (TTransportException ttx) {
168 logError("Client close failed: %s", ttx);
169 }
170 }
171
172 try {
173 serverTransport_.close();
174 } catch (TServerTransportException e) {
175 logError("Server transport failed to close(): %s", e);
176 }
177 }
178}
179
180unittest {
181 import thrift.internal.test.server;
182 testServeCancel!TSimpleServer();
183}