2019-01-24 08:43:03 +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.
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2020-04-11 08:47:51 +00:00
|
|
|
|
using System;
|
2019-03-22 02:55:35 +00:00
|
|
|
|
using System.Threading;
|
2019-11-29 11:03:14 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2019-02-21 10:04:31 +00:00
|
|
|
|
using osu.Framework.Bindables;
|
2019-03-22 02:55:35 +00:00
|
|
|
|
using osu.Framework.Graphics;
|
2023-06-07 23:50:14 +00:00
|
|
|
|
using osu.Game.Localisation;
|
2021-11-04 09:02:44 +00:00
|
|
|
|
using osu.Game.Online.API.Requests.Responses;
|
2022-11-01 12:34:34 +00:00
|
|
|
|
using osu.Game.Online.Notifications;
|
2022-11-04 09:52:57 +00:00
|
|
|
|
using osu.Game.Tests;
|
2018-02-16 04:47:30 +00:00
|
|
|
|
using osu.Game.Users;
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-02-16 04:47:30 +00:00
|
|
|
|
namespace osu.Game.Online.API
|
|
|
|
|
{
|
2019-03-22 02:55:35 +00:00
|
|
|
|
public partial class DummyAPIAccess : Component, IAPIProvider
|
2018-02-16 04:47:30 +00:00
|
|
|
|
{
|
2022-06-27 07:50:07 +00:00
|
|
|
|
public const int DUMMY_USER_ID = 1001;
|
|
|
|
|
|
2021-11-04 09:02:44 +00:00
|
|
|
|
public Bindable<APIUser> LocalUser { get; } = new Bindable<APIUser>(new APIUser
|
2018-02-16 04:47:30 +00:00
|
|
|
|
{
|
2023-08-16 04:52:23 +00:00
|
|
|
|
Username = @"Local user",
|
2022-06-27 07:50:07 +00:00
|
|
|
|
Id = DUMMY_USER_ID,
|
2018-02-16 04:47:30 +00:00
|
|
|
|
});
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2021-11-04 09:02:44 +00:00
|
|
|
|
public BindableList<APIUser> Friends { get; } = new BindableList<APIUser>();
|
2020-12-17 10:30:55 +00:00
|
|
|
|
|
2019-06-12 09:04:57 +00:00
|
|
|
|
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
|
|
|
|
|
|
2024-01-03 08:37:57 +00:00
|
|
|
|
public Bindable<UserStatistics?> Statistics { get; } = new Bindable<UserStatistics?>();
|
|
|
|
|
|
2023-06-07 23:50:14 +00:00
|
|
|
|
public Language Language => Language.en;
|
|
|
|
|
|
2020-10-22 06:03:43 +00:00
|
|
|
|
public string AccessToken => "token";
|
|
|
|
|
|
2023-06-22 21:08:30 +00:00
|
|
|
|
/// <seealso cref="APIAccess.IsLoggedIn"/>
|
2023-06-22 20:01:12 +00:00
|
|
|
|
public bool IsLoggedIn => State.Value > APIState.Offline;
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2019-03-13 03:56:47 +00:00
|
|
|
|
public string ProvidedUsername => LocalUser.Value.Username;
|
|
|
|
|
|
2020-12-24 09:11:40 +00:00
|
|
|
|
public string APIEndpointUrl => "http://localhost";
|
|
|
|
|
|
|
|
|
|
public string WebsiteRootUrl => "http://localhost";
|
2019-03-13 03:56:47 +00:00
|
|
|
|
|
2022-02-17 09:33:27 +00:00
|
|
|
|
public int APIVersion => int.Parse(DateTime.Now.ToString("yyyyMMdd"));
|
|
|
|
|
|
2023-06-26 04:26:07 +00:00
|
|
|
|
public Exception? LastLoginError { get; private set; }
|
2021-10-04 06:40:24 +00:00
|
|
|
|
|
2020-04-11 08:47:51 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provide handling logic for an arbitrary API request.
|
2021-03-23 09:08:32 +00:00
|
|
|
|
/// Should return true is a request was handled. If null or false return, the request will be failed with a <see cref="NotSupportedException"/>.
|
2020-04-11 08:47:51 +00:00
|
|
|
|
/// </summary>
|
2023-06-26 04:26:07 +00:00
|
|
|
|
public Func<APIRequest, bool>? HandleRequest;
|
2020-04-11 08:47:51 +00:00
|
|
|
|
|
2020-10-22 05:19:12 +00:00
|
|
|
|
private readonly Bindable<APIState> state = new Bindable<APIState>(APIState.Online);
|
2019-03-22 02:55:35 +00:00
|
|
|
|
|
2021-10-04 06:40:24 +00:00
|
|
|
|
private bool shouldFailNextLogin;
|
2023-06-25 18:22:05 +00:00
|
|
|
|
private bool stayConnectingNextLogin;
|
2023-11-16 09:16:02 +00:00
|
|
|
|
private bool requiredSecondFactorAuth = true;
|
2021-10-04 06:40:24 +00:00
|
|
|
|
|
2020-10-22 05:19:12 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The current connectivity state of the API.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public IBindable<APIState> State => state;
|
2019-06-12 09:04:57 +00:00
|
|
|
|
|
|
|
|
|
public DummyAPIAccess()
|
|
|
|
|
{
|
|
|
|
|
LocalUser.BindValueChanged(u =>
|
|
|
|
|
{
|
|
|
|
|
u.OldValue?.Activity.UnbindFrom(Activity);
|
|
|
|
|
u.NewValue.Activity.BindTo(Activity);
|
|
|
|
|
}, true);
|
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2018-02-16 04:47:30 +00:00
|
|
|
|
public virtual void Queue(APIRequest request)
|
|
|
|
|
{
|
2022-05-30 07:32:44 +00:00
|
|
|
|
Schedule(() =>
|
2021-03-23 09:08:32 +00:00
|
|
|
|
{
|
2022-05-30 07:32:44 +00:00
|
|
|
|
if (HandleRequest?.Invoke(request) != true)
|
|
|
|
|
{
|
|
|
|
|
request.Fail(new InvalidOperationException($@"{nameof(DummyAPIAccess)} cannot process this request."));
|
|
|
|
|
}
|
|
|
|
|
});
|
2018-02-16 04:47:30 +00:00
|
|
|
|
}
|
2018-04-13 09:19:50 +00:00
|
|
|
|
|
2020-04-13 12:35:35 +00:00
|
|
|
|
public void Perform(APIRequest request) => HandleRequest?.Invoke(request);
|
2019-11-29 11:03:14 +00:00
|
|
|
|
|
2020-04-13 12:35:35 +00:00
|
|
|
|
public Task PerformAsync(APIRequest request)
|
|
|
|
|
{
|
|
|
|
|
HandleRequest?.Invoke(request);
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
2019-11-29 11:03:14 +00:00
|
|
|
|
|
2019-03-13 03:56:47 +00:00
|
|
|
|
public void Login(string username, string password)
|
|
|
|
|
{
|
2021-10-04 06:40:24 +00:00
|
|
|
|
state.Value = APIState.Connecting;
|
|
|
|
|
|
2023-06-25 18:22:05 +00:00
|
|
|
|
if (stayConnectingNextLogin)
|
|
|
|
|
{
|
|
|
|
|
stayConnectingNextLogin = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 06:40:24 +00:00
|
|
|
|
if (shouldFailNextLogin)
|
|
|
|
|
{
|
|
|
|
|
LastLoginError = new APIException("Not powerful enough to login.", new ArgumentException(nameof(shouldFailNextLogin)));
|
|
|
|
|
|
|
|
|
|
state.Value = APIState.Offline;
|
|
|
|
|
shouldFailNextLogin = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LastLoginError = null;
|
2021-11-04 09:02:44 +00:00
|
|
|
|
LocalUser.Value = new APIUser
|
2019-03-13 03:56:47 +00:00
|
|
|
|
{
|
2019-03-22 02:55:35 +00:00
|
|
|
|
Username = username,
|
2023-10-30 06:44:16 +00:00
|
|
|
|
Id = DUMMY_USER_ID,
|
2019-03-13 03:56:47 +00:00
|
|
|
|
};
|
2019-03-22 02:55:35 +00:00
|
|
|
|
|
2023-11-16 09:16:02 +00:00
|
|
|
|
if (requiredSecondFactorAuth)
|
2023-11-15 11:00:09 +00:00
|
|
|
|
{
|
2023-11-16 07:38:07 +00:00
|
|
|
|
state.Value = APIState.RequiresSecondFactorAuth;
|
2023-11-15 11:00:09 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2023-11-16 09:16:02 +00:00
|
|
|
|
{
|
2024-01-23 15:51:21 +00:00
|
|
|
|
onSuccessfulLogin();
|
2023-11-16 09:16:02 +00:00
|
|
|
|
requiredSecondFactorAuth = true;
|
|
|
|
|
}
|
2019-03-13 03:56:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-23 15:51:21 +00:00
|
|
|
|
public void AuthenticateSecondFactor(string code) => onSuccessfulLogin();
|
|
|
|
|
|
|
|
|
|
private void onSuccessfulLogin()
|
2023-11-16 07:38:07 +00:00
|
|
|
|
{
|
|
|
|
|
state.Value = APIState.Online;
|
2024-01-03 08:37:57 +00:00
|
|
|
|
Statistics.Value = new UserStatistics
|
|
|
|
|
{
|
|
|
|
|
GlobalRank = 1,
|
|
|
|
|
CountryRank = 1
|
|
|
|
|
};
|
2023-11-16 07:38:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 03:56:47 +00:00
|
|
|
|
public void Logout()
|
|
|
|
|
{
|
2020-10-22 05:19:12 +00:00
|
|
|
|
state.Value = APIState.Offline;
|
2023-06-22 21:08:30 +00:00
|
|
|
|
// must happen after `state.Value` is changed such that subscribers to that bindable's value changes see the correct user.
|
|
|
|
|
// compare: `APIAccess.Logout()`.
|
2023-06-22 20:01:12 +00:00
|
|
|
|
LocalUser.Value = new GuestUser();
|
2019-03-13 03:56:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-03 08:37:57 +00:00
|
|
|
|
public void UpdateStatistics(UserStatistics newStatistics)
|
|
|
|
|
{
|
|
|
|
|
Statistics.Value = newStatistics;
|
2024-01-03 12:15:32 +00:00
|
|
|
|
|
|
|
|
|
if (IsLoggedIn)
|
|
|
|
|
LocalUser.Value.Statistics = newStatistics;
|
2024-01-03 08:37:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-26 04:26:07 +00:00
|
|
|
|
public IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
|
2021-02-15 07:31:00 +00:00
|
|
|
|
|
2022-11-01 12:34:34 +00:00
|
|
|
|
public NotificationsClientConnector GetNotificationsConnector() => new PollingNotificationsClientConnector(this);
|
|
|
|
|
|
2023-06-26 04:26:07 +00:00
|
|
|
|
public RegistrationRequest.RegistrationRequestErrors? CreateAccount(string email, string username, string password)
|
2019-03-22 02:55:35 +00:00
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(200);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2020-10-22 05:19:12 +00:00
|
|
|
|
|
|
|
|
|
public void SetState(APIState newState) => state.Value = newState;
|
2020-12-18 06:16:36 +00:00
|
|
|
|
|
2021-11-04 09:02:44 +00:00
|
|
|
|
IBindable<APIUser> IAPIProvider.LocalUser => LocalUser;
|
|
|
|
|
IBindableList<APIUser> IAPIProvider.Friends => Friends;
|
2020-12-18 06:16:36 +00:00
|
|
|
|
IBindable<UserActivity> IAPIProvider.Activity => Activity;
|
2024-01-03 08:37:57 +00:00
|
|
|
|
IBindable<UserStatistics?> IAPIProvider.Statistics => Statistics;
|
2021-10-04 06:40:24 +00:00
|
|
|
|
|
2023-11-16 09:16:02 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Skip 2FA requirement for next login.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void SkipSecondFactor() => requiredSecondFactorAuth = false;
|
2023-11-15 11:00:09 +00:00
|
|
|
|
|
2023-06-26 04:21:29 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// During the next simulated login, the process will fail immediately.
|
|
|
|
|
/// </summary>
|
2021-10-04 06:40:24 +00:00
|
|
|
|
public void FailNextLogin() => shouldFailNextLogin = true;
|
2023-06-26 04:21:29 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// During the next simulated login, the process will pause indefinitely at "connecting".
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void PauseOnConnectingNextLogin() => stayConnectingNextLogin = true;
|
2022-08-20 07:22:35 +00:00
|
|
|
|
|
|
|
|
|
protected override void Dispose(bool isDisposing)
|
|
|
|
|
{
|
|
|
|
|
base.Dispose(isDisposing);
|
|
|
|
|
|
|
|
|
|
// Ensure (as much as we can) that any pending tasks are run.
|
|
|
|
|
Scheduler.Update();
|
|
|
|
|
}
|
2018-02-16 04:47:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|