예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
                }
            }
        }
예제 #3
0
        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)));
            }
        }
예제 #4
0
        /// <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);
        }