/// <summary> /// Gets the connection. /// </summary> /// <returns></returns> public HubConnection GetConnection() { var hubUrl = _configuration.GetValue <string>("SignalR:HubUrl"); if (string.IsNullOrEmpty(hubUrl)) { return(null); } var builder = new HubConnectionBuilder() .WithUrl(hubUrl) .WithAutomaticReconnect(); if (_configuration.GetValue <bool>("SignalR:UseMessagePack")) { builder.AddMessagePackProtocol(); } _hubConnection = builder.Build(); _hubConnection.Closed += (error) => { return(StartConnectionAsync()); }; StartConnectionAsync().GetAwaiter().GetResult(); return(_hubConnection); }
private static async Task <SignalRStreamingCall> GetSignalRStateAsync(int i) { if (!SignalRCache.TryGetValue(i, out var state)) { var builder = new HubConnectionBuilder(); builder.WithUrl("http://localhost:5000/greeterhub"); builder.AddMessagePackProtocol(); var hubConnection = builder.Build(); await hubConnection.StartAsync(); var channel = System.Threading.Channels.Channel.CreateUnbounded <string>(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true }); var result = hubConnection.StreamAsync <string>("SayHelloBiDi", channel.Reader); state = new SignalRStreamingCall { RequestStream = channel.Writer, ResponseStream = result.GetAsyncEnumerator() }; bool success = SignalRCache.TryAdd(i, state); if (!success) { throw new InvalidOperationException(); } } return(state); }
private HubConnection buildConnection(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => { options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); options.Headers.Add("OsuVersionHash", versionHash); }); 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; }); } var newConnection = builder.Build(); ConfigureConnection?.Invoke(newConnection); newConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); return(newConnection); }
static async Task Main(string[] args) { var url = "http://localhost:5000/benchmark"; var transportType = HttpTransportType.WebSockets; // var transportType = HttpTransportType.ServerSentEvents; // var transportType = HttpTransportType.LongPolling; var hubConnectionBuilder = new HubConnectionBuilder() .WithUrl(url, httpConnectionOptions => { // set transport type httpConnectionOptions.Transports = transportType; }); if (useMessagePack) { hubConnectionBuilder.AddMessagePackProtocol(); } var connection = hubConnectionBuilder.Build(); await connection.StartAsync(); Console.WriteLine($"Starting connection with transport type {transportType}. Press Ctrl-C to close."); var cts = new CancellationTokenSource(); Console.CancelKeyPress += (sender, a) => { a.Cancel = true; cts.Cancel(); }; connection.Closed += e => { if (e != null) { Console.WriteLine("Connection closed with error: {0}", e); } else { Console.WriteLine("Connection closed"); } cts.Cancel(); return(Task.CompletedTask); }; connection.On("echo", (string name, string message) => { Console.WriteLine($"INFO: server -> client: {name}: {message}"); }); await connection.InvokeAsync <string>("Echo", "albert", "hello"); await connection.StopAsync(); }
public void GlobalSetup() { var writer = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, writer); var handshakeResponseResult = new ReadResult(new ReadOnlySequence <byte>(writer.ToArray()), false, false); _pipe = new TestDuplexPipe(); _pipe.AddReadResult(new ValueTask <ReadResult>(handshakeResponseResult)); } finally { MemoryBufferWriter.Return(writer); } _tcs = new TaskCompletionSource <ReadResult>(); _pipe.AddReadResult(new ValueTask <ReadResult>(_tcs.Task)); var hubConnectionBuilder = new HubConnectionBuilder(); if (Protocol == "json") { // JSON protocol added by default } else { hubConnectionBuilder.AddMessagePackProtocol(); } var delegateConnectionFactory = new DelegateConnectionFactory(format => { var connection = new DefaultConnectionContext(); // prevents keep alive time being activated connection.Features.Set <IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature()); connection.Transport = _pipe; return(Task.FromResult <ConnectionContext>(connection)); }, connection => { connection.Transport.Output.Complete(); connection.Transport.Input.Complete(); return(Task.CompletedTask); }); hubConnectionBuilder.Services.AddSingleton <IConnectionFactory>(delegateConnectionFactory); _hubConnection = hubConnectionBuilder.Build(); _hubConnection.StartAsync().GetAwaiter().GetResult(); _arguments = new object[ArgumentCount]; for (var i = 0; i < _arguments.Length; i++) { _arguments[i] = "Hello world!"; } }
protected void CreateConnections(HttpTransportType transportType = HttpTransportType.WebSockets) { _pkg.Connections = new List <HubConnection>(_pkg.Job.Connections); _pkg.SentMassage = new List <int>(_pkg.Job.Connections); for (var i = 0; i < _pkg.Job.Connections; i++) { var hubConnectionBuilder = new HubConnectionBuilder() .WithUrl(_pkg.Job.ServerBenchmarkUri, transportType, httpConnectionOptions => { httpConnectionOptions.HttpMessageHandlerFactory = _ => _httpClientHandler; httpConnectionOptions.Transports = transportType; httpConnectionOptions.CloseTimeout = TimeSpan.FromMinutes(100); //httpConnectionOptions.SkipNegotiation = true; //httpConnectionOptions.Url = new Uri(_pkg.Job.ServerBenchmarkUri); }); //hubConnectionBuilder = hubConnectionBuilder.ConfigureLogging(builder => builder.SetMinimumLevel(LogLevel.Trace)); HubConnection connection = null; switch (_pkg.Job.HubProtocol) { case "json": // json hub protocol is set by default connection = hubConnectionBuilder.ConfigureLogging(builder => builder.SetMinimumLevel(LogLevel.Debug)).Build(); break; case "messagepack": connection = hubConnectionBuilder.AddMessagePackProtocol().ConfigureLogging(builder => builder.SetMinimumLevel(LogLevel.Trace)).Build(); break; default: throw new Exception($"{_pkg.Job.HubProtocol} is an invalid hub protocol name."); } _pkg.Connections.Add(connection); _pkg.SentMassage.Add(0); // Capture the connection ID var ind = i; connection.Closed += e => { if (!_stopped) { var error = $"{ind}th Connection closed early: {e}"; _pkg.Job.Error += Environment.NewLine + $"[{DateTime.Now.ToString("hh:mm:ss.fff")}] " + error; Util.Log(error); } return(Task.CompletedTask); }; } }
public void AddMessagePackProtocolAddsProtocol() { var connectionBuilder = new HubConnectionBuilder(); connectionBuilder.AddMessagePackProtocol(); var serviceProvider = connectionBuilder.Services.BuildServiceProvider(); var resolvedHubProtocol = serviceProvider.GetService <IHubProtocol>(); Assert.IsType <MessagePackHubProtocol>(resolvedHubProtocol); }
/// <summary> /// Gets the connection. /// </summary> /// <returns></returns> public HubConnection GetConnection(CancellationToken cancellationToken) { var hubUrl = _configuration.GetValue <string>("SignalR:HubUrl"); if (string.IsNullOrEmpty(hubUrl)) { return(null); } if (_hubConnection != null) { return(_hubConnection); } lock (_syncLock) { if (_hubConnection != null) { return(_hubConnection); } var builder = new HubConnectionBuilder() .WithUrl(hubUrl, options => { options.HttpMessageHandlerFactory = _ => _provider.GetRequiredService <HubHttpMessageHandlerAccessor>().Handler; options.AccessTokenProvider = async() => { var manager = _provider.GetRequiredService <OAuthTokenManager>(); var token = await manager.GetTokenAsync().ConfigureAwait(false); return(token.Parameter); }; }) .WithAutomaticReconnect(); if (_configuration.GetValue <bool>("SignalR:UseMessagePack")) { builder.AddMessagePackProtocol(); } _hubConnection = builder.Build(); _hubConnection.Closed += (error) => { return(StartConnectionAsync(cancellationToken)); }; return(_hubConnection); } }
private HubConnection BuildHubConnection(string endpoint, string authToken) { var connectionBuilder = new HubConnectionBuilder() .WithUrl(endpoint, options => { options.Headers.Add("Auth-Token", authToken); }); if (GetSelectedProtocol() == Protocol.MessagePack) { connectionBuilder.AddMessagePackProtocol(); } return(connectionBuilder.Build()); }
private HubConnection createConnection(CancellationToken cancellationToken) { 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; }); } var newConnection = builder.Build(); // this is kind of SILLY // https://github.com/dotnet/aspnetcore/issues/15198 newConnection.On <MultiplayerRoomState>(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged); newConnection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined); newConnection.On <MultiplayerRoomUser>(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft); newConnection.On <int>(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); newConnection.On <MultiplayerRoomSettings>(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); newConnection.On <int, MultiplayerUserState>(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); newConnection.On(nameof(IMultiplayerClient.LoadRequested), ((IMultiplayerClient)this).LoadRequested); newConnection.On(nameof(IMultiplayerClient.MatchStarted), ((IMultiplayerClient)this).MatchStarted); newConnection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); newConnection.On <int, IEnumerable <APIMod> >(nameof(IMultiplayerClient.UserModsChanged), ((IMultiplayerClient)this).UserModsChanged); newConnection.On <int, BeatmapAvailability>(nameof(IMultiplayerClient.UserBeatmapAvailabilityChanged), ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged); newConnection.Closed += ex => { isConnected.Value = false; Logger.Log(ex != null ? $"Multiplayer client lost connection: {ex}" : "Multiplayer client disconnected", LoggingTarget.Network); // make sure a disconnect wasn't triggered (and this is still the active connection). if (!cancellationToken.IsCancellationRequested) { Task.Run(connect, default); } return(Task.CompletedTask); }; return(newConnection); }
private HubConnection buildConnection(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => { // Use HttpClient.DefaultProxy once on net6 everywhere. // The credential setter can also be removed at this point. options.Proxy = WebRequest.DefaultWebProxy; if (options.Proxy != null) { options.Proxy.Credentials = CredentialCache.DefaultCredentials; } options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); options.Headers.Add("OsuVersionHash", versionHash); }); if (RuntimeInfo.SupportsJIT && preferMessagePack) { builder.AddMessagePackProtocol(options => { options.SerializerOptions = SignalRUnionWorkaroundResolver.OPTIONS; }); } 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; options.PayloadSerializerSettings.Converters = new List <JsonConverter> { new SignalRDerivedTypeWorkaroundJsonConverter(), }; }); } var newConnection = builder.Build(); ConfigureConnection?.Invoke(newConnection); newConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); return(newConnection); }
/// <summary> /// Open connection /// </summary> /// <returns></returns> private async Task <HubConnection> OpenAsync() { var builder = new HubConnectionBuilder() .WithAutomaticReconnect(); if (_useMessagePack && _msgPack != null) { builder = builder.AddMessagePackProtocol(options => { options.FormatterResolvers = _msgPack.GetResolvers().ToList(); }); } else { var jsonSettings = _jsonSettings?.Settings; if (jsonSettings != null) { builder = builder.AddNewtonsoftJsonProtocol(options => { options.PayloadSerializerSettings = jsonSettings; }); } } var connection = builder .WithUrl(_endpointUri, options => { if (_provider != null) { options.AccessTokenProvider = async() => { var token = await _provider.GetTokenForAsync(_resourceId); if (token?.RawToken == null) { _logger.Error("Failed to aquire token for hub calling " + "({resource}) - calling without...", _resourceId); } return(token?.RawToken); }; } }) .Build(); connection.Closed += ex => OnClosedAsync(connection, ex); await connection.StartAsync(); return(connection); }
private HubConnection buildConnection(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => { options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); options.Headers.Add("OsuVersionHash", versionHash); }); if (RuntimeInfo.SupportsJIT && preferMessagePack) { builder.AddMessagePackProtocol(options => { options.SerializerOptions = SignalRUnionWorkaroundResolver.OPTIONS; }); } 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; // TODO: This should only be required to be `TypeNameHandling.Auto`. // See usage in osu-server-spectator for further documentation as to why this is required. options.PayloadSerializerSettings.TypeNameHandling = TypeNameHandling.All; }); } var newConnection = builder.Build(); ConfigureConnection?.Invoke(newConnection); newConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); return(newConnection); }
/// <summary> /// Starts the connection. /// </summary> /// <returns></returns> public async Task StartAsync() { if (IsStarted) { return; } var builder = new HubConnectionBuilder().WithUrl(Url).WithAutomaticReconnect(); if (UseMessagePackProtocol) { builder = builder.AddMessagePackProtocol(); } if (EnableAutoReconnection) { builder = builder.WithAutomaticReconnect(new TimeSpan[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1) }); } _connection = builder.Build(); bool reconnecting = false; _connection.Closed += (exception) => { if (EnableAutoReconnection) { if (reconnecting && _connection.State == HubConnectionState.Disconnected && exception.GetType() == typeof(OperationCanceledException)) { Error?.Invoke(this, new ResonanceExceptionEventArgs(exception)); } } return(Task.FromResult(true)); }; _connection.Reconnecting += (ex) => { if (!reconnecting) { reconnecting = true; if (EnableAutoReconnection) { Reconnecting?.Invoke(this, new EventArgs()); } else { try { Stop(); Error?.Invoke(this, new ResonanceExceptionEventArgs(ex)); } catch { } } } return(Task.FromResult(true)); }; _connection.Reconnected += (msg) => { if (EnableAutoReconnection) { Reconnected?.Invoke(this, new EventArgs()); reconnecting = false; } return(Task.FromResult(true)); }; await _connection.StartAsync(); IsStarted = true; }
private async Task RefreshConnection() { var connectionText = $"{addressBox.Text}/ua"; if (connection != null && connection.State == HubConnectionState.Connected) { await connection.StopAsync(); } var connectionBuilder = new HubConnectionBuilder() .WithUrl(connectionText); connectionBuilder.AddMessagePackProtocol(); connection = connectionBuilder.Build(); connection.On( "ShowSimpleTextStatistics", (ServerPresentationComputationSummary summary) => { Invoke(new Action(() => { int toCompute = summary.total - summary.finishedAutomata.Count; chart1.Series["UnaryFinishedSeries"].Points.Clear(); chart1.Series["UnaryFinishedSeries"].Points.AddXY("To compute", toCompute); chart1.Series["UnaryFinishedSeries"].Points.AddXY("Computed", summary.finishedAutomata.Count); if (summary.finishedAutomata.Count > 0) { chart1.Titles[0].Text = $"Unary Automata with n = {summary.n}"; totalComputingTime = GetTotalComputationTime(summary.finishedAutomata); var totalSpeed = GetAverageSpeed(summary.finishedAutomata); double leftSeconds; if (totalSpeed == 0) { if (toCompute == 0) { leftSeconds = 0; } else { leftSeconds = Double.MaxValue; } } else { leftSeconds = toCompute / totalSpeed; } startCountingTime = DateTime.Now; if (!timerLaunched && summary.finishedAutomata.Count == summary.total) { materialLabel1.Text = "Total computation time: " + totalComputingTime.ToString(); } else if (!timerLaunched && summary.finishedAutomata.Count < summary.total) { timer1.Tick += (o, e) => { materialLabel1.Text = "Total computation time: " + (totalComputingTime + (DateTime.Now - startCountingTime)).ToString(); }; timer1.Start(); timerLaunched = true; } else if (summary.finishedAutomata.Count == summary.total) { timer1.Stop(); timerLaunched = false; } materialLabel3.Text = $"Total speed: {totalSpeed:F2} automata per second."; materialLabel2.Text = "Expected end of computation at: " + DateTime.Now.AddSeconds(leftSeconds).ToString(); } var sortedLengths = new List <int>(); var sortedResults = new List <Tuple <int, string> >(); foreach (var a in summary.finishedAutomata) { if (a.solution.solvedB.Count > 0) { string b_tab, a_tab = byteTabToString(a.solution.unaryArray); for (int i = 0; i < a.solution.solvedB.Count; i++) { var b = a.solution.solvedB[i]; b_tab = byteTabToString(b); sortedLengths.Add(-a.solution.solvedSyncLength[i]); sortedResults.Add(new Tuple <int, string>(a.solution.unaryIndex, $"[{a_tab},{b_tab}]")); } } } listOfAutomata.Items.Clear(); automataToLaunch.Clear(); var resultingArray = sortedResults.ToArray(); var resultingLengthsNegated = sortedLengths.ToArray(); Array.Sort(resultingLengthsNegated, resultingArray); for (int i = 0; i < resultingArray.Length; i++) { automataToLaunch.Add(resultingArray[i].Item2); listOfAutomata.Items.Add($"{resultingArray[i].Item2}, index = {resultingArray[i].Item1} - synchronizing length {-1 * resultingLengthsNegated[i]}"); } var cernyLength = (summary.n - 1) * (summary.n - 1); var cernyConjectureViolated = resultingLengthsNegated.Length > 0 && Math.Abs(resultingLengthsNegated[0]) > cernyLength; var yetText = summary.finishedAutomata.Count < summary.total ? "yet " : string.Empty; var cernyConjectureViolatedText = cernyConjectureViolated ? $"VIOLATED for n = {summary.n}!" : $"not {yetText}violated for n = {summary.n}"; labelAutomataCount.Text = $"There are {listOfAutomata.Items.Count} interesting automata.\nCerny conjecture is {cernyConjectureViolatedText}"; })); } ); try { await connection.StartAsync(); connectionAddress = connectionText; } catch (Exception e) { } }
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(); // until strong typed client support is added, each method must be manually bound (see https://github.com/dotnet/aspnetcore/issues/15198) connection.On <int, SpectatorState>(nameof(ISpectatorClient.UserBeganPlaying), ((ISpectatorClient)this).UserBeganPlaying); connection.On <int, FrameDataBundle>(nameof(ISpectatorClient.UserSentFrames), ((ISpectatorClient)this).UserSentFrames); connection.On <int, SpectatorState>(nameof(ISpectatorClient.UserFinishedPlaying), ((ISpectatorClient)this).UserFinishedPlaying); connection.Closed += async ex => { isConnected = false; playingUsers.Clear(); if (ex != null) { Logger.Log($"Spectator client lost connection: {ex}", LoggingTarget.Network); await tryUntilConnected(); } }; await tryUntilConnected(); async Task tryUntilConnected() { Logger.Log("Spectator client connecting...", LoggingTarget.Network); while (api.State.Value == APIState.Online) { try { // reconnect on any failure await connection.StartAsync(); Logger.Log("Spectator client connected!", LoggingTarget.Network); // get all the users that were previously being watched int[] users; lock (userLock) { users = watchingUsers.ToArray(); watchingUsers.Clear(); } // success isConnected = true; // resubscribe to watched users foreach (var userId in users) { WatchUser(userId); } // re-send state in case it wasn't received if (isPlaying) { beginPlaying(); } break; } catch (Exception e) { Logger.Log($"Spectator client connection error: {e}", LoggingTarget.Network); await Task.Delay(5000); } } } }
private List <HubConnection> Create(int conn, string url, string transportTypeName = "Websockets", string hubProtocol = "json") { Util.Log($"transport type: {transportTypeName}"); var transportType = HttpTransportType.WebSockets; switch (transportTypeName) { case "LongPolling": transportType = HttpTransportType.LongPolling; break; case "ServerSentEvents": transportType = HttpTransportType.ServerSentEvents; break; case "None": transportType = HttpTransportType.None; break; default: transportType = HttpTransportType.WebSockets; break; } // Many Urls are allowed for sharding every connection to different Server var serverUrls = url.Split(';'); _tk.State = Stat.Types.State.HubconnCreating; var connections = new List <HubConnection>(conn); for (var i = 0; i < conn; i++) { var cookies = new CookieContainer(); var httpClientHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, CookieContainer = cookies, }; var hubConnectionBuilder = new HubConnectionBuilder() /* TODO. Console log is important for finding errors. * But if every connection enables it, there will be thousands of * 'Console logger queue processing thread' which degrade the system * response, and bring issues to counters statistic. * Temporarily, we disable it. We need to find the best way * to enable it. */ //.ConfigureLogging(logging => //{ // logging.AddConsole(); // logging.SetMinimumLevel(LogLevel.Warning); //}) .WithUrl(serverUrls[i % serverUrls.Length], httpConnectionOptions => { httpConnectionOptions.HttpMessageHandlerFactory = _ => httpClientHandler; httpConnectionOptions.Transports = transportType; httpConnectionOptions.CloseTimeout = TimeSpan.FromMinutes(100); httpConnectionOptions.Cookies = cookies; }); HubConnection connection = null; switch (hubProtocol) { case "json": connection = hubConnectionBuilder.Build(); break; case "messagepack": connection = hubConnectionBuilder.AddMessagePackProtocol().Build(); break; default: throw new Exception($"{hubProtocol} is invalid."); } connection.Closed += e => { if (_tk.State <= Stat.Types.State.SendComplete && _tk.State >= Stat.Types.State.SendReady) { var error = $"Connection closed early: {e}"; Util.Log(error); } return(Task.CompletedTask); }; connections.Add(connection); } _tk.State = Stat.Types.State.HubconnCreated; return(connections); }
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); } } } }