summaryrefslogtreecommitdiff
path: root/ThirdParty/CsvHelper-master/docs-src/CsvHelper.DocsGenerator/ConsoleHost.cs
blob: c7c3bc162c1a89480f5a5b899532f0ca86924cd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using System;
using System.Threading;
using System.Threading.Tasks;

namespace CsvHelper.DocsGenerator
{
	public static class ConsoleHost
	{
		/// <summary>
		/// Block the calling thread until shutdown is triggered via Ctrl+C or SIGTERM.
		/// </summary>
		public static void WaitForShutdown()
		{
			WaitForShutdownAsync().GetAwaiter().GetResult();
		}

		/// <summary>
		/// Returns a Task that completes when shutdown is triggered via the given token, Ctrl+C or SIGTERM.
		/// </summary>
		/// <param name="token">The token to trigger shutdown.</param>
		public static async Task WaitForShutdownAsync(CancellationToken token = default(CancellationToken))
		{
			var done = new ManualResetEventSlim(false);
			using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token))
			{
				AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: string.Empty);
				await WaitForTokenShutdownAsync(cts.Token);
				done.Set();
			}
		}

		/// <summary>
		/// Runs an application and block the calling thread until host shutdown.
		/// </summary>
		/// <param name="host">The <see cref="IWebHost"/> to run.</param>
		public static void Wait()
		{
			WaitAsync().GetAwaiter().GetResult();
		}

		/// <summary>
		/// Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered.
		/// </summary>
		/// <param name="host">The <see cref="IConsoleHost"/> to run.</param>
		/// <param name="token">The token to trigger shutdown.</param>
		public static async Task WaitAsync(CancellationToken token = default(CancellationToken))
		{
			//Wait for the token shutdown if it can be cancelled
			if (token.CanBeCanceled)
			{
				await WaitAsync(token, shutdownMessage: null);
				return;
			}

			//If token cannot be cancelled, attach Ctrl+C and SIGTERN shutdown
			var done = new ManualResetEventSlim(false);
			using (var cts = new CancellationTokenSource())
			{
				AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: "Application is shutting down...");
				await WaitAsync(cts.Token, "Application running. Press Ctrl+C to shut down.");
				done.Set();
			}
		}

		private static async Task WaitAsync(CancellationToken token, string shutdownMessage)
		{
			if (!string.IsNullOrEmpty(shutdownMessage))
			{
				Console.WriteLine(shutdownMessage);
			}

			await WaitForTokenShutdownAsync(token);
		}

		private static void AttachCtrlcSigtermShutdown(CancellationTokenSource cts, ManualResetEventSlim resetEvent, string shutdownMessage)
		{
			Action ShutDown = () =>
			{
				if (!cts.IsCancellationRequested)
				{
					if (!string.IsNullOrWhiteSpace(shutdownMessage))
					{
						Console.WriteLine(shutdownMessage);
					}

					try
					{
						cts.Cancel();
					}
					catch (ObjectDisposedException) { }
				}

				// Wait on the given reset event
				resetEvent.Wait();
			};

			AppDomain.CurrentDomain.ProcessExit += delegate { ShutDown(); };
			Console.CancelKeyPress += (sender, eventArgs) =>
			{
				ShutDown();
				//Don't terminate the process immediately, wait for the Main thread to exit gracefully.
				eventArgs.Cancel = true;
			};
		}

		private static async Task WaitForTokenShutdownAsync(CancellationToken token)
		{
			var waitForStop = new TaskCompletionSource<object>();
			token.Register(obj =>
			{
				var tcs = (TaskCompletionSource<object>)obj;
				tcs.TrySetResult(null);
			}, waitForStop);
			await waitForStop.Task;
		}
	}
}