Projekt

Obecné

Profil

Stáhnout (7.86 KB) Statistiky
| Větev: | Tag: | Revize:
1 e6a01bd8 Pultak
using LDClient.network;
2 f281acac silhavyj
using LDClient.network.data;
3
4 e6a01bd8 Pultak
namespace LDClient.detection; 
5
6
/// <summary>
7
/// This class takes care of process detection. When t32mtc (process)
8
/// is detected, it means that the debugger is currently being used.
9
/// The class keeps track of the current state of a debugger.
10
/// </summary>
11
public sealed class ProcessDetection : IProcessDetection {
12 12899c8b silhavyj
13
    /// <summary>
14 e6a01bd8 Pultak
    /// Datetime format used when sending payloads to the server.
15 12899c8b silhavyj
    /// </summary>
16 e6a01bd8 Pultak
    private const string DatetimeFormat = "yyyy-MM-dd hh:mm:ss";
17 6dab0250 silhavyj
18 e6a01bd8 Pultak
    /// <summary>
19
    /// Name of the process the application detects.
20
    /// </summary>
21
    private readonly string _processName;
22 12899c8b silhavyj
        
23 e6a01bd8 Pultak
    /// <summary>
24
    /// How often the application check the current status of the process (cunning / not running).
25
    /// </summary>
26
    private readonly uint _detectionPeriodMs;
27 12899c8b silhavyj
        
28 e6a01bd8 Pultak
    /// <summary>
29
    /// Instance of InfoFetcher used to fetch information from the debugger
30
    /// (when the process is detected).
31
    /// </summary>
32
    private readonly IInfoFetcher _infoFetcher;
33 12899c8b silhavyj
        
34 e6a01bd8 Pultak
    /// <summary>
35
    /// Instance of API clients used for sending data off to the server.
36
    /// </summary>
37
    private readonly IApiClient _apiClient;
38 12899c8b silhavyj
        
39 e6a01bd8 Pultak
    /// <summary>
40
    /// Instance of ProcessUtils which encapsulates common functionality
41
    /// when it comes to dealing with processes (limited by the needs of this application).
42
    /// </summary>
43
    private readonly IProcessUtils _processUtils;
44 0932a9e2 Pultak
45 e6a01bd8 Pultak
    /// <summary>
46
    /// Flag indicating whether the process is currently running or not.
47
    /// </summary>
48
    private bool _processIsActive;
49 12899c8b silhavyj
        
50 e6a01bd8 Pultak
    /// <summary>
51
    /// Flag if the application failed to retrieve data when the process was detected.
52
    /// </summary>
53
    private bool _failedToRetrieveData;
54 12899c8b silhavyj
        
55 e6a01bd8 Pultak
    /// <summary>
56
    /// Last payload that was sent to the server.
57
    /// </summary>
58
    private Payload? _lastConnectedPayload;
59 f281acac silhavyj
60 e6a01bd8 Pultak
    /// <summary>
61
    /// Flag used to stop the thread (process detection).
62
    /// </summary>
63
    public bool DetectionRunning = false;
64 2c9a5fda silhavyj
65
    /// <summary>
66
    /// Superior number of attempts to fetch the information (outer loop).
67
    /// </summary>
68
    private uint _fetchInfoSuperiorMaxAttempts;
69
    
70
    /// <summary>
71
    /// Period of the superior (outer) loop to fetch the data.
72
    /// </summary>
73
    private uint _fetchInfoSuperiorAttemptPeriod;
74 12899c8b silhavyj
        
75 e6a01bd8 Pultak
    /// <summary>
76
    /// Creates an instance of this class.
77
    /// </summary>
78
    /// <param name="processName">Name of the process the application detects</param>
79
    /// <param name="detectionPeriodMs">How often the application check the current status of the process (cunning / not running)</param>
80
    /// <param name="infoFetcher">Instance of InfoFetcher used to fetch information from the debugger</param>
81
    /// <param name="apiClient">Instance of API clients used for sending data off to the server</param>
82
    /// <param name="processUtils">Instance of ProcessUtils which encapsulates common functionality when it comes to dealing with processes (limited by the needs of this application)</param>
83
    public ProcessDetection(string processName, uint detectionPeriodMs, IInfoFetcher infoFetcher,
84 2c9a5fda silhavyj
        IApiClient apiClient, IProcessUtils processUtils, uint fetchInfoSuperiorMaxAttempts, uint fetchInfoSuperiorAttemptPeriod) {
85 e6a01bd8 Pultak
        _processName = processName;
86
        _detectionPeriodMs = detectionPeriodMs;
87
        _infoFetcher = infoFetcher;
88
        _apiClient = apiClient;
89
        _failedToRetrieveData = false;
90
        _processUtils = processUtils;
91 2c9a5fda silhavyj
        _fetchInfoSuperiorMaxAttempts = fetchInfoSuperiorMaxAttempts;
92
        _fetchInfoSuperiorAttemptPeriod = fetchInfoSuperiorAttemptPeriod;
93 e6a01bd8 Pultak
    }
94 f281acac silhavyj
95 e6a01bd8 Pultak
    /// <summary>
96
    /// Retrieves data from the debugger.
97
    /// </summary>
98
    /// <returns>True, if the data was fetched successfully. False, otherwise.</returns>
99
    private async Task<bool> RetrieveDataFromDebugger() {
100
        // Try to fetch data from the debugger.
101 2c9a5fda silhavyj
102
        for (var i = 0; i < _fetchInfoSuperiorMaxAttempts; i++) {
103
            var success = await _infoFetcher.FetchDataAsync();
104
105
            // If the data was fetched successfully, send a payload off to the server.
106
            if (success) {
107
                _lastConnectedPayload = await SendDataToServerAsync(_infoFetcher.HeadSerialNumber,
108
                    _infoFetcher.BodySerialNumber, DatetimeFormat);
109
                return true;
110
            }
111
            await Task.Delay((int)_fetchInfoSuperiorAttemptPeriod);
112 f281acac silhavyj
        }
113 2c9a5fda silhavyj
        return false;
114 e6a01bd8 Pultak
    }
115 08616eff silhavyj
116 e6a01bd8 Pultak
    /// <summary>
117
    /// Sends a payload to the server when a debugger gets disconnected.
118
    /// </summary>
119
    private async Task DebuggerDisconnected() {
120
        // Make sure the debugger was connected in the first place.
121
        if (_lastConnectedPayload is not null) {
122
            // Update the status and timestamp of the last payload
123
            // (the serial numbers remain the same).
124
            _lastConnectedPayload.Status = ConnectionStatus.Disconnected;
125
            _lastConnectedPayload.TimeStamp = DateTime.Now.ToString(DatetimeFormat);
126 12899c8b silhavyj
                
127 e6a01bd8 Pultak
            // Send the data to the server.
128
            await _apiClient.SendPayloadAsync(_lastConnectedPayload);
129 12899c8b silhavyj
                
130 e6a01bd8 Pultak
            // Clear the last payload.
131
            _lastConnectedPayload = null;
132 f281acac silhavyj
        }
133 e6a01bd8 Pultak
    }
134 f281acac silhavyj
135 e6a01bd8 Pultak
    /// <summary>
136
    /// Checks if the t32mtc process is running or not. 
137
    /// </summary>
138
    private async Task DetectProcessAsync() {
139
        // Check if the process is running.
140
        var processExists = _processUtils.IsProcessRunning(_processName);
141 f281acac silhavyj
142 e6a01bd8 Pultak
        // Check if the process was not running but now it is (flip flop ON). 
143
        if (processExists && !_processIsActive) {
144
            Program.DefaultLogger.Info($"Process started: {_processName}");
145
            if (!_failedToRetrieveData) {
146
                _failedToRetrieveData = !await RetrieveDataFromDebugger();
147 f281acac silhavyj
            }
148 e6a01bd8 Pultak
        }
149
        // Check if the process was running but now it is not (fli flop OFF).
150
        else if (!processExists && _processIsActive) {
151
            Program.DefaultLogger.Info($"Process stopped: {_processName}");
152
            _failedToRetrieveData = false;
153
            await DebuggerDisconnected();
154 f281acac silhavyj
        }
155 12899c8b silhavyj
156 e6a01bd8 Pultak
        // Keep track of the current state of the debugger.
157
        _processIsActive = processExists;
158
    }
159
160
    /// <summary>
161
    /// Creates a payload and sends it to the server.
162
    /// </summary>
163
    /// <param name="headSerialNumber">serial number of the head of the debugger</param>
164
    /// <param name="bodySerialNumber">serial number of the body of the debugger</param>
165
    /// <param name="datetimeFormat">datetime format (timestamp)</param>
166
    /// <returns>the newly-created payload</returns>
167
    private async Task<Payload> SendDataToServerAsync(string headSerialNumber, string bodySerialNumber, string datetimeFormat) {
168
        // Create a new payload. 
169
        Payload payload = new() {
170
            UserName = Environment.UserName,
171
            HostName = Environment.MachineName,
172
            TimeStamp = DateTime.Now.ToString(datetimeFormat),
173
            HeadDevice = new DebuggerInfo {
174
                SerialNumber = headSerialNumber
175
            },
176
            BodyDevice = new DebuggerInfo {
177
                SerialNumber = bodySerialNumber
178
            },
179
            Status = ConnectionStatus.Connected
180
        };
181 12899c8b silhavyj
            
182 e6a01bd8 Pultak
        // Send it to the server and return it.
183
        await _apiClient.SendPayloadAsync(payload);
184
        return payload;
185
    }
186 12899c8b silhavyj
187 e6a01bd8 Pultak
    /// <summary>
188
    /// Periodically runs process detection. This method is instantiated
189
    /// as a thread from the main class (Program.cs).
190
    /// </summary>
191
    public async void RunPeriodicDetection() {
192
        Program.DefaultLogger.Info("Process periodic detector has started");
193
        DetectionRunning = true;
194 12899c8b silhavyj
            
195 e6a01bd8 Pultak
        while (DetectionRunning) {
196
            await DetectProcessAsync();
197
            Thread.Sleep((int) _detectionPeriodMs);
198 f281acac silhavyj
        }
199
    }
200 e6a01bd8 Pultak
}