blob: f7183a75199410ccff4c7e9a21d298030fa4f2d0 [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) {
143 logError("Client died: %s", ttx);
144 } catch (Exception e) {
145 logError("Uncaught exception: %s", e);
146 }
147
148 if (eventHandler) {
149 eventHandler.deleteContext(connectionContext, inputProtocol,
150 outputProtocol);
151 }
152
153 try {
154 inputTransport.close();
155 } catch (TTransportException ttx) {
156 logError("Input close failed: %s", ttx);
157 }
158 try {
159 outputTransport.close();
160 } catch (TTransportException ttx) {
161 logError("Output close failed: %s", ttx);
162 }
163 try {
164 client.close();
165 } catch (TTransportException ttx) {
166 logError("Client close failed: %s", ttx);
167 }
168 }
169
170 try {
171 serverTransport_.close();
172 } catch (TServerTransportException e) {
173 logError("Server transport failed to close(): %s", e);
174 }
175 }
176}
177
178unittest {
179 import thrift.internal.test.server;
180 testServeCancel!TSimpleServer();
181}