Projekt

Obecné

Profil

Stáhnout (8.5 KB) Statistiky
| Větev: | Tag: | Revize:
1 f281acac silhavyj
using System.Diagnostics;
2 0932a9e2 Pultak
using LDClient.utils;
3 19c2a5c4 Pultak
using LDClient.utils.loggers;
4 f281acac silhavyj
5
namespace LDClient.detection {
6
7 f63d5489 silhavyj
    /// <summary>
8
    /// This class implements the IInfoFetcher interface
9
    /// which defines the functionality of an info fetcher.
10
    /// </summary>
11 0932a9e2 Pultak
    public class InfoFetcher : IInfoFetcher {
12 6dab0250 silhavyj
        
13 f63d5489 silhavyj
        /// <summary>
14
        /// Default value of a serial number (undefined).
15
        /// </summary>
16 f281acac silhavyj
        private const string UndefinedSerialNumber = "number";
17
18 f63d5489 silhavyj
        /// <summary>
19
        /// Path to the t32rem.exe file which is used to send commands to the debugger.
20
        /// </summary>
21 6dab0250 silhavyj
        private readonly string _f32RemExecutable;
22 f63d5489 silhavyj
        
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 4dcc6c07 silhavyj
        private readonly string[] _f32RemArguments;
28 f63d5489 silhavyj
        
29
        /// <summary>
30
        /// Status code indicating a successful termination of t32rem.exe
31
        /// </summary>
32 4dcc6c07 silhavyj
        private readonly int _f32SuccessExitCode;
33 f63d5489 silhavyj
        
34
        /// <summary>
35
        /// Timeout used when waiting for the t32rem.exe to finish.
36
        /// </summary>
37 4dcc6c07 silhavyj
        private readonly int _f32WaitTimeoutMs;
38 f63d5489 silhavyj
        
39
        /// <summary>
40
        /// Maximum number of attempts to locate and parse the .txt file.
41
        /// </summary>
42 6dab0250 silhavyj
        private readonly uint _maxAttempts;
43 f63d5489 silhavyj
        
44
        /// <summary>
45
        /// Period (how often) the application tries to locate and parse the .txt file.
46
        /// </summary>
47 6dab0250 silhavyj
        private readonly uint _waitPeriodMs;
48 f63d5489 silhavyj
        
49
        /// <summary>
50
        /// Path to the .txt file which is generated from the debugger.
51
        /// </summary>
52 f281acac silhavyj
        private readonly string _infoFilePath;
53
54 f63d5489 silhavyj
        /// <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 0932a9e2 Pultak
        public IProcessUtils ProcessUtils;
59 f63d5489 silhavyj
        
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 0932a9e2 Pultak
        public IFileUtils FileUtils;
65 f281acac silhavyj
66 f63d5489 silhavyj
        /// <summary>
67
        /// Returns the head serial number of the debugger.
68
        /// </summary>
69 0932a9e2 Pultak
        public string HeadSerialNumber { get; set; } = UndefinedSerialNumber;
70 f63d5489 silhavyj
        
71
        /// <summary>
72
        /// Returns the body serial number of the debugger.
73
        /// </summary>
74 0932a9e2 Pultak
        public string BodySerialNumber { get; set; } = UndefinedSerialNumber;
75 f63d5489 silhavyj
        
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 0932a9e2 Pultak
        public InfoFetcher(uint maxAttempts, uint waitPeriodMs, string infoFilePath, string f32RemExecutable,
87
            string[] f32RemArguments, int f32SuccessExitCode, int f32WaitTimeoutMs) {
88 f63d5489 silhavyj
            // Store the parameters into the class variables.
89 f281acac silhavyj
            _maxAttempts = maxAttempts;
90
            _waitPeriodMs = waitPeriodMs;
91
            _infoFilePath = infoFilePath;
92 6dab0250 silhavyj
            _f32RemExecutable = f32RemExecutable;
93
            _f32RemArguments = f32RemArguments;
94 4dcc6c07 silhavyj
            _f32SuccessExitCode = f32SuccessExitCode;
95
            _f32WaitTimeoutMs = f32WaitTimeoutMs;
96 f63d5489 silhavyj
            
97
            // Create an instance of ProcessUtils.
98 0932a9e2 Pultak
            ProcessUtils = new ProcessUtils();
99 f63d5489 silhavyj
            
100
            // Create an instance of FileUtils.
101 0932a9e2 Pultak
            FileUtils = new FileUtils();
102 f281acac silhavyj
        }
103
104 f63d5489 silhavyj
        /// <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 f281acac silhavyj
        public async Task<bool> FetchDataAsync() {
111
            Program.DefaultLogger.Info("Fetching data from the debugger.");
112 f63d5489 silhavyj
            
113
            // Send the commands to the debugger.
114 4dcc6c07 silhavyj
            var success = SendRetrieveInfoCommands(_f32RemExecutable, _f32RemArguments, _f32SuccessExitCode, _f32WaitTimeoutMs);
115 f63d5489 silhavyj
            
116
            // Make sure that all commands were sent and executed successfully.
117 f281acac silhavyj
            if (!success) {
118
                Program.DefaultLogger.Error("Failed to fetch data from the debugger.");
119
                return false;
120
            }
121 f63d5489 silhavyj
            
122
            // Periodically try to parse the .txt file. 
123 f281acac silhavyj
            for (var i = 0; i < _maxAttempts; i++) {
124
                Program.DefaultLogger.Info($"{i}. attempt to parse the info file.");
125 f63d5489 silhavyj
                
126
                // Try to parse .txt file.
127 f281acac silhavyj
                if (RetrieveDebuggerInfo(_infoFilePath)) {
128
                    Program.DefaultLogger.Info($"Info file has been parsed successfully.");
129
                    return true;
130
                }
131 f63d5489 silhavyj
                // Wait for a specified number of milliseconds.
132 6dab0250 silhavyj
                await Task.Delay((int)_waitPeriodMs);
133 f281acac silhavyj
            }
134
            Program.DefaultLogger.Error("Failed to parse the into file. It may have not been created.");
135
            return false;
136
        }
137
138 f63d5489 silhavyj
        /// <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 f281acac silhavyj
        private bool RetrieveDebuggerInfo(string filePath) {
144
            try {
145 f63d5489 silhavyj
                // Read the content of the .txt file.
146 0932a9e2 Pultak
                var fileContent = FileUtils.ReadFileAllLines(filePath).Aggregate("", (current, line) => $"{current}{line}\n");
147 f63d5489 silhavyj
                
148
                // Parse it (try to find the serial numbers)
149 f281acac silhavyj
                var (headSerialNumber, bodySerialNumber) = DebuggerInfoParser.Parse(fileContent);
150 f63d5489 silhavyj
                
151
                // Store the serial numbers into class variables (properties)
152 f281acac silhavyj
                HeadSerialNumber = headSerialNumber;
153
                BodySerialNumber = bodySerialNumber;
154 f63d5489 silhavyj
                
155
                // Finally, delete the file.
156 f281acac silhavyj
                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 f63d5489 silhavyj
        /// <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 0932a9e2 Pultak
        private bool SendRetrieveInfoCommands(string executableFile, IReadOnlyList<string>? arguments, int desiredExitCode, int waitTimeoutMs) {
173 4dcc6c07 silhavyj
            if (arguments == null) {
174
                Program.DefaultLogger.Error($"Failed to run {executableFile} - no parameters were given");
175 f281acac silhavyj
                return false;
176
            }
177 f63d5489 silhavyj
            // Execute one all arguments (commands) one by one.
178 4dcc6c07 silhavyj
            foreach (var argument in arguments) {
179 0932a9e2 Pultak
                if (!ProcessUtils.ExecuteNewProcess(executableFile, argument, waitTimeoutMs, desiredExitCode)) {
180 4dcc6c07 silhavyj
                    return false;
181
                }
182
            }
183 f281acac silhavyj
            return true;
184
        }
185
    }
186
}