GPAL - Generally Positive Automation Library v1.0
GPAL The Fluent Automation LIbrary
Loading...
Searching...
No Matches
BrowserSettings.cs
1// =============================================================================
2// GPAL - Generally Positive Automation Library
3// Copyright © 2026 Software Decisions, Inc. All rights reserved.
4//
5// This file is part of GPAL.
6// Licensed under the Business Source License 1.1
7//
8// Primary development, architecture, and vision by Michael B. Vederman,
9// CEO of Software Decisions, Inc., Texas.
10//
11// Internal development maintained privately.
12// Public releases appear on GitHub: https://github.com/SoftwareDecisionsInc/GPAL.
13//
14// See LICENSE for full terms, including Additional Use Grant.
15// =============================================================================
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21using System.Threading.Tasks;
22using System.Windows.Forms;
23using OpenQA.Selenium;
24using static GenerallyPositive.Enums;
25using System.Drawing;
26using System.Xml;
27using System.Diagnostics;
28using System.IO.Pipes;
29using System.IO;
30using Newtonsoft.Json.Linq;
31
33{
34 internal class TabInfo
35 {
36 public string URL { get; set; }
37 public bool ActiveTab { get; set; }
38
39 public TabInfo() { }
40 }
41 internal class URLInfo
42 {
43 public int TabId { get; set; }
44 public bool ActiveTab { get; set; }
45
46 public URLInfo() { }
47 }
48 public class BrowserSettings
49 {
50 internal IBrowser Browser { get; set; }
51 // Suppresses script-failure events for this browser only. Set while waiting on document ready, where a
52 // loading page rejecting script is expected
53 internal bool SuppressJavaScriptFailures { get; set; } = false;
54
55 internal bool ObeyRobotsTxt { get; set; } = false;
56 internal bool RespectRobotMetaTags { get; set; } = false;
57
58 internal List<string> RobotsTxt { get; set; }
59 internal Dictionary<int, TabInfo> TabIdsToURL { get; set; } = new Dictionary<int, TabInfo>(); // tabId > url, activeTab
60 internal Dictionary<string, URLInfo> URLsToTabId { get; set; } = new Dictionary<string, URLInfo>(); // ulr > tabId, activeTab
61 internal Dictionary<string, WindowInfo> WindowIdsToURL { get; set; } = new Dictionary<string, WindowInfo>();
62 // name of this browser instance, set by GPAL factory
63 internal string BrowserName { get; set; } = null;
64 internal string DriverLocation { get; set; } = null;
65 internal int ServiceDriverPid { get; set; } = 0;
66 // load images on a web page?
67 internal bool LoadImages { get; set; } = true;
68 // open pdf documents in external program?
69 internal bool OpenPDFExternally { get; set; } = false;
70 // open file save dialog
71 internal bool PromptForDownload { get; set; } = true;
72
73 // what to answer an alert, confirm or prompt the page raises. null leaves them alone, so they open and
74 // block the way they would for a person. set, and the browser answers them without anyone seeing one
75 internal bool? DialogsAccepted { get; set; } = null;
76
77 // what a prompt hands back when dialogs are accepted. null lets the prompt's own default stand
78 internal string DialogText { get; set; } = null;
79
80 // handlers for failures this browser is asked to decide about. Empty means fall through to the global ones
81 internal List<Browser.CallOnFailDelegate> CallOnFail { get; set; } = new List<Browser.CallOnFailDelegate>();
82
83 // who this browser is, supplied by .WithCredentials, acted on once at the first navigation. Whatever
84 // mechanism carries it, basic and proxy and bearer all persist for the session, so it is presented once
85 internal ICredentials Credentials { get; set; }
86 internal DateTime? CredentialsPresented { get; set; }
87 // filetypes to download, not open
88 internal List<string> DownloadFileTypeList { get; set; } = null;
89 // filetypes to open, not download
90 internal List<string> OpenFileTypeList { get; set; } = null;
91 // when performing an action, do we wait on document.ready?
92 internal bool WaitOnDocumentReady { get; set; } = true;
93 internal bool WaitOnNetworkIdle { get; set; } = false;
94 internal int NetworkIdleTimeoutMs { get; set; } = 30_000;
95 internal int NetworkIdleMaxConnections { get; set; } = 0;
96 internal int NetworkIdlePruneMs { get; set; } = 3_000;
97 internal bool TempProfileCreated { get; set; } = false; // so we know to delete it later
98 internal bool DownloadBehaviorSet { get; set; } = false; // we pointed the browser's downloads at our own directory, so it gets handed back when we close
99 internal Dictionary<string, JToken> PreviousDownloadPreferences { get; set; } = null; // the supplied profile's download settings as we found them, put back once the browser is gone
100
101 internal Dictionary<string, string> PreviousFirefoxPreferences { get; set; } = null; // the same for a firefox profile's user.js, which is where its download and pdf settings live
106 internal string ProfileDataDirectory { get; set; }
107 internal string ProfileName { get; set; }
108 internal string ProfileUserName { get; set; }
109 // current browser type
110 internal BrowserType BrowserType { get; set; } = BrowserType.Chrome;
111 internal string PlatformName { get; set; } = "Windows 10";
112
113 // whether to connect to existing browser to start controlling something on-screen
114 internal bool UseExistingBrowser { get; set; } = false;
115 internal int? ExistingBrowserPort { get; set; } = null;
116
117 // for using/connecting to an already open browser
118 internal int? DebugPort { get; set; }
119 internal bool DebugPipe { get; set; }
120 public PipeStream InboundPipe { get; set; } // Parent writes, Chrome reads
121 public PipeStream OutboundPipe { get; set; } // Parent reads, Chrome writes
122 public PipeStream ErrorPipe { get; set; } // Parent error, Chrome writes
123 internal string PuppeteerUrl { get; set; }
124
125 // asked for by .CaptureCalls, which can be said before there is a browser to say it to. read when the
126 // communicator comes up, so recording starts with the first request the first page makes
127 internal bool CaptureCalls { get; set; } = false;
128
129 // set by .WithCallFilter. when there is one, only calls whose url holds it are recorded, which keeps a
130 // long run from accumulating every image a page asked for
131 internal string CallFilter { get; set; }
132
133 // so an engine that cannot capture says so once rather than on every ask
134 internal bool CaptureUnavailableReported { get; set; } = false;
135
136 PuppeteerCommunicator _puppeteerCommunicator = null;
137
138 // whether there is one already, asked without the getter below building one. reaching for a communicator
139 // before the browser is up starts it connecting to a debug port nothing is listening on yet
140 internal bool HasPuppeteerCommunicator => null != _puppeteerCommunicator;
141
142 internal PuppeteerCommunicator PuppeteerCommunicator
143 {
144 get
145 {
146 if (null == _puppeteerCommunicator && true == UsePuppeteer)
147 {
148 if (null == PuppeteerUrl)
149 {
150 // no port means this browser has not been launched, and the default is not a spare: it is
151 // the port the first browser of the run took. pointed there, this one attaches to that
152 // browser and drives it, and both workflows quietly share a session. a port of our own
153 // that nothing is listening on fails to connect instead, which is the honest answer
154 int ours = BrowserHelper.FindFreePort();
155
156 GPAL.PublishSimpleEvent(GPALEventType.ERROR, $"A Puppeteer connection was asked for before [{BrowserType}] had a debugging port, so it is pointed at [{ours}] where nothing is listening rather than at another browser", this, GPALObjectType.Browser);
157
158 PuppeteerUrl = $"http://localhost:{ours}";
159 }
160
161 // .CaptureCalls can be said before there is a browser, so what was asked for is handed to
162 // the communicator as it is built. it connects and attaches inside its constructor, so
163 // setting this afterwards would be too late for the page it attaches to
164 _puppeteerCommunicator = new PuppeteerCommunicator(PuppeteerUrl, Browser, DebugPipe, CaptureCalls);
165 }
166 else if (null == _puppeteerCommunicator && false == UsePuppeteer)
167 {
168 // for example, if we are in debugger and inspect browser, it will attempt to resolve. built
169 // once like the other one, rather than replaced on every read
170 _puppeteerCommunicator = new PuppeteerCommunicator();
171 }
172
173 return _puppeteerCommunicator;
174 }
175 set
176 {
177 _puppeteerCommunicator = value;
178 }
179 }
180 internal IPuppeteerClient PuppeteerClient
181 {
182 get => PuppeteerCommunicator?.PuppeteerClient;
183 set => PuppeteerCommunicator.PuppeteerClient = value;
184 }
185 internal bool FullScreen { get; set; } = false;
186 internal bool Maximize { get; set; } = false;
187 internal bool Minimize { get; set; } = false;
188 public bool UseHardware { get => AutomationEngine.OttoMagicHW == AutomationEngine || AutomationEngine.PuppeteerPipeHW == AutomationEngine || AutomationEngine.PuppeteerPortHW == AutomationEngine || AutomationEngine.SeleniumHW == AutomationEngine; }
189 public bool UseJavaScript { get => AutomationEngine.OttoMagic == AutomationEngine || AutomationEngine.SeleniumJS == AutomationEngine; }
190 public bool UseOttoMagic { get => AutomationEngine.OttoMagic == AutomationEngine || AutomationEngine.OttoMagicHW == AutomationEngine; }
191 public bool UsePuppeteer { get => AutomationEngine.PuppeteerPipe == AutomationEngine || AutomationEngine.PuppeteerPort == AutomationEngine || AutomationEngine.PuppeteerPortHW == AutomationEngine || AutomationEngine.PuppeteerPipeHW == AutomationEngine; }
192 public bool UseSelenium { get => AutomationEngine.Selenium == AutomationEngine || AutomationEngine.SeleniumJS == AutomationEngine || AutomationEngine.SeleniumHW == AutomationEngine; }
193
194 public AutomationEngine AutomationEngine { get; set; } = AutomationEngine.PuppeteerPort;
195
196 // run on a Win32 desktop object rather than the one the user is looking at
197 internal bool HiddenDesktop { get; set; } = false;
198
199 // set by the browser image search while it runs: true when the match is made against the page rather than
200 // the screen, so CaptureScreen asks the engine for its own capture. false the rest of the time
201 internal bool ImageSearchInPage { get; set; } = false;
202
203 // which one. browsers naming the same desktop share it, and browsers naming different ones get one each
204 // filled in by WithHiddenDesktop: a name of this browser's own when none was given, or the name it was
205 // given. the value here only stands until one of those is called
206 internal string HiddenDesktopName { get; set; } = GenerallyPositive.Browser.HiddenDesktop.DefaultName;
207
208 // whether what a hidden desktop means for this browser has been worked out and said. WorkflowSetup runs
209 // on every action, and the engine it settles on is worth saying once rather than on all of them
210 internal bool HiddenDesktopReported { get; set; } = false;
211
212 // whether the desktop has been asked what actually arrived on it, which is worth doing once after the
213 // launch rather than on every action afterwards
214 internal bool HiddenDesktopChecked { get; set; } = false;
215
216 // whether hardware being turned down on this desktop has been said. a workflow on a hidden desktop
217 // resolves nearly every selector, and saying it each time buries the log
218 internal bool HiddenDesktopHardwareReported { get; set; } = false;
219 internal int WaitForDocumentReadyTimeoutMs { get; set; } = 30_000;
220
221 // how long a click waits to see whether it started a navigation. Only covers the browser committing the
222 // new url, not loading it - CheckDocumentReady owns the loading half once we know we are going somewhere
223 internal int NavigationGraceMs { get; set; } = 250;
224
225 internal int WithAllThatMatch { get; set; } = int.MaxValue; // all rows, default
226
227 internal string RestApiBaseUrl { get; set; }
228 // true when a workflow handed us the address rather than a browser announcing it, which means the
229 // browser was started by someone else and is not ours to launch, top or kill
230 internal bool AttachedRestApi { get; set; }
231
232 internal IMagicHelper _magicHelper = null;
239 {
240 get => _magicHelper;
241
242 internal set => _magicHelper = value;
243 }
244
252 internal void DetachFromRunningBrowser(Browser browser)
253 {
254 Browser = browser;
255 BrowserDriver = null;
256 Process = null;
257 RestApiBaseUrl = null;
258 _magicHelper = new MagicHelper(browser);
259 _puppeteerCommunicator = null;
260 }
261 internal StealthType StealthType { get; set; } = StealthType.None;
262 internal bool StealthApplied { get; set; } = false;
263 internal string CurrentURL { get; set; }
264 private GPALUrl _currentGPALUrl = null;
265 internal GPALUrl CurrentGPALUrl
266 {
267 get => _currentGPALUrl;
268 set
269 {
270 _currentGPALUrl = value;
271 StorageActionToRun = new StorageAction(); // any time we set this, we reset the action to run, but this doesn't help us clear values from a prior call
272 }
273 }
274 internal List<GPALUrl> GPALUrlList { get; set; }
275 internal string Referrer { get; set; } = null;
276 internal string OverrideUserAgent { get; set; } = null;
277
278 // launch a browser purely to read its real user agent, rather than working one out without one. Off by
279 // default: a headless start should not pay for a browser nobody asked for
280 internal bool UserAgentFromBrowser { get; set; } = false;
281 internal Selector CurrentSelector { get; set; } = null;
282 internal IWebDriver BrowserDriver { get; set; } = null;
283 internal System.Windows.Forms.Form CurrentForm { get; set; } = null;
284 internal int WaitForWindowTimeoutInSeconds { get; set; } = 30; // seconds
285 internal bool BlockPopUps { get; set; } = true;
286 internal int DownloadTimeoutInSec { get; set; } = 10;
287 internal bool UseDirectDownload { get; set; } = false;
288 internal string DownloadLocation { get; set; }
289 internal bool DeleteFileBeforeDownload { get; set; } = false;
290 internal bool OpenInTab { get; set; } = false; // caveat: note: only good for one GoTo
291 internal bool UseHeadless { get; set; } = false;
292 internal bool? FileDownloaded { get; set; }
293 internal bool ScrollIntoView { get; set; } = false;
294 internal Rectangle WindowSize { get; set; }
295 internal Size SavedWindowSize { get; set; }
296 internal PageOrientation PageOrientation { get; set; }
297 internal object JavaScriptResultObj { get; set; }
298 internal string JavaScriptResultStr { get; set; }
299 internal StorageAction StorageActionToRun { get; set; }
300 internal bool StorageActionCalled { get; set; }
301
302 internal string Version = string.Empty;
303 internal int ServerResponseCode { get; set; }
304
305 internal Bitmap ScreenShot;
306 internal Process Process { get; set; } = null; // set when using ottomatic/magic which launches the browser without a driver
307 internal int WhileLoopTimeoutMs { get; set; } = 30000; // Default: 30 seconds
308 internal int WhileLoopMaxIterations { get; set; } = 1000; // Default: 1000 iterations
309 internal List<Action<IBrowser>> Workflows { get; set; }
310 internal BrowserSettings(Browser browser)
311 {
312 DownloadFileTypeList = new List<string>();
313 OpenFileTypeList = new List<string>();
314 WindowSize = new Rectangle();
315 SavedWindowSize = new Size();
316 Workflows = new List<Action<IBrowser>>();
317 Browser = browser;
318 PageOrientation = PageOrientation.Portrait;
319 RobotsTxt = new List<string>();
320 StorageActionToRun = new StorageAction();
321 StorageActionCalled = false;
322 GPALUrlList = new List<GPALUrl>();
323 }
324 }
325}
326
Browser object that contains the fluent methods to create your Browser workflow. Instatiated using G...
Definition Browser.cs:68
IMagicHelper MagicHelper
This browser's own MagicHelper, talking to this browser's OttoMagic port. Assigned when the browser i...
Everything starts here, all the GPAL controls and global settings using fluent syntax are here....
Definition GPAL.cs:49
static void PublishSimpleEvent(GPALEventType gPALEventType, string msg, dynamic gPALObject=null, Enums.GPALObjectType gPALObjectType=GPALObjectType.None, Exception ex=null)
Publish a message to either the information channel or exception channel (if exception passed in) Pub...
Definition GPAL.cs:2568