Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify users of who is spectating them #259

Merged
merged 7 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions SampleSpectatorClient/SpectatorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ Task ISpectatorClient.UserScoreProcessed(int userId, long scoreId)
return Task.CompletedTask;
}

Task ISpectatorClient.UserStartedWatching(SpectatorUser[] users)
{
foreach (var user in users)
Console.WriteLine($"{connection.ConnectionId} User {user.OnlineID} started watching you");
return Task.CompletedTask;
}

Task ISpectatorClient.UserEndedWatching(int userId)
{
Console.WriteLine($"{connection.ConnectionId} User {userId} ended watching you");
return Task.CompletedTask;
}

public Task BeginPlaying(long? scoreToken, SpectatorState state) => connection.SendAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state);

public Task SendFrames(FrameDataBundle data) => connection.SendAsync(nameof(ISpectatorServer.SendFrameData), data);
Expand Down
13 changes: 11 additions & 2 deletions osu.Server.Spectator.Tests/SpectatorHubTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Moq;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Osu.Mods;
Expand Down Expand Up @@ -42,6 +41,7 @@ public class SpectatorHubTest
public SpectatorHubTest()
{
var clientStates = new EntityStore<SpectatorClientState>();
var spectatorLists = new EntityStore<SpectatorList>();

mockDatabase = new Mock<IDatabaseAccess>();
mockDatabase.Setup(db => db.GetUsernameAsync(streamer_id)).ReturnsAsync(() => streamer_username);
Expand All @@ -65,7 +65,7 @@ public SpectatorHubTest()

var mockScoreProcessedSubscriber = new Mock<IScoreProcessedSubscriber>();

hub = new SpectatorHub(loggerFactory.Object, clientStates, databaseFactory.Object, scoreUploader, mockScoreProcessedSubscriber.Object);
hub = new SpectatorHub(loggerFactory.Object, clientStates, spectatorLists, databaseFactory.Object, scoreUploader, mockScoreProcessedSubscriber.Object);
}

[Fact]
Expand Down Expand Up @@ -325,9 +325,12 @@ public async Task NewUserBeginsWatchingStream(bool ongoing)

Mock<IHubCallerClients<ISpectatorClient>> mockClients = new Mock<IHubCallerClients<ISpectatorClient>>();
Mock<ISpectatorClient> mockCaller = new Mock<ISpectatorClient>();
Mock<ISpectatorClient> mockStreamer = new Mock<ISpectatorClient>();

mockClients.Setup(clients => clients.Caller).Returns(mockCaller.Object);
mockClients.Setup(clients => clients.All).Returns(mockCaller.Object);
mockClients.Setup(clients => clients.User(streamer_id.ToString())).Returns(mockStreamer.Object);
mockDatabase.Setup(db => db.GetUsernameAsync(watcher_id)).ReturnsAsync("watcher");

Mock<IGroupManager> mockGroups = new Mock<IGroupManager>();

Expand Down Expand Up @@ -362,6 +365,12 @@ public async Task NewUserBeginsWatchingStream(bool ongoing)
mockGroups.Verify(groups => groups.AddToGroupAsync(connectionId, SpectatorHub.GetGroupId(streamer_id), default));

mockCaller.Verify(clients => clients.UserBeganPlaying(streamer_id, It.Is<SpectatorState>(m => m.Equals(state))), Times.Exactly(ongoing ? 2 : 0));
mockStreamer.Verify(client => client.UserStartedWatching(It.Is<SpectatorUser[]>(users => users.Single().OnlineID == watcher_id)), Times.Once);

await hub.EndWatchingUser(streamer_id);

mockGroups.Verify(groups => groups.RemoveFromGroupAsync(connectionId, SpectatorHub.GetGroupId(streamer_id), default));
mockStreamer.Verify(client => client.UserEndedWatching(watcher_id), Times.Once);
}

[Fact]
Expand Down
20 changes: 20 additions & 0 deletions osu.Server.Spectator/Hubs/Spectator/SpectatorHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,31 @@
}

await Groups.AddToGroupAsync(Context.ConnectionId, GetGroupId(userId));

int watcherId = Context.GetUserId();
string? watcherUsername;
using (var db = databaseFactory.GetInstance())
watcherUsername = await db.GetUsernameAsync(watcherId);

if (watcherUsername == null)
return;

var watcher = new SpectatorUser

Check failure on line 215 in osu.Server.Spectator/Hubs/Spectator/SpectatorHub.cs

View workflow job for this annotation

GitHub Actions / Unit testing

The type or namespace name 'SpectatorUser' could not be found (are you missing a using directive or an assembly reference?)
{
OnlineID = watcherId,
Username = watcherUsername,
};

await Clients.User(userId.ToString()).UserStartedWatching([watcher]);

Check failure on line 221 in osu.Server.Spectator/Hubs/Spectator/SpectatorHub.cs

View workflow job for this annotation

GitHub Actions / Unit testing

'ISpectatorClient' does not contain a definition for 'UserStartedWatching' and no accessible extension method 'UserStartedWatching' accepting a first argument of type 'ISpectatorClient' could be found (are you missing a using directive or an assembly reference?)
}

public async Task EndWatchingUser(int userId)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupId(userId));

int watcherId = Context.GetUserId();

await Clients.User(userId.ToString()).UserEndedWatching(watcherId);

Check failure on line 230 in osu.Server.Spectator/Hubs/Spectator/SpectatorHub.cs

View workflow job for this annotation

GitHub Actions / Unit testing

'ISpectatorClient' does not contain a definition for 'UserEndedWatching' and no accessible extension method 'UserEndedWatching' accepting a first argument of type 'ISpectatorClient' could be found (are you missing a using directive or an assembly reference?)
}

public override async Task OnConnectedAsync()
Expand Down
Loading