From 832822858ca2c17eac82ab669f4c10634978c58c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Apr 2020 17:47:51 +0900 Subject: [PATCH 1/5] Add basic request / response support --- .../Online/TestDummyAPIRequestHandling.cs | 39 +++++++++++++++++++ osu.Game/Online/API/APIRequest.cs | 2 + osu.Game/Online/API/DummyAPIAccess.cs | 7 ++++ 3 files changed, 48 insertions(+) create mode 100644 osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs diff --git a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs new file mode 100644 index 0000000000..bf3e1204d7 --- /dev/null +++ b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Tests.Visual; + +namespace osu.Game.Tests.Online +{ + public class TestDummyAPIRequestHandling : OsuTestScene + { + public TestDummyAPIRequestHandling() + { + AddStep("register request handling", () => ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case CommentVoteRequest cRequest: + cRequest.TriggerSuccess(new CommentBundle()); + break; + } + }); + + CommentVoteRequest request = null; + CommentBundle response = null; + + AddStep("fire request", () => + { + response = null; + request = new CommentVoteRequest(1, CommentVoteAction.Vote); + request.Success += res => response = res; + API.Queue(request); + }); + + AddAssert("got response", () => response != null); + } + } +} diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 6a6c7b72a8..1f0eae4965 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -30,6 +30,8 @@ namespace osu.Game.Online.API /// This will be scheduled to the API's internal scheduler (run on update thread automatically). /// public new event APISuccessHandler Success; + + internal void TriggerSuccess(T result) => Success?.Invoke(result); } /// diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index a1c3475fd9..fa5ad115d2 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -30,6 +31,11 @@ namespace osu.Game.Online.API private readonly List components = new List(); + /// + /// Provide handling logic for an arbitrary API request. + /// + public Action HandleRequest; + public APIState State { get => state; @@ -55,6 +61,7 @@ namespace osu.Game.Online.API public virtual void Queue(APIRequest request) { + HandleRequest?.Invoke(request); } public void Perform(APIRequest request) { } From 415adecdf68c07d8882ca7ecdb2c099d6749243a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Apr 2020 18:02:43 +0900 Subject: [PATCH 2/5] Add support for Result fetching --- osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs | 8 ++++++-- osu.Game/Online/API/APIRequest.cs | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs index bf3e1204d7..5b169cccdf 100644 --- a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs +++ b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs @@ -10,7 +10,8 @@ namespace osu.Game.Tests.Online { public class TestDummyAPIRequestHandling : OsuTestScene { - public TestDummyAPIRequestHandling() + [Test] + public void TestGenericRequestHandling() { AddStep("register request handling", () => ((DummyAPIAccess)API).HandleRequest = req => { @@ -33,7 +34,10 @@ namespace osu.Game.Tests.Online API.Queue(request); }); - AddAssert("got response", () => response != null); + AddAssert("response event fired", () => response != null); + + AddAssert("request has response", () => request.Result == response); + } } } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 1f0eae4965..34b69b3c09 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using Newtonsoft.Json; using osu.Framework.IO.Network; using osu.Framework.Logging; @@ -98,10 +99,15 @@ namespace osu.Game.Online.API { if (cancelled) return; - Success?.Invoke(); + TriggerSuccess(); }); } + internal void TriggerSuccess() + { + Success?.Invoke(); + } + public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled")); public void Fail(Exception e) From c96df9758674b58df599ca8f9153f9f5c1d3e206 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Apr 2020 18:02:49 +0900 Subject: [PATCH 3/5] Add support for non-generic requests --- .../Online/TestDummyAPIRequestHandling.cs | 29 +++++++++++++++++++ osu.Game/Online/API/APIRequest.cs | 15 ++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs index 5b169cccdf..b00b63f6d5 100644 --- a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs +++ b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs @@ -1,10 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; using osu.Game.Tests.Visual; +using osu.Game.Users; namespace osu.Game.Tests.Online { @@ -38,6 +41,32 @@ namespace osu.Game.Tests.Online AddAssert("request has response", () => request.Result == response); } + + [Test] + public void TestRequestHandling() + { + AddStep("register request handling", () => ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case LeaveChannelRequest cRequest: + cRequest.TriggerSuccess(); + break; + } + }); + + LeaveChannelRequest request; + bool gotResponse = false; + + AddStep("fire request", () => + { + gotResponse = false; + request = new LeaveChannelRequest(new Channel(), new User()); + request.Success += () => gotResponse = true; + API.Queue(request); + }); + + AddAssert("response event fired", () => gotResponse); } } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 34b69b3c09..6abb388c01 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -17,22 +17,27 @@ namespace osu.Game.Online.API { protected override WebRequest CreateWebRequest() => new OsuJsonWebRequest(Uri); - public T Result => ((OsuJsonWebRequest)WebRequest)?.ResponseObject; + public T Result { get; private set; } protected APIRequest() { - base.Success += onSuccess; + base.Success += () => TriggerSuccess(((OsuJsonWebRequest)WebRequest)?.ResponseObject); } - private void onSuccess() => Success?.Invoke(Result); - /// /// Invoked on successful completion of an API request. /// This will be scheduled to the API's internal scheduler (run on update thread automatically). /// public new event APISuccessHandler Success; - internal void TriggerSuccess(T result) => Success?.Invoke(result); + internal void TriggerSuccess(T result) + { + // disallow calling twice + Debug.Assert(Result == null); + + Result = result; + Success?.Invoke(result); + } } /// From 1c8a71b2842dd90ff1cdfc1c4d4cd3595a618925 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Apr 2020 21:24:47 +0900 Subject: [PATCH 4/5] Exception instead of assert --- osu.Game/Online/API/APIRequest.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 6abb388c01..47600e4f68 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using Newtonsoft.Json; using osu.Framework.IO.Network; using osu.Framework.Logging; @@ -32,8 +31,8 @@ namespace osu.Game.Online.API internal void TriggerSuccess(T result) { - // disallow calling twice - Debug.Assert(Result == null); + if (Result != null) + throw new InvalidOperationException("Attempted to trigger success more than once"); Result = result; Success?.Invoke(result); From 89d806358809b62ca0c8b81ec77abbc412ae8cbe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Apr 2020 21:35:35 +0900 Subject: [PATCH 5/5] Add support for Perform/PerformAsync --- .../Online/TestDummyAPIRequestHandling.cs | 63 ++++++++++++++++--- osu.Game/Online/API/DummyAPIAccess.cs | 8 ++- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs index b00b63f6d5..5ef01d5702 100644 --- a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs +++ b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs @@ -43,17 +43,9 @@ namespace osu.Game.Tests.Online } [Test] - public void TestRequestHandling() + public void TestQueueRequestHandling() { - AddStep("register request handling", () => ((DummyAPIAccess)API).HandleRequest = req => - { - switch (req) - { - case LeaveChannelRequest cRequest: - cRequest.TriggerSuccess(); - break; - } - }); + registerHandler(); LeaveChannelRequest request; bool gotResponse = false; @@ -68,5 +60,56 @@ namespace osu.Game.Tests.Online AddAssert("response event fired", () => gotResponse); } + + [Test] + public void TestPerformRequestHandling() + { + registerHandler(); + + LeaveChannelRequest request; + bool gotResponse = false; + + AddStep("fire request", () => + { + gotResponse = false; + request = new LeaveChannelRequest(new Channel(), new User()); + request.Success += () => gotResponse = true; + API.Perform(request); + }); + + AddAssert("response event fired", () => gotResponse); + } + + [Test] + public void TestPerformAsyncRequestHandling() + { + registerHandler(); + + LeaveChannelRequest request; + bool gotResponse = false; + + AddStep("fire request", () => + { + gotResponse = false; + request = new LeaveChannelRequest(new Channel(), new User()); + request.Success += () => gotResponse = true; + API.PerformAsync(request); + }); + + AddAssert("response event fired", () => gotResponse); + } + + private void registerHandler() + { + AddStep("register request handling", () => ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case LeaveChannelRequest cRequest: + cRequest.TriggerSuccess(); + break; + } + }); + } } } diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index fa5ad115d2..7800241904 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -64,9 +64,13 @@ namespace osu.Game.Online.API HandleRequest?.Invoke(request); } - public void Perform(APIRequest request) { } + public void Perform(APIRequest request) => HandleRequest?.Invoke(request); - public Task PerformAsync(APIRequest request) => Task.CompletedTask; + public Task PerformAsync(APIRequest request) + { + HandleRequest?.Invoke(request); + return Task.CompletedTask; + } public void Register(IOnlineComponent component) {