blob: d46d58a755f1bde324dd0698674588d6af8bac37 [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
26#pragma warning disable IDE0079 // remove unnecessary pragmas
27#pragma warning disable IDE0063 // using can be simplified, we don't
Jens Geyeraa0c8b32019-01-28 23:27:45 +010028
29namespace Thrift.Server
30{
Jens Geyeraa0c8b32019-01-28 23:27:45 +010031
32 // ReSharper disable once InconsistentNaming
33 public class TSimpleAsyncServer : TServer
34 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010035 private volatile bool stop = false;
36
37 private CancellationToken ServerCancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010038
Kyle Smith7b94dd42019-03-23 17:26:56 +010039 public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory,
40 TServerTransport serverTransport,
41 TTransportFactory inputTransportFactory,
42 TTransportFactory outputTransportFactory,
43 TProtocolFactory inputProtocolFactory,
44 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010045 ILogger logger)
Kyle Smith7b94dd42019-03-23 17:26:56 +010046 : base(itProcessorFactory,
47 serverTransport,
48 inputTransportFactory,
49 outputTransportFactory,
50 inputProtocolFactory,
51 outputProtocolFactory,
52 logger)
53 {
Kyle Smith7b94dd42019-03-23 17:26:56 +010054 }
55
56 public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory,
57 TServerTransport serverTransport,
58 TTransportFactory inputTransportFactory,
59 TTransportFactory outputTransportFactory,
60 TProtocolFactory inputProtocolFactory,
61 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010062 ILoggerFactory loggerFactory)
Kyle Smith7b94dd42019-03-23 17:26:56 +010063 : this(itProcessorFactory,
64 serverTransport,
65 inputTransportFactory,
66 outputTransportFactory,
67 inputProtocolFactory,
68 outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010069 loggerFactory.CreateLogger<TSimpleAsyncServer>())
Jens Geyeraa0c8b32019-01-28 23:27:45 +010070 {
71 }
72
Kyle Smith7b94dd42019-03-23 17:26:56 +010073 public TSimpleAsyncServer(ITAsyncProcessor processor,
74 TServerTransport serverTransport,
75 TProtocolFactory inputProtocolFactory,
76 TProtocolFactory outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010077 ILoggerFactory loggerFactory)
Kyle Smith7b94dd42019-03-23 17:26:56 +010078 : this(new TSingletonProcessorFactory(processor),
79 serverTransport,
80 null, // defaults to TTransportFactory()
81 null, // defaults to TTransportFactory()
82 inputProtocolFactory,
83 outputProtocolFactory,
Jens Geyerea1e8ff2021-11-13 23:21:02 +010084 loggerFactory.CreateLogger(nameof(TSimpleAsyncServer)))
Jens Geyeraa0c8b32019-01-28 23:27:45 +010085 {
Jens Geyeraa0c8b32019-01-28 23:27:45 +010086 }
87
88 public override async Task ServeAsync(CancellationToken cancellationToken)
89 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010090 ServerCancellationToken = cancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010091 try
92 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010093 try
Jens Geyeraa0c8b32019-01-28 23:27:45 +010094 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +010095 ServerTransport.Listen();
96 }
97 catch (TTransportException ttx)
98 {
99 LogError("Error, could not listen on ServerTransport: " + ttx);
100 return;
101 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100102
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100103 //Fire the preServe server event when server is up but before any client connections
104 if (ServerEventHandler != null)
105 await ServerEventHandler.PreServeAsync(cancellationToken);
106
107 while (!(stop || ServerCancellationToken.IsCancellationRequested))
108 {
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100109 try
110 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100111 using (TTransport client = await ServerTransport.AcceptAsync(cancellationToken))
112 {
113 await ExecuteAsync(client);
114 }
115 }
116 catch (TaskCanceledException)
117 {
118 stop = true;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100119 }
120 catch (TTransportException ttx)
121 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100122 if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100123 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100124 LogError(ttx.ToString());
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100125 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100126
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100127 }
128 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100129
130 if (stop)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100131 {
132 try
133 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100134 ServerTransport.Close();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100135 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100136 catch (TTransportException ttx)
137 {
138 LogError("TServerTransport failed on close: " + ttx.Message);
139 }
140 stop = false;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100141 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100142
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100143 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100144 finally
145 {
146 ServerCancellationToken = default;
147 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100148 }
149
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100150 /// <summary>
151 /// Loops on processing a client forever
152 /// client will be a TTransport instance
153 /// </summary>
154 /// <param name="client"></param>
155 private async Task ExecuteAsync(TTransport client)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100156 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100157 var cancellationToken = ServerCancellationToken;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100158
159 var processor = ProcessorFactory.GetAsyncProcessor(client, this);
160
161 TTransport inputTransport = null;
162 TTransport outputTransport = null;
163 TProtocol inputProtocol = null;
164 TProtocol outputProtocol = null;
165 object connectionContext = null;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100166 try
167 {
168 try
169 {
170 inputTransport = InputTransportFactory.GetTransport(client);
171 outputTransport = OutputTransportFactory.GetTransport(client);
172 inputProtocol = InputProtocolFactory.GetProtocol(inputTransport);
173 outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport);
174
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100175 //Recover event handler (if any) and fire createContext server event when a client connects
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100176 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100177 connectionContext = await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100178
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100179 //Process client requests until client disconnects
180 while (!(stop || cancellationToken.IsCancellationRequested))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100181 {
182 if (!await inputTransport.PeekAsync(cancellationToken))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100183 break;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100184
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100185 //Fire processContext server event
186 //N.B. This is the pattern implemented in C++ and the event fires provisionally.
187 //That is to say it may be many minutes between the event firing and the client request
188 //actually arriving or the client may hang up without ever makeing a request.
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100189 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100190 await ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100191
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100192 //Process client request (blocks until transport is readable)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100193 if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken))
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100194 break;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100195 }
196 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100197 catch (TTransportException)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100198 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100199 //Usually a client disconnect, expected
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100200 }
201 catch (Exception x)
202 {
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100203 //Unexpected
204 LogError("Error: " + x);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100205 }
206
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100207 //Fire deleteContext server event after client disconnects
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100208 if (ServerEventHandler != null)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100209 await ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100210
211 }
212 finally
213 {
214 //Close transports
215 inputTransport?.Close();
216 outputTransport?.Close();
217
218 // disposable stuff should be disposed
219 inputProtocol?.Dispose();
220 outputProtocol?.Dispose();
221 inputTransport?.Dispose();
222 outputTransport?.Dispose();
223 }
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100224 }
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100225
Jens Geyerea1e8ff2021-11-13 23:21:02 +0100226 public override void Stop()
227 {
228 stop = true;
229 ServerTransport?.Close();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100230 }
231 }
232}