From 1bc1b04dd4a9b0b50c142bd5418e6b8e9e9679e9 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sun, 22 May 2022 21:42:19 +0300 Subject: [PATCH 01/76] Feat: add controllers --- .../Controllers/FilesController.cs | 33 +++++++++++++++++++ .../Controllers/PlayerContextController.cs | 30 +++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs create mode 100644 Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs new file mode 100644 index 0000000..1f998de --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Sonar.Player.Api.Controllers; + +[ApiController] +[Route("files")] +public class FilesController +{ + [HttpPost("/track")] + public async Task UploadTrackAsync([FromQuery] string name) + { + //TODO: get file from request content + throw new NotImplementedException(); + } + + [HttpGet("/trackStreamInfo")] + public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] string trackId) + { + throw new NotImplementedException(); + } + + [HttpGet("/{streamPartName}")] + public async Task GetStreamPartAsync(string streamPartName) + { + throw new NotImplementedException(); + } + + [HttpDelete("/track}")] + public async Task DeleteTrackAsync([FromQuery] string trackId) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs new file mode 100644 index 0000000..45519d3 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Sonar.Player.Api.Controllers; + +public class PlayerContextController +{ + [HttpGet("/queue")] + public async Task GetQueueAsync() + { + throw new NotImplementedException(); + } + + [HttpPatch("/queue/track")] + public async Task AddTrackToQueueAsync([FromQuery] string trackId) + { + throw new NotImplementedException(); + } + + [HttpDelete("/queue")] + public async Task PurgeQueueAsync() + { + throw new NotImplementedException(); + } + + [HttpPatch("/queue/shuffle")] + public async Task ShuffleQueueAsync() + { + throw new NotImplementedException(); + } +} \ No newline at end of file From 6d084a31b8c7e7f175532c2de03a697ba87de0c7 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sun, 22 May 2022 21:47:53 +0300 Subject: [PATCH 02/76] Feat: add db context --- .../Sonar.Player.DataAccess/PlayerDbContext.cs | 11 +++++++++++ .../Sonar.Player.DataAccess.csproj | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs diff --git a/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs b/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs new file mode 100644 index 0000000..0e6d192 --- /dev/null +++ b/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore; + +namespace Sonar.Player.Data; + +public class PlayerDbContext : DbContext +{ + public PlayerDbContext(DbContextOptions options) + : base(options) + { + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj b/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj index e37bcde..19a4392 100644 --- a/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj +++ b/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj @@ -7,4 +7,8 @@ Sonar.Player.Data + + + + From 7ab18a98526a8a42527f2f318b42d970f26eb70a Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sun, 22 May 2022 22:30:41 +0300 Subject: [PATCH 03/76] chore: add sample command and query --- .../Sonar.Player.Application/IAssemblyMarker.cs | 5 +++++ .../PlayerContext/Commands/SampleCommand.cs | 17 +++++++++++++++++ .../PlayerContext/Queries/SampleQuery.cs | 17 +++++++++++++++++ .../Sonar.Player.Application.csproj | 4 ++++ 4 files changed, 43 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/IAssemblyMarker.cs create mode 100644 Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs create mode 100644 Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs diff --git a/Sonar.Player/Sonar.Player.Application/IAssemblyMarker.cs b/Sonar.Player/Sonar.Player.Application/IAssemblyMarker.cs new file mode 100644 index 0000000..00a8c77 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/IAssemblyMarker.cs @@ -0,0 +1,5 @@ +namespace Sonar.Player.Application; + +public interface IAssemblyMarker +{ +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs b/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs new file mode 100644 index 0000000..d12307b --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs @@ -0,0 +1,17 @@ +using MediatR; + +namespace Sonar.Player.Application.PlayerContext.Commands; + +public static class SampleCommand +{ + public record Command() : IRequest; + + public record Response(); + + public class CommandHandler : IRequestHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs b/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs new file mode 100644 index 0000000..0e1a996 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs @@ -0,0 +1,17 @@ +using MediatR; + +namespace Sonar.Player.Application.PlayerContext.Queries; + +public static class SampleQuery +{ + public record Query() : IRequest; + + public record Response(); + + public class QueryHandler : IRequestHandler + { + public async Task Handle(Query request, CancellationToken cancellationToken) + { + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj index eb2460e..38178eb 100644 --- a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj +++ b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj @@ -6,4 +6,8 @@ enable + + + + From 4a2137826dd87779f234c9a6f5cae31f1f5c4ad2 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sun, 22 May 2022 22:30:54 +0300 Subject: [PATCH 04/76] Feat: add bootstrap --- Sonar.Player/Sonar.Player.Api/Program.cs | 6 ++++++ Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj | 5 ++++- .../PlayerContext/Commands/SampleCommand.cs | 1 + .../PlayerContext/Queries/SampleQuery.cs | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 3fb425b..d3adf87 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -1,3 +1,7 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using Sonar.Player.Data; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. @@ -5,6 +9,8 @@ // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); +builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); var app = builder.Build(); diff --git a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj index ec26747..d5e2a61 100644 --- a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj +++ b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj @@ -7,11 +7,14 @@ + + - + + diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs b/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs index d12307b..b634c1c 100644 --- a/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs +++ b/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs @@ -12,6 +12,7 @@ public class CommandHandler : IRequestHandler { public async Task Handle(Command request, CancellationToken cancellationToken) { + throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs b/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs index 0e1a996..986a288 100644 --- a/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs +++ b/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs @@ -12,6 +12,7 @@ public class QueryHandler : IRequestHandler { public async Task Handle(Query request, CancellationToken cancellationToken) { + throw new NotImplementedException(); } } } \ No newline at end of file From 117ddb2b27555fb7d61fdc3f6aed830f02d07a8d Mon Sep 17 00:00:00 2001 From: bibletoon Date: Mon, 23 May 2022 18:19:16 +0300 Subject: [PATCH 05/76] Refactor: controller return types --- .../Sonar.Player.Api/Controllers/FilesController.cs | 7 ++++--- .../Controllers/PlayerContextController.cs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 1f998de..6000e60 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -4,9 +4,10 @@ namespace Sonar.Player.Api.Controllers; [ApiController] [Route("files")] -public class FilesController +public class FilesController : Controller { [HttpPost("/track")] + //TODO: Change to ActionResult or sth public async Task UploadTrackAsync([FromQuery] string name) { //TODO: get file from request content @@ -14,7 +15,7 @@ public async Task UploadTrackAsync([FromQuery] string name) } [HttpGet("/trackStreamInfo")] - public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] string trackId) + public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] Guid trackId) { throw new NotImplementedException(); } @@ -26,7 +27,7 @@ public async Task GetStreamPartAsync(string streamPartName) } [HttpDelete("/track}")] - public async Task DeleteTrackAsync([FromQuery] string trackId) + public async Task DeleteTrackAsync([FromQuery] Guid trackId) { throw new NotImplementedException(); } diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs index 45519d3..64fc0c6 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs @@ -5,13 +5,14 @@ namespace Sonar.Player.Api.Controllers; public class PlayerContextController { [HttpGet("/queue")] + //TODO: Change to ActionResult or sth public async Task GetQueueAsync() { throw new NotImplementedException(); } [HttpPatch("/queue/track")] - public async Task AddTrackToQueueAsync([FromQuery] string trackId) + public async Task AddTrackToQueueAsync([FromQuery] Guid trackId) { throw new NotImplementedException(); } From 5685542d70a485c538b41ae70fcd9ee289835e80 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Mon, 23 May 2022 20:06:46 +0300 Subject: [PATCH 06/76] Refactor: controllers --- .../Sonar.Player.Api/Controllers/FilesController.cs | 4 ++-- .../Controllers/PlayerContextController.cs | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 6000e60..a7171d0 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -3,7 +3,7 @@ namespace Sonar.Player.Api.Controllers; [ApiController] -[Route("files")] +[Route("{controller}")] public class FilesController : Controller { [HttpPost("/track")] @@ -26,7 +26,7 @@ public async Task GetStreamPartAsync(string streamPartName) throw new NotImplementedException(); } - [HttpDelete("/track}")] + [HttpDelete("/track")] public async Task DeleteTrackAsync([FromQuery] Guid trackId) { throw new NotImplementedException(); diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs index 64fc0c6..9f9ade2 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs @@ -2,28 +2,30 @@ namespace Sonar.Player.Api.Controllers; -public class PlayerContextController +[ApiController] +[Route("{controller}")] +public class QueueController : Controller { - [HttpGet("/queue")] + [HttpGet] //TODO: Change to ActionResult or sth public async Task GetQueueAsync() { throw new NotImplementedException(); } - [HttpPatch("/queue/track")] + [HttpPatch("/track")] public async Task AddTrackToQueueAsync([FromQuery] Guid trackId) { throw new NotImplementedException(); } - [HttpDelete("/queue")] + [HttpDelete] public async Task PurgeQueueAsync() { throw new NotImplementedException(); } - [HttpPatch("/queue/shuffle")] + [HttpPatch("/shuffle")] public async Task ShuffleQueueAsync() { throw new NotImplementedException(); From d8e483c363cd790db6bbe0fd45fd6b713aa553f8 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Mon, 23 May 2022 20:07:03 +0300 Subject: [PATCH 07/76] Feat: add api client --- .../Sonar.Player.ApiClient/ApiClient.cs | 992 ++++++++++++++++++ .../ApiClientExtensions.cs | 69 ++ .../Sonar.Player.ApiClient.csproj | 13 + .../Sonar.Player.ApiClient.nswag | 100 ++ Sonar.Player/Sonar.Player.sln | 6 + 5 files changed, 1180 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs create mode 100644 Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs create mode 100644 Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.csproj create mode 100644 Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs new file mode 100644 index 0000000..ac41fef --- /dev/null +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -0,0 +1,992 @@ +//---------------------- +// +// Generated using the NSwag toolchain v13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" + +namespace Sonar.Player.ApiClient +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial interface IFilesApiClient + { + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackPOSTAsync(string name); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName, System.Threading.CancellationToken cancellationToken); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FilesApiClient : IFilesApiClient + { + private string _baseUrl = ""; + private System.Net.Http.HttpClient _httpClient; + private System.Lazy _settings; + + public FilesApiClient(string baseUrl, System.Net.Http.HttpClient httpClient) + { + BaseUrl = baseUrl; + _httpClient = httpClient; + _settings = new System.Lazy(CreateSerializerSettings); + } + + private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) + { + return TrackPOSTAsync(name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); + if (name != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("name") + "=").Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId) + { + return TrackDELETEAsync(trackId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); + if (trackId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id) + { + return TrackStreamInfoAsync(id, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/trackStreamInfo?"); + if (id != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("id") + "=").Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName) + { + return AnonymousGETAsync(streamPartName, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName, System.Threading.CancellationToken cancellationToken) + { + if (streamPartName == null) + throw new System.ArgumentNullException("streamPartName"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{streamPartName}"); + urlBuilder_.Replace("{streamPartName}", System.Uri.EscapeDataString(ConvertToString(streamPartName, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial interface IQueueApiClient + { + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousGET2Async(string controller); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousGET2Async(string controller, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousDELETEAsync(string controller); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task AnonymousDELETEAsync(string controller, System.Threading.CancellationToken cancellationToken); + + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task ShuffleAsync(); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class QueueApiClient : IQueueApiClient + { + private string _baseUrl = ""; + private System.Net.Http.HttpClient _httpClient; + private System.Lazy _settings; + + public QueueApiClient(string baseUrl, System.Net.Http.HttpClient httpClient) + { + BaseUrl = baseUrl; + _httpClient = httpClient; + _settings = new System.Lazy(CreateSerializerSettings); + } + + private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId) + { + return TrackPATCHAsync(trackId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); + if (trackId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task AnonymousGET2Async(string controller) + { + return AnonymousGET2Async(controller, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task AnonymousGET2Async(string controller, System.Threading.CancellationToken cancellationToken) + { + if (controller == null) + throw new System.ArgumentNullException("controller"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{controller}"); + urlBuilder_.Replace("{controller}", System.Uri.EscapeDataString(ConvertToString(controller, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task AnonymousDELETEAsync(string controller) + { + return AnonymousDELETEAsync(controller, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task AnonymousDELETEAsync(string controller, System.Threading.CancellationToken cancellationToken) + { + if (controller == null) + throw new System.ArgumentNullException("controller"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{controller}"); + urlBuilder_.Replace("{controller}", System.Uri.EscapeDataString(ConvertToString(controller, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ShuffleAsync() + { + return ShuffleAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/shuffle"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 1591 +#pragma warning restore 1573 +#pragma warning restore 472 +#pragma warning restore 114 +#pragma warning restore 108 +#pragma warning restore 3016 +#pragma warning restore 8603 \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs new file mode 100644 index 0000000..e5c8158 --- /dev/null +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs @@ -0,0 +1,69 @@ +using System.Text; + +namespace Sonar.Player.ApiClient; + +public partial interface IFilesApiClient +{ + IFilesApiClient SetToken(string token); +} + +public partial class FilesApiClient +{ + private string _token; + + public IFilesApiClient SetToken(string token) + { + _token = token; + return this; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, string urlBuilder, CancellationToken cancellationToken) + { + if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); + return Task.CompletedTask; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder, CancellationToken cancellationToken) + { + if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); + return Task.CompletedTask; + } + + private Task ProcessResponseAsync(HttpClient client, HttpResponseMessage response, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} + +public partial interface IQueueApiClient +{ + IQueueApiClient SetToken(string token); +} + +public partial class QueueApiClient +{ + private string _token; + + public IQueueApiClient SetToken(string token) + { + _token = token; + return this; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, string urlBuilder, CancellationToken cancellationToken) + { + if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); + return Task.CompletedTask; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder, CancellationToken cancellationToken) + { + if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); + return Task.CompletedTask; + } + + private Task ProcessResponseAsync(HttpClient client, HttpResponseMessage response, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.csproj b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.csproj new file mode 100644 index 0000000..49b54fa --- /dev/null +++ b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag new file mode 100644 index 0000000..177dfc8 --- /dev/null +++ b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag @@ -0,0 +1,100 @@ +{ + "runtime": "Net60", + "defaultVariables": "", + "documentGenerator": { + "fromDocument": { + "json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"Sonar.Player.Api\",\r\n \"version\": \"1.0\"\r\n },\r\n \"paths\": {\r\n \"/track\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"name\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/trackStreamInfo\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"id\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/{streamPartName}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"streamPartName\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/{controller}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"controller\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"controller\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/shuffle\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {}\r\n}", + "url": "https://localhost:7153/swagger/v1/swagger.json", + "output": null, + "newLineBehavior": "Auto" + } + }, + "codeGenerators": { + "openApiToCSharpClient": { + "clientBaseClass": null, + "configurationClass": null, + "generateClientClasses": true, + "generateClientInterfaces": true, + "clientBaseInterface": null, + "injectHttpClient": true, + "disposeHttpClient": true, + "protectedMethods": [], + "generateExceptionClasses": true, + "exceptionClass": "ApiException", + "wrapDtoExceptions": true, + "useHttpClientCreationMethod": false, + "httpClientType": "System.Net.Http.HttpClient", + "useHttpRequestMessageCreationMethod": false, + "useBaseUrl": true, + "generateBaseUrlProperty": true, + "generateSyncMethods": false, + "generatePrepareRequestAndProcessResponseAsAsyncMethods": true, + "exposeJsonSerializerSettings": false, + "clientClassAccessModifier": "public", + "typeAccessModifier": "public", + "generateContractsOutput": false, + "contractsNamespace": null, + "contractsOutputFilePath": null, + "parameterDateTimeFormat": "s", + "parameterDateFormat": "yyyy-MM-dd", + "generateUpdateJsonSerializerSettingsMethod": true, + "useRequestAndResponseSerializationSettings": false, + "serializeTypeInformation": false, + "queryNullValue": "", + "className": "{controller}ApiClient", + "operationGenerationMode": "MultipleClientsFromFirstTagAndOperationId", + "additionalNamespaceUsages": [], + "additionalContractNamespaceUsages": [], + "generateOptionalParameters": false, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.ICollection", + "responseDictionaryType": "System.Collections.Generic.IDictionary", + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "namespace": "Sonar.Player.ApiClient", + "requiredPropertiesMustBeDefined": true, + "dateType": "System.DateTimeOffset", + "jsonConverters": null, + "anyType": "object", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "jsonLibrary": "NewtonsoftJson", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonSerializerSettingsTransformationMethod": null, + "inlineNamedArrays": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedAny": false, + "generateDtoTypes": true, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "templateDirectory": null, + "typeNameGeneratorType": null, + "propertyNameGeneratorType": null, + "enumNameGeneratorType": null, + "serviceHost": null, + "serviceSchemes": null, + "output": "ApiClient.cs", + "newLineBehavior": "Auto" + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.sln b/Sonar.Player/Sonar.Player.sln index 45067bd..cf0287b 100644 --- a/Sonar.Player/Sonar.Player.sln +++ b/Sonar.Player/Sonar.Player.sln @@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.DataAccess", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.Domain", "Sonar.Player.Domain\Sonar.Player.Domain.csproj", "{5A89E979-4864-4420-A1DE-957D2D285D60}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.ApiClient", "Sonar.Player.ApiClient\Sonar.Player.ApiClient.csproj", "{272D1464-823F-4DEE-9833-35E97DED2134}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,5 +32,9 @@ Global {5A89E979-4864-4420-A1DE-957D2D285D60}.Debug|Any CPU.Build.0 = Debug|Any CPU {5A89E979-4864-4420-A1DE-957D2D285D60}.Release|Any CPU.ActiveCfg = Release|Any CPU {5A89E979-4864-4420-A1DE-957D2D285D60}.Release|Any CPU.Build.0 = Release|Any CPU + {272D1464-823F-4DEE-9833-35E97DED2134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {272D1464-823F-4DEE-9833-35E97DED2134}.Debug|Any CPU.Build.0 = Debug|Any CPU + {272D1464-823F-4DEE-9833-35E97DED2134}.Release|Any CPU.ActiveCfg = Release|Any CPU + {272D1464-823F-4DEE-9833-35E97DED2134}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 4ce69dafed498cf133d5ec0bb1c0c0ac91b482ae Mon Sep 17 00:00:00 2001 From: bibletoon Date: Mon, 23 May 2022 20:20:19 +0300 Subject: [PATCH 08/76] Refactor: explicit param file --- Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index a7171d0..db02491 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -21,7 +21,7 @@ public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id") } [HttpGet("/{streamPartName}")] - public async Task GetStreamPartAsync(string streamPartName) + public async Task GetStreamPartAsync([FromRoute] string streamPartName) { throw new NotImplementedException(); } From 6cfd05899c16e851ec93492e36bab00e96924fa2 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 09:21:29 +0300 Subject: [PATCH 09/76] chore: update submodules --- Sonar.UserProfile | 2 +- Sonar.UserTracksManagment | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.UserProfile b/Sonar.UserProfile index 2e715b6..ce73aad 160000 --- a/Sonar.UserProfile +++ b/Sonar.UserProfile @@ -1 +1 @@ -Subproject commit 2e715b6a6c03694ad874cf44c8103325dd9bffc7 +Subproject commit ce73aad4b7862089812c9abad49b5c2a11b5b124 diff --git a/Sonar.UserTracksManagment b/Sonar.UserTracksManagment index 788eda4..13b9649 160000 --- a/Sonar.UserTracksManagment +++ b/Sonar.UserTracksManagment @@ -1 +1 @@ -Subproject commit 788eda4378a5d5ea5a60113ee73b0ac3a6c28820 +Subproject commit 13b9649946f9705e04d0d51dc32d85ee81664800 From 7708972b589b98cbdefdd2fd019afdb829e8c8ec Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 10:53:41 +0300 Subject: [PATCH 10/76] Refactor: PlayerContext -> Queue --- .../{PlayerContextController.cs => QueueController.cs} | 0 .../{PlayerContext => Queue}/Commands/SampleCommand.cs | 0 .../{PlayerContext => Queue}/Queries/SampleQuery.cs | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename Sonar.Player/Sonar.Player.Api/Controllers/{PlayerContextController.cs => QueueController.cs} (100%) rename Sonar.Player/Sonar.Player.Application/{PlayerContext => Queue}/Commands/SampleCommand.cs (100%) rename Sonar.Player/Sonar.Player.Application/{PlayerContext => Queue}/Queries/SampleQuery.cs (100%) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs similarity index 100% rename from Sonar.Player/Sonar.Player.Api/Controllers/PlayerContextController.cs rename to Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs b/Sonar.Player/Sonar.Player.Application/Queue/Commands/SampleCommand.cs similarity index 100% rename from Sonar.Player/Sonar.Player.Application/PlayerContext/Commands/SampleCommand.cs rename to Sonar.Player/Sonar.Player.Application/Queue/Commands/SampleCommand.cs diff --git a/Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs b/Sonar.Player/Sonar.Player.Application/Queue/Queries/SampleQuery.cs similarity index 100% rename from Sonar.Player/Sonar.Player.Application/PlayerContext/Queries/SampleQuery.cs rename to Sonar.Player/Sonar.Player.Application/Queue/Queries/SampleQuery.cs From b20350045c482185bc0e996954ed47dc3882ff40 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:07:27 +0300 Subject: [PATCH 11/76] Feat: add queue commands and queries --- .../Controllers/QueueController.cs | 29 ++++++++++++------- .../{SampleCommand.cs => AddTrackToQueue.cs} | 4 +-- .../Queue/Commands/PurgeQueue.cs | 18 ++++++++++++ .../Queue/Commands/ShuffleQueue.cs | 18 ++++++++++++ .../Queries/{SampleQuery.cs => GetQueue.cs} | 4 +-- 5 files changed, 59 insertions(+), 14 deletions(-) rename Sonar.Player/Sonar.Player.Application/Queue/Commands/{SampleCommand.cs => AddTrackToQueue.cs} (79%) create mode 100644 Sonar.Player/Sonar.Player.Application/Queue/Commands/PurgeQueue.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Queue/Commands/ShuffleQueue.cs rename Sonar.Player/Sonar.Player.Application/Queue/Queries/{SampleQuery.cs => GetQueue.cs} (79%) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs index 9f9ade2..5742f6a 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Mvc; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using Sonar.Player.Application.Queue.Commands; +using Sonar.Player.Application.Queue.Queries; namespace Sonar.Player.Api.Controllers; @@ -6,28 +9,34 @@ namespace Sonar.Player.Api.Controllers; [Route("{controller}")] public class QueueController : Controller { + private readonly IMediator _mediator; + + public QueueController(IMediator mediator) + { + _mediator = mediator; + } + [HttpGet] - //TODO: Change to ActionResult or sth - public async Task GetQueueAsync() + public async Task> GetQueueAsync(CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + return Ok(await _mediator.Send(new GetQueue.Query(), cancellationToken)); } [HttpPatch("/track")] - public async Task AddTrackToQueueAsync([FromQuery] Guid trackId) + public async Task> AddTrackToQueueAsync([FromQuery] Guid trackId, CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + return Ok(await _mediator.Send(new AddTrackToQueue.Command(), cancellationToken)); } [HttpDelete] - public async Task PurgeQueueAsync() + public async Task> PurgeQueueAsync(CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + return Ok(await _mediator.Send(new PurgeQueue.Command(), cancellationToken)); } [HttpPatch("/shuffle")] - public async Task ShuffleQueueAsync() + public async Task> ShuffleQueueAsync(CancellationToken cancellationToken = default) { - throw new NotImplementedException(); + return Ok(await _mediator.Send(new ShuffleQueue.Command(), cancellationToken)); } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Queue/Commands/SampleCommand.cs b/Sonar.Player/Sonar.Player.Application/Queue/Commands/AddTrackToQueue.cs similarity index 79% rename from Sonar.Player/Sonar.Player.Application/Queue/Commands/SampleCommand.cs rename to Sonar.Player/Sonar.Player.Application/Queue/Commands/AddTrackToQueue.cs index b634c1c..be20d10 100644 --- a/Sonar.Player/Sonar.Player.Application/Queue/Commands/SampleCommand.cs +++ b/Sonar.Player/Sonar.Player.Application/Queue/Commands/AddTrackToQueue.cs @@ -1,8 +1,8 @@ using MediatR; -namespace Sonar.Player.Application.PlayerContext.Commands; +namespace Sonar.Player.Application.Queue.Commands; -public static class SampleCommand +public static class AddTrackToQueue { public record Command() : IRequest; diff --git a/Sonar.Player/Sonar.Player.Application/Queue/Commands/PurgeQueue.cs b/Sonar.Player/Sonar.Player.Application/Queue/Commands/PurgeQueue.cs new file mode 100644 index 0000000..c0fab46 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Queue/Commands/PurgeQueue.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Queue.Commands; + +public static class PurgeQueue +{ + public record Command() : IRequest; + + public record Response(); + + public class CommandHandler : IRequestHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Queue/Commands/ShuffleQueue.cs b/Sonar.Player/Sonar.Player.Application/Queue/Commands/ShuffleQueue.cs new file mode 100644 index 0000000..dd3b7e7 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Queue/Commands/ShuffleQueue.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Queue.Commands; + +public static class ShuffleQueue +{ + public record Command() : IRequest; + + public record Response(); + + public class CommandHandler : IRequestHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Queue/Queries/SampleQuery.cs b/Sonar.Player/Sonar.Player.Application/Queue/Queries/GetQueue.cs similarity index 79% rename from Sonar.Player/Sonar.Player.Application/Queue/Queries/SampleQuery.cs rename to Sonar.Player/Sonar.Player.Application/Queue/Queries/GetQueue.cs index 986a288..77e0607 100644 --- a/Sonar.Player/Sonar.Player.Application/Queue/Queries/SampleQuery.cs +++ b/Sonar.Player/Sonar.Player.Application/Queue/Queries/GetQueue.cs @@ -1,8 +1,8 @@ using MediatR; -namespace Sonar.Player.Application.PlayerContext.Queries; +namespace Sonar.Player.Application.Queue.Queries; -public static class SampleQuery +public static class GetQueue { public record Query() : IRequest; From ef2fc952781e9cf0982d3a293470965300e38ca9 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:20:32 +0300 Subject: [PATCH 12/76] Feat: add file controller commands and queries --- .../Controllers/FilesController.cs | 27 +++++++++++++------ .../Files/Commands/DeleteTrack.cs | 18 +++++++++++++ .../Files/Commands/UploadTrack.cs | 18 +++++++++++++ .../Files/Queries/GetStreamPart.cs | 18 +++++++++++++ .../Files/Queries/GetTrackStreamInfo.cs | 18 +++++++++++++ 5 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index db02491..5d2ee03 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Mvc; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using Sonar.Player.Application.Files.Commands; +using Sonar.Player.Application.Files.Queries; namespace Sonar.Player.Api.Controllers; @@ -6,29 +9,37 @@ namespace Sonar.Player.Api.Controllers; [Route("{controller}")] public class FilesController : Controller { + private readonly IMediator _mediator; + + public FilesController(IMediator mediator) + { + _mediator = mediator; + } + [HttpPost("/track")] - //TODO: Change to ActionResult or sth - public async Task UploadTrackAsync([FromQuery] string name) + public async Task> UploadTrackAsync([FromQuery] string name) { //TODO: get file from request content - throw new NotImplementedException(); + return Ok(await _mediator.Send(new UploadTrack.Command())); } [HttpGet("/trackStreamInfo")] public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] Guid trackId) { - throw new NotImplementedException(); + var response = await _mediator.Send(new GetTrackStreamInfo.Query()); + return File(response.TrackInfoStream, "application/x-mpegURL", true); } [HttpGet("/{streamPartName}")] public async Task GetStreamPartAsync([FromRoute] string streamPartName) { - throw new NotImplementedException(); + var response = await _mediator.Send(new GetStreamPart.Query()); + return File(response.StreamPart, "audio/MPA", true); } [HttpDelete("/track")] - public async Task DeleteTrackAsync([FromQuery] Guid trackId) + public async Task> DeleteTrackAsync([FromQuery] Guid trackId) { - throw new NotImplementedException(); + return Ok(await _mediator.Send(new DeleteTrack.Command())); } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs new file mode 100644 index 0000000..79deebf --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Files.Commands; + +public static class DeleteTrack +{ + public record Command() : IRequest; + + public record Response(); + + public class CommandHandler : IRequestHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs new file mode 100644 index 0000000..5c1830c --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Files.Commands; + +public static class UploadTrack +{ + public record Command() : IRequest; + + public record Response(); + + public class CommandHandler : IRequestHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs new file mode 100644 index 0000000..dc52c55 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Files.Queries; + +public static class GetStreamPart +{ + public record Query() : IRequest; + + public record Response(FileStream StreamPart); + + public class QueryHandler : IRequestHandler + { + public async Task Handle(Query request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs new file mode 100644 index 0000000..61818f6 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace Sonar.Player.Application.Files.Queries; + +public static class GetTrackStreamInfo +{ + public record Query() : IRequest; + + public record Response(FileStream TrackInfoStream); + + public class QueryHandler : IRequestHandler + { + public async Task Handle(Query request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file From 4147cdd7f87350d250eb3a73bd23e73cd579c32f Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:22:51 +0300 Subject: [PATCH 13/76] Feat: add entities --- .../Sonar.Player.Domain/Entities/Track.cs | 17 ++++++++ .../Entities/TracksQueue.cs | 36 ++++++++++++++++ .../Enumerations/AudioFormat.cs | 26 ++++++++++++ .../Sonar.Player.Domain/Tools/Enumeration.cs | 41 +++++++++++++++++++ .../Exceptions/EnumerationParseException.cs | 8 ++++ 5 files changed, 128 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Domain/Entities/Track.cs create mode 100644 Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs create mode 100644 Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs create mode 100644 Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs create mode 100644 Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs b/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs new file mode 100644 index 0000000..35289d2 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs @@ -0,0 +1,17 @@ +using Sonar.Player.Domain.Enumerations; + +namespace Sonar.Player.Domain.Entities; + +public class Track +{ + public Guid Id { get; private init; } + public AudioFormat Format { get; private init; } + + public Track(Guid id, AudioFormat format) + { + Id = id; + Format = format; + } + + private Track() { } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs new file mode 100644 index 0000000..9acabb3 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -0,0 +1,36 @@ +namespace Sonar.Player.Domain.Entities; + +public class TracksQueue +{ + private List _tracks; + + public TracksQueue() + { + _tracks = new List(); + } + + private TracksQueue(ICollection tracks) + { + _tracks = tracks.ToList(); + } + + public Track Next() + { + throw new NotImplementedException(); + } + + public Track Previous() + { + throw new NotImplementedException(); + } + + public void Shuffle() + { + throw new NotImplementedException(); + } + + public void Purge() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs new file mode 100644 index 0000000..cbdb266 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs @@ -0,0 +1,26 @@ +using System.Text.RegularExpressions; +using Sonar.Player.Domain.Tools; +using Sonar.Player.Domain.Tools.Exceptions; + +namespace Sonar.Player.Domain.Enumerations; + +public class AudioFormat : Enumeration +{ + protected AudioFormat(string name, string format) + : base(name, format) { } + + protected AudioFormat() : base() {} + + public static AudioFormat Mp3 => new AudioFormat("Mp3", "mp3"); + public static AudioFormat Wav => new AudioFormat("Wav", "wav"); + + public static AudioFormat FromFileName(string filename) + { + return filename switch + { + _ when Regex.IsMatch(filename, @".+\.mp3") => Mp3, + _ when Regex.IsMatch(filename, @".+\.wav") => Wav, + _ => throw new EnumerationParseException(nameof(AudioFormat), filename) + }; + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs new file mode 100644 index 0000000..028aa85 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs @@ -0,0 +1,41 @@ +namespace Sonar.Player.Domain.Tools; + +public abstract class Enumeration : IEquatable + where TEnumeration : Enumeration +{ + protected Enumeration(string name, TValue value) + { + ArgumentNullException.ThrowIfNull(name); + + Name = name; + Value = value; + } + + protected Enumeration() { } + + public string Name { get; private init; } + public TValue Value { get; private init; } + + public static bool operator ==(Enumeration left, Enumeration right) + { + if ((left, right) is (null, null)) + return true; + + return left?.Equals(right) ?? false; + } + + public static bool operator !=(Enumeration left, Enumeration right) + => !(left == right); + + public bool Equals(TEnumeration? other) + => other is not null && (other.Value?.Equals(Value) ?? false); + + public override bool Equals(object? obj) + => Equals(obj as TEnumeration); + + public override int GetHashCode() + => Value?.GetHashCode() ?? 0; + + public override string ToString() + => Name; +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs new file mode 100644 index 0000000..b0a9ddb --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs @@ -0,0 +1,8 @@ +namespace Sonar.Player.Domain.Tools.Exceptions; + +//TODO: add base domain exception +public class EnumerationParseException : Exception +{ + public EnumerationParseException(string typeName, T value) + : base($"Can't parse {typeName} from {value}") { } +} \ No newline at end of file From f9e9e72200926573150a8e5fd66dc357dd15f04b Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:27:51 +0300 Subject: [PATCH 14/76] Feat: add user service --- .../Sonar.Player.Application/Services/IUserService.cs | 8 ++++++++ .../Sonar.Player.Application.csproj | 4 ++++ Sonar.Player/Sonar.Player.Domain/Models/User.cs | 11 +++++++++++ 3 files changed, 23 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Services/IUserService.cs create mode 100644 Sonar.Player/Sonar.Player.Domain/Models/User.cs diff --git a/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs b/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs new file mode 100644 index 0000000..26d22b4 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs @@ -0,0 +1,8 @@ +using Sonar.Player.Domain.Models; + +namespace Sonar.Player.Application.Services; + +public interface IUserService +{ + User GetUser(string token); +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj index 38178eb..cfcff75 100644 --- a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj +++ b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/Sonar.Player/Sonar.Player.Domain/Models/User.cs b/Sonar.Player/Sonar.Player.Domain/Models/User.cs new file mode 100644 index 0000000..1022dde --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Models/User.cs @@ -0,0 +1,11 @@ +namespace Sonar.Player.Domain.Models; + +public class User +{ + public Guid Id { get; } + + public User(Guid id) + { + Id = id; + } +} \ No newline at end of file From 471f6c35857df0a3b6f7febf4a04ce89b477f846 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:28:23 +0300 Subject: [PATCH 15/76] Feat: add UserProfile Api client --- Sonar.Player/Sonar.Player.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sonar.Player/Sonar.Player.sln b/Sonar.Player/Sonar.Player.sln index cf0287b..e7889a1 100644 --- a/Sonar.Player/Sonar.Player.sln +++ b/Sonar.Player/Sonar.Player.sln @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.Domain", "Sona EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.ApiClient", "Sonar.Player.ApiClient\Sonar.Player.ApiClient.csproj", "{272D1464-823F-4DEE-9833-35E97DED2134}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.UserProfile.ApiClient", "..\Sonar.UserProfile\Sonar.UserProfile.ApiClient\Sonar.UserProfile.ApiClient.csproj", "{7F1313DE-7C02-4752-9A46-C5054074EF1D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,5 +38,9 @@ Global {272D1464-823F-4DEE-9833-35E97DED2134}.Debug|Any CPU.Build.0 = Debug|Any CPU {272D1464-823F-4DEE-9833-35E97DED2134}.Release|Any CPU.ActiveCfg = Release|Any CPU {272D1464-823F-4DEE-9833-35E97DED2134}.Release|Any CPU.Build.0 = Release|Any CPU + {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 60a2d18c7dc5357594cd703d8fe31772749da952 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:57:33 +0300 Subject: [PATCH 16/76] Fix: routing --- .../Sonar.Player.Api/Controllers/FilesController.cs | 10 +++++----- .../Sonar.Player.Api/Controllers/QueueController.cs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 5d2ee03..621760c 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -5,8 +5,8 @@ namespace Sonar.Player.Api.Controllers; +[Route("[controller]")] [ApiController] -[Route("{controller}")] public class FilesController : Controller { private readonly IMediator _mediator; @@ -16,28 +16,28 @@ public FilesController(IMediator mediator) _mediator = mediator; } - [HttpPost("/track")] + [HttpPost("track")] public async Task> UploadTrackAsync([FromQuery] string name) { //TODO: get file from request content return Ok(await _mediator.Send(new UploadTrack.Command())); } - [HttpGet("/trackStreamInfo")] + [HttpGet("trackStreamInfo")] public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] Guid trackId) { var response = await _mediator.Send(new GetTrackStreamInfo.Query()); return File(response.TrackInfoStream, "application/x-mpegURL", true); } - [HttpGet("/{streamPartName}")] + [HttpGet("{streamPartName}")] public async Task GetStreamPartAsync([FromRoute] string streamPartName) { var response = await _mediator.Send(new GetStreamPart.Query()); return File(response.StreamPart, "audio/MPA", true); } - [HttpDelete("/track")] + [HttpDelete("track")] public async Task> DeleteTrackAsync([FromQuery] Guid trackId) { return Ok(await _mediator.Send(new DeleteTrack.Command())); diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs index 5742f6a..3a5c541 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs @@ -5,8 +5,8 @@ namespace Sonar.Player.Api.Controllers; +[Route("[controller]")] [ApiController] -[Route("{controller}")] public class QueueController : Controller { private readonly IMediator _mediator; @@ -22,7 +22,7 @@ public QueueController(IMediator mediator) return Ok(await _mediator.Send(new GetQueue.Query(), cancellationToken)); } - [HttpPatch("/track")] + [HttpPatch("track")] public async Task> AddTrackToQueueAsync([FromQuery] Guid trackId, CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new AddTrackToQueue.Command(), cancellationToken)); @@ -34,7 +34,7 @@ public QueueController(IMediator mediator) return Ok(await _mediator.Send(new PurgeQueue.Command(), cancellationToken)); } - [HttpPatch("/shuffle")] + [HttpPatch("shuffle")] public async Task> ShuffleQueueAsync(CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new ShuffleQueue.Command(), cancellationToken)); From 7adad14b2ced98d987a5ea14fcc77a139821e7eb Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:57:50 +0300 Subject: [PATCH 17/76] Feat: add swagger doc --- Sonar.Player/Sonar.Player.Api/Program.cs | 23 ++++++++++++++++++- .../Sonar.Player.Api/Sonar.Player.Api.csproj | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index d3adf87..2aff0f6 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -1,5 +1,7 @@ +using System.Reflection; using MediatR; using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Models; using Sonar.Player.Data; var builder = WebApplication.CreateBuilder(args); @@ -8,7 +10,26 @@ builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +builder.Services.AddSwaggerGen( + options => + { + options.CustomSchemaIds(type => type.FullName); + options.SwaggerDoc( + "v1", + new OpenApiInfo(){Title = "Sonar.Player", Version = "v1"}); + + options.AddSecurityDefinition("Token", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Token to access resources", + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + }); + + var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); + } +); builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); diff --git a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj index d5e2a61..edaab70 100644 --- a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj +++ b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj @@ -6,6 +6,10 @@ enable + + true + + From d6fec39f947ac2f456ab822f939e85f637c3a9d2 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 11:58:54 +0300 Subject: [PATCH 18/76] Chore: generate new api client --- .../Sonar.Player.ApiClient/ApiClient.cs | 190 ++++++++++++------ .../Sonar.Player.ApiClient.nswag | 2 +- 2 files changed, 126 insertions(+), 66 deletions(-) diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs index ac41fef..ca94755 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -22,21 +22,21 @@ public partial interface IFilesApiClient { /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string name); + System.Threading.Tasks.Task TrackPOSTAsync(string name); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId); + System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. @@ -49,12 +49,12 @@ public partial interface IFilesApiClient /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName); + System.Threading.Tasks.Task FilesAsync(string streamPartName); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task FilesAsync(string streamPartName, System.Threading.CancellationToken cancellationToken); } @@ -91,7 +91,7 @@ public string BaseUrl /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) + public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) { return TrackPOSTAsync(name, System.Threading.CancellationToken.None); } @@ -99,10 +99,10 @@ public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); if (name != null) { urlBuilder_.Append(System.Uri.EscapeDataString("name") + "=").Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -115,8 +115,9 @@ public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, Sys { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -141,7 +142,12 @@ public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, Sys var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -165,7 +171,7 @@ public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, Sys /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId) + public virtual System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId) { return TrackDELETEAsync(trackId, System.Threading.CancellationToken.None); } @@ -173,10 +179,10 @@ public virtual System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); if (trackId != null) { urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -190,6 +196,7 @@ public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? t using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -214,7 +221,12 @@ public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? t var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -249,7 +261,7 @@ public virtual System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id) public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/trackStreamInfo?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/trackStreamInfo?"); if (id != null) { urlBuilder_.Append(System.Uri.EscapeDataString("id") + "=").Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -311,21 +323,21 @@ public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Gui /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName) + public virtual System.Threading.Tasks.Task FilesAsync(string streamPartName) { - return AnonymousGETAsync(streamPartName, System.Threading.CancellationToken.None); + return FilesAsync(streamPartName, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AnonymousGETAsync(string streamPartName, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task FilesAsync(string streamPartName, System.Threading.CancellationToken cancellationToken) { if (streamPartName == null) throw new System.ArgumentNullException("streamPartName"); var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{streamPartName}"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/{streamPartName}"); urlBuilder_.Replace("{streamPartName}", System.Uri.EscapeDataString(ConvertToString(streamPartName, System.Globalization.CultureInfo.InvariantCulture))); var client_ = _httpClient; @@ -489,39 +501,39 @@ public partial interface IQueueApiClient { /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId); + System.Threading.Tasks.Task QueueGETAsync(); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task QueueGETAsync(System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousGET2Async(string controller); + System.Threading.Tasks.Task QueueDELETEAsync(); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousGET2Async(string controller, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task QueueDELETEAsync(System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousDELETEAsync(string controller); + System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task AnonymousDELETEAsync(string controller, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task ShuffleAsync(); + System.Threading.Tasks.Task ShuffleAsync(); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken); } @@ -558,23 +570,18 @@ public string BaseUrl /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId) + public virtual System.Threading.Tasks.Task QueueGETAsync() { - return TrackPATCHAsync(trackId, System.Threading.CancellationToken.None); + return QueueGETAsync(System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task QueueGETAsync(System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/track?"); - if (trackId != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); - } - urlBuilder_.Length--; + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); var client_ = _httpClient; var disposeClient_ = false; @@ -582,8 +589,8 @@ public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? tr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); - request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -608,7 +615,12 @@ public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? tr var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -632,22 +644,18 @@ public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? tr /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task AnonymousGET2Async(string controller) + public virtual System.Threading.Tasks.Task QueueDELETEAsync() { - return AnonymousGET2Async(controller, System.Threading.CancellationToken.None); + return QueueDELETEAsync(System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AnonymousGET2Async(string controller, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task QueueDELETEAsync(System.Threading.CancellationToken cancellationToken) { - if (controller == null) - throw new System.ArgumentNullException("controller"); - var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{controller}"); - urlBuilder_.Replace("{controller}", System.Uri.EscapeDataString(ConvertToString(controller, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); var client_ = _httpClient; var disposeClient_ = false; @@ -655,7 +663,8 @@ public virtual async System.Threading.Tasks.Task AnonymousGET2Async(string contr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -680,7 +689,12 @@ public virtual async System.Threading.Tasks.Task AnonymousGET2Async(string contr var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -704,22 +718,23 @@ public virtual async System.Threading.Tasks.Task AnonymousGET2Async(string contr /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task AnonymousDELETEAsync(string controller) + public virtual System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId) { - return AnonymousDELETEAsync(controller, System.Threading.CancellationToken.None); + return TrackPATCHAsync(trackId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AnonymousDELETEAsync(string controller, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { - if (controller == null) - throw new System.ArgumentNullException("controller"); - var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{controller}"); - urlBuilder_.Replace("{controller}", System.Uri.EscapeDataString(ConvertToString(controller, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/track?"); + if (trackId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; var client_ = _httpClient; var disposeClient_ = false; @@ -727,7 +742,9 @@ public virtual async System.Threading.Tasks.Task AnonymousDELETEAsync(string con { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -752,7 +769,12 @@ public virtual async System.Threading.Tasks.Task AnonymousDELETEAsync(string con var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -776,7 +798,7 @@ public virtual async System.Threading.Tasks.Task AnonymousDELETEAsync(string con /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task ShuffleAsync() + public virtual System.Threading.Tasks.Task ShuffleAsync() { return ShuffleAsync(System.Threading.CancellationToken.None); } @@ -784,10 +806,10 @@ public virtual System.Threading.Tasks.Task ShuffleAsync() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/shuffle"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/shuffle"); var client_ = _httpClient; var disposeClient_ = false; @@ -795,8 +817,9 @@ public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.C { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); @@ -821,7 +844,12 @@ public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.C var status_ = (int)response_.StatusCode; if (status_ == 200) { - return; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -946,6 +974,38 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu } } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DeleteTrack_Response + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UploadTrack_Response + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AddTrackToQueue_Response + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ShuffleQueue_Response + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class GetQueue_Response + { + + } + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : System.Exception { diff --git a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag index 177dfc8..55b504b 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag +++ b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag @@ -3,7 +3,7 @@ "defaultVariables": "", "documentGenerator": { "fromDocument": { - "json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"Sonar.Player.Api\",\r\n \"version\": \"1.0\"\r\n },\r\n \"paths\": {\r\n \"/track\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"name\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/trackStreamInfo\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"id\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/{streamPartName}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"streamPartName\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/{controller}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"controller\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"controller\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/shuffle\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {}\r\n}", + "json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"Sonar.Player\",\r\n \"version\": \"v1\"\r\n },\r\n \"paths\": {\r\n \"/Files/track\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"name\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Files/trackStreamInfo\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"id\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/Files/{streamPartName}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"streamPartName\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue/track\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue/shuffle\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {\r\n \"Sonar.Player.Application.Files.Commands.DeleteTrack+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Files.Commands.UploadTrack+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Queries.GetQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n }\r\n },\r\n \"securitySchemes\": {\r\n \"Token\": {\r\n \"type\": \"apiKey\",\r\n \"description\": \"Token to access resources\",\r\n \"name\": \"Authorization\",\r\n \"in\": \"header\"\r\n }\r\n }\r\n }\r\n}", "url": "https://localhost:7153/swagger/v1/swagger.json", "output": null, "newLineBehavior": "Auto" From aee7b8bb760357d7504f4f401b36ecfe84bc7ca3 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 15:16:24 +0300 Subject: [PATCH 19/76] Refactor: attributes order --- Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs | 2 +- Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 621760c..96f0218 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -5,8 +5,8 @@ namespace Sonar.Player.Api.Controllers; -[Route("[controller]")] [ApiController] +[Route("[controller]")] public class FilesController : Controller { private readonly IMediator _mediator; diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs index 3a5c541..57ab9d8 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs @@ -5,8 +5,8 @@ namespace Sonar.Player.Api.Controllers; -[Route("[controller]")] [ApiController] +[Route("[controller]")] public class QueueController : Controller { private readonly IMediator _mediator; From a688f586e0c30a05b62ec59b32d1440416d19879 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 15:28:21 +0300 Subject: [PATCH 20/76] Fix: pattern matching --- .../Sonar.Player.Domain/Enumerations/AudioFormat.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs index cbdb266..bd0b0bb 100644 --- a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs +++ b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs @@ -16,10 +16,11 @@ protected AudioFormat() : base() {} public static AudioFormat FromFileName(string filename) { - return filename switch + ArgumentNullException.ThrowIfNull(filename); + return Path.GetExtension(filename) switch { - _ when Regex.IsMatch(filename, @".+\.mp3") => Mp3, - _ when Regex.IsMatch(filename, @".+\.wav") => Wav, + "mp3" => Mp3, + "wav" => Wav, _ => throw new EnumerationParseException(nameof(AudioFormat), filename) }; } From 736150e128a792c315e4fc0a3baaaf188f46470f Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 15:34:35 +0300 Subject: [PATCH 21/76] Fix: equals --- Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs index 028aa85..a371874 100644 --- a/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Enumeration.cs @@ -28,7 +28,7 @@ protected Enumeration() { } => !(left == right); public bool Equals(TEnumeration? other) - => other is not null && (other.Value?.Equals(Value) ?? false); + => other?.Value?.Equals(Value) ?? false; public override bool Equals(object? obj) => Equals(obj as TEnumeration); From 643fed37ad75031f943cf661b96ee70ca62c08ec Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 21:37:55 +0300 Subject: [PATCH 22/76] Fix: from token param --- .../Controllers/FilesController.cs | 16 ++++++++++++---- .../Controllers/QueueController.cs | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 96f0218..122fa1a 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -17,28 +17,36 @@ public FilesController(IMediator mediator) } [HttpPost("track")] - public async Task> UploadTrackAsync([FromQuery] string name) + public async Task> UploadTrackAsync( + [FromHeader(Name = "Token")] string token, + [FromQuery] string name) { //TODO: get file from request content return Ok(await _mediator.Send(new UploadTrack.Command())); } [HttpGet("trackStreamInfo")] - public async Task GetTrackStreamInfoAsync([FromQuery(Name = "id")] Guid trackId) + public async Task GetTrackStreamInfoAsync( + [FromHeader(Name = "Token")] string token, + [FromQuery(Name = "id")] Guid trackId) { var response = await _mediator.Send(new GetTrackStreamInfo.Query()); return File(response.TrackInfoStream, "application/x-mpegURL", true); } [HttpGet("{streamPartName}")] - public async Task GetStreamPartAsync([FromRoute] string streamPartName) + public async Task GetStreamPartAsync( + [FromHeader(Name = "Token")] string token, + [FromRoute] string streamPartName) { var response = await _mediator.Send(new GetStreamPart.Query()); return File(response.StreamPart, "audio/MPA", true); } [HttpDelete("track")] - public async Task> DeleteTrackAsync([FromQuery] Guid trackId) + public async Task> DeleteTrackAsync( + [FromHeader(Name = "Token")] string token, + [FromQuery] Guid trackId) { return Ok(await _mediator.Send(new DeleteTrack.Command())); } diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs index 57ab9d8..3a4a361 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/QueueController.cs @@ -17,25 +17,33 @@ public QueueController(IMediator mediator) } [HttpGet] - public async Task> GetQueueAsync(CancellationToken cancellationToken = default) + public async Task> GetQueueAsync( + [FromHeader(Name = "Token")] string token, + CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new GetQueue.Query(), cancellationToken)); } [HttpPatch("track")] - public async Task> AddTrackToQueueAsync([FromQuery] Guid trackId, CancellationToken cancellationToken = default) + public async Task> AddTrackToQueueAsync( + [FromHeader(Name = "Token")] string token, + [FromQuery] Guid trackId, CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new AddTrackToQueue.Command(), cancellationToken)); } [HttpDelete] - public async Task> PurgeQueueAsync(CancellationToken cancellationToken = default) + public async Task> PurgeQueueAsync( + [FromHeader(Name = "Token")] string token, + CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new PurgeQueue.Command(), cancellationToken)); } [HttpPatch("shuffle")] - public async Task> ShuffleQueueAsync(CancellationToken cancellationToken = default) + public async Task> ShuffleQueueAsync( + [FromHeader(Name = "Token")] string token, + CancellationToken cancellationToken = default) { return Ok(await _mediator.Send(new ShuffleQueue.Command(), cancellationToken)); } From bf1838271081bc88fb6fe61b66ea7c80b9d7d93c Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 21:40:51 +0300 Subject: [PATCH 23/76] Chore: generate api client --- .../Sonar.Player.ApiClient/ApiClient.cs | 56 ++++++++------- .../ApiClientExtensions.cs | 69 ------------------- 2 files changed, 32 insertions(+), 93 deletions(-) delete mode 100644 Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs index ca94755..b622ce5 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -89,6 +89,10 @@ public string BaseUrl partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + /// Success /// A server side error occurred. public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) @@ -119,12 +123,12 @@ public virtual async System.Threading.Tasks.Task TrackPOST request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -137,7 +141,7 @@ public virtual async System.Threading.Tasks.Task TrackPOST headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -198,12 +202,12 @@ public virtual async System.Threading.Tasks.Task TrackDELE request_.Method = new System.Net.Http.HttpMethod("DELETE"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -216,7 +220,7 @@ public virtual async System.Threading.Tasks.Task TrackDELE headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -276,12 +280,12 @@ public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Gui { request_.Method = new System.Net.Http.HttpMethod("GET"); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -294,7 +298,7 @@ public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Gui headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -348,12 +352,12 @@ public virtual async System.Threading.Tasks.Task FilesAsync(string streamPartNam { request_.Method = new System.Net.Http.HttpMethod("GET"); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -366,7 +370,7 @@ public virtual async System.Threading.Tasks.Task FilesAsync(string streamPartNam headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -568,6 +572,10 @@ public string BaseUrl partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + /// Success /// A server side error occurred. public virtual System.Threading.Tasks.Task QueueGETAsync() @@ -592,12 +600,12 @@ public virtual async System.Threading.Tasks.Task QueueGETAsyn request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -610,7 +618,7 @@ public virtual async System.Threading.Tasks.Task QueueGETAsyn headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -666,12 +674,12 @@ public virtual async System.Threading.Tasks.Task QueueDEL request_.Method = new System.Net.Http.HttpMethod("DELETE"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -684,7 +692,7 @@ public virtual async System.Threading.Tasks.Task QueueDEL headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -746,12 +754,12 @@ public virtual async System.Threading.Tasks.Task Track request_.Method = new System.Net.Http.HttpMethod("PATCH"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -764,7 +772,7 @@ public virtual async System.Threading.Tasks.Task Track headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) @@ -821,12 +829,12 @@ public virtual async System.Threading.Tasks.Task ShuffleA request_.Method = new System.Net.Http.HttpMethod("PATCH"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); var disposeResponse_ = true; @@ -839,7 +847,7 @@ public virtual async System.Threading.Tasks.Task ShuffleA headers_[item_.Key] = item_.Value; } - await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; if (status_ == 200) diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs deleted file mode 100644 index e5c8158..0000000 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClientExtensions.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Text; - -namespace Sonar.Player.ApiClient; - -public partial interface IFilesApiClient -{ - IFilesApiClient SetToken(string token); -} - -public partial class FilesApiClient -{ - private string _token; - - public IFilesApiClient SetToken(string token) - { - _token = token; - return this; - } - - private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, string urlBuilder, CancellationToken cancellationToken) - { - if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); - return Task.CompletedTask; - } - - private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder, CancellationToken cancellationToken) - { - if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); - return Task.CompletedTask; - } - - private Task ProcessResponseAsync(HttpClient client, HttpResponseMessage response, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } -} - -public partial interface IQueueApiClient -{ - IQueueApiClient SetToken(string token); -} - -public partial class QueueApiClient -{ - private string _token; - - public IQueueApiClient SetToken(string token) - { - _token = token; - return this; - } - - private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, string urlBuilder, CancellationToken cancellationToken) - { - if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); - return Task.CompletedTask; - } - - private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder, CancellationToken cancellationToken) - { - if (!string.IsNullOrEmpty(_token) && !request.Headers.Contains("Token")) request.Headers.Add("Token", _token); - return Task.CompletedTask; - } - - private Task ProcessResponseAsync(HttpClient client, HttpResponseMessage response, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } -} \ No newline at end of file From bd1738d513eef76b3ace46891167f141ea9ce7ed Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 21:51:38 +0300 Subject: [PATCH 24/76] Fix: api client --- .../Sonar.Player.ApiClient/ApiClient.cs | 104 +++++++++++------- .../Sonar.Player.ApiClient.nswag | 4 +- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs index b622ce5..50f3e48 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -22,39 +22,39 @@ public partial interface IFilesApiClient { /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string name); + System.Threading.Tasks.Task TrackPOSTAsync(string token, string name); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId); + System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id); + System.Threading.Tasks.Task TrackStreamInfoAsync(string token, System.Guid? id); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackStreamInfoAsync(string token, System.Guid? id, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task FilesAsync(string streamPartName); + System.Threading.Tasks.Task FilesAsync(string token, string streamPartName); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task FilesAsync(string streamPartName, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task FilesAsync(string token, string streamPartName, System.Threading.CancellationToken cancellationToken); } @@ -95,15 +95,15 @@ public string BaseUrl /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackPOSTAsync(string name) + public virtual System.Threading.Tasks.Task TrackPOSTAsync(string token, string name) { - return TrackPOSTAsync(name, System.Threading.CancellationToken.None); + return TrackPOSTAsync(token, name, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string name, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); @@ -119,6 +119,9 @@ public virtual async System.Threading.Tasks.Task TrackPOST { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -175,15 +178,15 @@ public virtual async System.Threading.Tasks.Task TrackPOST /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId) + public virtual System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId) { - return TrackDELETEAsync(trackId, System.Threading.CancellationToken.None); + return TrackDELETEAsync(token, trackId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackDELETEAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); @@ -199,6 +202,9 @@ public virtual async System.Threading.Tasks.Task TrackDELE { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -254,15 +260,15 @@ public virtual async System.Threading.Tasks.Task TrackDELE /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id) + public virtual System.Threading.Tasks.Task TrackStreamInfoAsync(string token, System.Guid? id) { - return TrackStreamInfoAsync(id, System.Threading.CancellationToken.None); + return TrackStreamInfoAsync(token, id, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Guid? id, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(string token, System.Guid? id, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/trackStreamInfo?"); @@ -278,6 +284,9 @@ public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Gui { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("GET"); PrepareRequest(client_, request_, urlBuilder_); @@ -327,15 +336,15 @@ public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(System.Gui /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task FilesAsync(string streamPartName) + public virtual System.Threading.Tasks.Task FilesAsync(string token, string streamPartName) { - return FilesAsync(streamPartName, System.Threading.CancellationToken.None); + return FilesAsync(token, streamPartName, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task FilesAsync(string streamPartName, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task FilesAsync(string token, string streamPartName, System.Threading.CancellationToken cancellationToken) { if (streamPartName == null) throw new System.ArgumentNullException("streamPartName"); @@ -350,6 +359,9 @@ public virtual async System.Threading.Tasks.Task FilesAsync(string streamPartNam { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("GET"); PrepareRequest(client_, request_, urlBuilder_); @@ -505,39 +517,39 @@ public partial interface IQueueApiClient { /// Success /// A server side error occurred. - System.Threading.Tasks.Task QueueGETAsync(); + System.Threading.Tasks.Task QueueGETAsync(string token); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task QueueGETAsync(System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task QueueGETAsync(string token, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task QueueDELETEAsync(); + System.Threading.Tasks.Task QueueDELETEAsync(string token); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task QueueDELETEAsync(System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task QueueDELETEAsync(string token, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId); + System.Threading.Tasks.Task TrackPATCHAsync(string token, System.Guid? trackId); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackPATCHAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task ShuffleAsync(); + System.Threading.Tasks.Task ShuffleAsync(string token); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task ShuffleAsync(string token, System.Threading.CancellationToken cancellationToken); } @@ -578,15 +590,15 @@ public string BaseUrl /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task QueueGETAsync() + public virtual System.Threading.Tasks.Task QueueGETAsync(string token) { - return QueueGETAsync(System.Threading.CancellationToken.None); + return QueueGETAsync(token, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task QueueGETAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task QueueGETAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); @@ -597,6 +609,9 @@ public virtual async System.Threading.Tasks.Task QueueGETAsyn { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -652,15 +667,15 @@ public virtual async System.Threading.Tasks.Task QueueGETAsyn /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task QueueDELETEAsync() + public virtual System.Threading.Tasks.Task QueueDELETEAsync(string token) { - return QueueDELETEAsync(System.Threading.CancellationToken.None); + return QueueDELETEAsync(token, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task QueueDELETEAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task QueueDELETEAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); @@ -671,6 +686,9 @@ public virtual async System.Threading.Tasks.Task QueueDEL { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -726,15 +744,15 @@ public virtual async System.Threading.Tasks.Task QueueDEL /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId) + public virtual System.Threading.Tasks.Task TrackPATCHAsync(string token, System.Guid? trackId) { - return TrackPATCHAsync(trackId, System.Threading.CancellationToken.None); + return TrackPATCHAsync(token, trackId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackPATCHAsync(System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackPATCHAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/track?"); @@ -750,6 +768,9 @@ public virtual async System.Threading.Tasks.Task Track { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); request_.Method = new System.Net.Http.HttpMethod("PATCH"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -806,15 +827,15 @@ public virtual async System.Threading.Tasks.Task Track /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task ShuffleAsync() + public virtual System.Threading.Tasks.Task ShuffleAsync(string token) { - return ShuffleAsync(System.Threading.CancellationToken.None); + return ShuffleAsync(token, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ShuffleAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ShuffleAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/shuffle"); @@ -825,6 +846,9 @@ public virtual async System.Threading.Tasks.Task ShuffleA { using (var request_ = new System.Net.Http.HttpRequestMessage()) { + + if (token != null) + request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); request_.Method = new System.Net.Http.HttpMethod("PATCH"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); diff --git a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag index 55b504b..ebe3094 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag +++ b/Sonar.Player/Sonar.Player.ApiClient/Sonar.Player.ApiClient.nswag @@ -3,7 +3,7 @@ "defaultVariables": "", "documentGenerator": { "fromDocument": { - "json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"Sonar.Player\",\r\n \"version\": \"v1\"\r\n },\r\n \"paths\": {\r\n \"/Files/track\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"name\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.UploadTrack+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Files.Commands.DeleteTrack+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Files/trackStreamInfo\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"id\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/Files/{streamPartName}\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Files\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"streamPartName\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue\": {\r\n \"get\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Queries.GetQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"delete\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue/track\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"trackId\",\r\n \"in\": \"query\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"format\": \"uuid\"\r\n }\r\n }\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/Queue/shuffle\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"Queue\"\r\n ],\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {\r\n \"Sonar.Player.Application.Files.Commands.DeleteTrack+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Files.Commands.UploadTrack+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Commands.AddTrackToQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Commands.ShuffleQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n },\r\n \"Sonar.Player.Application.Queue.Queries.GetQueue+Response\": {\r\n \"type\": \"object\",\r\n \"additionalProperties\": false\r\n }\r\n },\r\n \"securitySchemes\": {\r\n \"Token\": {\r\n \"type\": \"apiKey\",\r\n \"description\": \"Token to access resources\",\r\n \"name\": \"Authorization\",\r\n \"in\": \"header\"\r\n }\r\n }\r\n }\r\n}", + "json": "", "url": "https://localhost:7153/swagger/v1/swagger.json", "output": null, "newLineBehavior": "Auto" @@ -28,7 +28,7 @@ "useBaseUrl": true, "generateBaseUrlProperty": true, "generateSyncMethods": false, - "generatePrepareRequestAndProcessResponseAsAsyncMethods": true, + "generatePrepareRequestAndProcessResponseAsAsyncMethods": false, "exposeJsonSerializerSettings": false, "clientClassAccessModifier": "public", "typeAccessModifier": "public", From b68df1136d9f22c66c52e6394429f95e15f8d5a6 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 22:11:45 +0300 Subject: [PATCH 25/76] Fix: add queue tracks property --- Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index 9acabb3..2e6130c 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -4,6 +4,8 @@ public class TracksQueue { private List _tracks; + public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); + public TracksQueue() { _tracks = new List(); From 0dba5f577fa7f1bbd61fee79819bb7e01d56a784 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Tue, 24 May 2022 22:18:06 +0300 Subject: [PATCH 26/76] Refactor: queue entity --- .../Sonar.Player.Domain/Entities/TracksQueue.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index 2e6130c..3164773 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -2,21 +2,16 @@ public class TracksQueue { - private List _tracks; + private readonly List _tracks = new List(); public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); - public TracksQueue() - { - _tracks = new List(); - } - - private TracksQueue(ICollection tracks) + public Track Next() { - _tracks = tracks.ToList(); + throw new NotImplementedException(); } - public Track Next() + public void Enqueue(Track track) { throw new NotImplementedException(); } From 363420d7a4c360bc325d84160da5f1c41dccdea2 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Wed, 25 May 2022 09:22:53 +0300 Subject: [PATCH 27/76] Refactor: kebab case routing --- .../Controllers/FilesController.cs | 2 +- Sonar.Player/Sonar.Player.Api/Program.cs | 1 + Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 122fa1a..e15b1b8 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -25,7 +25,7 @@ public FilesController(IMediator mediator) return Ok(await _mediator.Send(new UploadTrack.Command())); } - [HttpGet("trackStreamInfo")] + [HttpGet("track-stream-info")] public async Task GetTrackStreamInfoAsync( [FromHeader(Name = "Token")] string token, [FromQuery(Name = "id")] Guid trackId) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 2aff0f6..4e2f2e1 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -8,6 +8,7 @@ // Add services to the container. builder.Services.AddControllers(); +builder.Services.Configure(opt => opt.LowercaseUrls = true); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen( diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs index 50f3e48..62004f3 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -106,7 +106,7 @@ public virtual System.Threading.Tasks.Task TrackPOSTAsync( public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track?"); if (name != null) { urlBuilder_.Append(System.Uri.EscapeDataString("name") + "=").Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -189,7 +189,7 @@ public virtual System.Threading.Tasks.Task TrackDELETEAsyn public virtual async System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/track?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track?"); if (trackId != null) { urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -271,7 +271,7 @@ public virtual System.Threading.Tasks.Task TrackStreamInfoAsync(string token, Sy public virtual async System.Threading.Tasks.Task TrackStreamInfoAsync(string token, System.Guid? id, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/trackStreamInfo?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track-stream-info?"); if (id != null) { urlBuilder_.Append(System.Uri.EscapeDataString("id") + "=").Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -350,7 +350,7 @@ public virtual async System.Threading.Tasks.Task FilesAsync(string token, string throw new System.ArgumentNullException("streamPartName"); var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Files/{streamPartName}"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/{streamPartName}"); urlBuilder_.Replace("{streamPartName}", System.Uri.EscapeDataString(ConvertToString(streamPartName, System.Globalization.CultureInfo.InvariantCulture))); var client_ = _httpClient; @@ -601,7 +601,7 @@ public virtual System.Threading.Tasks.Task QueueGETAsync(stri public virtual async System.Threading.Tasks.Task QueueGETAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/queue"); var client_ = _httpClient; var disposeClient_ = false; @@ -678,7 +678,7 @@ public virtual System.Threading.Tasks.Task QueueDELETEAsy public virtual async System.Threading.Tasks.Task QueueDELETEAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/queue"); var client_ = _httpClient; var disposeClient_ = false; @@ -755,7 +755,7 @@ public virtual System.Threading.Tasks.Task TrackPATCHA public virtual async System.Threading.Tasks.Task TrackPATCHAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/track?"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/queue/track?"); if (trackId != null) { urlBuilder_.Append(System.Uri.EscapeDataString("trackId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(trackId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); @@ -838,7 +838,7 @@ public virtual System.Threading.Tasks.Task ShuffleAsync(s public virtual async System.Threading.Tasks.Task ShuffleAsync(string token, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Queue/shuffle"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/queue/shuffle"); var client_ = _httpClient; var disposeClient_ = false; From b1e9efb8827e50f27d8016ca8b52445311bbaaa1 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Wed, 25 May 2022 21:04:57 +0300 Subject: [PATCH 28/76] Chore: update submodules --- Sonar.UserProfile | 2 +- Sonar.UserTracksManagment | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.UserProfile b/Sonar.UserProfile index ce73aad..76c23a3 160000 --- a/Sonar.UserProfile +++ b/Sonar.UserProfile @@ -1 +1 @@ -Subproject commit ce73aad4b7862089812c9abad49b5c2a11b5b124 +Subproject commit 76c23a332454cd0b1a1553e4ea3a9d634bed0cbf diff --git a/Sonar.UserTracksManagment b/Sonar.UserTracksManagment index 13b9649..cc7c57a 160000 --- a/Sonar.UserTracksManagment +++ b/Sonar.UserTracksManagment @@ -1 +1 @@ -Subproject commit 13b9649946f9705e04d0d51dc32d85ee81664800 +Subproject commit cc7c57a533b320172aeb430ecf8f1573ecae9ea5 From 2eb079fd685fd2d1b4ac463bd2626bd664440334 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Wed, 25 May 2022 21:23:41 +0300 Subject: [PATCH 29/76] Feat: add token to user model --- Sonar.Player/Sonar.Player.Domain/Models/User.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Models/User.cs b/Sonar.Player/Sonar.Player.Domain/Models/User.cs index 1022dde..8ead21c 100644 --- a/Sonar.Player/Sonar.Player.Domain/Models/User.cs +++ b/Sonar.Player/Sonar.Player.Domain/Models/User.cs @@ -3,9 +3,11 @@ public class User { public Guid Id { get; } + public string Token { get; } - public User(Guid id) + public User(Guid id, string token) { Id = id; + Token = token; } } \ No newline at end of file From 5101f04c45206b1ca78bb1097ee71fada4a6b26c Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:07:16 +0300 Subject: [PATCH 30/76] Fix: audio format parse --- Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs index bd0b0bb..a604f51 100644 --- a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs +++ b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs @@ -19,8 +19,8 @@ public static AudioFormat FromFileName(string filename) ArgumentNullException.ThrowIfNull(filename); return Path.GetExtension(filename) switch { - "mp3" => Mp3, - "wav" => Wav, + ".mp3" => Mp3, + ".wav" => Wav, _ => throw new EnumerationParseException(nameof(AudioFormat), filename) }; } From 04fb25eebbc9bf94a9cfa6f4b1edf33da2a41008 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:07:41 +0300 Subject: [PATCH 31/76] Refactor: form data upload --- .../Controllers/Dto/TrackFormDto.cs | 7 ++++++ .../Controllers/FilesController.cs | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Api/Controllers/Dto/TrackFormDto.cs diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/Dto/TrackFormDto.cs b/Sonar.Player/Sonar.Player.Api/Controllers/Dto/TrackFormDto.cs new file mode 100644 index 0000000..8418059 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Controllers/Dto/TrackFormDto.cs @@ -0,0 +1,7 @@ +namespace Sonar.Player.Api.Controllers.Dto; + +public class TrackFormDto +{ + public string Name { get; set; } + public IFormFile File { get; set; } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index e15b1b8..2d5b82d 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -1,7 +1,9 @@ using MediatR; using Microsoft.AspNetCore.Mvc; +using Sonar.Player.Api.Controllers.Dto; using Sonar.Player.Application.Files.Commands; using Sonar.Player.Application.Files.Queries; +using Sonar.Player.Application.Services; namespace Sonar.Player.Api.Controllers; @@ -10,19 +12,31 @@ namespace Sonar.Player.Api.Controllers; public class FilesController : Controller { private readonly IMediator _mediator; + private readonly IUserService _userService; - public FilesController(IMediator mediator) + public FilesController(IMediator mediator, IUserService userService) { _mediator = mediator; + _userService = userService; } [HttpPost("track")] public async Task> UploadTrackAsync( [FromHeader(Name = "Token")] string token, - [FromQuery] string name) + [FromForm] TrackFormDto form) { - //TODO: get file from request content - return Ok(await _mediator.Send(new UploadTrack.Command())); + var user = _userService.GetUser(token); + await using var fileStream = form.File.OpenReadStream(); + + return Ok( + await _mediator.Send( + new UploadTrack.Command( + user, + form.Name, + new UploadTrack.Command.TrackFile( + form.File.FileName, + fileStream) + ))); } [HttpGet("track-stream-info")] From 5bfcce3269649dcd4f0a8a92eb220da26867906f Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:10:07 +0300 Subject: [PATCH 32/76] Feat: add serilog --- Sonar.Player/Sonar.Player.Api/Program.cs | 4 ++++ Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 4e2f2e1..98cd942 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -2,10 +2,13 @@ using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; +using Serilog; using Sonar.Player.Data; var builder = WebApplication.CreateBuilder(args); +builder.Host.UseSerilog((ctx, lc) => lc.WriteTo.Console()); + // Add services to the container. builder.Services.AddControllers(); builder.Services.Configure(opt => opt.LowercaseUrls = true); @@ -48,5 +51,6 @@ app.UseAuthorization(); app.MapControllers(); +app.UseSerilogRequestLogging(); app.Run(); \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj index edaab70..0d414e8 100644 --- a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj +++ b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj @@ -13,6 +13,8 @@ + + From c67ce157087c8a8a9c83de1655161022c0eb107c Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:10:31 +0300 Subject: [PATCH 33/76] Refactor: track entity --- Sonar.Player/Sonar.Player.Domain/Entities/Track.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs b/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs index 35289d2..34ad48a 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/Track.cs @@ -6,12 +6,17 @@ public class Track { public Guid Id { get; private init; } public AudioFormat Format { get; private init; } + public string FileName { get; private init; } - public Track(Guid id, AudioFormat format) + public Track(Guid id, AudioFormat format, string fileName) { Id = id; Format = format; + FileName = fileName; } - private Track() { } + private Track(string fileName) + { + FileName = fileName; + } } \ No newline at end of file From 75afde994d450b2207d8e36885ea191df0e16766 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:12:35 +0300 Subject: [PATCH 34/76] Feat: add tracks to dbContext --- .../Configurations/TrackConfiguration.cs | 14 ++++++++++++++ .../Sonar.Player.DataAccess/PlayerDbContext.cs | 9 +++++++++ .../Sonar.Player.DataAccess.csproj | 4 ++++ 3 files changed, 27 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.DataAccess/Configurations/TrackConfiguration.cs diff --git a/Sonar.Player/Sonar.Player.DataAccess/Configurations/TrackConfiguration.cs b/Sonar.Player/Sonar.Player.DataAccess/Configurations/TrackConfiguration.cs new file mode 100644 index 0000000..835d419 --- /dev/null +++ b/Sonar.Player/Sonar.Player.DataAccess/Configurations/TrackConfiguration.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Sonar.Player.Domain.Entities; +using Sonar.Player.Domain.Enumerations; + +namespace Sonar.Player.Data.Configurations; + +public class TrackConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.OwnsOne(f => f.Format); + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs b/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs index 0e6d192..5133059 100644 --- a/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs +++ b/Sonar.Player/Sonar.Player.DataAccess/PlayerDbContext.cs @@ -1,11 +1,20 @@ using Microsoft.EntityFrameworkCore; +using Sonar.Player.Domain.Entities; namespace Sonar.Player.Data; public class PlayerDbContext : DbContext { + public DbSet Tracks { get; set; } + public PlayerDbContext(DbContextOptions options) : base(options) { + Database.EnsureCreated(); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj b/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj index 19a4392..ac0b71a 100644 --- a/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj +++ b/Sonar.Player/Sonar.Player.DataAccess/Sonar.Player.DataAccess.csproj @@ -11,4 +11,8 @@ + + + + From 2600cc9ab1e75f8180e17a66854135d23ac3486d Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:12:54 +0300 Subject: [PATCH 35/76] Feat: add path builder --- .../Tools/ITrackPathBuilder.cs | 8 ++++++++ .../Tools/TrackPathBuilder.cs | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs diff --git a/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs new file mode 100644 index 0000000..2a151e1 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs @@ -0,0 +1,8 @@ +namespace Sonar.Player.Application.Tools; + +public interface ITrackPathBuilder +{ + string GetTrackFolderPath(Guid trackId); + string GetTrackStreamInfoPath(Guid trackId); + string GetTackStreamPartPath(Guid trackId, string partName); +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs new file mode 100644 index 0000000..865a773 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs @@ -0,0 +1,20 @@ +namespace Sonar.Player.Application.Tools; + +public class TrackPathBuilder : ITrackPathBuilder +{ + public string GetTrackFolderPath(Guid trackId) + { + //TODO: move base directory configuration to appsettings + return Path.Combine(Directory.GetCurrentDirectory(), "tracks", trackId.ToString()); + } + + public string GetTrackStreamInfoPath(Guid trackId) + { + return Path.Combine(GetTrackFolderPath(trackId), "stream", "streamInfo.m3u8"); + } + + public string GetTackStreamPartPath(Guid trackId, string partName) + { + return Path.Combine(GetTrackFolderPath(trackId), "stream", partName); + } +} \ No newline at end of file From 3dc53e0f64839481b08009ac839ca7a1049b8ad9 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:13:44 +0300 Subject: [PATCH 36/76] Feat: add api exception --- .../Tools/Exceptions/ExternalApiException.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs diff --git a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs new file mode 100644 index 0000000..4cf950a --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs @@ -0,0 +1,11 @@ +namespace Sonar.Player.Application.Tools.Exceptions; + +public class ExternalApiException : Exception +{ + public int StatusCode { get; } + + public ExternalApiException(string message, int statusCode) : base(message) + { + StatusCode = statusCode; + } +} \ No newline at end of file From da8121573a2c5e89071cf7a9e59777cc1cd83e62 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:14:09 +0300 Subject: [PATCH 37/76] Feat: add track storage --- .../Services/TracksStorage/ITrackStorage.cs | 9 ++++++ .../TracksStorage/LocalTrackStorage.cs | 30 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs new file mode 100644 index 0000000..d45aa98 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs @@ -0,0 +1,9 @@ +using Sonar.Player.Domain.Entities; +using Sonar.Player.Domain.Enumerations; + +namespace Sonar.Player.Application.Services.TracksStorage; + +public interface ITrackStorage +{ + Task SaveTrack(Guid id, AudioFormat format, Stream content); +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs new file mode 100644 index 0000000..bfb7d50 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs @@ -0,0 +1,30 @@ +using Sonar.Player.Application.Tools; +using Sonar.Player.Domain.Entities; +using Sonar.Player.Domain.Enumerations; + +namespace Sonar.Player.Application.Services.TracksStorage; + +public class LocalTrackStorage : ITrackStorage +{ + private readonly ITrackPathBuilder _pathBuilder; + + public LocalTrackStorage(ITrackPathBuilder pathBuilder) + { + _pathBuilder = pathBuilder; + } + + public async Task SaveTrack(Guid id, AudioFormat format, Stream content) + { + var trackDirectory = _pathBuilder.GetTrackFolderPath(id); + + if (!Directory.Exists(trackDirectory)) + Directory.CreateDirectory(trackDirectory); + + var fileName = $"track.{format.Value}"; + var filePath = Path.Combine(trackDirectory, fileName); + var fileStream = File.Create(filePath); + await content.CopyToAsync(fileStream); + + return new Track(id, format, fileName); + } +} \ No newline at end of file From 4cf010f26590745e8ae366bff4a27d614c4935d0 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:14:32 +0300 Subject: [PATCH 38/76] Feat: add user tracks module api client --- .../Sonar.Player.Application.csproj | 2 ++ Sonar.Player/Sonar.Player.sln | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj index cfcff75..9915d78 100644 --- a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj +++ b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj @@ -11,6 +11,8 @@ + + diff --git a/Sonar.Player/Sonar.Player.sln b/Sonar.Player/Sonar.Player.sln index e7889a1..d2c37b1 100644 --- a/Sonar.Player/Sonar.Player.sln +++ b/Sonar.Player/Sonar.Player.sln @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.ApiClient", "S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.UserProfile.ApiClient", "..\Sonar.UserProfile\Sonar.UserProfile.ApiClient\Sonar.UserProfile.ApiClient.csproj", "{7F1313DE-7C02-4752-9A46-C5054074EF1D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.UserTracksManagement.ApiClient", "..\Sonar.UserTracksManagment\Sonar.UserTracksManagement\Sonar.UserTracksManagement.ApiClient\Sonar.UserTracksManagement.ApiClient.csproj", "{FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -42,5 +44,9 @@ Global {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F1313DE-7C02-4752-9A46-C5054074EF1D}.Release|Any CPU.Build.0 = Release|Any CPU + {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 2e6e24fb285108e75dcc10db821c205ddd57b615 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:14:43 +0300 Subject: [PATCH 39/76] Feat: add upload command --- .../Files/Commands/UploadTrack.cs | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs index 5c1830c..24f91f8 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/UploadTrack.cs @@ -1,18 +1,52 @@ using MediatR; +using Sonar.Player.Application.Services.TracksStorage; +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Data; +using Sonar.Player.Domain.Enumerations; +using Sonar.Player.Domain.Models; +using Sonar.UserTracksManagement.ApiClient; namespace Sonar.Player.Application.Files.Commands; public static class UploadTrack { - public record Command() : IRequest; + public record Command(User User, string Name, Command.TrackFile File) : IRequest + { + public record TrackFile(string Name, Stream Content); + }; - public record Response(); + public record Response(Guid trackId); public class CommandHandler : IRequestHandler { + private readonly IUserTracksApiClient _userTracksApiClient; + private readonly ITrackStorage _trackStorage; + private readonly PlayerDbContext _dbContext; + + public CommandHandler(IUserTracksApiClient userTracksApiClient, ITrackStorage trackStorage, PlayerDbContext dbContext) + { + _userTracksApiClient = userTracksApiClient; + _trackStorage = trackStorage; + _dbContext = dbContext; + } + public async Task Handle(Command request, CancellationToken cancellationToken) { - throw new NotImplementedException(); + Guid trackId; + try + { + trackId = await _userTracksApiClient.TracksPOSTAsync(request.User.Token, request.Name, cancellationToken); + } + catch (ApiException e) + { + throw new ExternalApiException(e.Response, e.StatusCode); + } + + var track = await _trackStorage.SaveTrack(trackId, AudioFormat.FromFileName(request.File.Name), request.File.Content); + await _dbContext.Tracks.AddAsync(track, cancellationToken); + await _dbContext.SaveChangesAsync(cancellationToken); + + return new Response(trackId); } } } \ No newline at end of file From c7cc3c3832748a08eb79165d79f5eeb0af1fc047 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 12:17:26 +0300 Subject: [PATCH 40/76] Feat: add fake services and bootstraping --- Sonar.Player/Sonar.Player.Api/Program.cs | 12 ++++- .../Sonar.Player.Api/Sonar.Player.Api.csproj | 1 + .../ApiClients/FakeUserTracksClient.cs | 46 +++++++++++++++++++ .../Services/FakeUserService.cs | 12 +++++ .../Sonar.Player.Fakes.csproj | 14 ++++++ Sonar.Player/Sonar.Player.sln | 6 +++ 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs create mode 100644 Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs create mode 100644 Sonar.Player/Sonar.Player.Fakes/Sonar.Player.Fakes.csproj diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 98cd942..e02e120 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -3,7 +3,13 @@ using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using Serilog; +using Sonar.Player.Application.Services; +using Sonar.Player.Application.Services.TracksStorage; +using Sonar.Player.Application.Tools; using Sonar.Player.Data; +using Sonar.Player.Fakes.ApiClients; +using Sonar.Player.Fakes.Services; +using Sonar.UserTracksManagement.ApiClient; var builder = WebApplication.CreateBuilder(args); @@ -36,7 +42,10 @@ ); builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); - +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. @@ -51,6 +60,7 @@ app.UseAuthorization(); app.MapControllers(); +app.UseCors(opt => opt.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); app.UseSerilogRequestLogging(); app.Run(); \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj index 0d414e8..ac5609e 100644 --- a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj +++ b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj @@ -21,6 +21,7 @@ + diff --git a/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs b/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs new file mode 100644 index 0000000..addb035 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs @@ -0,0 +1,46 @@ +using Sonar.UserTracksManagement.ApiClient; + +namespace Sonar.Player.Fakes.ApiClients; + +public class FakeUserTracksClient : IUserTracksApiClient +{ + public Task TracksPOSTAsync(string token, string name) + { + return Task.FromResult(Guid.NewGuid()); + } + + public Task TracksPOSTAsync(string token, string name, CancellationToken cancellationToken) + { + return Task.FromResult(Guid.NewGuid()); + } + + public Task TracksGETAsync(string token, Guid? trackId) + { + throw new NotImplementedException(); + } + + public Task TracksGETAsync(string token, Guid? trackId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> AllAsync(string token) + { + throw new NotImplementedException(); + } + + public Task> AllAsync(string token, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task IsEnoughAccessAsync(string token, Guid? trackId) + { + throw new NotImplementedException(); + } + + public Task IsEnoughAccessAsync(string token, Guid? trackId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs b/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs new file mode 100644 index 0000000..0109e89 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs @@ -0,0 +1,12 @@ +using Sonar.Player.Application.Services; +using Sonar.Player.Domain.Models; + +namespace Sonar.Player.Fakes.Services; + +public class FakeUserService : IUserService +{ + public User GetUser(string token) + { + return new User(Guid.NewGuid(), token); + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Fakes/Sonar.Player.Fakes.csproj b/Sonar.Player/Sonar.Player.Fakes/Sonar.Player.Fakes.csproj new file mode 100644 index 0000000..bba4974 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Fakes/Sonar.Player.Fakes.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/Sonar.Player/Sonar.Player.sln b/Sonar.Player/Sonar.Player.sln index d2c37b1..7f17b6f 100644 --- a/Sonar.Player/Sonar.Player.sln +++ b/Sonar.Player/Sonar.Player.sln @@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.UserProfile.ApiClient EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.UserTracksManagement.ApiClient", "..\Sonar.UserTracksManagment\Sonar.UserTracksManagement\Sonar.UserTracksManagement.ApiClient\Sonar.UserTracksManagement.ApiClient.csproj", "{FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sonar.Player.Fakes", "Sonar.Player.Fakes\Sonar.Player.Fakes.csproj", "{D63539A0-F3A2-4387-A469-DAC1065A6923}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,5 +50,9 @@ Global {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA5BB509-AECD-4800-AC94-AB3EEA3DFF19}.Release|Any CPU.Build.0 = Release|Any CPU + {D63539A0-F3A2-4387-A469-DAC1065A6923}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D63539A0-F3A2-4387-A469-DAC1065A6923}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D63539A0-F3A2-4387-A469-DAC1065A6923}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D63539A0-F3A2-4387-A469-DAC1065A6923}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 148f29fb6fface8ad539f1fa66b91c4e42b7530c Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 14:09:33 +0300 Subject: [PATCH 41/76] Fix: paths --- .../Tools/ITrackPathBuilder.cs | 3 ++- .../Tools/TrackPathBuilder.cs | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs index 2a151e1..f49621e 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs @@ -3,6 +3,7 @@ public interface ITrackPathBuilder { string GetTrackFolderPath(Guid trackId); + string GetTrackStreamFolderPath(Guid trackId); string GetTrackStreamInfoPath(Guid trackId); - string GetTackStreamPartPath(Guid trackId, string partName); + string GetTackStreamPartPath(string partName); } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs index 865a773..a6d2461 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs @@ -8,13 +8,19 @@ public string GetTrackFolderPath(Guid trackId) return Path.Combine(Directory.GetCurrentDirectory(), "tracks", trackId.ToString()); } + public string GetTrackStreamFolderPath(Guid trackId) + { + return Path.Combine(GetTrackFolderPath(trackId), "stream"); + } + public string GetTrackStreamInfoPath(Guid trackId) { - return Path.Combine(GetTrackFolderPath(trackId), "stream", "streamInfo.m3u8"); + return Path.Combine(GetTrackStreamFolderPath(trackId), "streamInfo.m3u8"); } - public string GetTackStreamPartPath(Guid trackId, string partName) + public string GetTackStreamPartPath(string partName) { - return Path.Combine(GetTrackFolderPath(trackId), "stream", partName); + var trackId = partName.Split("-").First(); + return Path.Combine(GetTrackFolderPath(Guid.Parse(trackId)), "stream", partName); } } \ No newline at end of file From c7a9b2b89eae405737615ef49a05a37b54374d80 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 14:09:47 +0300 Subject: [PATCH 42/76] Fix: using --- .../Services/TracksStorage/LocalTrackStorage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs index bfb7d50..9e47f3e 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs @@ -22,7 +22,7 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) var fileName = $"track.{format.Value}"; var filePath = Path.Combine(trackDirectory, fileName); - var fileStream = File.Create(filePath); + await using var fileStream = File.Create(filePath); await content.CopyToAsync(fileStream); return new Track(id, format, fileName); From 93d8b33d60d265e4cc8604642a4202397d4ceb0d Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 26 May 2022 14:10:14 +0300 Subject: [PATCH 43/76] Feat: add hls preprocessing --- Sonar.Player/Sonar.Player.Api/Program.cs | 5 ++ .../Sonar.Player.Api/Sonar.Player.Api.csproj | 7 +++ .../TracksStorage/HlsTrackProcessor.cs | 55 +++++++++++++++++++ .../Tools/FfmpegArgumentsBuilder.cs | 37 +++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs create mode 100644 Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index e02e120..7704ac6 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -44,8 +44,13 @@ builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); +builder.Services.Decorate(); + builder.Services.AddSingleton(); + + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj index ac5609e..6666618 100644 --- a/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj +++ b/Sonar.Player/Sonar.Player.Api/Sonar.Player.Api.csproj @@ -13,6 +13,7 @@ + @@ -24,4 +25,10 @@ + + + PreserveNewest + + + diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs new file mode 100644 index 0000000..6f66b9b --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -0,0 +1,55 @@ +using System.Diagnostics; +using Sonar.Player.Application.Tools; +using Sonar.Player.Domain.Entities; +using Sonar.Player.Domain.Enumerations; + +namespace Sonar.Player.Application.Services.TracksStorage; + +public class HlsTrackProcessor : ITrackStorage +{ + private readonly ITrackStorage _decorated; + private readonly ITrackPathBuilder _pathBuilder; + + public HlsTrackProcessor(ITrackStorage decorated, ITrackPathBuilder pathBuilder) + { + _decorated = decorated; + _pathBuilder = pathBuilder; + } + + public async Task SaveTrack(Guid id, AudioFormat format, Stream content) + { + var track = await _decorated.SaveTrack(id, format, content); + + var trackPath = Path.Combine(_pathBuilder.GetTrackFolderPath(track.Id), track.FileName); + var streamFolderPath = _pathBuilder.GetTrackStreamFolderPath(track.Id); + + if (!Directory.Exists(streamFolderPath)) + Directory.CreateDirectory(streamFolderPath); + + var segmentFilename = $"{track.Id}-stream-%02d.ts"; + var segmentPath = Path.Combine(streamFolderPath, segmentFilename); + var infoFilePath = Path.Combine(streamFolderPath, "streamInfo.m3u8"); + + var arguments = new FfmpegArgumentsBuilder() + .Source(trackPath) + .Bitrate(4800) + .SegmentFilename(segmentPath) + .OutputFile(infoFilePath); + + Process process = new() + { + StartInfo = new() + { + FileName = "ffmpeg.exe", + Arguments = arguments, + UseShellExecute = false, + }, + EnableRaisingEvents = true, + }; + + process.Start(); + await process.WaitForExitAsync(); + + return track; + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs new file mode 100644 index 0000000..ea8f70b --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs @@ -0,0 +1,37 @@ +using System.Text; + +namespace Sonar.Player.Application.Tools; + +public class FfmpegArgumentsBuilder +{ + private readonly StringBuilder _builder; + + public FfmpegArgumentsBuilder() + { + _builder = new StringBuilder(); + } + + public FfmpegArgumentsBuilder Source(string sourcePath) + { + _builder.Append($"-i {sourcePath}"); + return this; + } + + public FfmpegArgumentsBuilder Bitrate(int bitrate) + { + _builder.Append($" -bitrate {bitrate}"); + return this; + } + + public FfmpegArgumentsBuilder SegmentFilename(string segmentName) + { + _builder.Append($" -f hls -hls_time 3 -hls_playlist_type vod -hls_flags independent_segments -hls_segment_type mpegts -hls_segment_filename {segmentName}"); + return this; + } + + public string OutputFile(string filename) + { + _builder.Append($" {filename}"); + return _builder.ToString(); + } +} \ No newline at end of file From 9c215fe1b06e0330fbc71f72508b9e2928309cb5 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Fri, 27 May 2022 10:14:09 +0300 Subject: [PATCH 44/76] Fix: typo --- .../Sonar.Player.Application/Tools/ITrackPathBuilder.cs | 2 +- Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs index f49621e..8e2791a 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/ITrackPathBuilder.cs @@ -5,5 +5,5 @@ public interface ITrackPathBuilder string GetTrackFolderPath(Guid trackId); string GetTrackStreamFolderPath(Guid trackId); string GetTrackStreamInfoPath(Guid trackId); - string GetTackStreamPartPath(string partName); + string GetTrackStreamPartPath(string partName); } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs index a6d2461..180190e 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs @@ -18,7 +18,7 @@ public string GetTrackStreamInfoPath(Guid trackId) return Path.Combine(GetTrackStreamFolderPath(trackId), "streamInfo.m3u8"); } - public string GetTackStreamPartPath(string partName) + public string GetTrackStreamPartPath(string partName) { var trackId = partName.Split("-").First(); return Path.Combine(GetTrackFolderPath(Guid.Parse(trackId)), "stream", partName); From 3bd69ee4c34513fb94f039352bf794cf4d8c5a76 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Fri, 27 May 2022 10:17:06 +0300 Subject: [PATCH 45/76] Fix: lifetime --- Sonar.Player/Sonar.Player.Api/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 7704ac6..9597b6a 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -42,10 +42,10 @@ ); builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); -builder.Services.AddTransient(); -builder.Services.AddTransient(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); -builder.Services.AddTransient(); +builder.Services.AddScoped(); builder.Services.Decorate(); builder.Services.AddSingleton(); From b55f0fa8b06457d8bc3bfb4d6c206c6b86a69091 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sat, 28 May 2022 10:17:19 +0300 Subject: [PATCH 46/76] Feat: add delete method to storage --- .../Services/TracksStorage/HlsTrackProcessor.cs | 5 +++++ .../Services/TracksStorage/ITrackStorage.cs | 2 ++ .../Services/TracksStorage/LocalTrackStorage.cs | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs index 6f66b9b..e9d225a 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -52,4 +52,9 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) return track; } + + public async Task DeleteTrack(Guid id) + { + await _decorated.DeleteTrack(id); + } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs index d45aa98..a391950 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/ITrackStorage.cs @@ -6,4 +6,6 @@ namespace Sonar.Player.Application.Services.TracksStorage; public interface ITrackStorage { Task SaveTrack(Guid id, AudioFormat format, Stream content); + + Task DeleteTrack(Guid id); } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs index 9e47f3e..a62d777 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/LocalTrackStorage.cs @@ -27,4 +27,13 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) return new Track(id, format, fileName); } + + public Task DeleteTrack(Guid id) + { + var trackDirectory = _pathBuilder.GetTrackFolderPath(id); + if (Directory.Exists(trackDirectory)) + Directory.Delete(trackDirectory, true); + + return Task.CompletedTask; + } } \ No newline at end of file From 375f2af5ca197385cc55e09f298dde670531be29 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sat, 28 May 2022 10:45:46 +0300 Subject: [PATCH 47/76] Feat: implement delete command --- .../Controllers/FilesController.cs | 6 ++-- .../Files/Commands/DeleteTrack.cs | 32 +++++++++++++++---- .../Exceptions/NotEnoughAccessException.cs | 7 ++++ 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 2d5b82d..acf178f 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -58,10 +58,12 @@ public async Task GetStreamPartAsync( } [HttpDelete("track")] - public async Task> DeleteTrackAsync( + public async Task DeleteTrackAsync( [FromHeader(Name = "Token")] string token, [FromQuery] Guid trackId) { - return Ok(await _mediator.Send(new DeleteTrack.Command())); + var user = _userService.GetUser(token); + await _mediator.Send(new DeleteTrack.Command(user, trackId)); + return Ok(); } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs index 79deebf..4352c7d 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs @@ -1,18 +1,38 @@ using MediatR; +using Sonar.Player.Application.Services.TracksStorage; +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Models; +using Sonar.UserTracksManagement.ApiClient; namespace Sonar.Player.Application.Files.Commands; public static class DeleteTrack { - public record Command() : IRequest; + public record Command(User User, Guid TrackId) : IRequest; - public record Response(); - - public class CommandHandler : IRequestHandler + public class CommandHandler : IRequestHandler { - public async Task Handle(Command request, CancellationToken cancellationToken) + private readonly IUserTracksApiClient _userTracksApiClient; + private readonly ITrackStorage _trackStorage; + + public CommandHandler(IUserTracksApiClient userTracksApiClient, ITrackStorage trackStorage) + { + _userTracksApiClient = userTracksApiClient; + _trackStorage = trackStorage; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var isEnoughAccess = await _userTracksApiClient.IsEnoughAccessAsync( + request.User.Token, + request.User.Id, + cancellationToken); + if (!isEnoughAccess) + throw new NotEnoughAccessException($"Not enough access to track {request.TrackId}"); + + //TODO: call _userTracksApiClient.DeleteAsync + await _trackStorage.DeleteTrack(request.TrackId); + return Unit.Value; } } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs new file mode 100644 index 0000000..e4de2bb --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs @@ -0,0 +1,7 @@ +namespace Sonar.Player.Application.Tools.Exceptions; + +public class NotEnoughAccessException : Exception +{ + public NotEnoughAccessException() { } + public NotEnoughAccessException(string message) : base(message) { } +} \ No newline at end of file From b58a1b02fa0be1f55f94d25d98860ef4979837f3 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sat, 28 May 2022 10:53:31 +0300 Subject: [PATCH 48/76] Feat: make user service async --- Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs | 2 +- .../Sonar.Player.Application/Services/IUserService.cs | 2 +- Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 2d5b82d..b5b82f1 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -25,7 +25,7 @@ public FilesController(IMediator mediator, IUserService userService) [FromHeader(Name = "Token")] string token, [FromForm] TrackFormDto form) { - var user = _userService.GetUser(token); + var user = await _userService.GetUserAsync(token); await using var fileStream = form.File.OpenReadStream(); return Ok( diff --git a/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs b/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs index 26d22b4..0a6e8a3 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/IUserService.cs @@ -4,5 +4,5 @@ namespace Sonar.Player.Application.Services; public interface IUserService { - User GetUser(string token); + Task GetUserAsync(string token); } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs b/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs index 0109e89..f679887 100644 --- a/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs +++ b/Sonar.Player/Sonar.Player.Fakes/Services/FakeUserService.cs @@ -5,8 +5,8 @@ namespace Sonar.Player.Fakes.Services; public class FakeUserService : IUserService { - public User GetUser(string token) + public Task GetUserAsync(string token) { - return new User(Guid.NewGuid(), token); + return Task.FromResult(new User(Guid.NewGuid(), token)); } } \ No newline at end of file From 6538a8a7688bf98a6166d64b8885e0b8dcf2449f Mon Sep 17 00:00:00 2001 From: bibletoon Date: Sat, 28 May 2022 10:57:38 +0300 Subject: [PATCH 49/76] Feat: add user service --- .../Services/UserService.cs | 28 +++++++++++++++++++ .../Sonar.Player.Application.csproj | 1 + 2 files changed, 29 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Application/Services/UserService.cs diff --git a/Sonar.Player/Sonar.Player.Application/Services/UserService.cs b/Sonar.Player/Sonar.Player.Application/Services/UserService.cs new file mode 100644 index 0000000..5d36b46 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Application/Services/UserService.cs @@ -0,0 +1,28 @@ +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Models; +using Sonar.UserProfile.ApiClient; + +namespace Sonar.Player.Application.Services; + +public class UserService : IUserService +{ + private readonly IUserApiClient _apiClient; + + public UserService(IUserApiClient apiClient) + { + _apiClient = apiClient; + } + + public async Task GetUserAsync(string token) + { + try + { + var userDto = await _apiClient.GetAsync(token); + return new User(userDto.Id, token); + } + catch (ApiException e) + { + throw new ExternalApiException(e.Response, e.StatusCode); + } + } +} \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj index 9915d78..927c52a 100644 --- a/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj +++ b/Sonar.Player/Sonar.Player.Application/Sonar.Player.Application.csproj @@ -11,6 +11,7 @@ + From f951381945514a24d8d926a7d2ec3931f03b5655 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sat, 28 May 2022 15:34:51 +0300 Subject: [PATCH 50/76] feat: add stage fragmentation --- .../TracksStorage/HlsTrackProcessor.cs | 15 +++--- .../Tools/FfmpegArgumentsBuilder.cs | 47 ++++++++++++++++--- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs index e9d225a..249d091 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -9,7 +9,7 @@ public class HlsTrackProcessor : ITrackStorage { private readonly ITrackStorage _decorated; private readonly ITrackPathBuilder _pathBuilder; - + public HlsTrackProcessor(ITrackStorage decorated, ITrackPathBuilder pathBuilder) { _decorated = decorated; @@ -30,11 +30,12 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) var segmentPath = Path.Combine(streamFolderPath, segmentFilename); var infoFilePath = Path.Combine(streamFolderPath, "streamInfo.m3u8"); - var arguments = new FfmpegArgumentsBuilder() - .Source(trackPath) - .Bitrate(4800) - .SegmentFilename(segmentPath) - .OutputFile(infoFilePath); + var arguments = FfmpegArgumentsBuilder.CreateBuilder() + .GetSource(trackPath) + .SetBitrate(4800) + .SetSegmentFilename(segmentPath) + .WriteTo(infoFilePath) + .Build(); Process process = new() { @@ -57,4 +58,4 @@ public async Task DeleteTrack(Guid id) { await _decorated.DeleteTrack(id); } -} \ No newline at end of file +} diff --git a/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs index ea8f70b..e07e559 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs @@ -2,36 +2,71 @@ namespace Sonar.Player.Application.Tools; -public class FfmpegArgumentsBuilder +public class FfmpegArgumentsBuilder : ISourceSelectionStage, IBitrateSelectionStage, ISegmentSelectionStage, IOutputSelectionStage, IBuildStage { private readonly StringBuilder _builder; - public FfmpegArgumentsBuilder() + private FfmpegArgumentsBuilder() { _builder = new StringBuilder(); } - public FfmpegArgumentsBuilder Source(string sourcePath) + public static ISourceSelectionStage CreateBuilder() + { + return new FfmpegArgumentsBuilder(); + } + + public IBitrateSelectionStage GetSource(string sourcePath) { _builder.Append($"-i {sourcePath}"); return this; } - public FfmpegArgumentsBuilder Bitrate(int bitrate) + public ISegmentSelectionStage SetBitrate(int bitrate) { _builder.Append($" -bitrate {bitrate}"); return this; } - public FfmpegArgumentsBuilder SegmentFilename(string segmentName) + public IOutputSelectionStage SetSegmentFilename(string segmentName) { _builder.Append($" -f hls -hls_time 3 -hls_playlist_type vod -hls_flags independent_segments -hls_segment_type mpegts -hls_segment_filename {segmentName}"); return this; } - public string OutputFile(string filename) + public IBuildStage WriteTo(string filename) { _builder.Append($" {filename}"); + return this; + } + + public string Build() + { return _builder.ToString(); } +} + +public interface ISourceSelectionStage +{ + IBitrateSelectionStage GetSource(string sourcePath); +} + +public interface IBitrateSelectionStage +{ + ISegmentSelectionStage SetBitrate(int bitrate); +} + +public interface ISegmentSelectionStage +{ + IOutputSelectionStage SetSegmentFilename(string segmentName); +} + +public interface IOutputSelectionStage +{ + IBuildStage WriteTo(string filename); +} + +public interface IBuildStage +{ + string Build(); } \ No newline at end of file From d80ef37c9925cf88527c818e122108fce3d98d85 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sat, 28 May 2022 15:35:15 +0300 Subject: [PATCH 51/76] fix: update interface call --- Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index 4c533ac..edd9841 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -62,7 +62,7 @@ public async Task DeleteTrackAsync( [FromHeader(Name = "Token")] string token, [FromQuery] Guid trackId) { - var user = _userService.GetUser(token); + var user = await _userService.GetUserAsync(token); await _mediator.Send(new DeleteTrack.Command(user, trackId)); return Ok(); } From e686075d327ba1a881bca9e1f937a4a16b23d3bd Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sat, 28 May 2022 15:39:47 +0300 Subject: [PATCH 52/76] chore: remove new line at the end of the file to be consistent with project codestyle --- .../Services/TracksStorage/HlsTrackProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs index 249d091..8892ae4 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -58,4 +58,4 @@ public async Task DeleteTrack(Guid id) { await _decorated.DeleteTrack(id); } -} +} \ No newline at end of file From e3e2a4aa9c4523fcd071587b3e2fefc18111d662 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sat, 28 May 2022 16:54:37 +0300 Subject: [PATCH 53/76] feat: implement missing queries --- .../Files/Commands/DeleteTrack.cs | 21 +++++++------- .../Files/Queries/GetStreamPart.cs | 13 +++++++-- .../Files/Queries/GetTrackStreamInfo.cs | 29 +++++++++++++++++-- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs index 4352c7d..a96ab78 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs @@ -8,7 +8,7 @@ namespace Sonar.Player.Application.Files.Commands; public static class DeleteTrack { - public record Command(User User, Guid TrackId) : IRequest; + public record Command(string Token, Guid TrackId) : IRequest; public class CommandHandler : IRequestHandler { @@ -23,16 +23,17 @@ public CommandHandler(IUserTracksApiClient userTracksApiClient, ITrackStorage tr public async Task Handle(Command request, CancellationToken cancellationToken) { - var isEnoughAccess = await _userTracksApiClient.IsEnoughAccessAsync( - request.User.Token, - request.User.Id, - cancellationToken); - if (!isEnoughAccess) - throw new NotEnoughAccessException($"Not enough access to track {request.TrackId}"); + bool isEnoughAccess = await _userTracksApiClient + .IsEnoughAccessAsync(request.Token, request.TrackId, cancellationToken); - //TODO: call _userTracksApiClient.DeleteAsync - await _trackStorage.DeleteTrack(request.TrackId); - return Unit.Value; + if (!isEnoughAccess) + { + throw new NotEnoughAccessException($"Not enough access to track {request.TrackId}"); + } + + //TODO: call _userTracksApiClient.DeleteAsync + await _trackStorage.DeleteTrack(request.TrackId); + return Unit.Value; } } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs index dc52c55..8b50244 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetStreamPart.cs @@ -1,18 +1,27 @@ using MediatR; +using Sonar.Player.Application.Tools; namespace Sonar.Player.Application.Files.Queries; public static class GetStreamPart { - public record Query() : IRequest; + public record Query(string fileName) : IRequest; public record Response(FileStream StreamPart); public class QueryHandler : IRequestHandler { + private readonly ITrackPathBuilder _builder; + + public QueryHandler(ITrackPathBuilder builder) + { + _builder = builder; + } + public async Task Handle(Query request, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var filePath = _builder.GetTrackStreamPartPath(request.fileName); + return new Response(File.OpenRead(filePath)); } } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs index 61818f6..a41e85b 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Queries/GetTrackStreamInfo.cs @@ -1,18 +1,41 @@ using MediatR; +using Sonar.Player.Application.Tools; +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.UserTracksManagement.ApiClient; namespace Sonar.Player.Application.Files.Queries; public static class GetTrackStreamInfo { - public record Query() : IRequest; + public record Query(string Token, Guid TrackId) : IRequest; public record Response(FileStream TrackInfoStream); public class QueryHandler : IRequestHandler { + private readonly ITrackPathBuilder _builder; + private readonly IUserTracksApiClient _apiClient; + + public QueryHandler(ITrackPathBuilder builder, IUserTracksApiClient apiClient) + { + _builder = builder; + _apiClient = apiClient; + } + public async Task Handle(Query request, CancellationToken cancellationToken) { - throw new NotImplementedException(); + bool isEnoughAccess = await _apiClient.IsEnoughAccessAsync( + request.Token, + request.TrackId, + cancellationToken); + + if (!isEnoughAccess) + { + throw new NotEnoughAccessException($"Not enough access to track {request.TrackId}"); + } + + var path = _builder.GetTrackStreamInfoPath(request.TrackId); + return new Response(File.OpenRead(path)); } } -} \ No newline at end of file +} From 861504547c5136bfb6383daa1c194119cef86334 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sat, 28 May 2022 16:55:11 +0300 Subject: [PATCH 54/76] fix: update apiClient calls for authorization purposes --- .../Sonar.Player.Api/Controllers/FilesController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs index edd9841..a3f2911 100644 --- a/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs +++ b/Sonar.Player/Sonar.Player.Api/Controllers/FilesController.cs @@ -44,7 +44,7 @@ public async Task GetTrackStreamInfoAsync( [FromHeader(Name = "Token")] string token, [FromQuery(Name = "id")] Guid trackId) { - var response = await _mediator.Send(new GetTrackStreamInfo.Query()); + var response = await _mediator.Send(new GetTrackStreamInfo.Query(token, trackId)); return File(response.TrackInfoStream, "application/x-mpegURL", true); } @@ -53,7 +53,8 @@ public async Task GetStreamPartAsync( [FromHeader(Name = "Token")] string token, [FromRoute] string streamPartName) { - var response = await _mediator.Send(new GetStreamPart.Query()); + var user = await _userService.GetUserAsync(token); + var response = await _mediator.Send(new GetStreamPart.Query(streamPartName)); return File(response.StreamPart, "audio/MPA", true); } @@ -62,8 +63,7 @@ public async Task DeleteTrackAsync( [FromHeader(Name = "Token")] string token, [FromQuery] Guid trackId) { - var user = await _userService.GetUserAsync(token); - await _mediator.Send(new DeleteTrack.Command(user, trackId)); + await _mediator.Send(new DeleteTrack.Command(token, trackId)); return Ok(); } } \ No newline at end of file From a79c4fd82510723b9187ecf612cf3154affdb58b Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sun, 29 May 2022 22:24:43 +0300 Subject: [PATCH 55/76] refactor: add swagger bootstrap --- .../Bootstrappers/SwaggerConfigurator.cs | 43 +++++++++++++++++++ Sonar.Player/Sonar.Player.Api/Program.cs | 35 +++------------ 2 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs diff --git a/Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs b/Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs new file mode 100644 index 0000000..09efc31 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using Microsoft.OpenApi.Models; + +namespace Sonar.Player.Api.Bootstrappers; + +public static class SwaggerConfigurator +{ + public static IServiceCollection AddSwaggerWithCustomAuthorization(this IServiceCollection services) + { + services.AddSwaggerGen( + options => + { + options.CustomSchemaIds(type => type.FullName); + options.SwaggerDoc( + "v1", + new OpenApiInfo { Title = "Sonar.Player", Version = "v1" }); + + options.AddSecurityDefinition( + "Token", + new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Token to access resources", + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + }); + + string xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); + } + ); + + return services; + } + + public static IApplicationBuilder UseSwaggerWithUI(this IApplicationBuilder app) + { + app.UseSwagger(); + app.UseSwaggerUI(); + + return app; + } +} diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 9597b6a..f93d479 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -1,8 +1,7 @@ -using System.Reflection; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Models; using Serilog; +using Sonar.Player.Api.Bootstrappers; using Sonar.Player.Application.Services; using Sonar.Player.Application.Services.TracksStorage; using Sonar.Player.Application.Tools; @@ -15,49 +14,28 @@ builder.Host.UseSerilog((ctx, lc) => lc.WriteTo.Console()); -// Add services to the container. builder.Services.AddControllers(); builder.Services.Configure(opt => opt.LowercaseUrls = true); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen( - options => - { - options.CustomSchemaIds(type => type.FullName); - options.SwaggerDoc( - "v1", - new OpenApiInfo(){Title = "Sonar.Player", Version = "v1"}); - - options.AddSecurityDefinition("Token", new OpenApiSecurityScheme - { - In = ParameterLocation.Header, - Description = "Token to access resources", - Name = "Authorization", - Type = SecuritySchemeType.ApiKey, - }); +builder.Services.AddSwaggerWithCustomAuthorization(); - var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); - } -); builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); + builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.Decorate(); - builder.Services.AddSingleton(); - var app = builder.Build(); -// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { - app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwaggerWithUI(); } app.UseHttpsRedirection(); @@ -66,6 +44,7 @@ app.MapControllers(); app.UseCors(opt => opt.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); + app.UseSerilogRequestLogging(); app.Run(); \ No newline at end of file From c37f31853fe7eeb948a76c3e7a0f85ad83c294af Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sun, 29 May 2022 22:25:06 +0300 Subject: [PATCH 56/76] chore: remove unused directives --- .../Sonar.Player.Application/Files/Commands/DeleteTrack.cs | 1 - Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs index a96ab78..417ae06 100644 --- a/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs +++ b/Sonar.Player/Sonar.Player.Application/Files/Commands/DeleteTrack.cs @@ -1,7 +1,6 @@ using MediatR; using Sonar.Player.Application.Services.TracksStorage; using Sonar.Player.Application.Tools.Exceptions; -using Sonar.Player.Domain.Models; using Sonar.UserTracksManagement.ApiClient; namespace Sonar.Player.Application.Files.Commands; diff --git a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs index a604f51..8406caa 100644 --- a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs +++ b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs @@ -1,5 +1,4 @@ -using System.Text.RegularExpressions; -using Sonar.Player.Domain.Tools; +using Sonar.Player.Domain.Tools; using Sonar.Player.Domain.Tools.Exceptions; namespace Sonar.Player.Domain.Enumerations; From b8f18cc3376bd85864c207cc852c75b196525c51 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sun, 29 May 2022 22:26:13 +0300 Subject: [PATCH 57/76] chore: rename folder --- .../{Bootstrappers => Bootstraps}/SwaggerConfigurator.cs | 2 +- Sonar.Player/Sonar.Player.Api/Program.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Sonar.Player/Sonar.Player.Api/{Bootstrappers => Bootstraps}/SwaggerConfigurator.cs (96%) diff --git a/Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs b/Sonar.Player/Sonar.Player.Api/Bootstraps/SwaggerConfigurator.cs similarity index 96% rename from Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs rename to Sonar.Player/Sonar.Player.Api/Bootstraps/SwaggerConfigurator.cs index 09efc31..4914146 100644 --- a/Sonar.Player/Sonar.Player.Api/Bootstrappers/SwaggerConfigurator.cs +++ b/Sonar.Player/Sonar.Player.Api/Bootstraps/SwaggerConfigurator.cs @@ -1,7 +1,7 @@ using System.Reflection; using Microsoft.OpenApi.Models; -namespace Sonar.Player.Api.Bootstrappers; +namespace Sonar.Player.Api.Bootstraps; public static class SwaggerConfigurator { diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index f93d479..a30e85a 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -1,7 +1,7 @@ using MediatR; using Microsoft.EntityFrameworkCore; using Serilog; -using Sonar.Player.Api.Bootstrappers; +using Sonar.Player.Api.Bootstraps; using Sonar.Player.Application.Services; using Sonar.Player.Application.Services.TracksStorage; using Sonar.Player.Application.Tools; From 1f07bbe1777d1157be85b822ae37157ade2a81b9 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Sun, 29 May 2022 22:57:11 +0300 Subject: [PATCH 58/76] chore: fix spacing --- Sonar.Player/Sonar.Player.Api/Program.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index a30e85a..ed6e5a4 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -23,14 +23,13 @@ builder.Services.AddDbContext(opt => opt.UseSqlite("Filename=player.db")); builder.Services.AddMediatR(typeof(Sonar.Player.Application.IAssemblyMarker)); - -builder.Services.AddScoped(); -builder.Services.AddScoped(); - builder.Services.AddScoped(); builder.Services.Decorate(); builder.Services.AddSingleton(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + var app = builder.Build(); if (app.Environment.IsDevelopment()) From e8e34f46c8de1a098ddfdf3524db2587fbc637f0 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:09:08 +0300 Subject: [PATCH 59/76] feat: add domain-wise base exception and inherit other exception from it --- .../Tools/Exceptions/ExternalApiException.cs | 6 ++++-- .../Tools/Exceptions/NotEnoughAccessException.cs | 6 ++++-- .../Tools/Exceptions/EnumerationParseException.cs | 3 +-- .../Tools/Exceptions/SonarPlayerException.cs | 9 +++++++++ 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/SonarPlayerException.cs diff --git a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs index 4cf950a..f7dbc90 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/ExternalApiException.cs @@ -1,6 +1,8 @@ -namespace Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Tools.Exceptions; -public class ExternalApiException : Exception +namespace Sonar.Player.Application.Tools.Exceptions; + +public class ExternalApiException : SonarPlayerException { public int StatusCode { get; } diff --git a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs index e4de2bb..0cc676d 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/Exceptions/NotEnoughAccessException.cs @@ -1,6 +1,8 @@ -namespace Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Tools.Exceptions; -public class NotEnoughAccessException : Exception +namespace Sonar.Player.Application.Tools.Exceptions; + +public class NotEnoughAccessException : SonarPlayerException { public NotEnoughAccessException() { } public NotEnoughAccessException(string message) : base(message) { } diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs index b0a9ddb..187da40 100644 --- a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs @@ -1,7 +1,6 @@ namespace Sonar.Player.Domain.Tools.Exceptions; -//TODO: add base domain exception -public class EnumerationParseException : Exception +public class EnumerationParseException : SonarPlayerException { public EnumerationParseException(string typeName, T value) : base($"Can't parse {typeName} from {value}") { } diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/SonarPlayerException.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/SonarPlayerException.cs new file mode 100644 index 0000000..8f841d8 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/SonarPlayerException.cs @@ -0,0 +1,9 @@ +namespace Sonar.Player.Domain.Tools.Exceptions; + +public class SonarPlayerException : Exception +{ + public SonarPlayerException() { } + + public SonarPlayerException(string message) + : base(message) { } +} From 7b44263f7e91ebd8571f6eaea6d63b31b076206a Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:16:07 +0300 Subject: [PATCH 60/76] feat: add middlewares to catch exceptions --- .../ApplicationExceptionMiddleware.cs | 37 +++++++++++++++++++ .../Middlewares/DefaultExceptionMiddleware.cs | 28 ++++++++++++++ Sonar.Player/Sonar.Player.Api/Program.cs | 4 ++ 3 files changed, 69 insertions(+) create mode 100644 Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs create mode 100644 Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs diff --git a/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs b/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs new file mode 100644 index 0000000..a87266f --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs @@ -0,0 +1,37 @@ +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Tools.Exceptions; +using ILogger = Serilog.ILogger; + +namespace Sonar.Player.Api.Middlewares; + +public class ApplicationExceptionMiddleware +{ + private readonly RequestDelegate _next; + + public ApplicationExceptionMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext, ILogger logger) + { + try + { + await _next(httpContext); + } + catch (SonarPlayerException exception) + { + logger.Error(exception, ""); + + httpContext.Response.StatusCode = exception switch + { + // TODO: catch EnumerationParseException in some form or another + ExternalApiException apiException => apiException.StatusCode, + NotEnoughAccessException => StatusCodes.Status403Forbidden, + _ => StatusCodes.Status500InternalServerError + }; + + await httpContext.Response.WriteAsJsonAsync(new { Message = "Something went wrong" }); + } + } +} diff --git a/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs b/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs new file mode 100644 index 0000000..c364d97 --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs @@ -0,0 +1,28 @@ +using ILogger = Serilog.ILogger; + +namespace Sonar.Player.Api.Middlewares; + +public class DefaultExceptionMiddleware +{ + private readonly RequestDelegate _next; + + public DefaultExceptionMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext, ILogger logger) + { + try + { + await _next(httpContext); + } + catch (Exception exception) + { + logger.Error(exception, ""); + + httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError; + await httpContext.Response.WriteAsJsonAsync(new { Message = "Internal server error" }); + } + } +} diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index ed6e5a4..86fef7d 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Serilog; using Sonar.Player.Api.Bootstraps; +using Sonar.Player.Api.Middlewares; using Sonar.Player.Application.Services; using Sonar.Player.Application.Services.TracksStorage; using Sonar.Player.Application.Tools; @@ -32,6 +33,9 @@ var app = builder.Build(); +app.UseMiddleware(); +app.UseMiddleware(); + if (app.Environment.IsDevelopment()) { app.UseSwaggerWithUI(); From e3737853b5faf41cc83cbb84a2f6b707f514c12a Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:48:50 +0300 Subject: [PATCH 61/76] chore: remove middlewares --- .../ApplicationExceptionMiddleware.cs | 37 ------------------- .../Middlewares/DefaultExceptionMiddleware.cs | 28 -------------- 2 files changed, 65 deletions(-) delete mode 100644 Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs delete mode 100644 Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs diff --git a/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs b/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs deleted file mode 100644 index a87266f..0000000 --- a/Sonar.Player/Sonar.Player.Api/Middlewares/ApplicationExceptionMiddleware.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Sonar.Player.Application.Tools.Exceptions; -using Sonar.Player.Domain.Tools.Exceptions; -using ILogger = Serilog.ILogger; - -namespace Sonar.Player.Api.Middlewares; - -public class ApplicationExceptionMiddleware -{ - private readonly RequestDelegate _next; - - public ApplicationExceptionMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext httpContext, ILogger logger) - { - try - { - await _next(httpContext); - } - catch (SonarPlayerException exception) - { - logger.Error(exception, ""); - - httpContext.Response.StatusCode = exception switch - { - // TODO: catch EnumerationParseException in some form or another - ExternalApiException apiException => apiException.StatusCode, - NotEnoughAccessException => StatusCodes.Status403Forbidden, - _ => StatusCodes.Status500InternalServerError - }; - - await httpContext.Response.WriteAsJsonAsync(new { Message = "Something went wrong" }); - } - } -} diff --git a/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs b/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs deleted file mode 100644 index c364d97..0000000 --- a/Sonar.Player/Sonar.Player.Api/Middlewares/DefaultExceptionMiddleware.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ILogger = Serilog.ILogger; - -namespace Sonar.Player.Api.Middlewares; - -public class DefaultExceptionMiddleware -{ - private readonly RequestDelegate _next; - - public DefaultExceptionMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext httpContext, ILogger logger) - { - try - { - await _next(httpContext); - } - catch (Exception exception) - { - logger.Error(exception, ""); - - httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError; - await httpContext.Response.WriteAsJsonAsync(new { Message = "Internal server error" }); - } - } -} From 6b00f94070e3f6a73f7219330b550512b73e5e19 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:49:35 +0300 Subject: [PATCH 62/76] chore: remove unused generic --- Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs | 4 ++-- .../Tools/Exceptions/EnumerationParseException.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs index 8406caa..9070503 100644 --- a/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs +++ b/Sonar.Player/Sonar.Player.Domain/Enumerations/AudioFormat.cs @@ -8,7 +8,7 @@ public class AudioFormat : Enumeration protected AudioFormat(string name, string format) : base(name, format) { } - protected AudioFormat() : base() {} + protected AudioFormat() {} public static AudioFormat Mp3 => new AudioFormat("Mp3", "mp3"); public static AudioFormat Wav => new AudioFormat("Wav", "wav"); @@ -20,7 +20,7 @@ public static AudioFormat FromFileName(string filename) { ".mp3" => Mp3, ".wav" => Wav, - _ => throw new EnumerationParseException(nameof(AudioFormat), filename) + _ => throw new EnumerationParseException(nameof(AudioFormat), filename) }; } } \ No newline at end of file diff --git a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs index 187da40..f20e64c 100644 --- a/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs +++ b/Sonar.Player/Sonar.Player.Domain/Tools/Exceptions/EnumerationParseException.cs @@ -1,7 +1,7 @@ namespace Sonar.Player.Domain.Tools.Exceptions; -public class EnumerationParseException : SonarPlayerException +public class EnumerationParseException : SonarPlayerException { - public EnumerationParseException(string typeName, T value) + public EnumerationParseException(string typeName, string value) : base($"Can't parse {typeName} from {value}") { } } \ No newline at end of file From 981275e057cbe148735515c1c73dab794b046af0 Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:49:57 +0300 Subject: [PATCH 63/76] feat: add filters --- .../Filters/ExceptionFilter.cs | 34 +++++++++++++++++++ Sonar.Player/Sonar.Player.Api/Program.cs | 7 ++-- 2 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 Sonar.Player/Sonar.Player.Api/Filters/ExceptionFilter.cs diff --git a/Sonar.Player/Sonar.Player.Api/Filters/ExceptionFilter.cs b/Sonar.Player/Sonar.Player.Api/Filters/ExceptionFilter.cs new file mode 100644 index 0000000..be0b62e --- /dev/null +++ b/Sonar.Player/Sonar.Player.Api/Filters/ExceptionFilter.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Sonar.Player.Application.Tools.Exceptions; +using Sonar.Player.Domain.Tools.Exceptions; +using ILogger = Serilog.ILogger; + +namespace Sonar.Player.Api.Filters; + +public class ExceptionFilter : IExceptionFilter +{ + private readonly ILogger _logger; + + public ExceptionFilter(ILogger logger) + { + _logger = logger; + } + + public void OnException(ExceptionContext context) + { + _logger.Error(context.Exception, ""); + + context.Result = new JsonResult(context.Exception.Message) + { + StatusCode = context.Exception switch + { + ExternalApiException apiException => apiException.StatusCode, + NotEnoughAccessException => StatusCodes.Status403Forbidden, + EnumerationParseException => StatusCodes.Status400BadRequest, + _ => StatusCodes.Status500InternalServerError + } + }; + context.ExceptionHandled = true; + } +} diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 86fef7d..c0dee95 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore; using Serilog; using Sonar.Player.Api.Bootstraps; -using Sonar.Player.Api.Middlewares; +using Sonar.Player.Api.Filters; using Sonar.Player.Application.Services; using Sonar.Player.Application.Services.TracksStorage; using Sonar.Player.Application.Tools; @@ -15,7 +15,7 @@ builder.Host.UseSerilog((ctx, lc) => lc.WriteTo.Console()); -builder.Services.AddControllers(); +builder.Services.AddControllers(options => { options.Filters.Add(); }); builder.Services.Configure(opt => opt.LowercaseUrls = true); builder.Services.AddEndpointsApiExplorer(); @@ -33,9 +33,6 @@ var app = builder.Build(); -app.UseMiddleware(); -app.UseMiddleware(); - if (app.Environment.IsDevelopment()) { app.UseSwaggerWithUI(); From 13e34fa9c21d9123bdd27d207dff31079d72512d Mon Sep 17 00:00:00 2001 From: Maksim Polukhin Date: Mon, 30 May 2022 19:51:38 +0300 Subject: [PATCH 64/76] chore: change configure to expression lambda --- Sonar.Player/Sonar.Player.Api/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index c0dee95..89bb6b6 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -15,7 +15,7 @@ builder.Host.UseSerilog((ctx, lc) => lc.WriteTo.Console()); -builder.Services.AddControllers(options => { options.Filters.Add(); }); +builder.Services.AddControllers(options => options.Filters.Add()); builder.Services.Configure(opt => opt.LowercaseUrls = true); builder.Services.AddEndpointsApiExplorer(); From 06eca2fde8a1a63b77d22d6dad9c61d786b3d4a6 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Wed, 1 Jun 2022 15:55:21 +0300 Subject: [PATCH 65/76] chore: update api client --- .../Sonar.Player.ApiClient/ApiClient.cs | 91 +++++++++++++------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs index 62004f3..c968c09 100644 --- a/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs +++ b/Sonar.Player/Sonar.Player.ApiClient/ApiClient.cs @@ -22,21 +22,21 @@ public partial interface IFilesApiClient { /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string token, string name); + System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, FileParameter file); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, FileParameter file, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId); + System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken); /// Success /// A server side error occurred. @@ -95,23 +95,18 @@ public string BaseUrl /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackPOSTAsync(string token, string name) + public virtual System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, FileParameter file) { - return TrackPOSTAsync(token, name, System.Threading.CancellationToken.None); + return TrackPOSTAsync(token, name, file, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackPOSTAsync(string token, string name, FileParameter file, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track?"); - if (name != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("name") + "=").Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); - } - urlBuilder_.Length--; + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track"); var client_ = _httpClient; var disposeClient_ = false; @@ -122,7 +117,28 @@ public virtual async System.Threading.Tasks.Task TrackPOST if (token != null) request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); + var boundary_ = System.Guid.NewGuid().ToString(); + var content_ = new System.Net.Http.MultipartFormDataContent(boundary_); + content_.Headers.Remove("Content-Type"); + content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_); + + if (name == null) + throw new System.ArgumentNullException("name"); + else + { + content_.Add(new System.Net.Http.StringContent(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture)), "Name"); + } + + if (file == null) + throw new System.ArgumentNullException("file"); + else + { + var content_file_ = new System.Net.Http.StreamContent(file.Data); + if (!string.IsNullOrEmpty(file.ContentType)) + content_file_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(file.ContentType); + content_.Add(content_file_, "File", file.FileName ?? "File"); + } + request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); @@ -178,7 +194,7 @@ public virtual async System.Threading.Tasks.Task TrackPOST /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId) + public virtual System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId) { return TrackDELETEAsync(token, trackId, System.Threading.CancellationToken.None); } @@ -186,7 +202,7 @@ public virtual System.Threading.Tasks.Task TrackDELETEAsyn /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task TrackDELETEAsync(string token, System.Guid? trackId, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/files/track?"); @@ -206,7 +222,6 @@ public virtual async System.Threading.Tasks.Task TrackDELE if (token != null) request_.Headers.TryAddWithoutValidation("Token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); PrepareRequest(client_, request_, urlBuilder_); @@ -231,12 +246,7 @@ public virtual async System.Threading.Tasks.Task TrackDELE var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; + return; } else { @@ -1006,15 +1016,11 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu } } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DeleteTrack_Response - { - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UploadTrack_Response { + [Newtonsoft.Json.JsonProperty("trackId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid TrackId { get; set; } } @@ -1036,6 +1042,33 @@ public partial class GetQueue_Response } + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileParameter + { + public FileParameter(System.IO.Stream data) + : this (data, null, null) + { + } + + public FileParameter(System.IO.Stream data, string fileName) + : this (data, fileName, null) + { + } + + public FileParameter(System.IO.Stream data, string fileName, string contentType) + { + Data = data; + FileName = fileName; + ContentType = contentType; + } + + public System.IO.Stream Data { get; private set; } + + public string FileName { get; private set; } + + public string ContentType { get; private set; } + } + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0))")] From ac90afddf9456457e563cc2f23ead889b0be42da Mon Sep 17 00:00:00 2001 From: bibletoon Date: Wed, 1 Jun 2022 15:55:33 +0300 Subject: [PATCH 66/76] chore: update user profile submodule --- Sonar.UserProfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sonar.UserProfile b/Sonar.UserProfile index 76c23a3..b675372 160000 --- a/Sonar.UserProfile +++ b/Sonar.UserProfile @@ -1 +1 @@ -Subproject commit 76c23a332454cd0b1a1553e4ea3a9d634bed0cbf +Subproject commit b675372db766c549bf437268be57af3eab0d0c25 From 9363d480de1f3a60c4f3c6c07c2982b22cda0311 Mon Sep 17 00:00:00 2001 From: DenChika Date: Wed, 1 Jun 2022 19:53:42 +0300 Subject: [PATCH 67/76] Feat: implemented queue methods --- .../Entities/TracksQueue.cs | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index 3164773..e081ef0 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -1,33 +1,49 @@ -namespace Sonar.Player.Domain.Entities; +using Sonar.Player.Domain.Tools.Exceptions; + +namespace Sonar.Player.Domain.Entities; public class TracksQueue { private readonly List _tracks = new List(); + public Track? Current = null; public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); public Track Next() { - throw new NotImplementedException(); + if (Current is null) + throw new SonarPlayerException("Cannot get the next track: queue is empty"); + + var next = Tracks.SkipWhile(x => x.Id != Current.Id).Skip(1).DefaultIfEmpty(null).First(); + Current = next ?? throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); + return Current; } public void Enqueue(Track track) { - throw new NotImplementedException(); + _tracks.Add(track); } public Track Previous() { - throw new NotImplementedException(); + if (Current is null) + throw new SonarPlayerException("Cannot get the last track: queue is empty"); + + var prev = Tracks.TakeWhile(x => x.Id != Current.Id).DefaultIfEmpty(null).Last(); + Current = prev ?? throw new SonarPlayerException("Cannot get the last track: this is the last track in queue"); + return Current; } public void Shuffle() { - throw new NotImplementedException(); + var rand = new Random(); + var newTracks = _tracks.OrderBy(x => rand.Next()).ToList(); + for (var i = 0; i < _tracks.Count; i++) + _tracks[i] = newTracks[i]; } public void Purge() { - throw new NotImplementedException(); + _tracks.Clear(); } } \ No newline at end of file From d14bb80cae9dfbd99dfcac9240dda847e0aab477 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 2 Jun 2022 16:05:41 +0300 Subject: [PATCH 68/76] Fix: paths --- .../Services/TracksStorage/HlsTrackProcessor.cs | 2 +- Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs index 8892ae4..f3cd174 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -26,7 +26,7 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) if (!Directory.Exists(streamFolderPath)) Directory.CreateDirectory(streamFolderPath); - var segmentFilename = $"{track.Id}-stream-%02d.ts"; + var segmentFilename = $"{track.Id}_stream-%02d.ts"; var segmentPath = Path.Combine(streamFolderPath, segmentFilename); var infoFilePath = Path.Combine(streamFolderPath, "streamInfo.m3u8"); diff --git a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs index 180190e..7658459 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/TrackPathBuilder.cs @@ -20,7 +20,7 @@ public string GetTrackStreamInfoPath(Guid trackId) public string GetTrackStreamPartPath(string partName) { - var trackId = partName.Split("-").First(); + var trackId = partName.Split("_").First(); return Path.Combine(GetTrackFolderPath(Guid.Parse(trackId)), "stream", partName); } } \ No newline at end of file From b627a181d2d4c99fa3cd895411c539d2a5624bde Mon Sep 17 00:00:00 2001 From: DenChika Date: Thu, 2 Jun 2022 17:00:48 +0300 Subject: [PATCH 69/76] fix: update queue methods --- .../Entities/TracksQueue.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index e081ef0..c4f6911 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -4,42 +4,49 @@ namespace Sonar.Player.Domain.Entities; public class TracksQueue { - private readonly List _tracks = new List(); + private List _tracks = new List(); - public Track? Current = null; + public int CurrentNumber = 0; public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); public Track Next() { - if (Current is null) + if (Tracks.Count == 0) throw new SonarPlayerException("Cannot get the next track: queue is empty"); - var next = Tracks.SkipWhile(x => x.Id != Current.Id).Skip(1).DefaultIfEmpty(null).First(); - Current = next ?? throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); - return Current; + var next = Tracks.ElementAtOrDefault(CurrentNumber + 1); + if (next is null) + throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); + + CurrentNumber++; + return next; } public void Enqueue(Track track) { _tracks.Add(track); + if (_tracks.Count == 1) + CurrentNumber++; } public Track Previous() { - if (Current is null) - throw new SonarPlayerException("Cannot get the last track: queue is empty"); + if (Tracks.Count == 0) + throw new SonarPlayerException("Cannot get the previous track: queue is empty"); + + var prev = Tracks.ElementAtOrDefault(CurrentNumber - 1); + if (prev is null) + throw new SonarPlayerException("Cannot get the previous track: this is the first track in queue"); - var prev = Tracks.TakeWhile(x => x.Id != Current.Id).DefaultIfEmpty(null).Last(); - Current = prev ?? throw new SonarPlayerException("Cannot get the last track: this is the last track in queue"); - return Current; + CurrentNumber--; + return prev; } public void Shuffle() { var rand = new Random(); var newTracks = _tracks.OrderBy(x => rand.Next()).ToList(); - for (var i = 0; i < _tracks.Count; i++) - _tracks[i] = newTracks[i]; + _tracks = newTracks; } public void Purge() From 21c1008f32116413731199335f99a597fe695af0 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 2 Jun 2022 20:24:20 +0300 Subject: [PATCH 70/76] Fix: audio mapping only --- .../Services/TracksStorage/HlsTrackProcessor.cs | 2 +- .../Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs index f3cd174..c155f7c 100644 --- a/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs +++ b/Sonar.Player/Sonar.Player.Application/Services/TracksStorage/HlsTrackProcessor.cs @@ -32,7 +32,7 @@ public async Task SaveTrack(Guid id, AudioFormat format, Stream content) var arguments = FfmpegArgumentsBuilder.CreateBuilder() .GetSource(trackPath) - .SetBitrate(4800) + .SetBitrate(324) .SetSegmentFilename(segmentPath) .WriteTo(infoFilePath) .Build(); diff --git a/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs index e07e559..24c6ec3 100644 --- a/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs +++ b/Sonar.Player/Sonar.Player.Application/Tools/FfmpegArgumentsBuilder.cs @@ -24,7 +24,7 @@ public IBitrateSelectionStage GetSource(string sourcePath) public ISegmentSelectionStage SetBitrate(int bitrate) { - _builder.Append($" -bitrate {bitrate}"); + _builder.Append($" -b:a {bitrate}k"); return this; } @@ -36,7 +36,7 @@ public IOutputSelectionStage SetSegmentFilename(string segmentName) public IBuildStage WriteTo(string filename) { - _builder.Append($" {filename}"); + _builder.Append($" -map a {filename}"); return this; } From bcecde85c1a908279411c860c3f6346b235a5844 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 2 Jun 2022 23:19:30 +0300 Subject: [PATCH 71/76] Feat: add services --- Sonar.Player/Sonar.Player.Api/Program.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Api/Program.cs b/Sonar.Player/Sonar.Player.Api/Program.cs index 89bb6b6..b3fcb3f 100644 --- a/Sonar.Player/Sonar.Player.Api/Program.cs +++ b/Sonar.Player/Sonar.Player.Api/Program.cs @@ -9,6 +9,7 @@ using Sonar.Player.Data; using Sonar.Player.Fakes.ApiClients; using Sonar.Player.Fakes.Services; +using Sonar.UserProfile.ApiClient; using Sonar.UserTracksManagement.ApiClient; var builder = WebApplication.CreateBuilder(args); @@ -28,8 +29,11 @@ builder.Services.Decorate(); builder.Services.AddSingleton(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +// builder.Services.AddScoped(); +builder.Services.AddScoped(f => new UserTracksApiClient("https://localhost:7055", f.GetRequiredService())); +builder.Services.AddScoped(f => new UserApiClient("https://localhost:7062", f.GetRequiredService())); var app = builder.Build(); From 5dd0ffd73126de7ab502212e8007d3cf3d8e4c6c Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 2 Jun 2022 23:20:20 +0300 Subject: [PATCH 72/76] Feat: update submodules --- Sonar.UserProfile | 2 +- Sonar.UserTracksManagment | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sonar.UserProfile b/Sonar.UserProfile index b675372..31cd617 160000 --- a/Sonar.UserProfile +++ b/Sonar.UserProfile @@ -1 +1 @@ -Subproject commit b675372db766c549bf437268be57af3eab0d0c25 +Subproject commit 31cd61767ca88528a850089442da3fe103c92011 diff --git a/Sonar.UserTracksManagment b/Sonar.UserTracksManagment index cc7c57a..999603f 160000 --- a/Sonar.UserTracksManagment +++ b/Sonar.UserTracksManagment @@ -1 +1 @@ -Subproject commit cc7c57a533b320172aeb430ecf8f1573ecae9ea5 +Subproject commit 999603fa6049886e85928847a0cc79df64f79c99 From 615b600e0e93c6e0b9ac1405e7858ecb30491ac0 Mon Sep 17 00:00:00 2001 From: bibletoon Date: Thu, 2 Jun 2022 23:21:02 +0300 Subject: [PATCH 73/76] Chore: add fake service --- .../ApiClients/FakeUserTracksClient.cs | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs b/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs index addb035..3f64fe4 100644 --- a/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs +++ b/Sonar.Player/Sonar.Player.Fakes/ApiClients/FakeUserTracksClient.cs @@ -4,43 +4,71 @@ namespace Sonar.Player.Fakes.ApiClients; public class FakeUserTracksClient : IUserTracksApiClient { + private readonly List _tracks = new List(); + public Task TracksPOSTAsync(string token, string name) { - return Task.FromResult(Guid.NewGuid()); + return TracksPOSTAsync(token, name, CancellationToken.None); } public Task TracksPOSTAsync(string token, string name, CancellationToken cancellationToken) { - return Task.FromResult(Guid.NewGuid()); + var tdto = new TrackDto() + { + Name = name, + Id = Guid.NewGuid() + }; + _tracks.Add(tdto); + return Task.FromResult(tdto.Id); } public Task TracksGETAsync(string token, Guid? trackId) { - throw new NotImplementedException(); + return TracksGETAsync(token, trackId); } public Task TracksGETAsync(string token, Guid? trackId, CancellationToken cancellationToken) + { + return Task.FromResult(_tracks.First(t => t.Id == trackId)); + } + + public Task TracksDELETEAsync(string token, Guid? trackId) { throw new NotImplementedException(); } - public Task> AllAsync(string token) + public Task TracksDELETEAsync(string token, Guid? trackId, CancellationToken cancellationToken) { throw new NotImplementedException(); } - public Task> AllAsync(string token, CancellationToken cancellationToken) + public Task> All2Async(string token) { throw new NotImplementedException(); } - public Task IsEnoughAccessAsync(string token, Guid? trackId) + public Task> All2Async(string token, CancellationToken cancellationToken) { throw new NotImplementedException(); } + public Task> AllAsync(string token) + { + return AllAsync(token, CancellationToken.None); + } + + public Task> AllAsync(string token, CancellationToken cancellationToken) + { + return Task.FromResult>(_tracks.ToList()); + } + + public Task IsEnoughAccessAsync(string token, Guid? trackId) + { + return IsEnoughAccessAsync(token, trackId, CancellationToken.None); + } + public Task IsEnoughAccessAsync(string token, Guid? trackId, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return Task.FromResult(true); } } \ No newline at end of file From c51521f1cdcb77ad288a4aa5e0cb0e5a9d67662c Mon Sep 17 00:00:00 2001 From: DenChika Date: Fri, 3 Jun 2022 00:09:48 +0300 Subject: [PATCH 74/76] fix: update queue methods --- .../Entities/TracksQueue.cs | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index c4f6911..8845dbe 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -6,47 +6,40 @@ public class TracksQueue { private List _tracks = new List(); - public int CurrentNumber = 0; + public Track? Current = null; public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); public Track Next() { - if (Tracks.Count == 0) + if (Current is null) throw new SonarPlayerException("Cannot get the next track: queue is empty"); - - var next = Tracks.ElementAtOrDefault(CurrentNumber + 1); - if (next is null) - throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); - CurrentNumber++; - return next; + var next = Tracks.SkipWhile(x => x.Id != Current.Id).Skip(1).DefaultIfEmpty(null).First(); + Current = next ?? throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); + return Current; } public void Enqueue(Track track) { _tracks.Add(track); - if (_tracks.Count == 1) - CurrentNumber++; } public Track Previous() { - if (Tracks.Count == 0) - throw new SonarPlayerException("Cannot get the previous track: queue is empty"); - - var prev = Tracks.ElementAtOrDefault(CurrentNumber - 1); - if (prev is null) - throw new SonarPlayerException("Cannot get the previous track: this is the first track in queue"); - - CurrentNumber--; - return prev; + if (Current is null) + throw new SonarPlayerException("Cannot get the last track: queue is empty"); + + var prev = Tracks.TakeWhile(x => x.Id != Current.Id).DefaultIfEmpty(null).Last(); + Current = prev ?? throw new SonarPlayerException("Cannot get the last track: this is the first track in queue"); + return Current; } public void Shuffle() { var rand = new Random(); var newTracks = _tracks.OrderBy(x => rand.Next()).ToList(); - _tracks = newTracks; + for (var i = 0; i < _tracks.Count; i++) + _tracks[i] = newTracks[i]; } public void Purge() From 3eff5cfaf01b030508b23f1bad03204ebe6a3f6b Mon Sep 17 00:00:00 2001 From: DenChika Date: Fri, 3 Jun 2022 00:11:29 +0300 Subject: [PATCH 75/76] fix: update queue methods --- .../Entities/TracksQueue.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index 8845dbe..c4f6911 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -6,40 +6,47 @@ public class TracksQueue { private List _tracks = new List(); - public Track? Current = null; + public int CurrentNumber = 0; public IReadOnlyCollection Tracks => _tracks.AsReadOnly(); public Track Next() { - if (Current is null) + if (Tracks.Count == 0) throw new SonarPlayerException("Cannot get the next track: queue is empty"); + + var next = Tracks.ElementAtOrDefault(CurrentNumber + 1); + if (next is null) + throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); - var next = Tracks.SkipWhile(x => x.Id != Current.Id).Skip(1).DefaultIfEmpty(null).First(); - Current = next ?? throw new SonarPlayerException("Cannot get the next track: this is the last track in queue"); - return Current; + CurrentNumber++; + return next; } public void Enqueue(Track track) { _tracks.Add(track); + if (_tracks.Count == 1) + CurrentNumber++; } public Track Previous() { - if (Current is null) - throw new SonarPlayerException("Cannot get the last track: queue is empty"); - - var prev = Tracks.TakeWhile(x => x.Id != Current.Id).DefaultIfEmpty(null).Last(); - Current = prev ?? throw new SonarPlayerException("Cannot get the last track: this is the first track in queue"); - return Current; + if (Tracks.Count == 0) + throw new SonarPlayerException("Cannot get the previous track: queue is empty"); + + var prev = Tracks.ElementAtOrDefault(CurrentNumber - 1); + if (prev is null) + throw new SonarPlayerException("Cannot get the previous track: this is the first track in queue"); + + CurrentNumber--; + return prev; } public void Shuffle() { var rand = new Random(); var newTracks = _tracks.OrderBy(x => rand.Next()).ToList(); - for (var i = 0; i < _tracks.Count; i++) - _tracks[i] = newTracks[i]; + _tracks = newTracks; } public void Purge() From b58924ced47d2e46f50a85719916e96cea1b2003 Mon Sep 17 00:00:00 2001 From: DenChika Date: Fri, 3 Jun 2022 00:20:46 +0300 Subject: [PATCH 76/76] fix: update enqueue method --- Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs index c4f6911..e5481e0 100644 --- a/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs +++ b/Sonar.Player/Sonar.Player.Domain/Entities/TracksQueue.cs @@ -25,8 +25,6 @@ public Track Next() public void Enqueue(Track track) { _tracks.Add(track); - if (_tracks.Count == 1) - CurrentNumber++; } public Track Previous()