-
-
Notifications
You must be signed in to change notification settings - Fork 142
/
Copy pathEventDispatcher.cs
103 lines (90 loc) · 2.97 KB
/
EventDispatcher.cs
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
// TSLib - A free TeamSpeak 3 and 5 client library
// Copyright (C) 2017 TSLib contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the Open Software License v. 3.0
//
// You should have received a copy of the Open Software License along with this
// program. If not, see <https://opensource.org/licenses/OSL-3.0>.
using System;
using System.Collections.Concurrent;
using System.Threading;
using TSLib.Helper;
namespace TSLib
{
internal static class EventDispatcherHelper
{
public const string DispatcherTitle = "TS Dispatcher";
public const string EventLoopTitle = "TS MessageLoop";
internal static string CreateLogThreadName(string threadName, Id id) => threadName + (id == Id.Null ? "" : $"[{id}]");
internal static string CreateDispatcherTitle(Id id) => CreateLogThreadName(DispatcherTitle, id);
}
/// <summary> Provides a function to run a receiving loop and asynchronously
/// dispatch notifications.
/// </summary>
internal interface IEventDispatcher : IDisposable
{
/// <summary>Initializes the dispatcher.</summary>
/// <param name="eventLoop">The main loop which will be receiving packets.</param>
/// <param name="dispatcher">The method to call asynchronously when a new
/// notification comes in.</param>
/// <param name="ctx">The current connection context.</param>
void Init(Action<LazyNotification> dispatcher, Id id);
/// <summary>Dispatches the notification.</summary>
/// <param name="lazyNotification"></param>
void Invoke(LazyNotification lazyNotification);
void DoWork();
}
internal sealed class ExtraThreadEventDispatcher : IEventDispatcher
{
private Action<LazyNotification> dispatcher;
private Thread dispatchThread;
private readonly ConcurrentQueue<LazyNotification> eventQueue = new ConcurrentQueue<LazyNotification>();
private readonly AutoResetEvent eventBlock = new AutoResetEvent(false);
private volatile bool run;
#pragma warning disable CS8618 // !NRT on Init
public ExtraThreadEventDispatcher() { }
#pragma warning restore CS8618
public void Init(Action<LazyNotification> dispatcher, Id id)
{
run = true;
this.dispatcher = dispatcher;
dispatchThread = new Thread(() =>
{
Tools.SetLogId(id);
DispatchLoop();
})
{ Name = EventDispatcherHelper.CreateDispatcherTitle(id) };
dispatchThread.Start();
}
public void Invoke(LazyNotification lazyNotification)
{
eventQueue.Enqueue(lazyNotification);
eventBlock.Set();
}
private void DispatchLoop()
{
while (run)
{
eventBlock.WaitOne();
while (!eventQueue.IsEmpty)
{
if (eventQueue.TryDequeue(out var lazyNotification))
dispatcher.Invoke(lazyNotification);
}
}
}
public void DoWork()
{
if (Thread.CurrentThread.ManagedThreadId != dispatchThread.ManagedThreadId)
return;
if (eventQueue.TryDequeue(out var lazyNotification))
dispatcher.Invoke(lazyNotification);
}
public void Dispose()
{
run = false;
eventBlock.Set();
}
}
}