-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added base classes, methods and etc.
- Loading branch information
Yucked
committed
Jun 17, 2019
1 parent
6448b14
commit d5edc28
Showing
18 changed files
with
435 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Victoria.Commons.Entities; | ||
|
||
namespace Victoria.Commons | ||
{ | ||
public abstract class BaseClient : IAsyncDisposable | ||
{ | ||
internal readonly WSClient _ws; | ||
|
||
public BaseClient(BaseConfiguration config) | ||
{ | ||
_ws = new WSClient($"ws://{config.Hostname}:{config.Port}", default); | ||
_ws.OnMessageReceived += OnMessageReceivedAsync; | ||
_ws.OnConnectionClosed += OnConnectionClosedAsync; | ||
} | ||
|
||
public async Task InitializeAsync() | ||
{ | ||
await _ws.ConnectAsync().ConfigureAwait(false); | ||
} | ||
|
||
public Task ConnectToVoiceChannelAsync() | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
public Task DisconnectFromVoiceChannelAsync() | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
public Task MoveVoiceChannelAsync() | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
private Task OnMessageReceivedAsync(ReadOnlyMemory<byte> bytes) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
private Task OnConnectionClosedAsync(object arg) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
await _ws.DisposeAsync().ConfigureAwait(false); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using Victoria.Commons.Entities; | ||
using Victoria.Commons.Entities.Enums; | ||
using Victoria.Commons.Queue; | ||
|
||
namespace Victoria.Commons | ||
{ | ||
/// <summary> | ||
/// | ||
/// </summary> | ||
public abstract class BasePlayer : IAsyncDisposable | ||
{ | ||
/// <summary> | ||
/// | ||
/// </summary> | ||
public int CurrentVolume { get; internal set; } | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public PlayerState PlayerState { get; internal set; } | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public DefaultQueue<IQueueObject> Queue { get; private set; } | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="track"></param> | ||
/// <returns></returns> | ||
public abstract Task PlayAsync(BaseTrack track); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="track"></param> | ||
/// <param name="startTime"></param> | ||
/// <param name="endTime"></param> | ||
/// <returns></returns> | ||
public abstract Task PlayAsync(BaseTrack track, TimeSpan startTime, TimeSpan endTime); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="tracks"></param> | ||
/// <returns></returns> | ||
public abstract Task PlayAsync(params BaseTrack[] tracks); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract Task StopAsync(); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract Task PauseAsync(); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract Task ResumeAsync(); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract Task<BaseTrack> SkipAsync(); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="volume"></param> | ||
/// <returns></returns> | ||
public abstract Task ChangeVolumeAsync(uint volume); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract Task ChangeEqualizerAsync(); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <returns></returns> | ||
public async ValueTask DisposeAsync() | ||
{ | ||
PlayerState = PlayerState.DISPOSED; | ||
await StopAsync().ConfigureAwait(false); | ||
// DESTROY PLAYER | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Victoria.Commons.Entities | ||
{ | ||
public sealed class BaseConfiguration | ||
{ | ||
public string Hostname { get; set; } | ||
public ushort Port { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Victoria.Commons.Queue; | ||
|
||
namespace Victoria.Commons.Entities | ||
{ | ||
public class BaseTrack : IQueueObject | ||
{ | ||
public string Hash { get; } | ||
public string Id { get; } | ||
public string Url { get; } | ||
public string Title { get; } | ||
public long Duration { get; } | ||
public long Position { get; } | ||
public bool CanStream { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Victoria.Commons.Entities.Enums | ||
{ | ||
public enum PlayerState | ||
{ | ||
CONNECTED, | ||
CONNECTING, | ||
PLAYING, | ||
STOPPED, | ||
PAUSED, | ||
DISCONNECTED, | ||
DISPOSED | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Victoria.Commons.Entities | ||
{ | ||
public class IqueueObject | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using Victoria.Commons.Entities.Enums; | ||
|
||
namespace Victoria.Commons | ||
{ | ||
public static class Extensions | ||
{ | ||
public static void EnsureState(this PlayerState playerState, params PlayerState[] states) | ||
{ | ||
foreach (var state in states) | ||
if (playerState == state) | ||
throw new Exception($"Player can't be used since player state is currently set to {state}."); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Victoria.Commons.Queue | ||
{ | ||
public sealed class DefaultQueue<T> where T : IQueueObject | ||
{ | ||
private readonly object _lock; | ||
private readonly LinkedList<T> _list; | ||
|
||
public DefaultQueue() | ||
{ | ||
_lock = new object(); | ||
_list = new LinkedList<T>(); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Victoria.Commons.Queue | ||
{ | ||
public interface IQueueObject | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,137 @@ | ||
using System; | ||
using System.Net.WebSockets; | ||
using System.Threading.Tasks; | ||
using System.Threading; | ||
using System.Text.Json.Serialization; | ||
using System.Collections.Generic; | ||
|
||
namespace Victoria.Commons | ||
{ | ||
public sealed class WSClient | ||
public sealed class WSClient : IAsyncDisposable | ||
{ | ||
private ClientWebSocket socket; | ||
private CancellationTokenSource | ||
connectionToken, | ||
normalToken, | ||
mainToken; | ||
private readonly string hostAddress; | ||
|
||
public event Func<object, Task> OnConnectionClosed; | ||
public event Func<ReadOnlyMemory<byte>, Task> OnMessageReceived; | ||
|
||
public WSClient(string url, IReadOnlyDictionary<string, string> headers) | ||
{ | ||
hostAddress = url; | ||
connectionToken = new CancellationTokenSource(); | ||
normalToken = new CancellationTokenSource(TimeSpan.FromSeconds(30)); | ||
mainToken = CancellationTokenSource.CreateLinkedTokenSource(connectionToken.Token, normalToken.Token); | ||
socket = new ClientWebSocket(); | ||
|
||
if (headers.Count != 0) | ||
foreach (var (key, value) in headers) | ||
socket.Options.SetRequestHeader(key, value); | ||
} | ||
|
||
public async Task ConnectAsync() | ||
{ | ||
try | ||
{ | ||
await socket.ConnectAsync(new Uri(hostAddress), connectionToken.Token) | ||
.ContinueWith(VerifyConnectionAsync) | ||
.ConfigureAwait(false); | ||
} | ||
catch | ||
{ | ||
// TODO: Ignore exceptions or log them? | ||
} | ||
} | ||
|
||
public async Task DisconnectAsync() | ||
{ | ||
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Requested.", normalToken.Token) | ||
.ConfigureAwait(false); | ||
|
||
// TODO: Log connection closed. | ||
} | ||
|
||
public async Task SendAsync<T>(T value) | ||
{ | ||
var bytes = JsonSerializer.ToUtf8Bytes(value); | ||
await socket.SendAsync(bytes, WebSocketMessageType.Text, true, normalToken.Token) | ||
.ConfigureAwait(false); | ||
|
||
// TODO: Log bytes sent. | ||
} | ||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
mainToken.Cancel(false); | ||
await DisconnectAsync() | ||
.ConfigureAwait(false); | ||
socket.Dispose(); | ||
} | ||
|
||
private async Task VerifyConnectionAsync(Task task) | ||
{ | ||
if (task.IsCanceled || task.IsFaulted || task.Exception != null) | ||
{ | ||
var error = | ||
task.IsCanceled ? | ||
"WS connection task was cancelled!" : | ||
task.IsFaulted ? | ||
"Task faulted when trying to connect to WS server." : | ||
task.Exception.Message; | ||
|
||
await RetryConnectionAsync() | ||
.ConfigureAwait(false); | ||
// TODO: Log error | ||
} | ||
else | ||
{ | ||
await ReceiveAsync() | ||
.ConfigureAwait(false); | ||
} | ||
|
||
async Task RetryConnectionAsync() | ||
{ | ||
while (socket.State != WebSocketState.Open) | ||
{ | ||
await Task.Delay(TimeSpan.FromSeconds(15)) | ||
.ConfigureAwait(false); | ||
|
||
await ConnectAsync() | ||
.ConfigureAwait(false); | ||
} | ||
} | ||
} | ||
|
||
private async Task ReceiveAsync() | ||
{ | ||
while (!connectionToken.IsCancellationRequested && socket.State is WebSocketState.Open) | ||
{ | ||
try | ||
{ | ||
var memory = new Memory<byte>(); | ||
var result = await socket.ReceiveAsync(memory, normalToken.Token) | ||
.ConfigureAwait(false); | ||
switch (result.MessageType) | ||
{ | ||
case WebSocketMessageType.Close: | ||
// TODO: Raise OnClosed event. | ||
break; | ||
|
||
case WebSocketMessageType.Text: | ||
await OnMessageReceived.Invoke(memory) | ||
.ConfigureAwait(false); | ||
break; | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
// TODO: Log exceptions. | ||
// TODO: Raise OnClosed event. | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.