18using Newtonsoft.Json.Linq;
21using System.Collections.Generic;
22using System.Diagnostics;
24using System.IO.Compression;
28using System.Threading.Tasks;
33 internal static class DriverHelper
35 static IBrowser browser =
null;
36 static string chromeVersionForSelector =
string.Empty;
37 static string edgeVersionForSelector =
string.Empty;
38 static bool updateSuccess =
false;
39 static GPALFile versionFile;
40 static string version =
string.Empty;
42 static Selector showMoreFiles = GPAL.Selector.WithXPath(GPAL.GPALSettings.FirefoxDriverShowAllXpath).WithSelectorName(
"ShowMoreFilesFF").ToGPALObject();
44 public static void UpdateDriver(BrowserSettings browserSettings)
46 Selector tdSelector =
null;
48 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Driver Auto Update running for [{browserSettings.BrowserType}]", browserSettings, GPALObjectType.Other);
52 if (BrowserType.FireFox == browserSettings.BrowserType)
54 UpdateFirefoxDriver(browserSettings);
59 GPAL.
Browser.
WithBrowserType(browserSettings.BrowserType).WithOpenPDFExternally(
false).WithDriverLocation(browserSettings.DriverLocation).ToGPALObject();
61 if (
false ==
string.IsNullOrEmpty(browserSettings.ProfileDataDirectory))
62 browser.WithProfileDataDirectory(browserSettings.ProfileDataDirectory);
65 .WithAutomationEngine(browserSettings.AutomationEngine);
67 switch (browser.BrowserType)
69 case Enums.BrowserType.Chrome:
70 chromeVersionForSelector = GetChromeVersion(out version);
71 tdSelector = CreateChromeSelector();
72 url = GPAL.GPALSettings.ChromeDriverUpdateURL;
74 case Enums.BrowserType.Edge:
75 edgeVersionForSelector = GetEdgeVersion(out version);
76 tdSelector = CreateEdgeSelector();
77 url = GPAL.GPALSettings.EdgeDriverUpdateURL;
79 case Enums.BrowserType.FireFox:
80 GetFirefoxVersion(out version);
81 tdSelector = CreateFirefoxSelector();
82 url = GPAL.GPALSettings.FirefoxDriverUpdateURL;
86 IGPALGrid<string> lastUpdatedVersion = GPAL.Grid.ToGPALObject();
87 string driverLocation = FileHelper.EnsureDirectoryEndsWithBackslash(browserSettings.DriverLocation);
90 string yamlFile = Path.Combine(driverLocation, $
"{browserSettings.BrowserType}.version.yaml");
91 versionFile = yamlFile;
92 GPAL.Converter.WithInput(versionFile).SaveTo(ref lastUpdatedVersion);
94 if (
true == lastUpdatedVersion.Contains(version))
96 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Web driver already current for version [{version}]");
100 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Attempting to update web driver for browser version [{version}]");
105 if (BrowserType.FireFox == browserSettings.BrowserType)
107 browser.LeftClick(showMoreFiles)
112 .WithSelector(tdSelector)
125 private static void UpdateFirefoxDriver(BrowserSettings browserSettings)
127 string path = FileHelper.EnsureDirectoryEndsWithBackslash(browserSettings.DriverLocation);
128 string driver = GPAL.GPALSettings.FirefoxDriverFilename;
129 string zipFilename = GPAL.GPALSettings.FirefoxDriverZipFilename;
130 string[] nameParts = zipFilename.Split(
'*');
131 string installed = GetGeckodriverVersion($
"{path}{driver}");
133 url = GPAL.GPALSettings.FirefoxDriverUpdateURL;
134 versionFile = Path.Combine(path, $
"{BrowserType.FireFox}.version.yaml");
138 using (HttpClient httpClient =
new HttpClient())
140 httpClient.DefaultRequestHeaders.Add(
"User-Agent", MagicHelper.GetUserAgentString(BrowserType.FireFox));
142 JObject release = JObject.Parse(httpClient.GetStringAsync(url).Result);
143 string latest = release[
"tag_name"]?.ToString().TrimStart(
'v');
145 JToken asset = release[
"assets"]?.FirstOrDefault(a =>
146 true == a[
"name"].ToString().StartsWith(nameParts[0], StringComparison.OrdinalIgnoreCase) &&
147 true == a[
"name"].ToString().EndsWith(nameParts[nameParts.Length - 1], StringComparison.OrdinalIgnoreCase));
149 if (
true ==
string.Equals(installed, latest, StringComparison.OrdinalIgnoreCase))
150 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Web driver already current for geckodriver [{installed}]", browserSettings, GPALObjectType.Browser);
151 else if (
null == asset)
153 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $
"Geckodriver [{latest}] publishes no asset matching [{zipFilename}]", browserSettings, GPALObjectType.Browser);
154 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $
"Please update driver manually at [{url}]", browserSettings, GPALObjectType.Browser);
157 DownloadAndExtractDriver(asset[
"browser_download_url"].ToString(), path, zipFilename.Replace(
"*",
""), driver, latest);
162 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION, $
"Unable to check for a geckodriver update at [{url}]", browserSettings, GPALObjectType.Browser, ex);
171 private static string GetGeckodriverVersion(
string driverPath)
173 string installed =
null;
175 if (
true == File.Exists(driverPath))
177 Process process = Process.Start(
new ProcessStartInfo
179 FileName = driverPath,
180 Arguments =
"--version",
181 RedirectStandardOutput =
true,
182 UseShellExecute =
false,
183 CreateNoWindow =
true
186 string[] parts = (process.StandardOutput.ReadLine() ??
string.Empty).Split(
' ');
187 process.WaitForExit();
189 if (1 < parts.Length)
190 installed = parts[1];
203 private static void DownloadAndExtractDriver(
string href,
string path,
string zipFilename,
string driver,
string driverVersion)
205 File.Delete($
"{path}{zipFilename}");
206 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Trying to download driver [{href}] to [{$"{path}{zipFilename}
"}]");
208 using (HttpClient httpClient =
new HttpClient())
210 httpClient.DefaultRequestHeaders.Add(
"User-Agent", MagicHelper.GetUserAgentString(BrowserType.FireFox));
211 File.WriteAllBytes($
"{path}{zipFilename}", httpClient.GetByteArrayAsync(href).Result);
214 using (ZipArchive archive = ZipFile.OpenRead($
"{path}{zipFilename}"))
216 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Extracting [{driver}] from zip file");
218 ZipArchiveEntry entryToExtract = archive.Entries.FirstOrDefault(e => e.Name.Equals(driver, StringComparison.OrdinalIgnoreCase));
220 if (
null != entryToExtract)
222 string destinationFilePath = Path.Combine(path, entryToExtract.Name);
224 if (
true == File.Exists(destinationFilePath))
225 File.Delete(destinationFilePath);
227 entryToExtract.ExtractToFile(destinationFilePath);
231 File.Delete($
"{path}{zipFilename}");
233 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"[{BrowserType.FireFox}] web driver updated to geckodriver [{driverVersion}]");
235 IGPALGrid<string> gPALGrid = GPAL.Grid.ToGPALObject();
236 gPALGrid.AddRow(
new List<string> { BrowserType.FireFox.ToString(), driverVersion });
238 GPAL.Converter.WithInput(gPALGrid).SaveTo(versionFile);
240 public static CallIfStatus CallIfFound(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector,
bool matchedAll)
242 if (
true == updateSuccess)
243 return CallIfStatus.Handled;
246 GPALElement webElement = (GPALElement)matchedElements[0];
248 string href =
string.Empty;
249 string path = ((Browser)browser).BrowserSettings.DriverLocation ??
".\\";
250 string filename =
string.Empty;
251 string driver =
string.Empty;
253 switch (browser.BrowserType)
255 case Enums.BrowserType.Chrome:
256 filename = GPAL.GPALSettings.ChromeDriverZipFilename;
257 driver = GPAL.GPALSettings.ChromeDriverFilename;
258 href = webElement.Text;
260 case Enums.BrowserType.Edge:
261 filename = GPAL.GPALSettings.EdgeDriverZipFilename;
262 driver = GPAL.GPALSettings.EdgeDriverFilename;
263 href = webElement.GetAttribute(
"href");
265 case Enums.BrowserType.FireFox:
266 filename = GPAL.GPALSettings.FirefoxDriverZipFilename;
267 driver = GPAL.GPALSettings.FirefoxDriverFilename;
268 href = webElement.GetAttribute(
"href");
276 filename = filename.Replace(
"*",
"");
278 File.Delete($
"{path}{filename}");
279 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Trying to download driver [{href}] to [{$"{path}{filename}
"}]");
283 using (HttpClient httpClient =
new HttpClient())
285 httpClient.DefaultRequestHeaders.Add(
"User-Agent", MagicHelper.GetUserAgentString(browser.BrowserType));
286 byte[] data = httpClient.GetByteArrayAsync(href).Result;
287 File.WriteAllBytes($
"{path}{filename}", data);
288 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"[{$"{path}{filename}
"}] downloaded");
293 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION, $
"Unable to download from [{href}]", browser, GPALObjectType.Browser, ex);
296 if (
true == File.Exists($
"{path}{filename}"))
298 using (ZipArchive archive = ZipFile.OpenRead($
"{path}{filename}"))
300 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Extracting [{driver}] from zip file", browser, GPALObjectType.Browser);
302 ZipArchiveEntry entryToExtract = archive.Entries.FirstOrDefault(e => e.Name.Equals(driver, StringComparison.OrdinalIgnoreCase));
304 if (entryToExtract !=
null)
306 string destinationFilePath = Path.Combine(path, entryToExtract.Name);
308 if (File.Exists(destinationFilePath))
309 File.Delete(destinationFilePath);
311 entryToExtract.ExtractToFile(destinationFilePath);
315 File.Delete($
"{path}{filename}");
316 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"[{browser.BrowserType}] web driver updated for version [{version}]. NOTE: Geckodriver is not tied to browser version.", browser, Enums.GPALObjectType.Browser);
317 IGPALGrid<string> gPALGrid = GPAL.Grid.ToGPALObject();
318 gPALGrid.AddRow(
new List<string> { browser.BrowserType.ToString(), version });
320 GPAL.Converter.WithInput(gPALGrid).SaveTo(versionFile);
324 return CallIfStatus.Handled;
326 public static CallIfStatus CallIfNotFound(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector,
bool matchedAll)
328 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $
"Auto web driver update unable to find driver for version [{version}]", browser, Enums.GPALObjectType.Browser);
329 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $
"Please update driver manually at [{url}]", browser, Enums.GPALObjectType.Browser);
332 return CallIfStatus.Handled;
334 private static Selector CreateSelector(
string xpathExpression)
337 .WithXPath(xpathExpression)
338 .CallIfNotFound(CallIfNotFound)
339 .CallIfFound(CallIfFound)
340 .WithSelectorName(
"DriverDownloadSelector")
343 private static Selector CreateChromeSelector()
345 string xpathExpression = GPAL.GPALSettings.ChromeDriverXpathExpression.Replace(
"@chromeVersionForSelector", chromeVersionForSelector).Replace(
"@chromeDriverZipFileName", GPAL.GPALSettings.ChromeDriverZipFilename);
346 return CreateSelector(xpathExpression);
348 internal static string GetChromeVersion(out
string fullVersion)
350 string version =
null;
351 RegistryKey regKey =
null;
355 regKey = Registry.CurrentUser.OpenSubKey(GPAL.GPALSettings.ChromeVersionRegistry);
356 version = regKey.GetValue(
"version").ToString();
360 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION,
"Unable to get Chrome version from registry",
null, Enums.GPALObjectType.None, ex);
366 fullVersion = version;
368 return string.Join(
".", version.Split(
'.').Take(3));
370 private static Selector CreateEdgeSelector()
372 string xpathExpression = GPAL.GPALSettings.EdgeDriverXpathExpression.Replace(
"@edgeDriverZipFilename", GPAL.GPALSettings.EdgeDriverZipFilename).Replace(
"@edgeVersionForSelector", edgeVersionForSelector);
373 return CreateSelector(xpathExpression);
375 internal static string GetEdgeVersion(out
string fullVersion)
377 string version =
null;
378 RegistryKey regKey =
null;
382 regKey = Registry.CurrentUser.OpenSubKey(GPAL.GPALSettings.EdgeVersionRegistry);
383 version = regKey.GetValue(
"version").ToString();
387 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION,
"Unable to get Edge version from registry",
null, Enums.GPALObjectType.None, ex);
394 fullVersion = version;
395 return version.Split(
'.')[0];
397 private static Selector CreateFirefoxSelector()
399 string[] nameParts = GPAL.GPALSettings.FirefoxDriverZipFilename.Split(
'*');
400 string xpathExpression = GPAL.GPALSettings.FirefoxDriverXpath.Replace(
"@firefoxDriverName1", nameParts[1]);
401 Selector tmpSelector = CreateSelector(xpathExpression);
402 tmpSelector.ContainsHRef(nameParts[1]);
406 internal static string GetFirefoxVersion(out
string fullVersion)
408 string version =
null;
409 RegistryKey regKey =
null;
413 regKey = Registry.CurrentUser.OpenSubKey(GPAL.GPALSettings.FirefoxVersionRegistry);
414 version = regKey.GetValue(
"CurrentVersion")?.ToString();
415 if (
true ==
string.IsNullOrEmpty(version))
417 regKey = Registry.CurrentUser.OpenSubKey(GPAL.GPALSettings.FirefoxVersionRegistry2);
418 version = regKey.GetValue(
"CurrentVersion")?.ToString();
423 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION,
"Unable to get Firefox version from registry",
null, Enums.GPALObjectType.None, ex);
429 fullVersion = version;
431 return version.Split(
'.')[0];
Browser object that contains the fluent methods to create your Browser workflow. Instatiated using G...
IAllowBrowserSettingsOrGoTo WithBrowserType(BrowserType browserType)
Specify which browser to run the workflow in. NOTE: Chrome and Edge act mostly the same,...