Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ppy
GitHub Repository: ppy/osu
Path: blob/master/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs
4391 views
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Logging;
using osu.Game.Utils;

namespace osu.Game.Online.Multiplayer
{
    public static class MultiplayerClientExtensions
    {
        public static void FireAndForget(this Task task, Action? onSuccess = null, Action<Exception>? onError = null) =>
            task.ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    Debug.Assert(t.Exception != null);
                    Exception exception = t.Exception.AsSingular();

                    onError?.Invoke(exception);

                    // OnlineStatusNotifier is already letting users know about interruptions to connections.
                    // Silence these because it gets very spammy otherwise.
                    if (SentryLogger.IsLocalUserConnectivityException(exception))
                        return;

                    if (exception.GetHubExceptionMessage() is string message)
                    {
                        // Hub exceptions generally contain something we can show the user directly.
                        Logger.Log(message, level: LogLevel.Important);
                        return;
                    }

                    Logger.Error(exception, $"Unobserved exception occurred via {nameof(FireAndForget)} call: {exception.Message}");
                }
                else
                {
                    onSuccess?.Invoke();
                }
            });

        public static string? GetHubExceptionMessage(this Exception exception)
        {
            if (exception is HubException hubException)
                // HubExceptions arrive with additional message context added, but we want to display the human readable message:
                // "An unexpected error occurred invoking 'AddPlaylistItem' on the server.InvalidStateException: Can't enqueue more than 3 items at once."
                // We generally use the message field for a user-parseable error (eventually to be replaced), so drop the first part for now.
                return hubException.Message.Substring(exception.Message.IndexOf(':') + 1).Trim();

            return null;
        }
    }
}