/// <summary> /// Create a new outbound live viewer to the default server /// </summary> public void StartLiveView(NetworkConnectionOptions options, Guid repositoryId, Guid channelId, long sequenceOffset = 0) { if (channelId == Guid.Empty) { throw new ArgumentNullException(nameof(channelId)); } //open an outbound pending connection. var newWriter = new NetworkWriter(this, options, repositoryId, channelId, sequenceOffset); newWriter.Start(); RegisterWriter(newWriter); }
/// <summary> /// Create a new network writer for a remote server /// </summary> public NetworkWriter(NetworkMessenger messenger, NetworkConnectionOptions options, Guid repositoryId, Guid channelId, long sequenceOffset, int majorVersion, int minorVersion) : base(options, false, majorVersion, minorVersion) { if (channelId == Guid.Empty) { throw new ArgumentNullException(nameof(channelId)); } lock (m_Lock) //since we promptly access these variables from another thread, I'm adding this as paranoia to ensure they get synchronized. { m_Messenger = messenger; m_RepositoryId = repositoryId; m_ChannelId = channelId; m_SequenceOffset = sequenceOffset; } }
/// <summary> /// Create a new network client to the specified endpoint /// </summary> /// <param name="options"></param> /// <param name="retryConnections">If true then network connections will automatically be retried (instead of the client being considered failed)</param> /// <param name="majorVersion">Major version of the serialization protocol</param> /// <param name="minorVersion">Minor version of the serialization protocol</param> protected NetworkClient(NetworkConnectionOptions options, bool retryConnections, int majorVersion, int minorVersion) { if (options == null) { throw new ArgumentNullException(nameof(options)); } lock (m_Lock) //since we promptly access these variables from another thread, I'm adding this as paranoia to ensure they get synchronized. { m_Options = options; m_RetryConnections = retryConnections; m_MajorVersion = majorVersion; m_MinorVersion = minorVersion; } CalculateStateMessage(null); //initializes to default }
/// <summary> /// Create a new network writer for a remote server /// </summary> public NetworkWriter(NetworkMessenger messenger, NetworkConnectionOptions options, Guid repositoryId, Guid channelId, long sequenceOffset = 0) : this(messenger, options, repositoryId, channelId, sequenceOffset, FileHeader.DefaultMajorVersion, FileHeader.DefaultMinorVersion) { }
/// <summary> /// Make sure we have an outbound proxy connection. /// </summary> /// <remarks>Intended for asynchronous execution from the thread pool.</remarks> private async Task AsyncEnsureRemoteConnection() { try { try { DateTimeOffset hubConfigurationExpiration; lock (m_HubConnection) { hubConfigurationExpiration = m_HubConfigurationExpiration; } NetworkConnectionOptions newLiveStreamOptions = null; if ((m_HubConnection.IsConnected == false) || (hubConfigurationExpiration < DateTimeOffset.Now)) { await m_HubConnection.Reconnect().ConfigureAwait(false); DateTimeOffset connectionAttemptTime = DateTimeOffset.Now; var status = await m_HubConnection.GetStatus().ConfigureAwait(false); if (status.Status == HubStatus.Expired) { //if it's expired we're not going to check again for a while. if (status.Repository?.ExpirationDt == null) { //should never happen, but treat as our long term case. hubConfigurationExpiration = connectionAttemptTime.AddDays(1); } else { TimeSpan expiredTimeframe = connectionAttemptTime - status.Repository.ExpirationDt.Value; if (expiredTimeframe.TotalHours < 24) { hubConfigurationExpiration = connectionAttemptTime.AddMinutes(15); //we'll check pretty fast for that first day. } else if (expiredTimeframe.TotalDays < 4) { hubConfigurationExpiration = connectionAttemptTime.AddHours(6); } else { hubConfigurationExpiration = connectionAttemptTime.AddDays(1); } } if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Verbose, LogCategory, "Loupe server status is expired so no remote live view possible.", "Will check the server configuration again at {0}", hubConfigurationExpiration); } } else { //we always want to periodically recheck the configuration in case it has changed anyway. //we want to coordinate to an exact hour point to provide some consistency to worried users wondering when things will reconnect. hubConfigurationExpiration = connectionAttemptTime.AddMinutes(60 - connectionAttemptTime.Minute); //so we go to a flush hour. newLiveStreamOptions = status.Repository?.AgentLiveStreamOptions; if ((newLiveStreamOptions == null) && (!Log.SilentMode)) { Log.Write(LogMessageSeverity.Information, LogCategory, "Remote live view not available due to server configuration", "The server is configured to have live view disabled so even though we have it enabled there is no live view."); } } lock (m_HubConnection) { m_HubConfigurationExpiration = hubConfigurationExpiration; } //if we got different options then we're going to have to drop & recreate the client. if (newLiveStreamOptions != m_ConnectionOptions) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Verbose, LogCategory, "Loupe server live view options are different than our running configuration so we will close the client.", "New configuration:\r\n{0}", newLiveStreamOptions); } m_ConnectionOptions = newLiveStreamOptions; CloseClient(m_Client); m_Client = null; } } } catch (Exception ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Warning, LogWriteMode.Queued, ex, LogCategory, "Remote viewer connection attempt failed", "While attempting to open our outbound connection to the proxy server an exception was thrown. We will retry again later.\r\nException: {0}", ex.Message); } } try { if ((m_Client == null) && (m_ConnectionOptions != null)) { LiveSessionPublisher newClient = new LiveSessionPublisher(this, m_ConnectionOptions); newClient.Start(); m_Client = newClient; SendSummary(m_Client); //since we just connected, we want to immediately tell it about us. } } catch (Exception ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Warning, LogWriteMode.Queued, ex, LogCategory, "Remote viewer connection attempt failed", "While attempting to open our outbound connection to the proxy server an exception was thrown. We will retry again later.\r\nException: {0}", ex.Message); } } } finally { m_ActiveRemoteConnectionAttempt = false; } }