public async Task ChangeHostUrl(string?newHost) { try { if (_hostUrl != newHost) { _logger.LogInformation($"Changing host from {_hostUrl} to {newHost}"); if (_underlyingConnection != null) { await _underlyingConnection.StopAsync(); } _hostUrl = newHost; if (_hostUrl != null) { _underlyingConnection = new HubConnectionBuilder().WithUrl(_hostUrl).WithAutomaticReconnect().Build(); _underlyingConnection.RegisterSpoke(_spoke); _messageHubImplementation = _underlyingConnection.AsDynamicHub <IMessageHub>(); await _underlyingConnection.StartAsync(); } } } catch (Exception e) { _logger.LogError($"Failed to bind to {_hostUrl}: {e}"); } }
public async Task <HubConnection> StartService(string url) { connection = new HubConnectionBuilder() .WithUrl(url) .Build(); connection.Closed += async(error) => { await Task.Delay(new Random().Next(0, 5) * 1000); await connection.StartAsync(); }; connection.Reconnecting += error => { Console.WriteLine($"Connection Lost attempting to reconnect: {error.Message}"); // Notify users the connection was lost and the client is reconnecting. // Start queuing or dropping messages. return(Task.CompletedTask); }; try { await connection.StartAsync(); BuildResponseActions(); } catch (Exception ex) { Console.WriteLine(ex.Message); Environment.Exit(-1); } return(connection); }
public async IAsyncEnumerable <Swap.EventWithId> ListenToEventsAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) { var sb = new System.Text.StringBuilder(); sb.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/v1/events"); var uri = new Uri(sb.ToString(), UriKind.RelativeOrAbsolute); connection = new HubConnectionBuilder() .WithUrl(uri) .WithAutomaticReconnect() .AddJsonProtocol(p => { p.PayloadSerializerOptions.AddNLoopJsonConverters(FSharpOption <Network> .None); }) .Build(); await connection.StartAsync(cancellationToken); var s = connection.StreamAsync <Swap.EventWithId>("ListenSwapEvents", cancellationToken); await foreach (var e in s.WithCancellation(cancellationToken)) { yield return(e); } }
public async Task <HubConnection?> ConnectAsync(string username, string password) { await CloseConnectionAsync(); HttpResponseMessage response; if (_jwt?.IsExpired ?? false) { Console.WriteLine("token expired"); var refreshContent = new StringContent(Convert.ToBase64String(Encoding.UTF8.GetBytes(_jwt.RefreshToken)), Encoding.UTF8, "application/json"); response = await _httpClient.PostAsync($"{_baseUrl}/{_jwt.RefreshUrl}", refreshContent); if (response.IsSuccessStatusCode) { var serializedJwt = await response.Content.ReadAsStringAsync(); var jwt = JsonSerializer.Deserialize <SecureJwtModel>(serializedJwt); _jwt = jwt.TokenModel; } } else { var userModel = new UserAuthenticationModel { Username = username, Password = password }; var content = new StringContent(JsonSerializer.Serialize(userModel), Encoding.UTF8, "application/json"); response = await _httpClient.PostAsync($"{_baseUrl}/jwt/requestjwt", content); if (response.IsSuccessStatusCode) { var serializedJwt = await response.Content.ReadAsStringAsync(); var jwt = JsonSerializer.Deserialize <SecureJwtModel>(serializedJwt); _jwt = jwt.TokenModel; _connection = new HubConnectionBuilder() .WithUrl($"{_baseUrl}/blazorhub?access_token={_jwt.Token}", opt => { opt.SkipNegotiation = true; opt.Transports = HttpTransportType.WebSockets; }) .Build(); _connection.On <string>("GuestEntered", id => { _notificationManager.ShowNotificationMessage($"User {id} just entered", "New User"); return(Task.CompletedTask); }); _connection.On <string>("GuestLeft", id => { _notificationManager.ShowNotificationMessage($"User {id} just left", "New User"); return(Task.CompletedTask); }); await _connection.StartAsync(); } } return(_connection); }
public async Task Initialize() { if (!_initialized) { _hubConnection = new HubConnectionBuilder() .WithUrl(_hubUrl) .Build(); _hubConnection.On <string, string>("ReceiveMessage", (user, message) => MessageReceived?.Invoke(user, message)); _hubConnection.On <Room>("UpdatePlayerState", (room) => PlayerStateUpdated?.Invoke(room)); _hubConnection.On <Room>("RoomOpened", (room) => RoomOpened?.Invoke(room)); _hubConnection.On <Room>("UpdateRoom", (room) => RoomUpdated?.Invoke(room)); await _hubConnection.StartAsync(); _initialized = true; } }
private async Task disconnect(bool takeLock) { cancelExistingConnect(); if (takeLock) { if (!await connectionLock.WaitAsync(10000)) { throw new TimeoutException("Could not obtain a lock to disconnect. A previous attempt is likely stuck."); } } try { if (connection != null) { await connection.DisposeAsync(); } } finally { connection = null; if (takeLock) { connectionLock.Release(); } } }
/// <summary> /// Initiates the connection with the SignalR hub /// </summary> /// <param name="state">The program cancellation token</param> private void InitiateHub(object?state) { if (_hubConnection?.State == HubConnectionState.Connected) { return; } if (state == null) { throw new ArgumentNullException(nameof(state), "State was null when initiating hub"); } _hubConnection = new HubConnectionBuilder() .WithUrl(_configuration.SignalRHubEndpoint) .WithAutomaticReconnect() .Build(); try { Task.Run(async() => await _hubConnection.StartAsync((CancellationToken)state)); } catch (Exception ex) { _logger.LogError(ex, "Hub not starting."); } }
private async void PrivateDisconnectAsync() { await _hubConnection !.StopAsync(); await _hubConnection.DisposeAsync(); _hubConnection = null; _isConnected = false; }
private async Task <string> InitConnectionAsync() { if (_connection == null) { using (await _lockInit.LockAsync()) { if (_connection == null) { if (_options.SignalRHubUrl != null) { _connection = new HubConnectionBuilder() .WithUrl(_options.SignalRHubUrl) .Build(); _notifier = new HubCallBackNotifier(_connection); _connection.On <string, string>("Callback", HubConnection_Callback); } } } } #if NETCOREAPP2_1 try { await _connection.StartAsync(); _connId = await _connection.InvokeAsync <string>("GetConnId"); return(_connId); } catch (Exception e) { _logger.LogWarning(e, "_connection.StartAsync() failed."); } #else // ReSharper disable once PossibleNullReferenceException if (_connection !.State == HubConnectionState.Disconnected) { using (await _lockInit.LockAsync()) { if (_connection.State == HubConnectionState.Disconnected) { try { await _connection.StartAsync(); _connId = await _connection.InvokeAsync <string>("GetConnId"); return(_connId); } catch (Exception e) { _logger.LogWarning(e, "_connection.StartAsync() failed."); } } } } #endif return(_connId !); }
public async Task <bool> ConnectAsync(Uri uri, bool connectAutomatically = true, Action <HubConnectionBuilder, Uri>?configure = null) { var builder = new HubConnectionBuilder(); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton <IHubProtocol, IgnitorMessagePackHubProtocol>()); var hubUrl = GetHubUrl(uri); builder.WithUrl(hubUrl); builder.ConfigureLogging(l => { l.SetMinimumLevel(LogLevel.Trace); if (LoggerProvider != null) { l.AddProvider(LoggerProvider); } }); configure?.Invoke(builder, hubUrl); _hubConnection = builder.Build(); HubConnection.On <int, string>("JS.AttachComponent", OnAttachComponent); HubConnection.On <int, string, string, int, long>("JS.BeginInvokeJS", OnBeginInvokeJS); HubConnection.On <string>("JS.EndInvokeDotNet", OnEndInvokeDotNet); HubConnection.On <int, byte[]>("JS.RenderBatch", OnRenderBatch); HubConnection.On <string>("JS.Error", OnError); HubConnection.Closed += OnClosedAsync; for (var i = 0; i < 10; i++) { try { await HubConnection.StartAsync(CancellationToken); break; } catch { await Task.Delay(500); // Retry 10 times } } if (!connectAutomatically) { return(true); } var descriptors = await GetPrerenderDescriptors(uri); await ExpectRenderBatch( async() => CircuitId = await HubConnection.InvokeAsync <string>("StartCircuit", uri, uri, descriptors, null, CancellationToken), DefaultConnectionTimeout); return(CircuitId != null); }
private async Task connect() { cancelExistingConnect(); if (!await connectionLock.WaitAsync(10000)) { throw new TimeoutException("Could not obtain a lock to connect. A previous attempt is likely stuck."); } try { while (api.State.Value == APIState.Online) { // ensure any previous connection was disposed. // this will also create a new cancellation token source. await disconnect(false); // this token will be valid for the scope of this connection. // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere. var cancellationToken = connectCancelSource.Token; cancellationToken.ThrowIfCancellationRequested(); Logger.Log("Multiplayer client connecting...", LoggingTarget.Network); try { // importantly, rebuild the connection each attempt to get an updated access token. connection = createConnection(cancellationToken); await connection.StartAsync(cancellationToken); Logger.Log("Multiplayer client connected!", LoggingTarget.Network); isConnected.Value = true; return; } catch (OperationCanceledException) { //connection process was cancelled. throw; } catch (Exception e) { Logger.Log($"Multiplayer client connection error: {e}", LoggingTarget.Network); // retry on any failure. await Task.Delay(5000, cancellationToken); } } } finally { connectionLock.Release(); } }
public async Task <bool> CloseConnectionAsync() { if (IsConnected) { await _connection !.StopAsync(); } _connection = null; _jwt = null; return(true); }
protected override async Task OnInitializedAsync() { _rooms = await Http.GetFromJsonAsync <List <RoomDetails> >("api/twilio/rooms"); _hubConnection = new HubConnectionBuilder() .AddMessagePackProtocol() .WithUrl(NavigationManager.ToAbsoluteUri(HubEndpoints.NotificationHub)) .WithAutomaticReconnect() .Build(); _hubConnection.On <string>(HubEndpoints.RoomsUpdated, OnRoomAdded); await _hubConnection.StartAsync(); }
public void Start( string address, GamemasterUser user, TaskCompletionSource <bool>?source, string?contentToCompare, IEnumerable <string> cookies, CancellationToken token) { this.token = token; this.user = user; this.source = source; this.contentToCompare = contentToCompare; this.reg = this.token.Register(() => { this.logger.LogWarning("The CancellationToken was cancelled, disposing SignalRClient"); this.source?.TrySetException(new MumbleException("Chat messages not delivered in time")); }); this.connection = new HubConnectionBuilder() .WithUrl(this.scheme + "://" + address + ":" + this.port + "/hubs/session", options => { options.Headers.Add("Cookie", cookies.FirstOrDefault()); }) .Build(); this.connection.On <ChatMessageView[]>("Chat", (messages) => { this.logger.LogInformation($"{user.Username} {this.connection.ConnectionId} ChatMessage received: {messages.Length}"); if (this.contentToCompare != null) { this.logger.LogDebug($"Comparing {messages.Count()} messages to: {this.contentToCompare}"); foreach (var e in messages) { if (e.Content == this.contentToCompare) { Task.Run(() => this.source?.SetResult(false)); return; } } } else { source?.SetResult(false); } }); this.connection.On <Scene>("Scene", (scene) => { this.logger.LogInformation($"{user.Username} Received scene with {scene.Units.Count} units {token.IsCancellationRequested} {this.connection.State} {this.connection.ConnectionId}"); }); this.connection.Closed += this.Connection_Closed; }
private void apiStateChanged(ValueChangedEvent <APIState> state) { switch (state.NewValue) { case APIState.Failing: case APIState.Offline: connection?.StopAsync(); connection = null; break; case APIState.Online: Task.Run(Connect); break; } }
/// <summary> /// Starts the communication. /// </summary> public async Task StartAsync() { var hubUrl = Configuration.SignalrHubUrl; Console.WriteLine($"Connecting to {hubUrl}"); connection = new HubConnectionBuilder() .WithUrl(hubUrl) .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) }) .Build(); await connection.StartAsync().ConfigureAwait(true); // test //Listen(); }
/// <summary> /// Attempt to connect to the Acces.sh API /// </summary> public async Task Connect() { _connection = new HubConnectionBuilder() .WithUrl(_configuration.Core.HubUrl !, options => { options.SkipNegotiation = true; options.Transports = HttpTransportType.WebSockets; options.AccessTokenProvider = () => Task.FromResult(Jwt) !; }) .ConfigureLogging(logging => { logging.SetMinimumLevel(LogLevel.Critical); logging.AddConsole(); }) .Build(); await _connection.StartAsync(); }
public void Dispose() { if (disposed) { return; } disposed = true; try { hubConnection.Transport?.Dispose(); hubConnection.Dispose(); } catch { // eat exceptions here, we don't care if it fails } hubConnection = null; }
public async Task InitializeAsync() { if (this.isInitialized) { return; } if (!this._config.IsConfigured) { return; } this.isInitialized = true; var connectionUrl = this._config.NotificationHubUrl; if (connectionUrl.EndsWith("notificationHub/") || connectionUrl.EndsWith("notificationHub")) { connectionUrl = connectionUrl.Replace("notificationHub", ""); connectionUrl = connectionUrl.TrimEnd('/'); } connectionUrl = $"{connectionUrl}notificationHub/"; this._hubConnection = new HubConnectionBuilder().WithUrl(connectionUrl).WithAutomaticReconnect().Build(); this._hubConnection.Closed += _hubConnection_Closed; this._hubConnection.Reconnected += _hubConnection_Reconnected; this._hubConnection.Reconnecting += _hubConnection_Reconnecting; this._hubConnection.MapClientMethods(this._notificationHandler); try { await _hubConnection.StartAsync(); } catch (Exception e) { Console.WriteLine($"Unable to setup SignalRNotificationReceiver: {e.Message}"); this.ConnectionStateChanged?.Invoke(this, new HubConnectionStateChangedEventArgs { ConnectionState = HubConnectionState.Disconnected }); } }
protected override async Task OnInitializedAsync() { _hubConnection = new HubConnectionBuilder() .AddMessagePackProtocol() .WithUrl(NavigationManager.ToAbsoluteUri(NotificationHub.Endpoint)) .WithAutomaticReconnect() .ConfigureLogging(builder => builder.AddDebug().AddConsole()) .Build(); _hubConnection.On <string>(NotificationHub.RoomAddedRoute, OnRoomAdded); await _hubConnection.StartAsync(); Devices = await VideoJS.GetVideoDevicesAsync(JsRuntime); State = Devices != null && Devices.Length > 0 ? CameraState.FoundCameras : CameraState.Error; StateHasChanged(); }
public async Task InitializeAsync() { if (_isInitialized) { return; } _entities.AddRange(await GetEntitiesAsync()); _hubConnection = new HubConnectionBuilder() .WithUrl(new Uri(new Uri(_navigationManager.BaseUri), "homeassistant/hub")) .WithAutomaticReconnect() .Build(); _hubConnection.On <Entity>( "EntityUpdated", entity => UpdateEntities(new[] { entity })); await _hubConnection.StartAsync(); _isInitialized = true; }
public async Task Build(string host) { var builder = new HubConnectionBuilder() .WithUrl(host) .WithAutomaticReconnect(); if (this.VerboseMode) { builder.ConfigureLogging(logging => logging.AddConsole()); } this.connection = builder.Build(); this.connection.Closed += this.HandleClosed; this.connection.Reconnected += this.HandleReconnected; this.connection.Reconnecting += this.HandleReconnecting; await this.connection.StartAsync(); if (!this.QuiteMode) { Console.Error.WriteLine(this.connection.State); } }
public async void OnConnect() { await CloseConnectionAsync(); _hubConnection = new HubConnectionBuilder() .WithUrl(_urlService.ChatAddress) .Build(); _hubConnection.Closed += HubConnectionClosed; _hubConnection.On <string, string>("BroadcastMessage", OnMessageReceived); try { await _hubConnection.StartAsync(); await _dialogService.ShowMessageAsync("client connected"); } catch (HttpRequestException ex) { await _dialogService.ShowMessageAsync(ex.Message); } }
public async Task <HubConnection> StartConnection(string url) { connection = new HubConnectionBuilder() .WithUrl(url) .WithAutomaticReconnect() .Build(); connection.Closed += async(error) => { await Task.Delay(new Random().Next(0, 5) * 1000); await connection.StartAsync(); }; connection.Reconnecting += error => { Log.Error("SigRConnection: 55: Connection Lost attempting to reconnect: {@error}", error); // Notify users the connection was lost and the client is reconnecting. // Start queuing or dropping messages. return(Task.CompletedTask); }; try { await connection.StartAsync(); SignalHandler(); } catch (Exception ex) { Log.Error("SigRConnect:71: Exception {@ex}", ex); Environment.Exit(-1); } return(connection); }
public async Task <HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) { HubConnection?connection = null; try { connection = _hubConnectionBuilder(); await connection.StartAsync(cancellationToken); return(HealthCheckResult.Healthy()); } catch (Exception ex) { return(new HealthCheckResult(context.Registration.FailureStatus, exception: ex)); } finally { if (connection != null) { await connection.DisposeAsync(); } } }
public async Task StartAsync() { // stop any previous hub connection hubConnection?.Stop(); hubConnection?.Dispose(); // make a new hub connection hubConnection = new HubConnection(ConnectionUrl, false); hubConnection.Closed += SocketClosed; #if DEBUG //hubConnection.TraceLevel = TraceLevels.All; //hubConnection.TraceWriter = Console.Out; #endif hubProxy = hubConnection.CreateHubProxy(HubName); if (hubProxy == null) { throw new APIException("CreateHubProxy - proxy is null, this should never happen"); } // assign callbacks for events foreach (string key in FunctionNamesToFullNames.Keys) { hubProxy.On(key, async(string data) => await HandleResponse(key, data)); } // create a custom transport, the default transport is really buggy DefaultHttpClient client = new DefaultHttpClient(); customTransport = new WebsocketCustomTransport(client, ConnectInterval, KeepAlive); var autoTransport = new AutoTransport(client, new IClientTransport[] { customTransport }); hubConnection.TransportConnectTimeout = hubConnection.DeadlockErrorTimeout = TimeSpan.FromSeconds(10.0); // setup connect event customTransport.WebSocket.Connected += async(ws) => { try { SignalrSocketConnection[] socketsCopy; lock (sockets) { socketsCopy = sockets.ToArray(); } foreach (SignalrSocketConnection socket in socketsCopy) { await socket.InvokeConnected(); } } catch (Exception ex) { Logger.Info(ex.ToString()); } }; // setup disconnect event customTransport.WebSocket.Disconnected += async(ws) => { try { SignalrSocketConnection[] socketsCopy; lock (sockets) { socketsCopy = sockets.ToArray(); } foreach (SignalrSocketConnection socket in socketsCopy) { await socket.InvokeDisconnected(); } } catch (Exception ex) { Logger.Info(ex.ToString()); } try { // tear down the hub connection, we must re-create it whenever a web socket disconnects hubConnection?.Dispose(); } catch (Exception ex) { Logger.Info(ex.ToString()); } }; try { // it's possible for the hub connection to disconnect during this code if connection is crappy // so we simply catch the exception and log an info message, the disconnect/reconnect loop will // catch the close and re-initiate this whole method again await hubConnection.Start(autoTransport); // get list of listeners quickly to limit lock HubListener[] listeners; lock (this.listeners) { listeners = this.listeners.Values.ToArray(); } // re-call the end point to enable messages foreach (var listener in listeners) { foreach (object[] p in listener.Param) { await hubProxy.Invoke <bool>(listener.FunctionFullName, p); } } } catch (Exception ex) { Logger.Info(ex.ToString()); } }
public async Task <bool> ConnectToServerAsync() { if (_isConnected == true) { throw new BasicBlankException("Already connected. Rethink"); } bool isAzure = await _connectInfo.IsAzureAsync(); int port = 0; if (isAzure == false) { port = await _connectInfo.GetPortAsync(); } string ipAddress = await _connectInfo.GetIPAddressAsync(); string endPoint = await _connectInfo.GetEndPointAsync(); //i do like the interface method for this. //autoreconnect can be risky because we don't know what it needs to resend unfortunately. if (isAzure == false) { _hubConnection = new HubConnectionBuilder() .WithUrl($"{ipAddress}:{port}{endPoint}" ) //.WithAutomaticReconnect() //great new feature released september 23, 2019. i guess this was client side. //bad news is the new 3.0 does not seem to work with xamarin forms for now. .Build(); } else { _hubConnection = new HubConnectionBuilder() .WithUrl($"{ipAddress}{endPoint}") //.WithAutomaticReconnect() .Build(); } _hubConnection.On("Hosting", () => { _thisProgress.Report(new CustomEventHandler(EnumNetworkCategory.Hosting)); }); _hubConnection.On <string>("ConnectionError", Items => { _thisProgress.Report(new CustomEventHandler(EnumNetworkCategory.Error, Items)); }); _hubConnection.On <string>("HostName", Items => { _thisProgress.Report(new CustomEventHandler(EnumNetworkCategory.Client, Items)); //this will mean the client will get the host name. }); _hubConnection.On("NoHost", () => { _thisProgress.Report(new CustomEventHandler(EnumNetworkCategory.None)); //this means nobody is hosting. }); _hubConnection.On <string>("ReceiveMessage", Items => { _thisProgress.Report(new CustomEventHandler(EnumNetworkCategory.Message, Items)); }); _hubConnection.On("Close", () => { PrivateDisconnectAsync(); }); try { await _hubConnection.StartAsync(); _isConnected = true; return(true); //i think this simple. } catch { return(false); } }
protected virtual async Task Connect() { if (connection != null) { return; } var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => { options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); }); if (RuntimeInfo.SupportsJIT) { builder.AddMessagePackProtocol(); } else { // eventually we will precompile resolvers for messagepack, but this isn't working currently // see https://github.com/neuecc/MessagePack-CSharp/issues/780#issuecomment-768794308. builder.AddNewtonsoftJsonProtocol(options => { options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); } connection = builder.Build(); // this is kind of SILLY // https://github.com/dotnet/aspnetcore/issues/15198 connection.On <MultiplayerRoomState>(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged); connection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined); connection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft); connection.On <int>(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); connection.On <MultiplayerRoomSettings>(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); connection.On <int, MultiplayerUserState>(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); connection.On(nameof(IMultiplayerClient.LoadRequested), ((IMultiplayerClient)this).LoadRequested); connection.On(nameof(IMultiplayerClient.MatchStarted), ((IMultiplayerClient)this).MatchStarted); connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); connection.Closed += async ex => { isConnected.Value = false; Logger.Log(ex != null ? $"Multiplayer client lost connection: {ex}" : "Multiplayer client disconnected", LoggingTarget.Network); if (connection != null) { await tryUntilConnected(); } }; await tryUntilConnected(); async Task tryUntilConnected() { Logger.Log("Multiplayer client connecting...", LoggingTarget.Network); while (api.State.Value == APIState.Online) { try { Debug.Assert(connection != null); // reconnect on any failure await connection.StartAsync(); Logger.Log("Multiplayer client connected!", LoggingTarget.Network); // Success. isConnected.Value = true; break; } catch (Exception e) { Logger.Log($"Multiplayer client connection error: {e}", LoggingTarget.Network); await Task.Delay(5000); } } } }
protected virtual async Task Connect() { if (connection != null) { return; } connection = new HubConnectionBuilder() .WithUrl(endpoint, options => { options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); }) .AddMessagePackProtocol() .Build(); // this is kind of SILLY // https://github.com/dotnet/aspnetcore/issues/15198 connection.On <MultiplayerRoomState>(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged); connection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined); connection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft); connection.On <int>(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); connection.On <MultiplayerRoomSettings>(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); connection.On <int, MultiplayerUserState>(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); connection.On(nameof(IMultiplayerClient.LoadRequested), ((IMultiplayerClient)this).LoadRequested); connection.On(nameof(IMultiplayerClient.MatchStarted), ((IMultiplayerClient)this).MatchStarted); connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); connection.Closed += async ex => { isConnected.Value = false; Logger.Log(ex != null ? $"Multiplayer client lost connection: {ex}" : "Multiplayer client disconnected", LoggingTarget.Network); if (connection != null) { await tryUntilConnected(); } }; await tryUntilConnected(); async Task tryUntilConnected() { Logger.Log("Multiplayer client connecting...", LoggingTarget.Network); while (api.State.Value == APIState.Online) { try { Debug.Assert(connection != null); // reconnect on any failure await connection.StartAsync(); Logger.Log("Multiplayer client connected!", LoggingTarget.Network); // Success. isConnected.Value = true; break; } catch (Exception e) { Logger.Log($"Multiplayer client connection error: {e}", LoggingTarget.Network); await Task.Delay(5000); } } } }