blob: f1f6277d5af548a4560d3ff1e37dde27a8f68f66 [file] [log] [blame]
Jens Geyeraa0c8b32019-01-28 23:27:45 +01001// Licensed to the Apache Software Foundation(ASF) under one
2// or more contributor license agreements.See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18using System;
19using System.Threading;
Jens Geyerea1e8ff2021-11-13 23:21:02 +010020using Thrift.Protocol;
21using Thrift.Transport;
22using Thrift.Processor;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010023using System.Threading.Tasks;
24using Microsoft.Extensions.Logging;
Jens Geyerea1e8ff2021-11-13 23:21:02 +010025
Jens Geyeraa0c8b32019-01-28 23:27:45 +010026
27namespace Thrift.Server
28{
Jens Geyeraa0c8b32019-01-28 23:27:45 +010029
30 // ReSharper disable once InconsistentNaming
31 public class TSimpleAsyncServer : TServer
32 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010033 private volatile bool stop = false;
34
35 private CancellationToken ServerCancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010036
Kyle Smith7b94dd42019-03-23 17:26:56 +010037 public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory,
38 TServerTransport serverTransport,
39 TTransportFactory inputTransportFactory,
40 TTransportFactory outputTransportFactory,
41 TProtocolFactory inputProtocolFactory,
42 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010043 ILogger logger)
Kyle Smith7b94dd42019-03-23 17:26:56 +010044 : base(itProcessorFactory,
45 serverTransport,
46 inputTransportFactory,
47 outputTransportFactory,
48 inputProtocolFactory,
49 outputProtocolFactory,
50 logger)
51 {
Kyle Smith7b94dd42019-03-23 17:26:56 +010052 }
53
54 public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory,
55 TServerTransport serverTransport,
56 TTransportFactory inputTransportFactory,
57 TTransportFactory outputTransportFactory,
58 TProtocolFactory inputProtocolFactory,
59 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010060 ILoggerFactory loggerFactory)
Kyle Smith7b94dd42019-03-23 17:26:56 +010061 : this(itProcessorFactory,
62 serverTransport,
63 inputTransportFactory,
64 outputTransportFactory,
65 inputProtocolFactory,
66 outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010067 loggerFactory.CreateLogger<TSimpleAsyncServer>())
Jens Geyeraa0c8b32019-01-28 23:27:45 +010068 {
69 }
70
Kyle Smith7b94dd42019-03-23 17:26:56 +010071 public TSimpleAsyncServer(ITAsyncProcessor processor,
72 TServerTransport serverTransport,
73 TProtocolFactory inputProtocolFactory,
74 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010075 ILoggerFactory loggerFactory)
Kyle Smith7b94dd42019-03-23 17:26:56 +010076 : this(new TSingletonProcessorFactory(processor),
77 serverTransport,
78 null, // defaults to TTransportFactory()
79 null, // defaults to TTransportFactory()
80 inputProtocolFactory,
81 outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010082 loggerFactory.CreateLogger(nameof(TSimpleAsyncServer)))
Jens Geyeraa0c8b32019-01-28 23:27:45 +010083 {
Jens Geyeraa0c8b32019-01-28 23:27:45 +010084 }
85
86 public override async Task ServeAsync(CancellationToken cancellationToken)
87 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010088 ServerCancellationToken = cancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010089 try
90 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010091 try
Jens Geyeraa0c8b32019-01-28 23:27:45 +010092 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010093 ServerTransport.Listen();
94 }
95 catch (TTransportException ttx)
96 {
97 LogError("Error, could not listen on ServerTransport: " + ttx);
98 return;
99 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100100
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100101 //Fire the preServe server event when server is up but before any client connections
102 if (ServerEventHandler != null)
103 await ServerEventHandler.PreServeAsync(cancellationToken);
104
105 while (!(stop || ServerCancellationToken.IsCancellationRequested))
106 {
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100107 try
108 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100109 using (TTransport client = await ServerTransport.AcceptAsync(cancellationToken))
110 {
111 await ExecuteAsync(client);
112 }
113 }
114 catch (TaskCanceledException)
115 {
116 stop = true;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100117 }
118 catch (TTransportException ttx)
119 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100120 if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100121 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100122 LogError(ttx.ToString());
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100123 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100124
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100125 }
126 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100127
128 if (stop)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100129 {
130 try
131 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100132 ServerTransport.Close();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100133 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100134 catch (TTransportException ttx)
135 {
136 LogError("TServerTransport failed on close: " + ttx.Message);
137 }
138 stop = false;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100139 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100140
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100141 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100142 finally
143 {
144 ServerCancellationToken = default;
145 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100146 }
147
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100148 /// <summary>
149 /// Loops on processing a client forever
150 /// client will be a TTransport instance
151 /// </summary>
152 /// <param name="client"></param>
153 private async Task ExecuteAsync(TTransport client)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100154 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100155 var cancellationToken = ServerCancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100156
157 var processor = ProcessorFactory.GetAsyncProcessor(client, this);
158
159 TTransport inputTransport = null;
160 TTransport outputTransport = null;
161 TProtocol inputProtocol = null;
162 TProtocol outputProtocol = null;
163 object connectionContext = null;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100164 try
165 {
166 try
167 {
168 inputTransport = InputTransportFactory.GetTransport(client);
169 outputTransport = OutputTransportFactory.GetTransport(client);
170 inputProtocol = InputProtocolFactory.GetProtocol(inputTransport);
171 outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport);
172
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100173 //Recover event handler (if any) and fire createContext server event when a client connects
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100174 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100175 connectionContext = await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100176
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100177 //Process client requests until client disconnects
178 while (!(stop || cancellationToken.IsCancellationRequested))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100179 {
180 if (!await inputTransport.PeekAsync(cancellationToken))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100181 break;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100182
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100183 //Fire processContext server event
184 //N.B. This is the pattern implemented in C++ and the event fires provisionally.
185 //That is to say it may be many minutes between the event firing and the client request
186 //actually arriving or the client may hang up without ever makeing a request.
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100187 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100188 await ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100189
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100190 //Process client request (blocks until transport is readable)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100191 if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100192 break;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100193 }
194 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100195 catch (TTransportException)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100196 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100197 //Usually a client disconnect, expected
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100198 }
199 catch (Exception x)
200 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100201 //Unexpected
202 LogError("Error: " + x);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100203 }
204
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100205 //Fire deleteContext server event after client disconnects
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100206 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100207 await ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100208
209 }
210 finally
211 {
212 //Close transports
213 inputTransport?.Close();
214 outputTransport?.Close();
215
216 // disposable stuff should be disposed
217 inputProtocol?.Dispose();
218 outputProtocol?.Dispose();
219 inputTransport?.Dispose();
220 outputTransport?.Dispose();
221 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100222 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100223
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100224 public override void Stop()
225 {
226 stop = true;
227 ServerTransport?.Close();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100228 }
229 }
230}