If the user has been disconnected for some recoverable reason, we can automatically attempt reconnection.
Reconnecter
public class GFApiReconnecter { private IGFClient _client; private CancellationTokenSource _cts; private ConnectionContext _connectionContext; private GF.Api.Utils.GFApiEventHandler<LoginFailedEventArgs> _loginFailed; public void Register(IGFClient client, GF.Api.Utils.GFApiEventHandler<LoginFailedEventArgs> loginFailed) { _client = client; _loginFailed = loginFailed; client.Connection.Aggregate.LoginCompleted += (gfClient, args) => EndReconnect(); client.Connection.Aggregate.LoginFailed += (gfClient, args) => { if (args.FailReason != GF.Api.Values.Users.FailReason.ConnectionError || _cts?.IsCancellationRequested != false) { EndReconnect(); _loginFailed(gfClient, args); } else { Reconnect(); } }; client.Connection.Aggregate.Disconnected += (gfClient, args) => { if (args.Reason != DisconnectionReason.SocketError || _cts?.IsCancellationRequested == false) return; _cts = new CancellationTokenSource(); Reconnect(); }; } public void Connect(ConnectionContext context) { _connectionContext = context; _client.Connection.Aggregate.Connect(context); } private void Reconnect() { if (_client.Connection.Aggregate.IsClosed) { _client.Threading.BeginDelayedInvoke( TimeSpan.FromSeconds(1), () => _client.Connection.Aggregate.Connect(_connectionContext), _cts.Token); } } private void EndReconnect() { _cts?.Cancel(); if (_client.Connection.Aggregate.IsConnecting) _client.Connection.Aggregate.Disconnect(); } }