blob: 004ea77d83c1ed272b2c231ba74c0dc9d9ae8c9d [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
Jens Geyere26b4a82024-11-12 23:53:04 +010018using Microsoft.AspNetCore.Builder;
19using Microsoft.AspNetCore.Hosting;
20using Microsoft.Extensions.Configuration;
21using Microsoft.Extensions.DependencyInjection;
Jens Geyer2f214c22025-11-13 23:24:45 +010022using Microsoft.Extensions.Hosting;
Jens Geyere26b4a82024-11-12 23:53:04 +010023using Microsoft.Extensions.Logging;
24using shared;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010025using System;
26using System.Collections.Generic;
27using System.IO;
28using System.Linq;
29using System.Net.Security;
30using System.Security.Cryptography.X509Certificates;
31using System.Threading;
32using System.Threading.Tasks;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010033using Thrift;
Jens Geyere26b4a82024-11-12 23:53:04 +010034using Thrift.Processor;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010035using Thrift.Protocol;
36using Thrift.Server;
37using Thrift.Transport;
38using Thrift.Transport.Server;
39using tutorial;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010040
Jens Geyer0d128322021-02-25 09:42:52 +010041#pragma warning disable IDE0057 // substr
42
Jens Geyeraa0c8b32019-01-28 23:27:45 +010043namespace Server
44{
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010045 public static class LoggingHelper
46 {
47 public static ILoggerFactory LogFactory { get; } = LoggerFactory.Create(builder => {
48 ConfigureLogging(builder);
49 });
50
51 public static void ConfigureLogging(ILoggingBuilder logging)
52 {
53 logging.SetMinimumLevel(LogLevel.Trace);
54 logging.AddConsole();
55 logging.AddDebug();
56 }
57
58 public static ILogger<T> CreateLogger<T>() => LogFactory.CreateLogger<T>();
59 }
60
Jens Geyeraa0c8b32019-01-28 23:27:45 +010061 public class Program
62 {
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010063 private static readonly ILogger Logger = LoggingHelper.CreateLogger<Program>();
Jens Geyere26b4a82024-11-12 23:53:04 +010064 private static readonly TConfiguration Configuration = new();
Jens Geyeraa0c8b32019-01-28 23:27:45 +010065
Jens Geyere26b4a82024-11-12 23:53:04 +010066 public static async Task Main(string[] args)
Jens Geyeraa0c8b32019-01-28 23:27:45 +010067 {
Jens Geyere26b4a82024-11-12 23:53:04 +010068 args ??= [];
Jens Geyeraa0c8b32019-01-28 23:27:45 +010069
Jens Geyere26b4a82024-11-12 23:53:04 +010070 // -help is rather unusual but we leave it for compatibility
71 if (args.Any(x => x.Equals("-help") || x.Equals("--help") || x.Equals("-h") || x.Equals("-?")))
Jens Geyeraa0c8b32019-01-28 23:27:45 +010072 {
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010073 DisplayHelp();
74 return;
Jens Geyeraa0c8b32019-01-28 23:27:45 +010075 }
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010076
Jens Geyere26b4a82024-11-12 23:53:04 +010077 using var source = new CancellationTokenSource();
78 await RunAsync(args, source.Token);
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010079
Jens Geyere26b4a82024-11-12 23:53:04 +010080 Logger.LogInformation("Press any key to stop...");
81 Console.ReadLine();
82 source.Cancel();
Jens Geyer4c7b9fd2021-12-04 22:48:37 +010083
84 Logger.LogInformation("Server stopped");
Jens Geyeraa0c8b32019-01-28 23:27:45 +010085 }
86
Jens Geyerb11f63c2019-03-14 21:12:38 +010087
Jens Geyeraa0c8b32019-01-28 23:27:45 +010088 private static void DisplayHelp()
89 {
90 Logger.LogInformation(@"
91Usage:
Kengo Sekibee4f2f2019-12-29 17:04:50 +090092 Server -help
Jens Geyeraa0c8b32019-01-28 23:27:45 +010093 will diplay help information
94
Jens Geyer0d128322021-02-25 09:42:52 +010095 Server -tr:<transport> -bf:<buffering> -pr:<protocol> [-multiplex]
Kyle Smith7b94dd42019-03-23 17:26:56 +010096 will run server with specified arguments (tcp transport, no buffering, and binary protocol by default)
Jens Geyeraa0c8b32019-01-28 23:27:45 +010097
98Options:
99 -tr (transport):
Jens Geyer0d128322021-02-25 09:42:52 +0100100 tcp - (default) tcp transport (localhost:9090)
101 tcptls - tcp transport with tls (localhost:9090)
102 namedpipe - namedpipe transport (pipe "".test"")
103 http - http transport (localhost:9090)
Kyle Smith7b94dd42019-03-23 17:26:56 +0100104
105 -bf (buffering):
Jens Geyer0d128322021-02-25 09:42:52 +0100106 none - (default) no buffering
107 buffered - buffered transport
108 framed - framed transport
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100109
110 -pr (protocol):
Jens Geyer0d128322021-02-25 09:42:52 +0100111 binary - (default) binary protocol
112 compact - compact protocol
113 json - json protocol
114
115 -multiplex - adds multiplexed protocol
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100116
117Sample:
Kengo Sekibee4f2f2019-12-29 17:04:50 +0900118 Server -tr:tcp
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100119");
120 }
121
122 private static async Task RunAsync(string[] args, CancellationToken cancellationToken)
123 {
124 var selectedTransport = GetTransport(args);
Kyle Smith7b94dd42019-03-23 17:26:56 +0100125 var selectedBuffering = GetBuffering(args);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100126 var selectedProtocol = GetProtocol(args);
Jens Geyer0d128322021-02-25 09:42:52 +0100127 var multiplex = GetMultiplex(args);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100128
129 if (selectedTransport == Transport.Http)
130 {
Jens Geyer0d128322021-02-25 09:42:52 +0100131 if (multiplex)
Jens Geyer3cac3202022-01-31 18:04:35 +0100132 throw new Exception("This tutorial sample code does not yet allow multiplex over http (although Thrift itself of course does)");
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100133 new HttpServerSample().Run(cancellationToken);
134 }
135 else
136 {
Jens Geyer0d128322021-02-25 09:42:52 +0100137 await RunSelectedConfigurationAsync(selectedTransport, selectedBuffering, selectedProtocol, multiplex, cancellationToken);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100138 }
139 }
140
Jens Geyer0d128322021-02-25 09:42:52 +0100141
142 private static bool GetMultiplex(string[] args)
143 {
144 var mplex = args.FirstOrDefault(x => x.StartsWith("-multiplex"));
145 return !string.IsNullOrEmpty(mplex);
146 }
147
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100148 private static Protocol GetProtocol(string[] args)
149 {
Jens Geyere26b4a82024-11-12 23:53:04 +0100150 var protocol = args.FirstOrDefault(x => x.StartsWith("-pr"))?.Split(':').Skip(1).Take(1).FirstOrDefault();
Jens Geyer0d128322021-02-25 09:42:52 +0100151 if (string.IsNullOrEmpty(protocol))
152 return Protocol.Binary;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100153
Jens Geyer0d128322021-02-25 09:42:52 +0100154 protocol = protocol.Substring(0, 1).ToUpperInvariant() + protocol.Substring(1).ToLowerInvariant();
155 if (Enum.TryParse(protocol, true, out Protocol selectedProtocol))
156 return selectedProtocol;
157 else
158 return Protocol.Binary;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100159 }
160
Kyle Smith7b94dd42019-03-23 17:26:56 +0100161 private static Buffering GetBuffering(string[] args)
162 {
Jens Geyere26b4a82024-11-12 23:53:04 +0100163 var buffering = args.FirstOrDefault(x => x.StartsWith("-bf"))?.Split(':').Skip(1).Take(1).FirstOrDefault();
Jens Geyer0d128322021-02-25 09:42:52 +0100164 if (string.IsNullOrEmpty(buffering))
165 return Buffering.None;
Kyle Smith7b94dd42019-03-23 17:26:56 +0100166
Jens Geyer0d128322021-02-25 09:42:52 +0100167 buffering = buffering.Substring(0, 1).ToUpperInvariant() + buffering.Substring(1).ToLowerInvariant();
168 if( Enum.TryParse<Buffering>(buffering, out var selectedBuffering))
169 return selectedBuffering;
170 else
171 return Buffering.None;
Kyle Smith7b94dd42019-03-23 17:26:56 +0100172 }
173
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100174 private static Transport GetTransport(string[] args)
175 {
Jens Geyere26b4a82024-11-12 23:53:04 +0100176 var transport = args.FirstOrDefault(x => x.StartsWith("-tr"))?.Split(':').Skip(1).Take(1).FirstOrDefault();
Jens Geyer0d128322021-02-25 09:42:52 +0100177 if (string.IsNullOrEmpty(transport))
178 return Transport.Tcp;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100179
Jens Geyer0d128322021-02-25 09:42:52 +0100180 transport = transport.Substring(0, 1).ToUpperInvariant() + transport.Substring(1).ToLowerInvariant();
181 if( Enum.TryParse(transport, true, out Transport selectedTransport))
182 return selectedTransport;
183 else
184 return Transport.Tcp;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100185 }
186
Jens Geyer0d128322021-02-25 09:42:52 +0100187 private static async Task RunSelectedConfigurationAsync(Transport transport, Buffering buffering, Protocol protocol, bool multiplex, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100188 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200189 TServerTransport serverTransport = transport switch
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100190 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200191 Transport.Tcp => new TServerSocketTransport(9090, Configuration),
Jens Geyer51fc54f2023-02-14 23:51:16 +0100192 Transport.NamedPipe => new TNamedPipeServerTransport(".test", Configuration, NamedPipeServerFlags.None, 64),
Jens Geyer2b2ea622021-04-09 22:55:11 +0200193 Transport.TcpTls => new TTlsServerSocketTransport(9090, Configuration, GetCertificate(), ClientCertValidator, LocalCertificateSelectionCallback),
194 _ => throw new ArgumentException("unsupported value $transport", nameof(transport)),
195 };
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100196
Jens Geyere26b4a82024-11-12 23:53:04 +0100197 TTransportFactory? transportFactory = buffering switch
Kyle Smith7b94dd42019-03-23 17:26:56 +0100198 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200199 Buffering.Buffered => new TBufferedTransport.Factory(),
200 Buffering.Framed => new TFramedTransport.Factory(),
201 // layered transport(s) are optional
202 Buffering.None => null,
203 _ => throw new ArgumentException("unsupported value $buffering", nameof(buffering)),
204 };
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100205
Jens Geyer2b2ea622021-04-09 22:55:11 +0200206 TProtocolFactory protocolFactory = protocol switch
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100207 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200208 Protocol.Binary => new TBinaryProtocol.Factory(),
209 Protocol.Compact => new TCompactProtocol.Factory(),
210 Protocol.Json => new TJsonProtocol.Factory(),
211 _ => throw new ArgumentException("unsupported value $protocol", nameof(protocol)),
212 };
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100213
Jens Geyer0d128322021-02-25 09:42:52 +0100214 var handler = new CalculatorAsyncHandler();
215 ITAsyncProcessor processor = new Calculator.AsyncProcessor(handler);
216
217 if (multiplex)
218 {
219 var multiplexedProcessor = new TMultiplexedProcessor();
220 multiplexedProcessor.RegisterProcessor(nameof(Calculator), processor);
221
222 processor = multiplexedProcessor;
223 }
224
Kyle Smith7b94dd42019-03-23 17:26:56 +0100225
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100226 try
227 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100228 if( Logger.IsEnabled(LogLevel.Information))
229 Logger.LogInformation(
230 "TSimpleAsyncServer with \n{transport} transport\n{buffering} buffering\nmultiplex = {multiplex}\n{protocol} protocol",
231 transport,
232 buffering,
233 multiplex ? "yes" : "no",
234 protocol
235 );
Kyle Smith7b94dd42019-03-23 17:26:56 +0100236
237 var server = new TSimpleAsyncServer(
238 itProcessorFactory: new TSingletonProcessorFactory(processor),
239 serverTransport: serverTransport,
Jens Geyer0d128322021-02-25 09:42:52 +0100240 inputTransportFactory: transportFactory,
241 outputTransportFactory: transportFactory,
242 inputProtocolFactory: protocolFactory,
243 outputProtocolFactory: protocolFactory,
Jens Geyer4c7b9fd2021-12-04 22:48:37 +0100244 logger: LoggingHelper.CreateLogger<TSimpleAsyncServer >());
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100245
246 Logger.LogInformation("Starting the server...");
Kyle Smith7b94dd42019-03-23 17:26:56 +0100247
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100248 await server.ServeAsync(cancellationToken);
249 }
250 catch (Exception x)
251 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100252 if (Logger.IsEnabled(LogLevel.Information))
253 Logger.LogInformation("{x}",x);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100254 }
255 }
256
257 private static X509Certificate2 GetCertificate()
258 {
259 // due to files location in net core better to take certs from top folder
260 var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory()));
Jens Geyere26b4a82024-11-12 23:53:04 +0100261 //return new X509Certificate2(certFile, "ThriftTest");
262 return X509CertificateLoader.LoadPkcs12FromFile(certFile, "ThriftTest");
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100263 }
264
Jens Geyere26b4a82024-11-12 23:53:04 +0100265 private static string GetCertPath(DirectoryInfo? di, int maxCount = 6)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100266 {
267 var topDir = di;
Jens Geyere26b4a82024-11-12 23:53:04 +0100268 var certFile = topDir?.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories).FirstOrDefault();
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100269 if (certFile == null)
270 {
271 if (maxCount == 0)
272 throw new FileNotFoundException("Cannot find file in directories");
Jens Geyere26b4a82024-11-12 23:53:04 +0100273 return GetCertPath(di?.Parent, --maxCount);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100274 }
275
276 return certFile.FullName;
277 }
278
Jens Geyere26b4a82024-11-12 23:53:04 +0100279 private static X509Certificate2 LocalCertificateSelectionCallback(object sender,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100280 string targetHost, X509CertificateCollection localCertificates,
Jens Geyere26b4a82024-11-12 23:53:04 +0100281 X509Certificate? remoteCertificate, string[] acceptableIssuers)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100282 {
283 return GetCertificate();
284 }
285
Jens Geyere26b4a82024-11-12 23:53:04 +0100286 private static bool ClientCertValidator(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100287 {
288 return true;
289 }
290
291 private enum Transport
292 {
293 Tcp,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100294 NamedPipe,
295 Http,
296 TcpTls,
Kyle Smith7b94dd42019-03-23 17:26:56 +0100297 }
298
299 private enum Buffering
300 {
301 None,
302 Buffered,
303 Framed,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100304 }
305
306 private enum Protocol
307 {
308 Binary,
309 Compact,
310 Json,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100311 }
312
313 public class HttpServerSample
314 {
315 public void Run(CancellationToken cancellationToken)
316 {
317 var config = new ConfigurationBuilder()
318 .AddEnvironmentVariables(prefix: "ASPNETCORE_")
319 .Build();
320
Jens Geyer2f214c22025-11-13 23:24:45 +0100321 var host = new HostBuilder().
322 ConfigureWebHost(webhostbuilder => {
323 webhostbuilder.UseConfiguration(config)
324 .UseUrls("http://localhost:9090")
325 .UseContentRoot(Directory.GetCurrentDirectory())
326 .UseStartup<Startup>()
327 .UseKestrel()
328 .ConfigureLogging((ctx, logging) => LoggingHelper.ConfigureLogging(logging))
329 ;
330 })
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100331 .Build();
332
Jens Geyerb11f63c2019-03-14 21:12:38 +0100333 Logger.LogTrace("test");
334 Logger.LogCritical("test");
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100335 host.RunAsync(cancellationToken).GetAwaiter().GetResult();
336 }
337
338 public class Startup
339 {
Jens Geyerec439542019-11-01 19:19:44 +0100340 public Startup(IWebHostEnvironment env)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100341 {
342 var builder = new ConfigurationBuilder()
343 .SetBasePath(env.ContentRootPath)
344 .AddEnvironmentVariables();
345
346 Configuration = builder.Build();
347 }
348
349 public IConfigurationRoot Configuration { get; }
350
351 // This method gets called by the runtime. Use this method to add services to the container.
352 public void ConfigureServices(IServiceCollection services)
353 {
Jens Geyer0d128322021-02-25 09:42:52 +0100354 // NOTE: this is not really the recommended way to do it
355 // because the HTTP server cannot be configured properly to e.g. accept framed or multiplex
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100356 services.AddTransient<Calculator.IAsync, CalculatorAsyncHandler>();
357 services.AddTransient<ITAsyncProcessor, Calculator.AsyncProcessor>();
358 services.AddTransient<THttpServerTransport, THttpServerTransport>();
359 }
360
361 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Jens Geyerec439542019-11-01 19:19:44 +0100362 public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100363 {
Jens Geyer0d128322021-02-25 09:42:52 +0100364 _ = env;
365 _ = loggerFactory;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100366 app.UseMiddleware<THttpServerTransport>();
367 }
368 }
369 }
370
371 public class CalculatorAsyncHandler : Calculator.IAsync
372 {
Jens Geyere26b4a82024-11-12 23:53:04 +0100373 private readonly Dictionary<int, SharedStruct> _log = [];
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100374
375 public CalculatorAsyncHandler()
376 {
377 }
378
Jens Geyer2b2ea622021-04-09 22:55:11 +0200379 public async Task<SharedStruct> getStruct(int key,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100380 CancellationToken cancellationToken)
381 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100382 if (Logger.IsEnabled(LogLevel.Information))
383 Logger.LogInformation("GetStruct({key})", key);
384 return _log[key];
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100385 }
386
Jens Geyer2b2ea622021-04-09 22:55:11 +0200387 public async Task ping(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100388 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200389 Logger.LogInformation("Ping()");
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100390 }
391
Jens Geyer2b2ea622021-04-09 22:55:11 +0200392 public async Task<int> add(int num1, int num2, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100393 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100394 if (Logger.IsEnabled(LogLevel.Information))
395 Logger.LogInformation("Add({num1},{num2})", num1, num2);
396 return num1 + num2;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100397 }
398
Jens Geyere26b4a82024-11-12 23:53:04 +0100399 public async Task<int> calculate(int logid, Work? w, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100400 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100401 if (Logger.IsEnabled(LogLevel.Information))
402 Logger.LogInformation("Calculate({logid}, [{w.Op},{w.Num1},{w.Num2}])", logid, w?.Op, w?.Num1, w?.Num2);
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100403
Jens Geyer0d128322021-02-25 09:42:52 +0100404 int val;
Jens Geyere26b4a82024-11-12 23:53:04 +0100405 switch (w?.Op)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100406 {
407 case Operation.ADD:
408 val = w.Num1 + w.Num2;
409 break;
410
411 case Operation.SUBTRACT:
412 val = w.Num1 - w.Num2;
413 break;
414
415 case Operation.MULTIPLY:
416 val = w.Num1 * w.Num2;
417 break;
418
419 case Operation.DIVIDE:
420 if (w.Num2 == 0)
421 {
422 var io = new InvalidOperation
423 {
424 WhatOp = (int) w.Op,
425 Why = "Cannot divide by 0"
426 };
427
428 throw io;
429 }
430 val = w.Num1 / w.Num2;
431 break;
432
433 default:
434 {
435 var io = new InvalidOperation
436 {
Jens Geyere26b4a82024-11-12 23:53:04 +0100437 WhatOp = ((int?)w?.Op) ?? -1,
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100438 Why = "Unknown operation"
439 };
440
441 throw io;
442 }
443 }
444
445 var entry = new SharedStruct
446 {
447 Key = logid,
448 Value = val.ToString()
449 };
450
451 _log[logid] = entry;
Jens Geyer2f214c22025-11-13 23:24:45 +0100452 return val;
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100453 }
454
Jens Geyer2b2ea622021-04-09 22:55:11 +0200455 public async Task zip(CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100456 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200457 Logger.LogInformation("Zip() with delay 100mc");
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100458 await Task.Delay(100, CancellationToken.None);
459 }
460 }
461
462 public class SharedServiceAsyncHandler : SharedService.IAsync
463 {
Jens Geyer2b2ea622021-04-09 22:55:11 +0200464 public async Task<SharedStruct> getStruct(int key, CancellationToken cancellationToken)
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100465 {
Jens Geyer2f214c22025-11-13 23:24:45 +0100466 if (Logger.IsEnabled(LogLevel.Information))
467 Logger.LogInformation("GetStruct({key})", key);
468
469 return new SharedStruct()
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100470 {
471 Key = key,
Jens Geyer2b2ea622021-04-09 22:55:11 +0200472 Value = "GetStruct"
Jens Geyer2f214c22025-11-13 23:24:45 +0100473 };
Jens Geyeraa0c8b32019-01-28 23:27:45 +0100474 }
475 }
476 }
477}