1 /* 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 */ 19 module thrift.server.simple; 20 21 import std.variant : Variant; 22 import thrift.base; 23 import thrift.protocol.base; 24 import thrift.protocol.processor; 25 import thrift.server.base; 26 import thrift.server.transport.base; 27 import thrift.transport.base; 28 import 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 */ 39 class 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 if (ttx.type() != TTransportException.Type.END_OF_FILE) { 144 logError("Client died unexpectedly: %s", ttx); 145 } 146 } 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 180 unittest { 181 import thrift.internal.test.server; 182 testServeCancel!TSimpleServer(); 183 }