• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

luttje / Key2Joy / 6602636543

22 Oct 2023 08:16AM UTC coverage: 44.104% (-8.4%) from 52.519%
6602636543

Pull #50

github

web-flow
Merge cf342a7b3 into 14b7ce9a7
Pull Request #50: Add XInput in preparation for gamepad triggers + add xmldoc

764 of 2383 branches covered (0.0%)

Branch coverage included in aggregate %.

3060 of 3060 new or added lines in 106 files covered. (100.0%)

3896 of 8183 relevant lines covered (47.61%)

15812.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.07
/Core/Key2Joy.Contracts/Plugins/Remoting/RemoteEventSubscriberHost.cs
1
using System;
2
using System.Diagnostics;
3
using System.IO;
4
using System.IO.Pipes;
5
using System.Threading.Tasks;
6
using System.Threading;
7
using Key2Joy.Contracts.Util;
8

9
namespace Key2Joy.Contracts.Plugins.Remoting;
10

11
public class RemoteEventSubscriberHost : IDisposable
12
{
13
    public event EventHandler Disposing;
14

15
    private readonly NamedPipeServerStream pipeStream;
16
    private bool isPipeServerStreamReady = false;
17

18
    private readonly CancellationTokenSource pipeCancellation;
19
    private static readonly TimeSpan HeartbeatWithMargin = RemoteEventSubscriber.MaxHeartbeatInterval - TimeSpan.FromSeconds(2);
1✔
20
    private static readonly TimeSpan MaxWaitForReady = TimingHelper.FromSeconds(5);
1✔
21

22
    internal RemoteEventSubscriberHost(string portName)
16✔
23
    {
24
        this.pipeStream = new NamedPipeServerStream(
16✔
25
            RemotePipe.GetAbsolutePipeName(portName),
16✔
26
            PipeDirection.InOut,
16✔
27
            1,
16✔
28
            PipeTransmissionMode.Message,
16✔
29
            PipeOptions.Asynchronous);
16✔
30

31
        this.pipeCancellation = new CancellationTokenSource();
16✔
32

33
        this.InitBackgroundEventThread();
16✔
34
        this.InitBackgroundHeartbeatThread();
16✔
35
    }
16✔
36

37
    /// <summary>
38
    /// Listens in the background for any incoming messages from the client.
39
    /// </summary>
40
    private async void InitBackgroundEventThread()
41
    {
42
        var backgroundThread = Task.Run(() =>
16✔
43
        {
16✔
44
            this.pipeStream.WaitForConnection();
16✔
45

16✔
46
            StreamReader reader = new(this.pipeStream);
16✔
47

16✔
48
            while (!this.pipeCancellation.IsCancellationRequested)
2,380,035✔
49
            {
16✔
50
                try
16✔
51
                {
16✔
52
                    var messageOrSubscriptionId = RemotePipe.ReadMessage(this.pipeStream);
2,380,035✔
53

16✔
54
                    if (string.IsNullOrEmpty(messageOrSubscriptionId))
2,380,019✔
55
                    {
16✔
56
                        continue;
2,380,003✔
57
                    }
16✔
58

16✔
59
                    if (messageOrSubscriptionId == RemoteEventSubscriber.SignalReady)
16!
60
                    {
16✔
61
                        this.isPipeServerStreamReady = true;
16✔
62
                        continue;
16✔
63
                    }
16✔
64
                    else if (messageOrSubscriptionId == RemoteEventSubscriber.SignalExit)
×
65
                    {
16✔
66
                        this.Dispose();
×
67
                        return;
×
68
                    }
16✔
69

16✔
70
                    RemoteEventSubscriber.HandleInvoke(messageOrSubscriptionId);
×
71
                }
×
72
                catch (Exception ex)
14✔
73
                {
16✔
74
                    Output.WriteLine(ex);
14✔
75
                    Debug.WriteLine($"-------------> Exception: {ex.Message}");
16✔
76
                    return;
14✔
77
                }
16✔
78
            }
16✔
79
        });
30✔
80

81
        await backgroundThread;
16✔
82
    }
14✔
83

84
    /// <summary>
85
    /// Sends heartbeats in the background at the commonly agreed interval.
86
    /// </summary>
87
    private async void InitBackgroundHeartbeatThread()
88
    {
89
        var backgroundThread = Task.Run(async () =>
16✔
90
        {
16✔
91
            while (!this.pipeCancellation.IsCancellationRequested)
18✔
92
            {
16✔
93
                await Task.Delay(HeartbeatWithMargin);
16✔
94
                if (!this.isPipeServerStreamReady)
15✔
95
                {
16✔
96
                    continue;
16✔
97
                }
16✔
98

16✔
99
                try
16✔
100
                {
16✔
101
                    RemotePipe.WriteMessage(this.pipeStream, RemoteEventSubscriber.SignalHeartbeat);
15✔
102
                }
2✔
103
                catch (Exception ex)
13✔
104
                {
16✔
105
                    Output.WriteLine(ex);
13✔
106
                    Debug.WriteLine($"-------------> Exception: {ex.Message}");
16✔
107
                    return;
13✔
108
                }
16✔
109
            }
16✔
110
        });
31✔
111

112
        await backgroundThread;
16✔
113
    }
15✔
114

115
    /// <summary>
116
    /// Stops execution until the event pipe has received the ready signal
117
    /// </summary>
118
    public void WaitForEventPipeReady()
119
    {
120
        var waitStart = DateTime.Now;
16✔
121

122
        while (!this.isPipeServerStreamReady)
11,757,450✔
123
        {
124
            Task.Delay(10);
11,757,434✔
125

126
            if ((DateTime.Now - waitStart) > MaxWaitForReady)
11,757,434!
127
            {
128
                throw new TimeoutException($"WaitForEventPipeReady timed out after {MaxWaitForReady.TotalMilliseconds}ms");
×
129
            }
130
        }
131
    }
16✔
132

133
    public void Dispose()
134
    {
135
        this.Disposing?.Invoke(this, EventArgs.Empty);
14!
136

137
        this.pipeStream?.Dispose();
14!
138

139
        this.pipeCancellation?.Cancel();
14!
140
    }
14✔
141
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc