mirror of
https://github.com/ppy/osu.git
synced 2026-06-03 02:31:25 +08:00
Fix leak from polling chat client being initialised too early
This one is quite dumb. `OsuGame` uses [`loadComponentSingleFile`](https://github.com/ppy/osu/blob/15878f7f9fc7088494d3b66e98a7bc1004a1a06d/osu.Game/OsuGame.cs#L1228) to load the `ChannelManager`. Importantly, this process does _not_ add the component to any place in the hierarchy where it would normally be disposed - this includes `InternalChildren`, but _also_ a lesser known list of [currently-loading components](https://github.com/ppy/osu-framework/blob/cfb0d7b4b673583f0cf56273e94352769aa5bc9a/osu.Framework/Graphics/Containers/CompositeDrawable.cs#L316-L323) (those which have been sent through a `LoadComponentAsync` call). The end result of this is that, `ChannelManager` creates the `IChatClient` in its constructor, expecting to be able to dispose it, but `Dispose` is never called! And the failure case here is that `PollingChatClient` creates a background task to continuously poll the API, unfortunately keeping a reference to the rest of the world in the process.
This commit is contained in:
@@ -9,6 +9,7 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
@@ -64,7 +65,6 @@ namespace osu.Game.Online.Chat
|
||||
public IBindableList<Channel> AvailableChannels => availableChannels;
|
||||
|
||||
private readonly IAPIProvider api;
|
||||
private readonly IChatClient chatClient;
|
||||
|
||||
[Resolved]
|
||||
private UserLookupCache users { get; set; }
|
||||
@@ -72,6 +72,7 @@ namespace osu.Game.Online.Chat
|
||||
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
||||
private ScheduledDelegate scheduledAck;
|
||||
|
||||
private IChatClient chatClient = null!;
|
||||
private long? lastSilenceMessageId;
|
||||
private uint? lastSilenceId;
|
||||
|
||||
@@ -79,14 +80,13 @@ namespace osu.Game.Online.Chat
|
||||
{
|
||||
this.api = api;
|
||||
|
||||
chatClient = api.GetChatClient();
|
||||
|
||||
CurrentChannel.ValueChanged += currentChannelChanged;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
chatClient = api.GetChatClient();
|
||||
chatClient.ChannelJoined += ch => Schedule(() => joinChannel(ch));
|
||||
chatClient.ChannelParted += ch => Schedule(() => leaveChannel(getChannel(ch), false));
|
||||
chatClient.NewMessages += msgs => Schedule(() => addMessages(msgs));
|
||||
@@ -282,8 +282,7 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
// Check if the user has joined the requested channel already.
|
||||
// This uses the channel name for comparison as the PM user's username is unavailable after a restart.
|
||||
var privateChannel = JoinedChannels.FirstOrDefault(
|
||||
c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase));
|
||||
var privateChannel = JoinedChannels.FirstOrDefault(c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (privateChannel != null)
|
||||
{
|
||||
@@ -645,7 +644,9 @@ namespace osu.Game.Online.Chat
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
chatClient?.Dispose();
|
||||
|
||||
if (chatClient.IsNotNull())
|
||||
chatClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user