osu/osu.Game/Online/Metadata/OnlineMetadataClient.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

126 lines
4.4 KiB
C#
Raw Normal View History

2022-07-04 08:18:33 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
2022-07-04 08:49:08 +00:00
using System.Diagnostics;
2022-07-04 08:18:33 +00:00
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using osu.Framework.Allocation;
2022-07-04 08:49:08 +00:00
using osu.Framework.Bindables;
2022-07-04 08:18:33 +00:00
using osu.Framework.Logging;
using osu.Game.Configuration;
2022-07-04 08:18:33 +00:00
using osu.Game.Online.API;
namespace osu.Game.Online.Metadata
{
public class OnlineMetadataClient : MetadataClient
{
private readonly string endpoint;
private IHubClientConnector? connector;
private Bindable<int> lastQueueId = null!;
2022-07-04 08:49:08 +00:00
2022-07-04 08:18:33 +00:00
private HubConnection? connection => connector?.CurrentConnection;
public OnlineMetadataClient(EndpointConfiguration endpoints)
2022-07-04 08:18:33 +00:00
{
endpoint = endpoints.MetadataEndpointUrl;
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api, OsuConfigManager config)
2022-07-04 08:18:33 +00:00
{
// Importantly, we are intentionally not using MessagePack here to correctly support derived class serialization.
// More information on the limitations / reasoning can be found in osu-server-spectator's initialisation code.
connector = api.GetHubConnector(nameof(OnlineMetadataClient), endpoint);
if (connector != null)
{
connector.ConfigureConnection = connection =>
{
// this is kind of SILLY
// https://github.com/dotnet/aspnetcore/issues/15198
connection.On<BeatmapUpdates>(nameof(IMetadataClient.BeatmapSetsUpdated), ((IMetadataClient)this).BeatmapSetsUpdated);
};
2022-07-04 08:49:08 +00:00
connector.IsConnected.BindValueChanged(isConnectedChanged, true);
}
lastQueueId = config.GetBindable<int>(OsuSetting.LastProcessedMetadataId);
2022-07-04 08:49:08 +00:00
}
private bool catchingUp;
private void isConnectedChanged(ValueChangedEvent<bool> connected)
{
if (!connected.NewValue)
return;
if (lastQueueId.Value >= 0)
2022-07-04 08:49:08 +00:00
{
catchingUp = true;
Task.Run(async () =>
{
try
{
while (true)
{
Logger.Log($"Requesting catch-up from {lastQueueId.Value}");
var catchUpChanges = await GetChangesSince(lastQueueId.Value);
lastQueueId.Value = catchUpChanges.LastProcessedQueueID;
2022-07-04 08:49:08 +00:00
if (catchUpChanges.BeatmapSetIDs.Length == 0)
{
Logger.Log($"Catch-up complete at {lastQueueId.Value}");
break;
}
await ProcessChanges(catchUpChanges.BeatmapSetIDs);
}
}
catch (Exception e)
{
Logger.Log($"Error while processing catch-up of metadata ({e.Message})");
}
2022-07-04 08:49:08 +00:00
finally
{
catchingUp = false;
}
});
2022-07-04 08:18:33 +00:00
}
}
2022-07-04 08:49:08 +00:00
public override async Task BeatmapSetsUpdated(BeatmapUpdates updates)
2022-07-04 08:18:33 +00:00
{
Logger.Log($"Received beatmap updates {updates.BeatmapSetIDs.Length} updates with last id {updates.LastProcessedQueueID}");
2022-07-04 08:49:08 +00:00
// If we're still catching up, avoid updating the last ID as it will interfere with catch-up efforts.
if (!catchingUp)
lastQueueId.Value = updates.LastProcessedQueueID;
2022-07-04 08:49:08 +00:00
await ProcessChanges(updates.BeatmapSetIDs);
}
public override Task<BeatmapUpdates> GetChangesSince(int queueId)
2022-07-04 08:18:33 +00:00
{
2022-07-04 08:49:08 +00:00
if (connector?.IsConnected.Value != true)
return Task.FromCanceled<BeatmapUpdates>(default);
Logger.Log($"Requesting any changes since last known queue id {queueId}");
Debug.Assert(connection != null);
return connection.InvokeAsync<BeatmapUpdates>(nameof(IMetadataServer.GetChangesSince), queueId);
2022-07-04 08:18:33 +00:00
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
connector?.Dispose();
}
}
}