/// <summary> /// Starts the IB Gateway /// </summary> /// <param name="waitForExit">true if it should wait for the IB Gateway process to exit</param> /// <remarks>The IB Gateway application will be launched</remarks> public StartResult Start(bool waitForExit) { lock (_locker) { if (_lastStartResult.HasError) { // IBAutomater errors are unrecoverable return(_lastStartResult); } if (IsRunning()) { return(StartResult.Success); } _process = null; _ibAutomaterInitializeEvent.Reset(); if (IsLinux) { // need permission for execution OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs("Setting execute permissions on IBAutomater.sh")); ExecuteProcessAndWaitForExit("chmod", "+x IBAutomater.sh"); } OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"Loading IBGateway version: {_ibVersion}")); var fileName = IsWindows ? "IBAutomater.bat" : "IBAutomater.sh"; var arguments = $"{_ibDirectory} {_ibVersion} {_userName} {_password} {_tradingMode} {_portNumber}"; var process = new Process { StartInfo = new ProcessStartInfo(fileName, arguments) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true }, EnableRaisingEvents = true }; process.OutputDataReceived += (sender, e) => { if (e.Data != null) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(e.Data)); // login failed if (e.Data.Contains("Login failed")) { _lastStartResult = new StartResult(ErrorCode.LoginFailed); _ibAutomaterInitializeEvent.Set(); } // an existing session was detected else if (e.Data.Contains("Existing session detected")) { _lastStartResult = new StartResult(ErrorCode.ExistingSessionDetected); _ibAutomaterInitializeEvent.Set(); } // a security dialog (2FA) was detected by IBAutomater else if (e.Data.Contains("Second Factor Authentication")) { if (e.Data.Contains("[WINDOW_OPENED]")) { // waiting for 2FA confirmation on IBKR mobile app const string message = "Waiting for 2FA confirmation on IBKR mobile app (to be confirmed within 3 minutes)."; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); _twoFactorConfirmationPending = true; } } // a security dialog (code card) was detected by IBAutomater else if (e.Data.Contains("Security Code Card Authentication") || e.Data.Contains("Enter security code")) { _lastStartResult = new StartResult(ErrorCode.SecurityDialogDetected); _ibAutomaterInitializeEvent.Set(); } // initialization completed else if (e.Data.Contains("Configuration settings updated")) { _ibAutomaterInitializeEvent.Set(); } } }; process.ErrorDataReceived += (sender, e) => { if (e.Data != null) { ErrorDataReceived?.Invoke(this, new ErrorDataReceivedEventArgs(e.Data)); } }; process.Exited += (sender, e) => { Exited?.Invoke(this, new ExitedEventArgs(process.ExitCode)); }; try { var started = process.Start(); if (!started) { return(new StartResult(ErrorCode.ProcessStartFailed)); } } catch (Exception exception) { return(new StartResult(ErrorCode.ProcessStartFailed, exception.Message)); } OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"IBAutomater process started - Id:{process.Id}")); _process = process; process.BeginErrorReadLine(); process.BeginOutputReadLine(); if (waitForExit) { process.WaitForExit(); } else { // wait for completion of IBGateway login and configuration string message; if (_ibAutomaterInitializeEvent.WaitOne(TimeSpan.FromSeconds(60))) { message = "IB Automater initialized."; } else { if (_twoFactorConfirmationPending) { // wait for completion of two-factor authentication if (!_ibAutomaterInitializeEvent.WaitOne(TimeSpan.FromMinutes(3))) { _lastStartResult = new StartResult(ErrorCode.TwoFactorConfirmationTimeout); message = "IB Automater 2FA timeout."; } else { // 2FA confirmation successful message = "IB Automater initialized."; } } else { message = "IB Automater initialization timeout."; } } OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); // reset the flag, this method is called multiple times _twoFactorConfirmationPending = false; if (_lastStartResult.HasError) { message = $"IBAutomater error - Code: {_lastStartResult.ErrorCode} Message: {_lastStartResult.ErrorMessage}"; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); return(_lastStartResult); } } } return(StartResult.Success); }
private void OnProcessOutputDataReceived(string text) { if (text != null) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(text)); // login failed if (text.Contains("Login failed")) { if (!IsWithinScheduledServerResetTimes()) { _lastStartResult = new StartResult(ErrorCode.LoginFailed); } _ibAutomaterInitializeEvent.Set(); } // an existing session was detected else if (text.Contains("Existing session detected")) { _lastStartResult = new StartResult(ErrorCode.ExistingSessionDetected); _ibAutomaterInitializeEvent.Set(); } // a security dialog (2FA) was detected by IBAutomater else if (text.Contains("Second Factor Authentication")) { if (text.Contains("[WINDOW_OPENED]")) { // waiting for 2FA confirmation on IBKR mobile app const string message = "Waiting for 2FA confirmation on IBKR mobile app (to be confirmed within 3 minutes)."; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); } } // 2FA timed out for the maximum number of attempts else if (text.Contains("2FA maximum attempts reached")) { const string message = "IB Automater 2FA timeout."; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); _lastStartResult = new StartResult(ErrorCode.TwoFactorConfirmationTimeout); _ibAutomaterInitializeEvent.Set(); } // a security dialog (code card) was detected by IBAutomater else if (text.Contains("Security Code Card Authentication") || text.Contains("Enter security code")) { _lastStartResult = new StartResult(ErrorCode.SecurityDialogDetected); _ibAutomaterInitializeEvent.Set(); } // the IBGateway version is no longer supported else if (text.Contains("is no longer supported")) { _lastStartResult = new StartResult(ErrorCode.UnsupportedVersion); _ibAutomaterInitializeEvent.Set(); } // a Java exception was thrown if (text.StartsWith("Exception")) { TraceIbLauncherLogFile(); _lastStartResult = new StartResult(ErrorCode.JavaException, text); _ibAutomaterInitializeEvent.Set(); } // API support is not available for accounts that support free trading else if (text.Contains("API support is not available")) { _lastStartResult = new StartResult(ErrorCode.ApiSupportNotAvailable); _ibAutomaterInitializeEvent.Set(); } // an unknown message window was detected else if (text.StartsWith("Unknown message window detected")) { TraceIbLauncherLogFile(); _lastStartResult = new StartResult(ErrorCode.UnknownMessageWindowDetected, text); _ibAutomaterInitializeEvent.Set(); } // initialization completed else if (text.Contains("Configuration settings updated")) { // load server name and region LoadIbServerInformation(); _ibAutomaterInitializeEvent.Set(); } // daily restart with no authentication required else if (text.Contains("Restart in progress")) { _isRestartInProgress = true; } // weekly restart with full authentication else if (text.Contains("Auto-restart token expired")) { _isRestartInProgress = false; _ibAutomaterInitializeEvent.Set(); } // authentication/connection in progress if (text.Contains("Window event:")) { _isAuthenticating = text.Contains("Authenticating", StringComparison.InvariantCultureIgnoreCase) || text.Contains("Connecting to server", StringComparison.InvariantCultureIgnoreCase) || text.Contains("server error, will retry", StringComparison.InvariantCultureIgnoreCase); } } }
private void OnProcessExited(object sender, EventArgs e) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs("IBGateway process exited")); if (_isRestartInProgress) { _ibAutomaterInitializeEvent.Reset(); OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs("Waiting for IBGateway auto-restart")); if (!_ibAutomaterInitializeEvent.WaitOne(_initializationTimeout)) { TraceIbLauncherLogFile(); _lastStartResult = new StartResult(ErrorCode.InitializationTimeout); return; } if (_isRestartInProgress) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs("IB Automater initialized.")); // find new IBGateway process (created by auto-restart) var processName = IsWindows ? "ibgateway" : "java"; var process = Process.GetProcessesByName(processName).FirstOrDefault(); if (process == null) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"IBGateway restarted process not found: {processName}")); TraceIbLauncherLogFile(); _lastStartResult = new StartResult(ErrorCode.RestartedProcessNotFound); } else { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"IBGateway restarted process found: Id:{process.Id} - Name:{process.ProcessName}")); // fire Restarted event so the client can reconnect only (without starting IBGateway) Restarted?.Invoke(this, new EventArgs()); process.Exited -= OnProcessExited; // replace process _process = process; // we cannot add output/error redirection event handlers here as we didn't start the process process.Exited += OnProcessExited; process.EnableRaisingEvents = true; } _isRestartInProgress = false; } else { Exited?.Invoke(this, new ExitedEventArgs(GetProcessExitCode(_process))); } } else { Exited?.Invoke(this, new ExitedEventArgs(GetProcessExitCode(_process))); } }
/// <summary> /// Starts the IB Gateway /// </summary> /// <param name="waitForExit">true if it should wait for the IB Gateway process to exit</param> /// <remarks>The IB Gateway application will be launched</remarks> public StartResult Start(bool waitForExit) { lock (_locker) { if (_lastStartResult.HasError) { // IBAutomater errors are unrecoverable return(_lastStartResult); } if (IsRunning()) { return(StartResult.Success); } _process = null; _ibAutomaterInitializeEvent.Reset(); if (IsLinux) { // need permission for execution OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs("Setting execute permissions on IBAutomater.sh")); ExecuteProcessAndWaitForExit("chmod", "+x IBAutomater.sh"); } var ibGatewayVersionPath = GetIbGatewayVersionPath(); OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"Loading IBGateway - Version: {_ibVersion} - Path: {ibGatewayVersionPath} - User: {_userName}")); if (!Directory.Exists(ibGatewayVersionPath)) { return(new StartResult(ErrorCode.IbGatewayVersionNotInstalled, $"Version: {_ibVersion} - Path: {ibGatewayVersionPath}")); } var jreInstallPath = GetJreInstallPath(ibGatewayVersionPath); if (string.IsNullOrWhiteSpace(jreInstallPath)) { return(new StartResult(ErrorCode.JavaNotFound)); } UpdateIbGatewayIniFile(); UpdateIbGatewayConfiguration(ibGatewayVersionPath, true); _timerLogReader.Change(Timeout.Infinite, Timeout.Infinite); _ibGatewayLogFileName = Path.Combine(ibGatewayVersionPath, "IBAutomater.log"); lock (_logLocker) { if (File.Exists(_ibGatewayLogFileName)) { File.Delete(_ibGatewayLogFileName); } } _timerLogReader.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1)); string fileName; string arguments; if (IsWindows) { fileName = $"{ibGatewayVersionPath}/ibgateway.exe"; arguments = string.Empty; } else { fileName = "IBAutomater.sh"; arguments = ibGatewayVersionPath; } var process = new Process { StartInfo = new ProcessStartInfo(fileName, arguments) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true }, EnableRaisingEvents = true }; process.OutputDataReceived += (s, e) => { if (e.Data != null) { OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(e.Data.Replace(_password, "***"))); } }; process.ErrorDataReceived += (s, e) => { if (e.Data != null) { ErrorDataReceived?.Invoke(this, new ErrorDataReceivedEventArgs(e.Data.Replace(_password, "***"))); } }; process.Exited += OnProcessExited; try { var started = process.Start(); if (!started) { return(new StartResult(ErrorCode.ProcessStartFailed)); } } catch (Exception exception) { return(new StartResult( ErrorCode.ProcessStartFailed, exception.Message.Replace(_password, "***"))); } OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs($"IBAutomater process started - Id:{process.Id} - Name:{process.ProcessName} - InitializationTimeout:{_initializationTimeout}")); _process = process; process.BeginErrorReadLine(); process.BeginOutputReadLine(); if (waitForExit) { process.WaitForExit(); } else { // wait for completion of IBGateway login and configuration string message; if (_ibAutomaterInitializeEvent.WaitOne(_initializationTimeout)) { var processName = IsWindows ? "ibgateway" : "java"; var p = Process.GetProcessesByName(processName).FirstOrDefault(); OutputDataReceived?.Invoke(this, p != null ? new OutputDataReceivedEventArgs($"IBGateway process found - Id:{p.Id} - Name:{p.ProcessName}") : new OutputDataReceivedEventArgs($"IBGateway process not found: {processName}")); message = "IB Automater initialized."; } else { TraceIbLauncherLogFile(); var additionalMessage = string.Empty; if (_isFirstStart && _isAuthenticating) { // unable to complete logon because IB weekend server reset is in progress additionalMessage = "The logon process could not be completed because the IB server is busy or being reset for the weekend, please try again later."; } _lastStartResult = new StartResult(ErrorCode.InitializationTimeout, additionalMessage); message = "IB Automater initialization timeout. " + additionalMessage; } _isFirstStart = false; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); if (_lastStartResult.HasError) { message = $"IBAutomater error - Code: {_lastStartResult.ErrorCode} Message: {_lastStartResult.ErrorMessage}"; OutputDataReceived?.Invoke(this, new OutputDataReceivedEventArgs(message)); return(_lastStartResult); } } } return(StartResult.Success); }