Projekt

Obecné

Profil

Stáhnout (8.5 KB) Statistiky
| Větev: | Tag: | Revize:
1
using System.Diagnostics;
2
using LDClient.utils;
3
using LDClient.utils.loggers;
4

    
5
namespace LDClient.detection {
6

    
7
    /// <summary>
8
    /// This class implements the IInfoFetcher interface
9
    /// which defines the functionality of an info fetcher.
10
    /// </summary>
11
    public class InfoFetcher : IInfoFetcher {
12
        
13
        /// <summary>
14
        /// Default value of a serial number (undefined).
15
        /// </summary>
16
        private const string UndefinedSerialNumber = "number";
17

    
18
        /// <summary>
19
        /// Path to the t32rem.exe file which is used to send commands to the debugger.
20
        /// </summary>
21
        private readonly string _f32RemExecutable;
22
        
23
        /// <summary>
24
        /// Arguments (commands) sent to the debugger in order to generate a .txt file
25
        /// containing all the desired information.
26
        /// </summary>
27
        private readonly string[] _f32RemArguments;
28
        
29
        /// <summary>
30
        /// Status code indicating a successful termination of t32rem.exe
31
        /// </summary>
32
        private readonly int _f32SuccessExitCode;
33
        
34
        /// <summary>
35
        /// Timeout used when waiting for the t32rem.exe to finish.
36
        /// </summary>
37
        private readonly int _f32WaitTimeoutMs;
38
        
39
        /// <summary>
40
        /// Maximum number of attempts to locate and parse the .txt file.
41
        /// </summary>
42
        private readonly uint _maxAttempts;
43
        
44
        /// <summary>
45
        /// Period (how often) the application tries to locate and parse the .txt file.
46
        /// </summary>
47
        private readonly uint _waitPeriodMs;
48
        
49
        /// <summary>
50
        /// Path to the .txt file which is generated from the debugger.
51
        /// </summary>
52
        private readonly string _infoFilePath;
53

    
54
        /// <summary>
55
        /// Instance of ProcessUtils which encapsulates common functionality
56
        /// when it comes to dealing with processes (limited by the needs of this application).
57
        /// </summary>
58
        public IProcessUtils ProcessUtils;
59
        
60
        /// <summary>
61
        /// Instance of FileUtils which encapsulates common functionality
62
        /// when it comes to dealing with files (limited by the needs of this application).
63
        /// </summary>
64
        public IFileUtils FileUtils;
65

    
66
        /// <summary>
67
        /// Returns the head serial number of the debugger.
68
        /// </summary>
69
        public string HeadSerialNumber { get; set; } = UndefinedSerialNumber;
70
        
71
        /// <summary>
72
        /// Returns the body serial number of the debugger.
73
        /// </summary>
74
        public string BodySerialNumber { get; set; } = UndefinedSerialNumber;
75
        
76
        /// <summary>
77
        /// Creates an instance of this class.
78
        /// </summary>
79
        /// <param name="maxAttempts">Maximum number of attempts to locate and parse the .txt file</param>
80
        /// <param name="waitPeriodMs">Period (how often) the application tries to locate and parse the .txt file</param>
81
        /// <param name="infoFilePath">Path to the .txt file which is generated from the debugger</param>
82
        /// <param name="f32RemExecutable">Path to the t32rem.exe file which is used to send commands to the debugger</param>
83
        /// <param name="f32RemArguments">Arguments (commands) sent to the debugger in order to generate a .txt file containing all the desired information.</param>
84
        /// <param name="f32SuccessExitCode">Status code indicating a successful termination of t32rem.exe</param>
85
        /// <param name="f32WaitTimeoutMs">Timeout used when waiting for the t32rem.exe to finish</param>
86
        public InfoFetcher(uint maxAttempts, uint waitPeriodMs, string infoFilePath, string f32RemExecutable,
87
            string[] f32RemArguments, int f32SuccessExitCode, int f32WaitTimeoutMs) {
88
            // Store the parameters into the class variables.
89
            _maxAttempts = maxAttempts;
90
            _waitPeriodMs = waitPeriodMs;
91
            _infoFilePath = infoFilePath;
92
            _f32RemExecutable = f32RemExecutable;
93
            _f32RemArguments = f32RemArguments;
94
            _f32SuccessExitCode = f32SuccessExitCode;
95
            _f32WaitTimeoutMs = f32WaitTimeoutMs;
96
            
97
            // Create an instance of ProcessUtils.
98
            ProcessUtils = new ProcessUtils();
99
            
100
            // Create an instance of FileUtils.
101
            FileUtils = new FileUtils();
102
        }
103

    
104
        /// <summary>
105
        /// Fetches data from the debugger. It sends the commands defined
106
        /// in the appsettings.json file to the debugger and tries to
107
        /// parse the .txt (contains the serial numbers).
108
        /// </summary>
109
        /// <returns>True, if data was fetched successfully. False otherwise.</returns>
110
        public async Task<bool> FetchDataAsync() {
111
            Program.DefaultLogger.Info("Fetching data from the debugger.");
112
            
113
            // Send the commands to the debugger.
114
            var success = SendRetrieveInfoCommands(_f32RemExecutable, _f32RemArguments, _f32SuccessExitCode, _f32WaitTimeoutMs);
115
            
116
            // Make sure that all commands were sent and executed successfully.
117
            if (!success) {
118
                Program.DefaultLogger.Error("Failed to fetch data from the debugger.");
119
                return false;
120
            }
121
            
122
            // Periodically try to parse the .txt file. 
123
            for (var i = 0; i < _maxAttempts; i++) {
124
                Program.DefaultLogger.Info($"{i}. attempt to parse the info file.");
125
                
126
                // Try to parse .txt file.
127
                if (RetrieveDebuggerInfo(_infoFilePath)) {
128
                    Program.DefaultLogger.Info($"Info file has been parsed successfully.");
129
                    return true;
130
                }
131
                // Wait for a specified number of milliseconds.
132
                await Task.Delay((int)_waitPeriodMs);
133
            }
134
            Program.DefaultLogger.Error("Failed to parse the into file. It may have not been created.");
135
            return false;
136
        }
137

    
138
        /// <summary>
139
        /// Tries to retrieve information from the debugger.
140
        /// </summary>
141
        /// <param name="filePath">path to the .txt file that contains all information</param>
142
        /// <returns>True if the information was retrieved successfully. False, otherwise.</returns>
143
        private bool RetrieveDebuggerInfo(string filePath) {
144
            try {
145
                // Read the content of the .txt file.
146
                var fileContent = FileUtils.ReadFileAllLines(filePath).Aggregate("", (current, line) => $"{current}{line}\n");
147
                
148
                // Parse it (try to find the serial numbers)
149
                var (headSerialNumber, bodySerialNumber) = DebuggerInfoParser.Parse(fileContent);
150
                
151
                // Store the serial numbers into class variables (properties)
152
                HeadSerialNumber = headSerialNumber;
153
                BodySerialNumber = bodySerialNumber;
154
                
155
                // Finally, delete the file.
156
                File.Delete(filePath);
157
            } catch (Exception exception) {
158
                Program.DefaultLogger.Error($"Failed to retrieve debugger info. File {filePath} may not exist or it does not have the right format. {exception.Message}");
159
                return false;
160
            }
161
            return true;
162
        }
163

    
164
        /// <summary>
165
        /// Sends commands to the debugger.
166
        /// </summary>
167
        /// <param name="executableFile">Path to the t32rem.exe file</param>
168
        /// <param name="arguments">Arguments sent to the debugger through t32rem.exe (one argument is one command)</param>
169
        /// <param name="desiredExitCode">Status code indicating successful termination of t32rem.exe</param>
170
        /// <param name="waitTimeoutMs">Timeout used when waiting for t32rem.exe to finish</param>
171
        /// <returns>True if all the commands were executed successfully. False, otherwise.</returns>
172
        private bool SendRetrieveInfoCommands(string executableFile, IReadOnlyList<string>? arguments, int desiredExitCode, int waitTimeoutMs) {
173
            if (arguments == null) {
174
                Program.DefaultLogger.Error($"Failed to run {executableFile} - no parameters were given");
175
                return false;
176
            }
177
            // Execute one all arguments (commands) one by one.
178
            foreach (var argument in arguments) {
179
                if (!ProcessUtils.ExecuteNewProcess(executableFile, argument, waitTimeoutMs, desiredExitCode)) {
180
                    return false;
181
                }
182
            }
183
            return true;
184
        }
185
    }
186
}
(5-5/7)