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

Add support for creating, joining, and parting osu!web rooms via interop #265

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
11 changes: 5 additions & 6 deletions SampleMultiplayerClient/MultiplayerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,14 @@ public MultiplayerClient(HubConnection connection, int userId)

public MultiplayerRoom? Room { get; private set; }

public Task<MultiplayerRoom> CreateRoom(MultiplayerRoom room)
=> connection.InvokeAsync<MultiplayerRoom>(nameof(IMultiplayerServer.CreateRoom), room);

public async Task<MultiplayerRoom> JoinRoom(long roomId)
{
return await JoinRoomWithPassword(roomId, string.Empty);
}
=> await JoinRoomWithPassword(roomId, string.Empty);

public async Task<MultiplayerRoom> JoinRoomWithPassword(long roomId, string? password = null)
{
return Room = await connection.InvokeAsync<MultiplayerRoom>(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty);
}
=> Room = await connection.InvokeAsync<MultiplayerRoom>(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty);

public async Task LeaveRoom()
{
Expand Down
6 changes: 5 additions & 1 deletion osu.Server.Spectator.Tests/Multiplayer/MultiplayerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using osu.Server.Spectator.Database.Models;
using osu.Server.Spectator.Entities;
using osu.Server.Spectator.Hubs.Multiplayer;
using osu.Server.Spectator.Services;

namespace osu.Server.Spectator.Tests.Multiplayer
{
Expand Down Expand Up @@ -130,13 +131,16 @@ protected MultiplayerTest()
loggerFactoryMock.Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(new Mock<ILogger>().Object);

var legacyIOMock = new Mock<ILegacyIO>();

Hub = new TestMultiplayerHub(
loggerFactoryMock.Object,
Rooms,
UserStates,
DatabaseFactory.Object,
new ChatFilters(DatabaseFactory.Object),
hubContext.Object);
hubContext.Object,
legacyIOMock.Object);
Hub.Groups = Groups.Object;
Hub.Clients = Clients.Object;

Expand Down
6 changes: 4 additions & 2 deletions osu.Server.Spectator.Tests/Multiplayer/TestMultiplayerHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using osu.Server.Spectator.Database;
using osu.Server.Spectator.Entities;
using osu.Server.Spectator.Hubs.Multiplayer;
using osu.Server.Spectator.Services;

namespace osu.Server.Spectator.Tests.Multiplayer
{
Expand All @@ -19,8 +20,9 @@ public TestMultiplayerHub(
EntityStore<MultiplayerClientState> users,
IDatabaseFactory databaseFactory,
ChatFilters chatFilters,
IHubContext<MultiplayerHub> hubContext)
: base(loggerFactory, rooms, users, databaseFactory, chatFilters, hubContext)
IHubContext<MultiplayerHub> hubContext,
ILegacyIO legacyIO)
: base(loggerFactory, rooms, users, databaseFactory, chatFilters, hubContext, legacyIO)
{
}

Expand Down
1 change: 1 addition & 0 deletions osu.Server.Spectator.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUD/@EntryIndexedValue">HUD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IL/@EntryIndexedValue">IL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IO/@EntryIndexedValue">IO</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IOS/@EntryIndexedValue">IOS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IPC/@EntryIndexedValue">IPC</s:String>
Expand Down
11 changes: 11 additions & 0 deletions osu.Server.Spectator/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public static class AppSettings
public static string DatabaseUser { get; }
public static string DatabasePort { get; }

public static string LegacyIODomain { get; }
public static string SharedInteropSecret { get; }

static AppSettings()
{
SaveReplays = Environment.GetEnvironmentVariable("SAVE_REPLAYS") == "1";
Expand All @@ -53,6 +56,14 @@ static AppSettings()
DatabaseHost = Environment.GetEnvironmentVariable("DB_HOST") ?? "localhost";
DatabaseUser = Environment.GetEnvironmentVariable("DB_USER") ?? "osuweb";
DatabasePort = Environment.GetEnvironmentVariable("DB_PORT") ?? "3306";

LegacyIODomain = Environment.GetEnvironmentVariable("LEGACY_IO_DOMAIN")
?? throw new InvalidOperationException("LEGACY_IO_DOMAIN environment variable not set. "
+ "Please set the value of this variable to the root URL of the osu-web instance to which legacy IO call should be submitted.");

SharedInteropSecret = Environment.GetEnvironmentVariable("SHARED_INTEROP_SECRET")
?? throw new InvalidOperationException("SHARED_INTEROP_SECRET environment variable not set. "
+ "Please set the value of this variable to the value of the same environment variable that the target osu-web instance specifies in `.env`.");
bdach marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using osu.Server.Spectator.Hubs.Metadata;
using osu.Server.Spectator.Hubs.Multiplayer;
using osu.Server.Spectator.Hubs.Spectator;
using osu.Server.Spectator.Services;
using osu.Server.Spectator.Storage;
using StackExchange.Redis;

Expand All @@ -17,7 +18,9 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection AddHubEntities(this IServiceCollection serviceCollection)
{
return serviceCollection.AddSingleton<EntityStore<SpectatorClientState>>()
return serviceCollection.AddHttpClient()
.AddTransient<ILegacyIO, LegacyIO>()
.AddSingleton<EntityStore<SpectatorClientState>>()
.AddSingleton<EntityStore<MultiplayerClientState>>()
.AddSingleton<EntityStore<ServerMultiplayerRoom>>()
.AddSingleton<EntityStore<ConnectionState>>()
Expand Down
25 changes: 19 additions & 6 deletions osu.Server.Spectator/Hubs/Multiplayer/MultiplayerHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using osu.Server.Spectator.Database.Models;
using osu.Server.Spectator.Entities;
using osu.Server.Spectator.Extensions;
using osu.Server.Spectator.Services;

namespace osu.Server.Spectator.Hubs.Multiplayer
{
Expand All @@ -25,34 +26,44 @@ public class MultiplayerHub : StatefulUserHub<IMultiplayerClient, MultiplayerCli
protected readonly MultiplayerHubContext HubContext;
private readonly IDatabaseFactory databaseFactory;
private readonly ChatFilters chatFilters;
private readonly ILegacyIO legacyIO;

public MultiplayerHub(
ILoggerFactory loggerFactory,
EntityStore<ServerMultiplayerRoom> rooms,
EntityStore<MultiplayerClientState> users,
IDatabaseFactory databaseFactory,
ChatFilters chatFilters,
IHubContext<MultiplayerHub> hubContext)
IHubContext<MultiplayerHub> hubContext,
ILegacyIO legacyIO)
: base(loggerFactory, users)
{
Rooms = rooms;
this.databaseFactory = databaseFactory;
this.chatFilters = chatFilters;
this.legacyIO = legacyIO;
HubContext = new MultiplayerHubContext(hubContext, rooms, users, databaseFactory, loggerFactory);
}

public async Task<MultiplayerRoom> CreateRoom(MultiplayerRoom room)
{
Log($"{Context.GetUserId()} creating room");
return await JoinRoomWithPassword(await legacyIO.CreateRoom(Context.GetUserId(), room), room.Settings.Password);
}

public Task<MultiplayerRoom> JoinRoom(long roomId) => JoinRoomWithPassword(roomId, string.Empty);

public async Task<MultiplayerRoom> JoinRoomWithPassword(long roomId, string password)
{
Log($"Attempting to join room {roomId}");

bool isRestricted;
using (var db = databaseFactory.GetInstance())
isRestricted = await db.IsUserRestrictedAsync(Context.GetUserId());
{
if (await db.IsUserRestrictedAsync(Context.GetUserId()))
throw new InvalidStateException("Can't join a room when restricted.");
}

if (isRestricted)
throw new InvalidStateException("Can't join a room when restricted.");
await legacyIO.JoinRoom(roomId, Context.GetUserId());

using (var userUsage = await GetOrCreateLocalUserState())
{
Expand Down Expand Up @@ -720,8 +731,8 @@ private async Task removeDatabaseUser(MultiplayerRoom room, MultiplayerRoomUser

protected override async Task CleanUpState(MultiplayerClientState state)
{
await leaveRoom(state, true);
await base.CleanUpState(state);
await leaveRoom(state, true);
Comment on lines -723 to +735
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meaningless change because the base implementation is empty. I just thought I'd make this consistent with other implementations, seeing as leaveRoom can throw an exception.

}

private async Task setNewHost(MultiplayerRoom room, MultiplayerRoomUser newHost)
Expand Down Expand Up @@ -883,6 +894,8 @@ private async Task<ItemUsage<ServerMultiplayerRoom>> getLocalUserRoom(Multiplaye

private async Task leaveRoom(MultiplayerClientState state, bool wasKick)
{
await legacyIO.PartRoom(state.CurrentRoomID, state.UserId);

using (var roomUsage = await getLocalUserRoom(state))
await leaveRoom(state, roomUsage, wasKick);
}
Expand Down
33 changes: 33 additions & 0 deletions osu.Server.Spectator/Services/ILegacyIO.cs
bdach marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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.Threading.Tasks;
using osu.Game.Online.Multiplayer;

namespace osu.Server.Spectator.Services
{
public interface ILegacyIO
{
/// <summary>
/// Creates an osu!web Room.
/// </summary>
/// <param name="userId">The ID of the user that wants to create the room.</param>
/// <param name="room">The room.</param>
/// <returns>The room's ID.</returns>
Task<long> CreateRoom(int userId, MultiplayerRoom room);

/// <summary>
/// Joins an osu!web Room.
/// </summary>
/// <param name="roomId">The ID of the room to join.</param>
/// <param name="userId">The ID of the user wanting to join the room.</param>
Task JoinRoom(long roomId, int userId);

/// <summary>
/// Parts an osu!web Room.
/// </summary>
/// <param name="roomId">The ID of the room to part.</param>
/// <param name="userId">The ID of the user wanting to part the room.</param>
Task PartRoom(long roomId, int userId);
}
}
Loading
Loading