diff --git a/README.md b/README.md index c2992e4..009ed47 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # C# TeamSpeak3Query API [![Travis Build Status](https://travis-ci.org/nikeee/TeamSpeak3QueryAPI.svg?branch=master)](https://travis-ci.org/nikeee/TeamSpeak3QueryAPI) ![NuGet Downloads](https://img.shields.io/nuget/dt/TeamSpeak3QueryApi.svg) -An API wrapper for the TeamSpeak 3 Query API written in C#. Still work in progress. +An API wrapper for the TeamSpeak 3 Query API written in C#. **Still work in progress**. Key features of this library: - Built entirely with the .NET TAP pattern for perfect async/await usage opportunities - Robust library architecture - Query responses are fully mapped to .NET objects, including the naming style - Usable via Middleware/Rich Client +- SSH and Telnet protocol will be supported ## Contents 1. [Documentation](#documentation) @@ -26,9 +27,10 @@ The TeamSpeak 3 Query API is documented [here](http://media.teamspeak.com/ts3_li This library has an online documentation which was created using [sharpDox](http://sharpdox.de). You can find the documentation on the [GitHub Page of this repository](https://nikeee.github.io/TeamSpeak3QueryAPI). ## Compatibility -This library requires .NET Standard `1.3`. You can look at [this table](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support) to see whether your platform is supported. If you find something that is missing (espacially in the `TeamSpeakClient` class), just submit a PR or an issue! +This library requires .NET Core `3.0`. You can look at [this table](https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support) to see whether your platform is supported. If you find something that is missing (espacially in the `TeamSpeakClient` class), just submit a PR or an issue! ### NuGet +*This is currently not possible.* ```Shell Install-Package TeamSpeak3QueryApi # or @@ -39,10 +41,17 @@ dotnet add package TeamSpeak3QueryApi Using the rich client, you can connect to a TeamSpeak Query server like this: ### Connect and Login -```C# +```C# Telnet query var rc = new TeamSpeakClient(host, port); // Create rich client instance -await rc.Connect(); // connect to the server -await rc.Login(user, password); // login to do some stuff that requires permission +await rc.ConnectAsync(); // connect to the server +await rc.LoginAsync(user, password); // login to do some stuff that requires permission +await rc.UseServer(1); // Use the server with id '1' +var me = await rc.WhoAmI(); // Get information about yourself! +``` + +```C# SSH query +var rc = new TeamSpeakClient(host, 10022, Protocol.SSH); // Create rich client instance +await rc.Connect(user, password); // connect to the server with login data await rc.UseServer(1); // Use the server with id '1' var me = await rc.WhoAmI(); // Get information about yourself! ``` @@ -70,7 +79,7 @@ rc.Subscribe(data => { Getting all clients and moving them to a specific channel is as simple as: ```C# -var currentClients = await rc.GetClients(); +var currentClients = await rc.GetClientsAsync(); await rc.MoveClient(currentClients, 30); // Where 30 is the channel id ``` ...and kick someone whose name is "Foobar". @@ -78,7 +87,7 @@ await rc.MoveClient(currentClients, 30); // Where 30 is the channel id ```C# var fooBar = currentClients.SingleOrDefault(c => c.NickName == "Foobar"); // Using linq to find our dude if(fooBar != null) // Make sure we pass a valid reference - await rc.KickClient(fooBar, 30); + await rc.KickClientAsync(fooBar, 30); ``` ### Exceptions @@ -100,16 +109,16 @@ If you want to work more loose-typed, you can do this. This is possible using th ```C# var qc = new QueryClient(host, port); -await qc.Connect(); +await qc.ConnectAsync(); -await qc.Send("login", new Parameter("client_login_name", userName), new Parameter("client_login_password", password)); +await qc.SendAsync("login", new Parameter("client_login_name", userName), new Parameter("client_login_password", password)); -await qc.Send("use", new Parameter("sid", "1")); +await qc.SendAsync("use", new Parameter("sid", "1")); -var me = await qc.Send("whoami"); +var me = await qc.SendAsync("whoami"); -await qc.Send("servernotifyregister", new Parameter("event", "server")); -await qc.Send("servernotifyregister", new Parameter("event", "channel"), new Parameter("id", channelId)); +await qc.SendAsync("servernotifyregister", new Parameter("event", "server")); +await qc.SendAsync("servernotifyregister", new Parameter("event", "channel"), new Parameter("id", channelId)); // and so on. ``` diff --git a/src/TeamSpeak3QueryApi.Demo/Program.cs b/src/TeamSpeak3QueryApi.Demo/Program.cs index 6520838..0399ec8 100644 --- a/src/TeamSpeak3QueryApi.Demo/Program.cs +++ b/src/TeamSpeak3QueryApi.Demo/Program.cs @@ -4,8 +4,8 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using TeamSpeak3QueryApi.Net.Specialized; -using TeamSpeak3QueryApi.Net.Specialized.Notifications; +using TeamSpeak3QueryApi.Net.Query.Enums; +using TeamSpeak3QueryApi.Net.Query.Notifications; namespace TeamSpeak3QueryApi.Net.Demo { @@ -19,29 +19,34 @@ static async Task Main(string[] args) var user = loginData[1].Trim(); var password = loginData[2].Trim(); - var rc = new TeamSpeakClient(host); - - await rc.Connect(); + // Ssh connection + //var rc = new TeamSpeakClient(host, 10022, Protocol.SSH); + //rc.Connect(user, password); - await rc.Login(user, password); - await rc.UseServer(1); + // Telnet connection + var rc = new TeamSpeakClient(host); + await rc.ConnectAsync(); + await rc.LoginAsync(user, password); - await rc.WhoAmI(); + await rc.LoginAsync(user, password); + await rc.UseServerAsync(1); - await rc.RegisterServerNotification(); - await rc.RegisterChannelNotification(30); + await rc.WhoAmIAsync(); - var serverGroups = await rc.GetServerGroups(); - var firstNormalGroup = serverGroups?.FirstOrDefault(s => s.ServerGroupType == ServerGroupType.NormalGroup); - var groupClients = await rc.GetServerGroupClientList(firstNormalGroup.Id); + await rc.RegisterServerNotificationAsync(); + await rc.RegisterAllChannelNotificationAsync(); + + var serverGroups = await rc.GetServerGroupsAsync(); + var firstNormalGroup = serverGroups?.FirstOrDefault(s => s.ServerGroupType == ServerGroupType.NormalGroup && s.Id != 46); // Id 46 is default Servergroup - var currentClients = await rc.GetClients(); + var groupClients = await rc.GetServerGroupClientListAsync(firstNormalGroup.Id); + var currentClients = await rc.GetClientsAsync(); var fullClients = currentClients.Where(c => c.Type == ClientType.FullClient).ToList(); - await rc.KickClient(fullClients, KickOrigin.Channel); + await rc.KickClientAsync(fullClients, KickOrigin.Channel, "You're kicked from channel"); - // await rc.MoveClient(1, 1); - // await rc.KickClient(1, KickTarget.Server); + // await rc.MoveClientAsync(1, 1); + // await rc.KickClientAsync(1, KickTarget.Server); rc.Subscribe(data => data.ForEach(c => Debug.WriteLine($"Client {c.NickName} joined."))); rc.Subscribe(data => data.ForEach(c => Debug.WriteLine($"Client with id {c.Id} left (kicked/banned/left)."))); diff --git a/src/TeamSpeak3QueryApi.Demo/TeamSpeak3QueryApi.Demo.csproj b/src/TeamSpeak3QueryApi.Demo/TeamSpeak3QueryApi.Demo.csproj index 10ece9a..8566bf3 100644 --- a/src/TeamSpeak3QueryApi.Demo/TeamSpeak3QueryApi.Demo.csproj +++ b/src/TeamSpeak3QueryApi.Demo/TeamSpeak3QueryApi.Demo.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp1.1 + netcoreapp3.1 diff --git a/src/TeamSpeak3QueryApi/Specialized/DataProxy.cs b/src/TeamSpeak3QueryApi/DataProxy.cs similarity index 95% rename from src/TeamSpeak3QueryApi/Specialized/DataProxy.cs rename to src/TeamSpeak3QueryApi/DataProxy.cs index 847827a..926189e 100644 --- a/src/TeamSpeak3QueryApi/Specialized/DataProxy.cs +++ b/src/TeamSpeak3QueryApi/DataProxy.cs @@ -4,8 +4,12 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using TeamSpeak3QueryApi.Net.Enums; +using TeamSpeak3QueryApi.Net.Interfaces; +using TeamSpeak3QueryApi.Net.Query; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net { internal static class DataProxy { diff --git a/src/TeamSpeak3QueryApi/Specialized/NotificationEventTarget.cs b/src/TeamSpeak3QueryApi/Enums/NotificationEventTarget.cs similarity index 77% rename from src/TeamSpeak3QueryApi/Specialized/NotificationEventTarget.cs rename to src/TeamSpeak3QueryApi/Enums/NotificationEventTarget.cs index 68b6cba..c730746 100644 --- a/src/TeamSpeak3QueryApi/Specialized/NotificationEventTarget.cs +++ b/src/TeamSpeak3QueryApi/Enums/NotificationEventTarget.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Enums { internal enum NotificationEventTarget { diff --git a/src/TeamSpeak3QueryApi/Specialized/NotificationType.cs b/src/TeamSpeak3QueryApi/Enums/NotificationType.cs similarity index 92% rename from src/TeamSpeak3QueryApi/Specialized/NotificationType.cs rename to src/TeamSpeak3QueryApi/Enums/NotificationType.cs index ae4539c..d6f6de6 100644 --- a/src/TeamSpeak3QueryApi/Specialized/NotificationType.cs +++ b/src/TeamSpeak3QueryApi/Enums/NotificationType.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Enums { ///http://redeemer.biz/medien/artikel/ts3-query-notify/ public enum NotificationType diff --git a/src/TeamSpeak3QueryApi/Enums/Protocol.cs b/src/TeamSpeak3QueryApi/Enums/Protocol.cs new file mode 100644 index 0000000..8177580 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Enums/Protocol.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TeamSpeak3QueryApi.Net.Enums +{ + public enum Protocol + { + Telnet = 0, + SSH = 1 + } +} diff --git a/src/TeamSpeak3QueryApi/Specialized/EnumExtensions.cs b/src/TeamSpeak3QueryApi/Extensions/EnumExtensions.cs similarity index 92% rename from src/TeamSpeak3QueryApi/Specialized/EnumExtensions.cs rename to src/TeamSpeak3QueryApi/Extensions/EnumExtensions.cs index bbae776..10de798 100644 --- a/src/TeamSpeak3QueryApi/Specialized/EnumExtensions.cs +++ b/src/TeamSpeak3QueryApi/Extensions/EnumExtensions.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Collections.Generic; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Extensions { internal static class EnumExtensions { diff --git a/src/TeamSpeak3QueryApi/ListExtensions.cs b/src/TeamSpeak3QueryApi/Extensions/ListExtensions.cs similarity index 84% rename from src/TeamSpeak3QueryApi/ListExtensions.cs rename to src/TeamSpeak3QueryApi/Extensions/ListExtensions.cs index a247d6e..0094c3b 100644 --- a/src/TeamSpeak3QueryApi/ListExtensions.cs +++ b/src/TeamSpeak3QueryApi/Extensions/ListExtensions.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Extensions { internal static class ListExtensions { diff --git a/src/TeamSpeak3QueryApi/StringExtensions.cs b/src/TeamSpeak3QueryApi/Extensions/StringExtensions.cs similarity index 97% rename from src/TeamSpeak3QueryApi/StringExtensions.cs rename to src/TeamSpeak3QueryApi/Extensions/StringExtensions.cs index a11db9c..6280f91 100644 --- a/src/TeamSpeak3QueryApi/StringExtensions.cs +++ b/src/TeamSpeak3QueryApi/Extensions/StringExtensions.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Extensions { internal static class StringExtensions { diff --git a/src/TeamSpeak3QueryApi/TaskExtensions.cs b/src/TeamSpeak3QueryApi/Extensions/TaskExtensions.cs similarity index 95% rename from src/TeamSpeak3QueryApi/TaskExtensions.cs rename to src/TeamSpeak3QueryApi/Extensions/TaskExtensions.cs index efb4544..347723e 100644 --- a/src/TeamSpeak3QueryApi/TaskExtensions.cs +++ b/src/TeamSpeak3QueryApi/Extensions/TaskExtensions.cs @@ -1,7 +1,7 @@ using System.Threading; using System.Threading.Tasks; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Extensions { internal static class TaskExtensions { diff --git a/src/TeamSpeak3QueryApi/FileTransferClient.cs b/src/TeamSpeak3QueryApi/FileTransfer/FileTransferClient.cs similarity index 82% rename from src/TeamSpeak3QueryApi/FileTransferClient.cs rename to src/TeamSpeak3QueryApi/FileTransfer/FileTransferClient.cs index 18fa8b5..f9569c2 100644 --- a/src/TeamSpeak3QueryApi/FileTransferClient.cs +++ b/src/TeamSpeak3QueryApi/FileTransfer/FileTransferClient.cs @@ -3,7 +3,7 @@ using System.Text; using System.Threading.Tasks; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.FileTransfer { internal class FileTransferClient { @@ -20,43 +20,43 @@ public int GetFileTransferId() return _currentFileTransferId++; } - public async Task SendFile(byte[] data, int port, string key) + public async Task SendFileAsync(byte[] data, int port, string key) { using var client = new TcpClient(); await client.ConnectAsync(_host, port).ConfigureAwait(false); using var ns = client.GetStream(); - // Send key + // SendAsync key var keyBytes = Encoding.ASCII.GetBytes(key); await ns.WriteAsync(keyBytes, 0, keyBytes.Length).ConfigureAwait(false); await ns.FlushAsync().ConfigureAwait(false); - // Send data + // SendAsync data await ns.WriteAsync(data, 0, data.Length).ConfigureAwait(false); } - public async Task SendFile(Stream dataStream, int port, string key) + public async Task SendFileAsync(Stream dataStream, int port, string key) { using var client = new TcpClient(); await client.ConnectAsync(_host, port).ConfigureAwait(false); using var ns = client.GetStream(); - // Send key + // SendAsync key var keyBytes = Encoding.ASCII.GetBytes(key); await ns.WriteAsync(keyBytes, 0, keyBytes.Length).ConfigureAwait(false); await ns.FlushAsync().ConfigureAwait(false); - // Send data + // SendAsync data await dataStream.CopyToAsync(ns).ConfigureAwait(false); } - public async Task ReceiveFile(int size, int port, string key) + public async Task ReceiveFileAsync(int size, int port, string key) { using var client = new TcpClient(); await client.ConnectAsync(_host, port).ConfigureAwait(false); using var ns = client.GetStream(); - // Send key + // SendAsync key var keyBytes = Encoding.ASCII.GetBytes(key); await ns.WriteAsync(keyBytes, 0, keyBytes.Length).ConfigureAwait(false); await ns.FlushAsync().ConfigureAwait(false); diff --git a/src/TeamSpeak3QueryApi/FileTransferException.cs b/src/TeamSpeak3QueryApi/FileTransfer/FileTransferException.cs similarity index 96% rename from src/TeamSpeak3QueryApi/FileTransferException.cs rename to src/TeamSpeak3QueryApi/FileTransfer/FileTransferException.cs index 21ce6e4..00c48b0 100644 --- a/src/TeamSpeak3QueryApi/FileTransferException.cs +++ b/src/TeamSpeak3QueryApi/FileTransfer/FileTransferException.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.FileTransfer { /// Represents errors that occur during file transfers. [Serializable] diff --git a/src/TeamSpeak3QueryApi/Specialized/ITeamSpeakSerializable.cs b/src/TeamSpeak3QueryApi/Interfaces/ITeamSpeakSerializable.cs similarity index 68% rename from src/TeamSpeak3QueryApi/Specialized/ITeamSpeakSerializable.cs rename to src/TeamSpeak3QueryApi/Interfaces/ITeamSpeakSerializable.cs index 2042c29..614e7c6 100644 --- a/src/TeamSpeak3QueryApi/Specialized/ITeamSpeakSerializable.cs +++ b/src/TeamSpeak3QueryApi/Interfaces/ITeamSpeakSerializable.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Interfaces { interface ITeamSpeakSerializable { diff --git a/src/TeamSpeak3QueryApi/Specialized/ITypeCaster.cs b/src/TeamSpeak3QueryApi/Interfaces/ITypeCaster.cs similarity index 97% rename from src/TeamSpeak3QueryApi/Specialized/ITypeCaster.cs rename to src/TeamSpeak3QueryApi/Interfaces/ITypeCaster.cs index 789acdb..4c6386d 100644 --- a/src/TeamSpeak3QueryApi/Specialized/ITypeCaster.cs +++ b/src/TeamSpeak3QueryApi/Interfaces/ITypeCaster.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using TeamSpeak3QueryApi.Net.Extensions; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Interfaces { interface ITypeCaster { diff --git a/src/TeamSpeak3QueryApi/Specialized/ClientType.cs b/src/TeamSpeak3QueryApi/Query/Enums/ClientType.cs similarity index 65% rename from src/TeamSpeak3QueryApi/Specialized/ClientType.cs rename to src/TeamSpeak3QueryApi/Query/Enums/ClientType.cs index f685ac2..aef817d 100644 --- a/src/TeamSpeak3QueryApi/Specialized/ClientType.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/ClientType.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum ClientType { diff --git a/src/TeamSpeak3QueryApi/Specialized/GetChannelOptions.cs b/src/TeamSpeak3QueryApi/Query/Enums/GetChannelOptions.cs similarity index 81% rename from src/TeamSpeak3QueryApi/Specialized/GetChannelOptions.cs rename to src/TeamSpeak3QueryApi/Query/Enums/GetChannelOptions.cs index 6c55f8e..169a5be 100644 --- a/src/TeamSpeak3QueryApi/Specialized/GetChannelOptions.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/GetChannelOptions.cs @@ -1,6 +1,6 @@ using System; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { [Flags] public enum GetChannelOptions diff --git a/src/TeamSpeak3QueryApi/Specialized/GetClientOptions.cs b/src/TeamSpeak3QueryApi/Query/Enums/GetClientOptions.cs similarity index 85% rename from src/TeamSpeak3QueryApi/Specialized/GetClientOptions.cs rename to src/TeamSpeak3QueryApi/Query/Enums/GetClientOptions.cs index 90ae501..738b323 100644 --- a/src/TeamSpeak3QueryApi/Specialized/GetClientOptions.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/GetClientOptions.cs @@ -1,6 +1,6 @@ using System; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { [Flags] public enum GetClientOptions diff --git a/src/TeamSpeak3QueryApi/Specialized/GetServerOptions.cs b/src/TeamSpeak3QueryApi/Query/Enums/GetServerOptions.cs similarity index 79% rename from src/TeamSpeak3QueryApi/Specialized/GetServerOptions.cs rename to src/TeamSpeak3QueryApi/Query/Enums/GetServerOptions.cs index 72ff8b0..6f320b7 100644 --- a/src/TeamSpeak3QueryApi/Specialized/GetServerOptions.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/GetServerOptions.cs @@ -1,6 +1,6 @@ using System; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { [Flags] public enum GetServerOptions diff --git a/src/TeamSpeak3QueryApi/Specialized/KickOrigin.cs b/src/TeamSpeak3QueryApi/Query/Enums/KickOrigin.cs similarity index 64% rename from src/TeamSpeak3QueryApi/Specialized/KickOrigin.cs rename to src/TeamSpeak3QueryApi/Query/Enums/KickOrigin.cs index 5779d00..95c5ac9 100644 --- a/src/TeamSpeak3QueryApi/Specialized/KickOrigin.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/KickOrigin.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum KickOrigin { diff --git a/src/TeamSpeak3QueryApi/ManualEnums.cs b/src/TeamSpeak3QueryApi/Query/Enums/ManualEnums.cs similarity index 98% rename from src/TeamSpeak3QueryApi/ManualEnums.cs rename to src/TeamSpeak3QueryApi/Query/Enums/ManualEnums.cs index 6d92b9a..b3b54ae 100644 --- a/src/TeamSpeak3QueryApi/ManualEnums.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/ManualEnums.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum HostMessageMode { diff --git a/src/TeamSpeak3QueryApi/Specialized/MessageTarget.cs b/src/TeamSpeak3QueryApi/Query/Enums/MessageTarget.cs similarity index 70% rename from src/TeamSpeak3QueryApi/Specialized/MessageTarget.cs rename to src/TeamSpeak3QueryApi/Query/Enums/MessageTarget.cs index cd8983c..a584b65 100644 --- a/src/TeamSpeak3QueryApi/Specialized/MessageTarget.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/MessageTarget.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum MessageTarget { diff --git a/src/TeamSpeak3QueryApi/Specialized/ReasonId.cs b/src/TeamSpeak3QueryApi/Query/Enums/ReasonId.cs similarity index 86% rename from src/TeamSpeak3QueryApi/Specialized/ReasonId.cs rename to src/TeamSpeak3QueryApi/Query/Enums/ReasonId.cs index b4fdfb5..495eb92 100644 --- a/src/TeamSpeak3QueryApi/Specialized/ReasonId.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/ReasonId.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum ReasonId { diff --git a/src/TeamSpeak3QueryApi/Specialized/ServerGroupType.cs b/src/TeamSpeak3QueryApi/Query/Enums/ServerGroupType.cs similarity index 73% rename from src/TeamSpeak3QueryApi/Specialized/ServerGroupType.cs rename to src/TeamSpeak3QueryApi/Query/Enums/ServerGroupType.cs index 175effa..7d3052e 100644 --- a/src/TeamSpeak3QueryApi/Specialized/ServerGroupType.cs +++ b/src/TeamSpeak3QueryApi/Query/Enums/ServerGroupType.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net.Query.Enums { public enum ServerGroupType { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelCreated.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelCreated.cs similarity index 95% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelCreated.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelCreated.cs index 9f1367a..272bdf3 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelCreated.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelCreated.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelCreated : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDeleted.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelDeleted.cs similarity index 78% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDeleted.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelDeleted.cs index 85f6b64..32d72d4 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDeleted.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelDeleted.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelDeleted : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDescriptionChanged.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelDescriptionChanged.cs similarity index 69% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDescriptionChanged.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelDescriptionChanged.cs index 99e8da8..4e64e89 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelDescriptionChanged.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelDescriptionChanged.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelDescriptionChanged : Notification { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelEdited.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelEdited.cs similarity index 95% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelEdited.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelEdited.cs index ac7d75b..ae281de 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelEdited.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelEdited.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelEdited : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelMoved.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelMoved.cs similarity index 81% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelMoved.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelMoved.cs index e2bc1ce..751ebf8 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelMoved.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelMoved.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelMoved : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelPasswordChanged.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelPasswordChanged.cs similarity index 69% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelPasswordChanged.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ChannelPasswordChanged.cs index efd9ae7..098c1c0 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ChannelPasswordChanged.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ChannelPasswordChanged.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ChannelPasswordChanged : Notification { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientEnterView.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ClientEnterView.cs similarity index 97% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ClientEnterView.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ClientEnterView.cs index 0a31352..11fde38 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientEnterView.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ClientEnterView.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ClientEnterView : Notification { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientLeftView.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ClientLeftView.cs similarity index 88% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ClientLeftView.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ClientLeftView.cs index 0cdc6a1..788f1b0 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientLeftView.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ClientLeftView.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ClientLeftView : Notification { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientMoved.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ClientMoved.cs similarity index 77% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ClientMoved.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ClientMoved.cs index 449bedc..612829b 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ClientMoved.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ClientMoved.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ClientMoved : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/InvokerInformation.cs b/src/TeamSpeak3QueryApi/Query/Notifications/InvokerInformation.cs similarity index 79% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/InvokerInformation.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/InvokerInformation.cs index 7d02567..cd06b3b 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/InvokerInformation.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/InvokerInformation.cs @@ -1,4 +1,6 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +using TeamSpeak3QueryApi.Net.Query.Enums; + +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public abstract class InvokerInformation : Notification { diff --git a/src/TeamSpeak3QueryApi/Query/Notifications/Notification.cs b/src/TeamSpeak3QueryApi/Query/Notifications/Notification.cs new file mode 100644 index 0000000..eb2c631 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/Notifications/Notification.cs @@ -0,0 +1,7 @@ +using TeamSpeak3QueryApi.Net.Interfaces; + +namespace TeamSpeak3QueryApi.Net.Query.Notifications +{ + public abstract class Notification : ITeamSpeakSerializable + { } +} diff --git a/src/TeamSpeak3QueryApi/NotificationData.cs b/src/TeamSpeak3QueryApi/Query/Notifications/NotificationData.cs similarity index 88% rename from src/TeamSpeak3QueryApi/NotificationData.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/NotificationData.cs index 9afab69..629dd4c 100644 --- a/src/TeamSpeak3QueryApi/NotificationData.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/NotificationData.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using TeamSpeak3QueryApi.Net.Query; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Notifications { /// Provides data that was retrieved by a notification. public class NotificationData diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/ServerEdited.cs b/src/TeamSpeak3QueryApi/Query/Notifications/ServerEdited.cs similarity index 95% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/ServerEdited.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/ServerEdited.cs index 190fb18..b5b8375 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/ServerEdited.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/ServerEdited.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class ServerEdited : Notification { diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/TextMessage.cs b/src/TeamSpeak3QueryApi/Query/Notifications/TextMessage.cs similarity index 55% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/TextMessage.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/TextMessage.cs index 371749c..c61d67d 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/TextMessage.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/TextMessage.cs @@ -1,4 +1,6 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +using TeamSpeak3QueryApi.Net.Query.Enums; + +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class TextMessage : InvokerInformation { @@ -9,6 +11,6 @@ public class TextMessage : InvokerInformation public string Message; [QuerySerialize("target")] - public int TargetClientId; // (clid des Empfängers; Parameter nur bei textprivate vorhanden) + public int TargetClientId; // (clid des Empfängers; Parameter nur bei textprivate vorhanden) } } diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/TokenUsed.cs b/src/TeamSpeak3QueryApi/Query/Notifications/TokenUsed.cs similarity index 90% rename from src/TeamSpeak3QueryApi/Specialized/Notifications/TokenUsed.cs rename to src/TeamSpeak3QueryApi/Query/Notifications/TokenUsed.cs index 46675d4..b269f21 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/TokenUsed.cs +++ b/src/TeamSpeak3QueryApi/Query/Notifications/TokenUsed.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications +namespace TeamSpeak3QueryApi.Net.Query.Notifications { public class TokenUsed : InvokerInformation { diff --git a/src/TeamSpeak3QueryApi/IParameterValue.cs b/src/TeamSpeak3QueryApi/Query/Parameters/IParameterValue.cs similarity index 88% rename from src/TeamSpeak3QueryApi/IParameterValue.cs rename to src/TeamSpeak3QueryApi/Query/Parameters/IParameterValue.cs index 5541fd5..e613f50 100644 --- a/src/TeamSpeak3QueryApi/IParameterValue.cs +++ b/src/TeamSpeak3QueryApi/Query/Parameters/IParameterValue.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Parameters { /// Represents an abstraction of a parameter value. public interface IParameterValue diff --git a/src/TeamSpeak3QueryApi/Parameter.cs b/src/TeamSpeak3QueryApi/Query/Parameters/Parameter.cs similarity index 98% rename from src/TeamSpeak3QueryApi/Parameter.cs rename to src/TeamSpeak3QueryApi/Query/Parameters/Parameter.cs index 20c484e..eac68fd 100644 --- a/src/TeamSpeak3QueryApi/Parameter.cs +++ b/src/TeamSpeak3QueryApi/Query/Parameters/Parameter.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Parameters { /// Represents a Query API parameter. public class Parameter diff --git a/src/TeamSpeak3QueryApi/ParameterValue.cs b/src/TeamSpeak3QueryApi/Query/Parameters/ParameterValue.cs similarity index 97% rename from src/TeamSpeak3QueryApi/ParameterValue.cs rename to src/TeamSpeak3QueryApi/Query/Parameters/ParameterValue.cs index 80fcd8a..8782dbe 100644 --- a/src/TeamSpeak3QueryApi/ParameterValue.cs +++ b/src/TeamSpeak3QueryApi/Query/Parameters/ParameterValue.cs @@ -1,6 +1,7 @@ using System.Globalization; +using TeamSpeak3QueryApi.Net.Extensions; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Parameters { /// Represents the value of a parameter which consits of a single value. public class ParameterValue : IParameterValue diff --git a/src/TeamSpeak3QueryApi/ParameterValueArray.cs b/src/TeamSpeak3QueryApi/Query/Parameters/ParameterValueArray.cs similarity index 97% rename from src/TeamSpeak3QueryApi/ParameterValueArray.cs rename to src/TeamSpeak3QueryApi/Query/Parameters/ParameterValueArray.cs index e04635e..625391b 100644 --- a/src/TeamSpeak3QueryApi/ParameterValueArray.cs +++ b/src/TeamSpeak3QueryApi/Query/Parameters/ParameterValueArray.cs @@ -1,6 +1,6 @@ using System.Linq; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query.Parameters { /// Represents the value of a parameter which consits of a multiple values. public class ParameterValueArray : IParameterValue diff --git a/src/TeamSpeak3QueryApi/QueryClient.cs b/src/TeamSpeak3QueryApi/Query/QueryClient.cs similarity index 68% rename from src/TeamSpeak3QueryApi/QueryClient.cs rename to src/TeamSpeak3QueryApi/Query/QueryClient.cs index f47c778..3a203b2 100644 --- a/src/TeamSpeak3QueryApi/QueryClient.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryClient.cs @@ -9,114 +9,87 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Renci.SshNet; +using TeamSpeak3QueryApi.Net.Enums; +using TeamSpeak3QueryApi.Net.Extensions; +using TeamSpeak3QueryApi.Net.Query.Notifications; +using TeamSpeak3QueryApi.Net.Query.Parameters; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { /// Represents a client that can be used to access the TeamSpeak Query API on a remote server. - public class QueryClient : IDisposable + public abstract class QueryClient : IDisposable { + /// + /// Events for handling in the correct moment + /// + public EventHandler OnConnectionLost; + public EventHandler OnConnected; + public EventHandler OnDisconnected; + /// Gets the remote host of the Query API client. /// The remote host of the Query API client. - public string Host { get; } + public string Host { get; internal set; } /// Gets the remote port of the Query API client. /// The remote port of the Query API client. - public int Port { get; } + public int Port { get; internal set; } + + public Protocol ConnectionType { get; internal set; } - public bool IsConnected { get; private set; } + public bool IsConnected { get; internal set; } /// The default host which is used when no host is provided. public const string DefaultHost = "localhost"; - /// The default port which is used when no port is provided. - public const short DefaultPort = 10011; - - public TcpClient Client { get; } - private StreamReader _reader; - private StreamWriter _writer; - private NetworkStream _ns; - private CancellationTokenSource _cts; + public TcpClient Client { get; internal set; } + protected StreamReader _reader; + protected StreamWriter _writer; + protected NetworkStream _ns; + protected CancellationTokenSource _cts; private readonly Queue _queue = new Queue(); private readonly ConcurrentDictionary>> _subscriptions = new ConcurrentDictionary>>(); - #region Ctors - - /// Creates a new instance of using the and . - public QueryClient() - : this(DefaultHost, DefaultPort) - { } - - /// Creates a new instance of using the provided host and the . - /// The host name of the remote server. - public QueryClient(string hostName) - : this(hostName, DefaultPort) - { } - /// Creates a new instance of using the provided host TCP port. - /// The host name of the remote server. - /// The TCP port of the Query API server. - public QueryClient(string hostName, int port) - { - if (string.IsNullOrWhiteSpace(hostName)) - throw new ArgumentNullException(nameof(hostName)); - if (!ValidationHelper.ValidateTcpPort(port)) - throw new ArgumentOutOfRangeException(nameof(port)); - - Host = hostName; - Port = port; - IsConnected = false; - Client = new TcpClient(); - } - - #endregion - - /// Connects to the Query API server. - /// An awaitable . - public async Task Connect() - { - await Client.ConnectAsync(Host, Port).ConfigureAwait(false); - if (!Client.Connected) - throw new InvalidOperationException("Could not connect."); - - _ns = Client.GetStream(); - _reader = new StreamReader(_ns); - _writer = new StreamWriter(_ns) { NewLine = "\n" }; - - IsConnected = true; - - await _reader.ReadLineAsync().ConfigureAwait(false); - await _reader.ReadLineAsync().ConfigureAwait(false); // Ignore welcome message - await _reader.ReadLineAsync().ConfigureAwait(false); - - return ResponseProcessingLoop(); - } + protected SshClient _sshClient; + protected ShellStream _shell; + protected string username; public void Disconnect() { if (_cts == null) return; + OnDisconnected?.Invoke(this, EventArgs.Empty); _cts.Cancel(); } + /// Connects to the Query API server. + /// An awaitable . + public abstract Task ConnectAsync(); + + /// Connects to the Query API server. + /// An awaitable . + public abstract CancellationTokenSource Connect(string username, string password); + #region Send /// Sends a Query API command wihtout parameters to the server. /// The command. /// An awaitable . - public Task Send(string cmd) => Send(cmd, null); + public Task SendAsync(string cmd) => SendAsync(cmd, null); /// Sends a Query API command with parameters to the server. /// The command. /// The parameters of the command. /// An awaitable . - public Task Send(string cmd, params Parameter[] parameters) => Send(cmd, parameters, null); + public Task SendAsync(string cmd, params Parameter[] parameters) => SendAsync(cmd, parameters, null); /// Sends a Query API command with parameters and options to the server. /// The command. /// The parameters of the command. /// The options of the command. /// An awaitable . - public async Task Send(string cmd, Parameter[] parameters, string[] options) + public async Task SendAsync(string cmd, Parameter[] parameters, string[] options) { if (string.IsNullOrWhiteSpace(cmd)) throw new ArgumentNullException(nameof(cmd)); //return Task.Run( () => throw new ArgumentNullException("cmd")); @@ -141,11 +114,10 @@ public async Task Send(string cmd, Parameter[] parame var d = new TaskCompletionSource(); var newItem = new QueryCommand(cmd, ps.AsReadOnly(), options, d, toSend.ToString()); - + _queue.Enqueue(newItem); - await CheckQueue().ConfigureAwait(false); - + await CheckQueueAsync().ConfigureAwait(false); return await d.Task.ConfigureAwait(false); } @@ -210,7 +182,7 @@ public void Unsubscribe(string notificationName, Action callba #endregion #region Parsing - private static QueryResponseDictionary[] ParseResponse(string rawResponse) + protected static QueryResponseDictionary[] ParseResponse(string rawResponse) { var records = rawResponse.Split('|'); var response = records.Select(s => @@ -242,7 +214,7 @@ private static QueryResponseDictionary[] ParseResponse(string rawResponse) return response.ToArray(); } - private static QueryError ParseError(string errorString) + protected static QueryError ParseError(string errorString) { // Ex: // error id=2568 msg=insufficient\sclient\spermissions failed_permid=27 @@ -276,6 +248,9 @@ private static QueryError ParseError(string errorString) case "FAILED_PERMID": parsedError.FailedPermissionId = errData.Length > 1 ? int.Parse(errData[1], NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.CurrentCulture) : -1; continue; + case "EXTRA_MSG": + parsedError.ExtraMessage = errData.Length > 1 ? errData[1].TeamSpeakUnescape() : null; + continue; default: throw new QueryProtocolException(); } @@ -283,7 +258,7 @@ private static QueryError ParseError(string errorString) return parsedError; } - private static QueryNotification ParseNotification(string notificationString) + protected static QueryNotification ParseNotification(string notificationString) { Debug.Assert(!string.IsNullOrWhiteSpace(notificationString)); @@ -301,7 +276,7 @@ private static QueryNotification ParseNotification(string notificationString) return new QueryNotification(notificationName, notData); } - private static void InvokeResponse(QueryCommand forCommand) + protected static void InvokeResponse(QueryCommand forCommand) { Debug.Assert(forCommand != null); Debug.Assert(forCommand.Defer != null); @@ -320,7 +295,7 @@ private static void InvokeResponse(QueryCommand forCommand) #endregion #region Invocation - private void InvokeNotification(QueryNotification notification) + protected void InvokeNotification(QueryNotification notification) { Debug.Assert(notification != null); Debug.Assert(notification.Name != null); @@ -340,70 +315,14 @@ private void InvokeNotification(QueryNotification notification) } } - private CancellationTokenSource ResponseProcessingLoop() - { - var cts = _cts = new CancellationTokenSource(); - Task.Run(async () => - { - while (!cts.Token.IsCancellationRequested) - { - string line = null; - try - { - line = await _reader.ReadLineAsync().WithCancellation(cts.Token).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } - - Debug.WriteLine(line); - - if (line == null) - { - cts.Cancel(); - continue; - } - - if (string.IsNullOrWhiteSpace(line)) - continue; - - var s = line.Trim(); - if (s.StartsWith("error", StringComparison.OrdinalIgnoreCase)) - { - Debug.Assert(_currentCommand != null); - - var error = ParseError(s); - _currentCommand.Error = error; - InvokeResponse(_currentCommand); - } - else if (s.StartsWith("notify", StringComparison.OrdinalIgnoreCase)) - { - s = s.Remove(0, "notify".Length); - var not = ParseNotification(s); - InvokeNotification(not); - } - else - { - Debug.Assert(_currentCommand != null); - _currentCommand.RawResponse = s; - _currentCommand.ResponseDictionary = ParseResponse(s); - } - } - - IsConnected = false; - }); - return cts; - } - - private QueryCommand _currentCommand; - private async Task CheckQueue() + protected QueryCommand _currentCommand; + private async Task CheckQueueAsync() { if (_queue.Count > 0) { _currentCommand = _queue.Dequeue(); - Debug.WriteLine(_currentCommand.SentText); - await _writer.WriteLineAsync(_currentCommand.SentText).ConfigureAwait(false); + Debug.WriteLine($"{ConnectionType}: {_currentCommand.SentText}"); + await _writer.WriteLineAsync((ConnectionType == Protocol.Telnet ? _currentCommand.SentText : _currentCommand.SentText + "\n")).ConfigureAwait(false); await _writer.FlushAsync().ConfigureAwait(false); } } @@ -436,9 +355,10 @@ protected virtual void Dispose(bool disposing) _ns?.Dispose(); _reader?.Dispose(); _writer?.Dispose(); + _shell?.Dispose(); + _sshClient?.Dispose(); } } - #endregion } } diff --git a/src/TeamSpeak3QueryApi/QueryCommand.cs b/src/TeamSpeak3QueryApi/Query/QueryCommand.cs similarity index 88% rename from src/TeamSpeak3QueryApi/QueryCommand.cs rename to src/TeamSpeak3QueryApi/Query/QueryCommand.cs index aae8ac9..ea8042c 100644 --- a/src/TeamSpeak3QueryApi/QueryCommand.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryCommand.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; using System.Threading.Tasks; +using TeamSpeak3QueryApi.Net.Query.Parameters; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { - internal class QueryCommand + public class QueryCommand { public string Command { get; } public string[] Options { get; } diff --git a/src/TeamSpeak3QueryApi/QueryError.cs b/src/TeamSpeak3QueryApi/Query/QueryError.cs similarity index 80% rename from src/TeamSpeak3QueryApi/QueryError.cs rename to src/TeamSpeak3QueryApi/Query/QueryError.cs index 069f90d..c5a0637 100644 --- a/src/TeamSpeak3QueryApi/QueryError.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryError.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { /// Represents a query error that comes with every API response. public class QueryError @@ -11,6 +11,10 @@ public class QueryError /// The error message. public string Message { get; internal set; } + /// The extra error message. Is only set if there is an extra error message. + /// The error message. + public string ExtraMessage { get; internal set; } + /// If the cause of the error was a missing permission, this property represents the ID of the permission the client does not have. A value of 0 means that there was no permission error. /// The ID of the missing permission. If there is none, 0. /// Check the of the to determine if there was a permission error. diff --git a/src/TeamSpeak3QueryApi/QueryException.cs b/src/TeamSpeak3QueryApi/Query/QueryException.cs similarity index 94% rename from src/TeamSpeak3QueryApi/QueryException.cs rename to src/TeamSpeak3QueryApi/Query/QueryException.cs index 188ee10..5719fef 100644 --- a/src/TeamSpeak3QueryApi/QueryException.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { /// Represents errors that occur during query execution. [Serializable] @@ -27,7 +27,7 @@ public QueryException(string message, Exception innerException) /// Initializes a new instance of the class with a specified error returned by the Query API. /// The that was returned by the Query API. public QueryException(QueryError error) - : this("An error occurred during the query.") + : this("An error occurred during the teamspeak query.") { Error = error; } diff --git a/src/TeamSpeak3QueryApi/QueryNotification.cs b/src/TeamSpeak3QueryApi/Query/QueryNotification.cs similarity index 71% rename from src/TeamSpeak3QueryApi/QueryNotification.cs rename to src/TeamSpeak3QueryApi/Query/QueryNotification.cs index 5d3cd7e..ceb69ea 100644 --- a/src/TeamSpeak3QueryApi/QueryNotification.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryNotification.cs @@ -1,8 +1,9 @@ using System.Diagnostics; +using TeamSpeak3QueryApi.Net.Query.Notifications; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { - internal class QueryNotification + public class QueryNotification { public string Name { get; set; } public NotificationData Data { get; set; } diff --git a/src/TeamSpeak3QueryApi/QueryProtocolException.cs b/src/TeamSpeak3QueryApi/Query/QueryProtocolException.cs similarity index 93% rename from src/TeamSpeak3QueryApi/QueryProtocolException.cs rename to src/TeamSpeak3QueryApi/Query/QueryProtocolException.cs index 23c081a..ec76b1c 100644 --- a/src/TeamSpeak3QueryApi/QueryProtocolException.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryProtocolException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { /// Represents errors that occur during queries caused by protcol violations. [Serializable] @@ -9,7 +9,7 @@ public class QueryProtocolException : Exception { /// Initializes a new instance of the class. public QueryProtocolException() - : this("An error occurred during the query.") + : this("An error occurred during the teamspeak query.") { } /// Initializes a new instance of the class with a specified error message. diff --git a/src/TeamSpeak3QueryApi/QueryResponseDictionary.cs b/src/TeamSpeak3QueryApi/Query/QueryResponseDictionary.cs similarity index 91% rename from src/TeamSpeak3QueryApi/QueryResponseDictionary.cs rename to src/TeamSpeak3QueryApi/Query/QueryResponseDictionary.cs index 8aae0b8..36b4a8c 100644 --- a/src/TeamSpeak3QueryApi/QueryResponseDictionary.cs +++ b/src/TeamSpeak3QueryApi/Query/QueryResponseDictionary.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace TeamSpeak3QueryApi.Net +namespace TeamSpeak3QueryApi.Net.Query { /// Represents the data of a query response. [Serializable] diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/ClientBan.cs b/src/TeamSpeak3QueryApi/Query/Responses/ClientBan.cs similarity index 66% rename from src/TeamSpeak3QueryApi/Specialized/Responses/ClientBan.cs rename to src/TeamSpeak3QueryApi/Query/Responses/ClientBan.cs index 491c9fb..8528ceb 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/ClientBan.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/ClientBan.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class ClientBan : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/CreatedChannel.cs b/src/TeamSpeak3QueryApi/Query/Responses/CreatedChannel.cs similarity index 67% rename from src/TeamSpeak3QueryApi/Specialized/Responses/CreatedChannel.cs rename to src/TeamSpeak3QueryApi/Query/Responses/CreatedChannel.cs index b2b3c23..7ebdc36 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/CreatedChannel.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/CreatedChannel.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class CreatedChannel : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/EditChannelInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/EditChannelInfo.cs similarity index 96% rename from src/TeamSpeak3QueryApi/Specialized/Responses/EditChannelInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/EditChannelInfo.cs index e8bcae2..3812515 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/EditChannelInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/EditChannelInfo.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class EditChannelInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/FoundChannel.cs b/src/TeamSpeak3QueryApi/Query/Responses/FoundChannel.cs similarity index 76% rename from src/TeamSpeak3QueryApi/Specialized/Responses/FoundChannel.cs rename to src/TeamSpeak3QueryApi/Query/Responses/FoundChannel.cs index a2c08b3..7e6f9f3 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/FoundChannel.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/FoundChannel.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class FoundChannel : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetChannelInfo.cs similarity index 96% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetChannelInfo.cs index dcd3633..8e9979c 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetChannelInfo.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetChannelInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelListInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetChannelListInfo.cs similarity index 94% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelListInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetChannelListInfo.cs index f3518ba..621028f 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetChannelListInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetChannelListInfo.cs @@ -1,6 +1,7 @@ using System; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetChannelListInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetClientDetailedInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetClientDetailedInfo.cs similarity index 96% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetClientDetailedInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetClientDetailedInfo.cs index 20c2d6a..b91ef70 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetClientDetailedInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetClientDetailedInfo.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using TeamSpeak3QueryApi.Net.Query.Enums; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetClientDetailedInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Query/Responses/GetClientInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetClientInfo.cs new file mode 100644 index 0000000..2407de8 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetClientInfo.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using TeamSpeak3QueryApi.Net.Query.Enums; + +namespace TeamSpeak3QueryApi.Net.Query.Responses +{ + public class GetClientInfo : Response + { + [QuerySerialize("clid")] + public int Id; + + [QuerySerialize("cid")] + public int ChannelId; + + [QuerySerialize("client_database_id")] + public int DatabaseId; + + [QuerySerialize("client_nickname")] + public string NickName; + + [QuerySerialize("client_type")] + public ClientType Type; + + [QuerySerialize("client_unique_identifier")] + public string UniqueIdentifier; + + [QuerySerialize("client_version")] + public string Version; + + [QuerySerialize("client_platform")] + public string Plattform; + + [QuerySerialize("client_input_muted")] + public bool InputMuted; + + [QuerySerialize("client_output_muted")] + public bool OutputMuted; + + [QuerySerialize("client_is_recording")] + public bool IsRecording; + + [QuerySerialize("client_servergroups")] + public IReadOnlyList ServerGroupIds; + + [QuerySerialize("client_channel_group_id")] + public IReadOnlyList ChannelGroupsIds; + + [QuerySerialize("client_created")] + public DateTime Created; + + [QuerySerialize("client_lastconnected")] + public DateTime LastConnected; + + [QuerySerialize("client_away")] + public bool Away; + + [QuerySerialize("client_away_message")] + public string AwayMessage; + + [QuerySerialize("client_idle_time")] + private long _idleTime; //Because it is in ms instead if s defined in Typecaster + public TimeSpan IdleTime => TimeSpan.FromMilliseconds(_idleTime); + } +} diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetCurrentFileTransfer.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetCurrentFileTransfer.cs similarity index 94% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetCurrentFileTransfer.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetCurrentFileTransfer.cs index 9dfbd39..877cce4 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetCurrentFileTransfer.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetCurrentFileTransfer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetCurrentFileTransfer : Response { diff --git a/src/TeamSpeak3QueryApi/Query/Responses/GetDbClientInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetDbClientInfo.cs new file mode 100644 index 0000000..a6df532 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetDbClientInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace TeamSpeak3QueryApi.Net.Query.Responses +{ + public class GetDbClientInfo : Response + { + [QuerySerialize("cldbid")] + public int DatabaseId; + + [QuerySerialize("client_nickname")] + public string NickName; + + [QuerySerialize("client_unique_identifier")] + public string UniqueIdentifier; + + [QuerySerialize("client_created")] + public DateTime Created; + + [QuerySerialize("client_lastconnected")] + public DateTime LastConnected; + + [QuerySerialize("client_totalconnections")] + public int TotalConnectionCount; + + [QuerySerialize("client_description")] + public string Description; + + [QuerySerialize("client_login_name")] + public string LoginName; + + [QuerySerialize("client_lastip")] + public string LastConnectionIp; + } +} diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetFileInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetFileInfo.cs similarity index 85% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetFileInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetFileInfo.cs index 45f0709..abb12dc 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetFileInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetFileInfo.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetFileInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetFiles.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetFiles.cs similarity index 87% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetFiles.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetFiles.cs index 773797e..168e322 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetFiles.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetFiles.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetFiles : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroup.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroup.cs similarity index 81% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroup.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetServerGroup.cs index 2774918..757fe07 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroup.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroup.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetServerGroup : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupClientList.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupClientList.cs similarity index 71% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupClientList.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupClientList.cs index f987ff9..add70b4 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupClientList.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupClientList.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetServerGroupClientList : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupListInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupListInfo.cs similarity index 89% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupListInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupListInfo.cs index f92f58a..39b2880 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerGroupListInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetServerGroupListInfo.cs @@ -1,4 +1,6 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +using TeamSpeak3QueryApi.Net.Query.Enums; + +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetServerGroupListInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerListInfo.cs b/src/TeamSpeak3QueryApi/Query/Responses/GetServerListInfo.cs similarity index 94% rename from src/TeamSpeak3QueryApi/Specialized/Responses/GetServerListInfo.cs rename to src/TeamSpeak3QueryApi/Query/Responses/GetServerListInfo.cs index 0d01187..efc8756 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetServerListInfo.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/GetServerListInfo.cs @@ -1,6 +1,6 @@ using System; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class GetServerListInfo : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/InitDownload.cs b/src/TeamSpeak3QueryApi/Query/Responses/InitDownload.cs similarity index 89% rename from src/TeamSpeak3QueryApi/Specialized/Responses/InitDownload.cs rename to src/TeamSpeak3QueryApi/Query/Responses/InitDownload.cs index 624f805..b1ff8ce 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/InitDownload.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/InitDownload.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class InitDownload : Response { diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/InitUpload.cs b/src/TeamSpeak3QueryApi/Query/Responses/InitUpload.cs similarity index 88% rename from src/TeamSpeak3QueryApi/Specialized/Responses/InitUpload.cs rename to src/TeamSpeak3QueryApi/Query/Responses/InitUpload.cs index 092396e..b057f3f 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/InitUpload.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/InitUpload.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class InitUpload : Response { diff --git a/src/TeamSpeak3QueryApi/Query/Responses/Response.cs b/src/TeamSpeak3QueryApi/Query/Responses/Response.cs new file mode 100644 index 0000000..bc34bd9 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/Responses/Response.cs @@ -0,0 +1,7 @@ +using TeamSpeak3QueryApi.Net.Interfaces; + +namespace TeamSpeak3QueryApi.Net.Query.Responses +{ + public abstract class Response : ITeamSpeakSerializable + { } +} diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/WhoAmI.cs b/src/TeamSpeak3QueryApi/Query/Responses/WhoAmI.cs similarity index 95% rename from src/TeamSpeak3QueryApi/Specialized/Responses/WhoAmI.cs rename to src/TeamSpeak3QueryApi/Query/Responses/WhoAmI.cs index 1e0d0c7..5d54ac1 100644 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/WhoAmI.cs +++ b/src/TeamSpeak3QueryApi/Query/Responses/WhoAmI.cs @@ -1,4 +1,4 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses +namespace TeamSpeak3QueryApi.Net.Query.Responses { public class WhoAmI : Response { diff --git a/src/TeamSpeak3QueryApi/Query/SshQueryClient.cs b/src/TeamSpeak3QueryApi/Query/SshQueryClient.cs new file mode 100644 index 0000000..4c82393 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/SshQueryClient.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Renci.SshNet; +using Renci.SshNet.Common; +using TeamSpeak3QueryApi.Net.Enums; +using TeamSpeak3QueryApi.Net.Extensions; + +namespace TeamSpeak3QueryApi.Net.Query +{ + public class SshQueryClient : QueryClient + { + /// The default port which is used when no port is provided. + public const short DefaultPort = 10022; + + /// Creates a new instance of using the and . + public SshQueryClient() + : this(DefaultHost, DefaultPort) + { } + + /// Creates a new instance of using the provided host and the . + /// The host name of the remote server. + public SshQueryClient(string hostName) + : this(hostName, DefaultPort) + { } + /// Creates a new instance of using the provided host TCP port. + /// The host name of the remote server. + /// The TCP port of the Query API server. + public SshQueryClient(string hostName, int port) + { + if (string.IsNullOrWhiteSpace(hostName)) + throw new ArgumentNullException(nameof(hostName)); + if (!ValidationHelper.ValidateTcpPort(port)) + throw new ArgumentOutOfRangeException(nameof(port)); + + Host = hostName; + Port = port; + ConnectionType = Protocol.SSH; + IsConnected = false; + Client = new TcpClient(); + } + + /// Connects to the Query API server. + /// An awaitable . + public override CancellationTokenSource Connect(string username, string password) + { + this.username = username; + + _sshClient = new SshClient(Host, Port, username, password); + _sshClient.Connect(); + + var terminalMode = new Dictionary(); + terminalMode.Add(TerminalModes.ECHO, 53); + + _shell = _sshClient.CreateShellStream("", 0, 0, 0, 0, 4096); + + _reader = new StreamReader(_shell, Encoding.UTF8, true, 1024, true); + _writer = new StreamWriter(_shell) { NewLine = "\n", AutoFlush = true }; + + var headline = _shell.Expect("\r\n", new TimeSpan(0, 0, 3)); + if (!headline.Contains("TS3")) + { + throw new QueryProtocolException("Telnet Query isn't a valid Teamspeak Query"); + } + _shell.Expect("\n", new TimeSpan(0, 0, 3)); // Ignore welcome message + _shell.Expect("\n", new TimeSpan(0, 0, 3)); // Ignore welcome message + + return ResponseProcessingLoop(); + } + + /// Connects to the Query API server. + /// An awaitable . + public override Task ConnectAsync() + { + throw new InvalidOperationException("ConnectAsync Method is not supported in ssh query. Please use the telnet query."); + } + + private CancellationTokenSource ResponseProcessingLoop() + { + var cts = _cts = new CancellationTokenSource(); + Task.Run(async () => + { + while (!cts.Token.IsCancellationRequested) + { + string line = null; + try + { + line = _shell.ReadLine(); + } + catch (OperationCanceledException) + { + break; + } + + if (line == null) + { + cts.Cancel(); + continue; + } + + if (string.IsNullOrWhiteSpace(line) || string.IsNullOrEmpty(line) || line.StartsWith(username)) + continue; + + var s = line.Trim(); + Debug.WriteLine(line); + + if (s.StartsWith("error", StringComparison.OrdinalIgnoreCase)) + { + Debug.Assert(_currentCommand != null); + + var error = ParseError(s); + _currentCommand.Error = error; + InvokeResponse(_currentCommand); + } + else if (s.StartsWith("notify", StringComparison.OrdinalIgnoreCase)) + { + s = s.Remove(0, "notify".Length); + var not = ParseNotification(s); + InvokeNotification(not); + } + else + { + Debug.Assert(_currentCommand != null); + _currentCommand.RawResponse = s; + _currentCommand.ResponseDictionary = ParseResponse(s); + } + } + + IsConnected = false; + OnConnectionLost?.Invoke(this, EventArgs.Empty); + OnDisconnected?.Invoke(this, EventArgs.Empty); + + }); + return cts; + } + } +} diff --git a/src/TeamSpeak3QueryApi/Query/TelnetQueryClient.cs b/src/TeamSpeak3QueryApi/Query/TelnetQueryClient.cs new file mode 100644 index 0000000..44e7323 --- /dev/null +++ b/src/TeamSpeak3QueryApi/Query/TelnetQueryClient.cs @@ -0,0 +1,140 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using TeamSpeak3QueryApi.Net.Enums; +using TeamSpeak3QueryApi.Net.Extensions; + +namespace TeamSpeak3QueryApi.Net.Query +{ + public class TelnetQueryClient : QueryClient + { + /// The default port which is used when no port is provided. + public const short DefaultPort = 10011; + + /// Creates a new instance of using the and . + public TelnetQueryClient() + : this(DefaultHost, DefaultPort) + { } + + /// Creates a new instance of using the provided host and the . + /// The host name of the remote server. + public TelnetQueryClient(string hostName) + : this(hostName, DefaultPort) + { } + /// Creates a new instance of using the provided host TCP port. + /// The host name of the remote server. + /// The TCP port of the Query API server. + public TelnetQueryClient(string hostName, int port) + { + if (string.IsNullOrWhiteSpace(hostName)) + throw new ArgumentNullException(nameof(hostName)); + if (!ValidationHelper.ValidateTcpPort(port)) + throw new ArgumentOutOfRangeException(nameof(port)); + + Host = hostName; + Port = port; + ConnectionType = Protocol.Telnet; + IsConnected = false; + Client = new TcpClient(); + } + + /// Connects to the Query API server. + /// An awaitable . + public override CancellationTokenSource Connect(string username, string password) + { + throw new InvalidOperationException("Connect Method is not supported in telnet query. Please use the ssh query."); + } + + /// Connects to the Query API server. + /// An awaitable . + public override async Task ConnectAsync() + { + if (ConnectionType != Protocol.Telnet) + throw new InvalidOperationException("ConnectAsync Method without parameters can only be used with telnet Query. Please use Connect method."); + + await Client.ConnectAsync(Host, Port).ConfigureAwait(false); + if (!Client.Connected) + throw new InvalidOperationException("Could not connect."); + + _ns = Client.GetStream(); + _reader = new StreamReader(_ns); + _writer = new StreamWriter(_ns) { NewLine = "\n" }; + + IsConnected = true; + OnConnected?.Invoke(this, EventArgs.Empty); + + + var headline = await _reader.ReadLineAsync().ConfigureAwait(false); + if (headline != "TS3") + { + throw new QueryProtocolException("Telnet Query isn't a valid Teamspeak Query"); + } + await _reader.ReadLineAsync().ConfigureAwait(false); // Ignore welcome message + await _reader.ReadLineAsync().ConfigureAwait(false); + + return ResponseProcessingLoop(); + } + + private CancellationTokenSource ResponseProcessingLoop() + { + var cts = _cts = new CancellationTokenSource(); + Task.Run(async () => + { + while (!cts.Token.IsCancellationRequested) + { + string line = null; + try + { + line = await _reader.ReadLineAsync().WithCancellation(cts.Token).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + break; + } + + if (line == null) + { + cts.Cancel(); + continue; + } + + if (string.IsNullOrWhiteSpace(line) || string.IsNullOrEmpty(line)) + continue; + + var s = line.Trim(); + Debug.WriteLine(line); + + if (s.StartsWith("error", StringComparison.OrdinalIgnoreCase)) + { + Debug.Assert(_currentCommand != null); + + var error = ParseError(s); + _currentCommand.Error = error; + InvokeResponse(_currentCommand); + } + else if (s.StartsWith("notify", StringComparison.OrdinalIgnoreCase)) + { + s = s.Remove(0, "notify".Length); + var not = ParseNotification(s); + InvokeNotification(not); + } + else + { + Debug.Assert(_currentCommand != null); + _currentCommand.RawResponse = s; + _currentCommand.ResponseDictionary = ParseResponse(s); + } + } + + IsConnected = false; + OnConnectionLost?.Invoke(this, EventArgs.Empty); + OnDisconnected?.Invoke(this, EventArgs.Empty); + + }); + return cts; + } + } +} diff --git a/src/TeamSpeak3QueryApi/Specialized/QuerySerializeAttribute.cs b/src/TeamSpeak3QueryApi/QuerySerializeAttribute.cs similarity index 87% rename from src/TeamSpeak3QueryApi/Specialized/QuerySerializeAttribute.cs rename to src/TeamSpeak3QueryApi/QuerySerializeAttribute.cs index 006711d..f52f917 100644 --- a/src/TeamSpeak3QueryApi/Specialized/QuerySerializeAttribute.cs +++ b/src/TeamSpeak3QueryApi/QuerySerializeAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace TeamSpeak3QueryApi.Net.Specialized +namespace TeamSpeak3QueryApi.Net { [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] class QuerySerializeAttribute : Attribute diff --git a/src/TeamSpeak3QueryApi/Specialized/Notifications/Notification.cs b/src/TeamSpeak3QueryApi/Specialized/Notifications/Notification.cs deleted file mode 100644 index 5844791..0000000 --- a/src/TeamSpeak3QueryApi/Specialized/Notifications/Notification.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Notifications -{ - public abstract class Notification : ITeamSpeakSerializable - { } -} diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/GetClientInfo.cs b/src/TeamSpeak3QueryApi/Specialized/Responses/GetClientInfo.cs deleted file mode 100644 index 40acc11..0000000 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/GetClientInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses -{ - public class GetClientInfo : Response - { - [QuerySerialize("clid")] - public int Id; - - [QuerySerialize("cid")] - public int ChannelId; - - [QuerySerialize("client_database_id")] - public int DatabaseId; - - [QuerySerialize("client_nickname")] - public string NickName; - - [QuerySerialize("client_type")] - public ClientType Type; - } -} diff --git a/src/TeamSpeak3QueryApi/Specialized/Responses/Response.cs b/src/TeamSpeak3QueryApi/Specialized/Responses/Response.cs deleted file mode 100644 index 587cd21..0000000 --- a/src/TeamSpeak3QueryApi/Specialized/Responses/Response.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace TeamSpeak3QueryApi.Net.Specialized.Responses -{ - public abstract class Response : ITeamSpeakSerializable - { } -} diff --git a/src/TeamSpeak3QueryApi/TeamSpeak3QueryApi.csproj b/src/TeamSpeak3QueryApi/TeamSpeak3QueryApi.csproj index 3e01ff1..6d58760 100644 --- a/src/TeamSpeak3QueryApi/TeamSpeak3QueryApi.csproj +++ b/src/TeamSpeak3QueryApi/TeamSpeak3QueryApi.csproj @@ -25,7 +25,8 @@ - + + diff --git a/src/TeamSpeak3QueryApi/Specialized/TeamSpeakClient.cs b/src/TeamSpeak3QueryApi/TeamSpeakClient.cs similarity index 51% rename from src/TeamSpeak3QueryApi/Specialized/TeamSpeakClient.cs rename to src/TeamSpeak3QueryApi/TeamSpeakClient.cs index f57e000..5cf29f7 100644 --- a/src/TeamSpeak3QueryApi/Specialized/TeamSpeakClient.cs +++ b/src/TeamSpeak3QueryApi/TeamSpeakClient.cs @@ -6,10 +6,16 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; -using TeamSpeak3QueryApi.Net.Specialized.Notifications; -using TeamSpeak3QueryApi.Net.Specialized.Responses; - -namespace TeamSpeak3QueryApi.Net.Specialized +using TeamSpeak3QueryApi.Net.FileTransfer; +using TeamSpeak3QueryApi.Net.Query; +using TeamSpeak3QueryApi.Net.Enums; +using TeamSpeak3QueryApi.Net.Extensions; +using TeamSpeak3QueryApi.Net.Query.Parameters; +using TeamSpeak3QueryApi.Net.Query.Responses; +using TeamSpeak3QueryApi.Net.Query.Enums; +using TeamSpeak3QueryApi.Net.Query.Notifications; + +namespace TeamSpeak3QueryApi.Net { public class TeamSpeakClient : IDisposable { @@ -24,27 +30,31 @@ public class TeamSpeakClient : IDisposable /// Creates a new instance of using the and . public TeamSpeakClient() - : this(QueryClient.DefaultHost, QueryClient.DefaultPort) - { } - - /// Creates a new instance of using the provided host and the . - /// The host name of the remote server. - public TeamSpeakClient(string hostName) - : this(hostName, QueryClient.DefaultPort) + : this(QueryClient.DefaultHost, TelnetQueryClient.DefaultPort, Protocol.Telnet) { } /// Creates a new instance of using the provided host TCP port. /// The host name of the remote server. /// The TCP port of the Query API server. - public TeamSpeakClient(string hostName, int port) + public TeamSpeakClient(string hostName, int port = TelnetQueryClient.DefaultPort, Protocol type = Protocol.Telnet) { - Client = new QueryClient(hostName, port); + switch (type) + { + case Protocol.Telnet: + Client = new TelnetQueryClient(hostName, port); + break; + case Protocol.SSH: + Client = new SshQueryClient(hostName, port); + break; + } _fileTransferClient = new FileTransferClient(hostName); } #endregion - public Task Connect() => Client.Connect(); + public Task ConnectAsync() => Client.ConnectAsync(); + public void Connect(string username, string password) => Client.Connect(username, password); + #region Subscriptions @@ -70,7 +80,7 @@ public void Unsubscribe(Action> callback) where T : Notification { var notification = GetNotificationType(); - var cbt = _callbacks.SingleOrDefault(t => t.Item1 == notification && t.Item2 == callback as object); + var cbt = _callbacks.SingleOrDefault(t => t.Item1 == notification && t.Item2.Equals(callback)); if (cbt != null) Client.Unsubscribe(notification.ToString(), cbt.Item3); } @@ -85,38 +95,42 @@ private static NotificationType GetNotificationType() #endregion #region Implented api methods - public Task Login(string userName, string password) + public Task LoginAsync(string userName, string password) { - return Client.Send("login", new Parameter("client_login_name", userName), new Parameter("client_login_password", password)); + if (Client.ConnectionType == Protocol.SSH) + throw new InvalidOperationException("Login is not needed in ssh protocol"); + + return Client.SendAsync("login", new Parameter("client_login_name", userName), new Parameter("client_login_password", password)); } - public Task Logout() => Client.Send("logout"); + public Task LogoutAsync() => Client.SendAsync("logout"); - public Task UseServer(int serverId) + public Task UseServerAsync(int serverId) { - return Client.Send("use", new Parameter("sid", serverId.ToString(CultureInfo.InvariantCulture))); + return Client.SendAsync("use", new Parameter("sid", serverId.ToString(CultureInfo.InvariantCulture))); } - public async Task WhoAmI() + public async Task WhoAmIAsync() { - var res = await Client.Send("whoami").ConfigureAwait(false); + var res = await Client.SendAsync("whoami").ConfigureAwait(false); var proxied = DataProxy.SerializeGeneric(res); return proxied.FirstOrDefault(); } #region Notification Methods - public Task RegisterChannelNotification(int channelId) => RegisterNotification(NotificationEventTarget.Channel, channelId); - public Task RegisterServerNotification() => RegisterNotification(NotificationEventTarget.Server, -1); - public Task RegisterTextServerNotification() => RegisterNotification(NotificationEventTarget.TextServer, -1); - public Task RegisterTextChannelNotification() => RegisterNotification(NotificationEventTarget.TextChannel, -1); - public Task RegisterTextPrivateNotification() => RegisterNotification(NotificationEventTarget.TextPrivate, -1); - private Task RegisterNotification(NotificationEventTarget target, int channelId) + public Task RegisterChannelNotificationAsync(int channelId) => RegisterNotificationAsync(NotificationEventTarget.Channel, channelId); + public Task RegisterAllChannelNotificationAsync() => RegisterNotificationAsync(NotificationEventTarget.Channel, 0); + public Task RegisterServerNotificationAsync() => RegisterNotificationAsync(NotificationEventTarget.Server, -1); + public Task RegisterTextServerNotificationAsync() => RegisterNotificationAsync(NotificationEventTarget.TextServer, -1); + public Task RegisterTextChannelNotificationAsync() => RegisterNotificationAsync(NotificationEventTarget.TextChannel, -1); + public Task RegisterTextPrivateNotificationAsync() => RegisterNotificationAsync(NotificationEventTarget.TextPrivate, -1); + private Task RegisterNotificationAsync(NotificationEventTarget target, int channelId) { var ev = new Parameter("event", target.ToString().ToLowerInvariant()); if (target == NotificationEventTarget.Channel) - return Client.Send("servernotifyregister", ev, new Parameter("id", channelId)); - return Client.Send("servernotifyregister", ev); + return Client.SendAsync("servernotifyregister", ev, new Parameter("id", channelId)); + return Client.SendAsync("servernotifyregister", ev); } #endregion @@ -125,29 +139,29 @@ private Task RegisterNotification(NotificationEventTarget target, int channelId) #region MoveClient - public Task MoveClient(int clientId, int targetChannelId) => MoveClient(new[] { clientId }, targetChannelId); - public Task MoveClient(int clientId, int targetChannelId, string channelPassword) => MoveClient(new[] { clientId }, targetChannelId, channelPassword); + public Task MoveClientAsync(int clientId, int targetChannelId) => MoveClientAsync(new[] { clientId }, targetChannelId); + public Task MoveClientAsync(int clientId, int targetChannelId, string channelPassword) => MoveClientAsync(new[] { clientId }, targetChannelId, channelPassword); - public Task MoveClient(IEnumerable clients, int targetChannelId) + public Task MoveClientAsync(IEnumerable clients, int targetChannelId) { var clIds = clients.Select(c => c.Id).ToArray(); - return MoveClient(clIds, targetChannelId); + return MoveClientAsync(clIds, targetChannelId); } - public Task MoveClient(IEnumerable clients, int targetChannelId, string channelPassword) + public Task MoveClientAsync(IEnumerable clients, int targetChannelId, string channelPassword) { var clIds = clients.Select(c => c.Id).ToArray(); - return MoveClient(clIds, targetChannelId, channelPassword); + return MoveClientAsync(clIds, targetChannelId, channelPassword); } - public Task MoveClient(IList clientIds, int targetChannelId) + public Task MoveClientAsync(IList clientIds, int targetChannelId) { - return Client.Send("clientmove", + return Client.SendAsync("clientmove", new Parameter("clid", clientIds.Select(i => new ParameterValue(i)).ToArray()), new Parameter("cid", targetChannelId)); } - public Task MoveClient(IList clientIds, int targetChannelId, string channelPassword) + public Task MoveClientAsync(IList clientIds, int targetChannelId, string channelPassword) { - return Client.Send("clientmove", + return Client.SendAsync("clientmove", new Parameter("clid", clientIds.Select(i => new ParameterValue(i)).ToArray()), new Parameter("cid", targetChannelId), new Parameter("cpw", channelPassword)); @@ -156,23 +170,23 @@ public Task MoveClient(IList clientIds, int targetChannelId, string channel #endregion #region KickClient - public Task KickClient(int clientId, KickOrigin from) => KickClient(new[] { clientId }, from); - public Task KickClient(int clientId, KickOrigin from, string reasonMessage) => KickClient(new[] { clientId }, from, reasonMessage); - public Task KickClient(GetClientInfo client, KickOrigin from) => KickClient(client.Id, from); - public Task KickClient(IEnumerable clients, KickOrigin from) + public Task KickClientAsync(int clientId, KickOrigin from) => KickClientAsync(new[] { clientId }, from); + public Task KickClientAsync(int clientId, KickOrigin from, string reasonMessage) => KickClientAsync(new[] { clientId }, from, reasonMessage); + public Task KickClientAsync(GetClientInfo client, KickOrigin from) => KickClientAsync(client.Id, from); + public Task KickClientAsync(IEnumerable clients, KickOrigin from, string v) { var clIds = clients.Select(c => c.Id).ToArray(); - return KickClient(clIds, from); + return KickClientAsync(clIds, from); } - public Task KickClient(IList clientIds, KickOrigin from) + public Task KickClientAsync(IList clientIds, KickOrigin from) { - return Client.Send("clientkick", + return Client.SendAsync("clientkick", new Parameter("reasonid", (int)from), new Parameter("clid", clientIds.Select(i => new ParameterValue(i)).ToArray())); } - public Task KickClient(IList clientIds, KickOrigin from, string reasonMessage) + public Task KickClientAsync(IList clientIds, KickOrigin from, string reasonMessage) { - return Client.Send("clientkick", + return Client.SendAsync("clientkick", new Parameter("reasonid", (int)from), new Parameter("reasonmsg", reasonMessage), new Parameter("clid", clientIds.Select(i => new ParameterValue(i)).ToArray())); @@ -181,43 +195,43 @@ public Task KickClient(IList clientIds, KickOrigin from, string reasonMessa #endregion #region BanClient - public Task> BanClient(GetClientInfo client) + public Task> BanClientAsync(GetClientInfo client) { if (client == null) throw new ArgumentNullException(nameof(client)); - return BanClient(client.Id); + return BanClientAsync(client.Id); } - public Task> BanClient(GetClientInfo client, TimeSpan duration) + public Task> BanClientAsync(GetClientInfo client, TimeSpan duration) { if (client == null) throw new ArgumentNullException(nameof(client)); - return BanClient(client.Id, duration); + return BanClientAsync(client.Id, duration); } - public Task> BanClient(GetClientInfo client, TimeSpan duration, string reason) + public Task> BanClientAsync(GetClientInfo client, TimeSpan duration, string reason) { if (client == null) throw new ArgumentNullException(nameof(client)); - return BanClient(client.Id, duration, reason); + return BanClientAsync(client.Id, duration, reason); } - public async Task> BanClient(int clientId) + public async Task> BanClientAsync(int clientId) { - var res = await Client.Send("banclient", + var res = await Client.SendAsync("banclient", new Parameter("clid", clientId)) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> BanClient(int clientId, TimeSpan duration) + public async Task> BanClientAsync(int clientId, TimeSpan duration) { - var res = await Client.Send("banclient", + var res = await Client.SendAsync("banclient", new Parameter("clid", clientId), new Parameter("time", (int)Math.Ceiling(duration.TotalSeconds))) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> BanClient(int clientId, TimeSpan duration, string reason) + public async Task> BanClientAsync(int clientId, TimeSpan duration, string reason) { - var res = await Client.Send("banclient", + var res = await Client.SendAsync("banclient", new Parameter("clid", clientId), new Parameter("time", (int)Math.Ceiling(duration.TotalSeconds)), new Parameter("banreason", reason ?? string.Empty)) @@ -228,43 +242,53 @@ public async Task> BanClient(int clientId, TimeSpan dur #endregion #region GetClients - public async Task> GetClients() + public async Task> GetClientsAsync() { - var res = await Client.Send("clientlist").ConfigureAwait(false); + var res = await Client.SendAsync("clientlist").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> GetClients(GetClientOptions options) + public async Task> GetClientsAsync(GetClientOptions options) { var optionList = options.GetFlagsName(); - var res = await Client.Send("clientlist", null, optionList.ToArray()).ConfigureAwait(false); + var res = await Client.SendAsync("clientlist", null, optionList.ToArray()).ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public Task GetClientInfo(GetClientInfo client) => GetClientInfo(client.Id); + public Task GetClientInfoAsync(GetClientInfo client) => GetClientInfoAsync(client.Id); - public async Task GetClientInfo(int clientId) + public async Task GetClientInfoAsync(int clientId) { - var res = await Client.Send("clientinfo", + var res = await Client.SendAsync("clientinfo", new Parameter("clid", clientId)) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res).FirstOrDefault(); } + public async Task> GetDbClientsAsync(int start = 0, long duration = 9999999999) // Duration must be that long cause without this parameters it won't work. Bug from Teamspeak... + { + var res = await Client.SendAsync("clientdblist", + new Parameter("start", start), + new Parameter("duration", duration)) + .ConfigureAwait(false); + + return DataProxy.SerializeGeneric(res); + } + #endregion #region GetServerGroups - public async Task> GetServerGroups(int clientDatabaseId) + public async Task> GetServerGroupsAsync(int clientDatabaseId) { - var res = await Client.Send("servergroupsbyclientid", new Parameter("cldbid", clientDatabaseId)).ConfigureAwait(false); + var res = await Client.SendAsync("servergroupsbyclientid", new Parameter("cldbid", clientDatabaseId)).ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public Task> GetServerGroups(GetClientInfo clientInfo) => GetServerGroups(clientInfo.DatabaseId); + public Task> GetServerGroupsAsync(GetClientInfo clientInfo) => GetServerGroupsAsync(clientInfo.DatabaseId); - public Task> GetServerGroups(WhoAmI clientInfo) => GetServerGroups(clientInfo.DatabaseId); + public Task> GetServerGroupsAsync(WhoAmI clientInfo) => GetServerGroupsAsync(clientInfo.DatabaseId); #endregion @@ -272,27 +296,27 @@ public async Task> GetServerGroups(int clientDatab #region One User - public Task AddServerGroup(int serverGroupId, int clientDatabaseId) => AddServerGroup(serverGroupId, new int[] { clientDatabaseId }); + public Task AddServerGroupAsync(int serverGroupId, int clientDatabaseId) => AddServerGroupAsync(serverGroupId, new int[] { clientDatabaseId }); - public Task AddServerGroup(int serverGroupId, GetClientInfo clientInfo) => AddServerGroup(serverGroupId, clientInfo.DatabaseId); + public Task AddServerGroupAsync(int serverGroupId, GetClientInfo clientInfo) => AddServerGroupAsync(serverGroupId, clientInfo.DatabaseId); - public Task AddServerGroup(GetServerGroup serverGroup, int clientDatabaseId) => AddServerGroup(serverGroup.Id, clientDatabaseId); + public Task AddServerGroupAsync(GetServerGroup serverGroup, int clientDatabaseId) => AddServerGroupAsync(serverGroup.Id, clientDatabaseId); - public Task AddServerGroup(GetServerGroup serverGroup, GetClientInfo clientInfo) => AddServerGroup(serverGroup.Id, clientInfo.DatabaseId); + public Task AddServerGroupAsync(GetServerGroup serverGroup, GetClientInfo clientInfo) => AddServerGroupAsync(serverGroup.Id, clientInfo.DatabaseId); #endregion #region Multiple Users - public Task AddServerGroup(int serverGroupId, IEnumerable clientInfo) => AddServerGroup(serverGroupId, clientInfo.Select(info => info.DatabaseId)); + public Task AddServerGroupAsync(int serverGroupId, IEnumerable clientInfo) => AddServerGroupAsync(serverGroupId, clientInfo.Select(info => info.DatabaseId)); - public Task AddServerGroup(GetServerGroup serverGroup, IEnumerable clientDatabaseIds) => AddServerGroup(serverGroup.Id, clientDatabaseIds); + public Task AddServerGroupAsync(GetServerGroup serverGroup, IEnumerable clientDatabaseIds) => AddServerGroupAsync(serverGroup.Id, clientDatabaseIds); - public Task AddServerGroup(GetServerGroup serverGroup, IEnumerable clientInfo) => AddServerGroup(serverGroup.Id, clientInfo.Select(info => info.DatabaseId)); + public Task AddServerGroupAsync(GetServerGroup serverGroup, IEnumerable clientInfo) => AddServerGroupAsync(serverGroup.Id, clientInfo.Select(info => info.DatabaseId)); - public Task AddServerGroup(int serverGroupId, IEnumerable clientDatabaseIds) + public Task AddServerGroupAsync(int serverGroupId, IEnumerable clientDatabaseIds) { - return Client.Send("servergroupaddclient", + return Client.SendAsync("servergroupaddclient", new Parameter("sgid", serverGroupId), new Parameter("cldbid", clientDatabaseIds.Select(id => new ParameterValue(id)).ToArray())); } @@ -305,27 +329,27 @@ public Task AddServerGroup(int serverGroupId, IEnumerable clientDatabaseIds #region One User - public Task RemoveServerGroup(int serverGroupId, int clientDatabaseId) => RemoveServerGroup(serverGroupId, new int[] { clientDatabaseId }); + public Task RemoveServerGroupAsync(int serverGroupId, int clientDatabaseId) => RemoveServerGroupAsync(serverGroupId, new int[] { clientDatabaseId }); - public Task RemoveServerGroup(int serverGroupId, GetClientInfo clientInfo) => RemoveServerGroup(serverGroupId, clientInfo.DatabaseId); + public Task RemoveServerGroupAsync(int serverGroupId, GetClientInfo clientInfo) => RemoveServerGroupAsync(serverGroupId, clientInfo.DatabaseId); - public Task RemoveServerGroup(GetServerGroup serverGroup, int clientDatabaseId) => RemoveServerGroup(serverGroup.Id, clientDatabaseId); + public Task RemoveServerGroupAsync(GetServerGroup serverGroup, int clientDatabaseId) => RemoveServerGroupAsync(serverGroup.Id, clientDatabaseId); - public Task RemoveServerGroup(GetServerGroup serverGroup, GetClientInfo clientInfo) => RemoveServerGroup(serverGroup.Id, clientInfo.DatabaseId); + public Task RemoveServerGroupAsync(GetServerGroup serverGroup, GetClientInfo clientInfo) => RemoveServerGroupAsync(serverGroup.Id, clientInfo.DatabaseId); #endregion #region Multiple Users - public Task RemoveServerGroup(int serverGroupId, IEnumerable clientInfo) => RemoveServerGroup(serverGroupId, clientInfo.Select(info => info.DatabaseId)); + public Task RemoveServerGroupAsync(int serverGroupId, IEnumerable clientInfo) => RemoveServerGroupAsync(serverGroupId, clientInfo.Select(info => info.DatabaseId)); - public Task RemoveServerGroup(GetServerGroup serverGroup, IEnumerable clientDatabaseIds) => RemoveServerGroup(serverGroup.Id, clientDatabaseIds); + public Task RemoveServerGroupAsync(GetServerGroup serverGroup, IEnumerable clientDatabaseIds) => RemoveServerGroupAsync(serverGroup.Id, clientDatabaseIds); - public Task RemoveServerGroup(GetServerGroup serverGroup, IEnumerable clientInfo) => RemoveServerGroup(serverGroup.Id, clientInfo.Select(info => info.DatabaseId)); + public Task RemoveServerGroupAsync(GetServerGroup serverGroup, IEnumerable clientInfo) => RemoveServerGroupAsync(serverGroup.Id, clientInfo.Select(info => info.DatabaseId)); - public Task RemoveServerGroup(int serverGroupId, IEnumerable clientDatabaseIds) + public Task RemoveServerGroupAsync(int serverGroupId, IEnumerable clientDatabaseIds) { - return Client.Send("servergroupdelclient", + return Client.SendAsync("servergroupdelclient", new Parameter("sgid", serverGroupId), new Parameter("cldbid", clientDatabaseIds.Select(id => new ParameterValue(id)).ToArray())); } @@ -340,32 +364,32 @@ public Task RemoveServerGroup(int serverGroupId, IEnumerable clientDatabase #region GetChannels - public async Task> GetChannels() + public async Task> GetChannelsAsync() { - var res = await Client.Send("channellist").ConfigureAwait(false); + var res = await Client.SendAsync("channellist").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> GetChannels(GetChannelOptions options) + public async Task> GetChannelsAsync(GetChannelOptions options) { var optionList = options.GetFlagsName(); - var res = await Client.Send("channellist", null, optionList.ToArray()).ConfigureAwait(false); + var res = await Client.SendAsync("channellist", null, optionList.ToArray()).ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } #endregion #region GetChannelInfo - public Task GetChannelInfo(GetChannelListInfo channel) + public Task GetChannelInfoAsync(GetChannelListInfo channel) { if (channel == null) throw new ArgumentNullException(nameof(channel)); - return GetChannelInfo(channel.Id); + return GetChannelInfoAsync(channel.Id); } - public async Task GetChannelInfo(int channelId) + public async Task GetChannelInfoAsync(int channelId) { - var res = await Client.Send("channelinfo", + var res = await Client.SendAsync("channelinfo", new Parameter("cid", channelId)) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res).FirstOrDefault(); @@ -374,14 +398,14 @@ public async Task GetChannelInfo(int channelId) #endregion #region FindChannel - public async Task> FindChannel() + public async Task> FindChannelAsync() { - var res = await Client.Send("channelfind").ConfigureAwait(false); + var res = await Client.SendAsync("channelfind").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> FindChannel(string pattern) + public async Task> FindChannelAsync(string pattern) { - var res = await Client.Send("channelfind", + var res = await Client.SendAsync("channelfind", new Parameter("pattern", pattern ?? string.Empty)) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res); @@ -390,32 +414,32 @@ public async Task> FindChannel(string pattern) #endregion #region MoveChannel - public Task MoveChannel(GetChannelListInfo channel, GetChannelListInfo parent) + public Task MoveChannelAsync(GetChannelListInfo channel, GetChannelListInfo parent) { if (channel == null) throw new ArgumentNullException(nameof(channel)); if (parent == null) throw new ArgumentNullException(nameof(parent)); - return MoveChannel(channel.Id, parent.Id); + return MoveChannelAsync(channel.Id, parent.Id); } - public Task MoveChannel(GetChannelListInfo channel, GetChannelListInfo parent, int order) + public Task MoveChannelAsync(GetChannelListInfo channel, GetChannelListInfo parent, int order) { if (channel == null) throw new ArgumentNullException(nameof(channel)); if (parent == null) throw new ArgumentNullException(nameof(parent)); - return MoveChannel(channel.Id, parent.Id, order); + return MoveChannelAsync(channel.Id, parent.Id, order); } - public Task MoveChannel(int channelId, int parentChannelId) + public Task MoveChannelAsync(int channelId, int parentChannelId) { - return Client.Send("channelmove", + return Client.SendAsync("channelmove", new Parameter("cid", channelId), new Parameter("cpid", parentChannelId)); } - public Task MoveChannel(int channelId, int parentChannelId, int order) + public Task MoveChannelAsync(int channelId, int parentChannelId, int order) { - return Client.Send("channelmove", + return Client.SendAsync("channelmove", new Parameter("cid", channelId), new Parameter("cpid", parentChannelId), new Parameter("order", order)); @@ -426,41 +450,78 @@ public Task MoveChannel(int channelId, int parentChannelId, int order) // Region setting properties not supported yet - public async Task CreateChannel(string name) + public async Task CreateChannelAsync(string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - var res = await Client.Send("channelcreate", + var res = await Client.SendAsync("channelcreate", new Parameter("channel_name", name)) .ConfigureAwait(false); return DataProxy.SerializeGeneric(res).FirstOrDefault(); } + public async Task CreateChannelAsync(string name, EditChannelInfo channel) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + + var addParameters = new List + { + new Parameter("channel_name", name), + }; + + if (channel.Topic != null) { addParameters.Add(new Parameter("channel_topic", channel.Topic)); } + if (channel.Description != null) { addParameters.Add(new Parameter("channel_description", channel.Description)); } + if (channel.Password != null) { addParameters.Add(new Parameter("channel_password", channel.Password)); } + if (channel.Codec != null) { addParameters.Add(new Parameter("channel_codec", (int)channel.Codec)); } + if (channel.CodecQuality != null) { addParameters.Add(new Parameter("channel_codec_quality", channel.CodecQuality)); } + if (channel.MaxClients != null) { addParameters.Add(new Parameter("channel_maxclients", channel.MaxClients)); } + if (channel.MaxFamilyClients != null) { addParameters.Add(new Parameter("channel_maxfamilyclients", channel.MaxFamilyClients)); } + if (channel.Order != null) { addParameters.Add(new Parameter("channel_order", channel.Order)); } + if (channel.IsPermanent != null) { addParameters.Add(new Parameter("channel_flag_permanent", channel.IsPermanent)); } + if (channel.IsSemiPermanent != null) { addParameters.Add(new Parameter("channel_flag_semi_permanent", channel.IsSemiPermanent)); } + if (channel.IsTemporary != null) { addParameters.Add(new Parameter("channel_flag_temporary", channel.IsTemporary)); } + if (channel.IsDefaultChannel != null) { addParameters.Add(new Parameter("channel_flag_default", channel.IsDefaultChannel)); } + if (channel.IsMaxClientsUnlimited != null) { addParameters.Add(new Parameter("channel_flag_maxclients_unlimited", channel.IsMaxClientsUnlimited)); } + if (channel.IsMaxFamilyClientsUnlimited != null) { addParameters.Add(new Parameter("channel_flag_maxfamilyclients_unlimited", channel.IsMaxFamilyClientsUnlimited)); } + if (channel.IsMaxFamilyClientsInherited != null) { addParameters.Add(new Parameter("channel_flag_maxfamilyclients_inherited", channel.IsMaxFamilyClientsInherited)); } + if (channel.NeededTalkPower != null) { addParameters.Add(new Parameter("channel_needed_talk_power", channel.NeededTalkPower)); } + if (channel.PhoneticName != null) { addParameters.Add(new Parameter("channel_name_phonetic", channel.PhoneticName)); } + if (channel.IconId != null) { addParameters.Add(new Parameter("channel_icon_id", (int)channel.IconId)); } + if (channel.IsCodecUnencrypted != null) { addParameters.Add(new Parameter("channel_codec_is_unencrypted", channel.IsCodecUnencrypted)); } + if (channel.ParentChannelId != null) { addParameters.Add(new Parameter("cpid", channel.ParentChannelId)); } + + var res = await Client + .SendAsync("channelcreate", addParameters.ToArray()) + .ConfigureAwait(false); + return DataProxy.SerializeGeneric(res).FirstOrDefault(); + } + #endregion #region DeleteChannel - public Task DeleteChannel(GetChannelListInfo channel) + public Task DeleteChannelAsync(GetChannelListInfo channel) { if (channel == null) throw new ArgumentNullException(nameof(channel)); - return DeleteChannel(channel.Id); + return DeleteChannelAsync(channel.Id); } - public Task DeleteChannel(GetChannelListInfo channel, bool force) + public Task DeleteChannelAsync(GetChannelListInfo channel, bool force) { if (channel == null) throw new ArgumentNullException(nameof(channel)); - return DeleteChannel(channel.Id, force); + return DeleteChannelAsync(channel.Id, force); } - public Task DeleteChannel(int channelId) + public Task DeleteChannelAsync(int channelId) { - return Client.Send("channeldelete", + return Client.SendAsync("channeldelete", new Parameter("cid", channelId)); } - public Task DeleteChannel(int channelId, bool force) + public Task DeleteChannelAsync(int channelId, bool force) { - return Client.Send("channeldelete", + return Client.SendAsync("channeldelete", new Parameter("cid", channelId), new Parameter("force", force)); } @@ -468,7 +529,7 @@ public Task DeleteChannel(int channelId, bool force) #endregion #region EditChannel - public Task EditChannel(int channelId, EditChannelInfo channel) + public Task EditChannelAsync(int channelId, EditChannelInfo channel) { var updateParameters = new List { @@ -495,16 +556,16 @@ public Task EditChannel(int channelId, EditChannelInfo channel) if (channel.PhoneticName != null) { updateParameters.Add(new Parameter("channel_name_phonetic", channel.PhoneticName)); } if (channel.IconId != null) { updateParameters.Add(new Parameter("channel_icon_id", (int)channel.IconId)); } if (channel.IsCodecUnencrypted != null) { updateParameters.Add(new Parameter("channel_codec_is_unencrypted", channel.IsCodecUnencrypted)); } - if (channel.ParentChannelId != null) { updateParameters.Add(new Parameter("channel_cpid", channel.ParentChannelId)); } + if (channel.ParentChannelId != null) { updateParameters.Add(new Parameter("cpid", channel.ParentChannelId)); } - return Client.Send("channeledit", updateParameters.ToArray()); + return Client.SendAsync("channeledit", updateParameters.ToArray()); } #endregion #region ChannelAddPerm - public Task ChannelAddPerm(int channelId, string permsId, int permValue) + public Task ChannelAddPermAsync(int channelId, string permsId, int permValue) { - return Client.Send("channeladdperm", + return Client.SendAsync("channeladdperm", new Parameter("cid", channelId), new Parameter("permsid", permsId), new Parameter("permvalue", permValue)); @@ -517,28 +578,28 @@ public Task ChannelAddPerm(int channelId, string permsId, int permValue) #region GetServers - public async Task> GetServers() + public async Task> GetServersAsync() { - var res = await Client.Send("serverlist").ConfigureAwait(false); + var res = await Client.SendAsync("serverlist").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> GetServers(GetServerOptions options) + public async Task> GetServersAsync(GetServerOptions options) { var optionList = options.GetFlagsName(); - var res = await Client.Send("serverlist", null, optionList.ToArray()).ConfigureAwait(false); + var res = await Client.SendAsync("serverlist", null, optionList.ToArray()).ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> GetServerGroups() + public async Task> GetServerGroupsAsync() { - var res = await Client.Send("servergrouplist").ConfigureAwait(false); + var res = await Client.SendAsync("servergrouplist").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } - public async Task> GetServerGroupClientList(int serverGroupDatabaseId) + public async Task> GetServerGroupClientListAsync(int serverGroupDatabaseId) { - var res = await Client.Send("servergroupclientlist", new Parameter("sgid", serverGroupDatabaseId)).ConfigureAwait(false); + var res = await Client.SendAsync("servergroupclientlist", new Parameter("sgid", serverGroupDatabaseId)).ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } @@ -550,28 +611,28 @@ public async Task> GetServerGroupClientL #region SendTextMessage - public Task SendMessage(string message, GetServerListInfo targetServer) + public Task SendMessageAsync(string message, GetServerListInfo targetServer) { if (targetServer == null) throw new ArgumentNullException(nameof(targetServer)); - return SendMessage(message, MessageTarget.Server, targetServer.Id); + return SendMessageAsync(message, MessageTarget.Server, targetServer.Id); } - public Task SendMessage(string message, GetChannelListInfo targetChannel) + public Task SendMessageAsync(string message, GetChannelListInfo targetChannel) { if (targetChannel == null) throw new ArgumentNullException(nameof(targetChannel)); - return SendMessage(message, MessageTarget.Channel, targetChannel.Id); + return SendMessageAsync(message, MessageTarget.Channel, targetChannel.Id); } - public Task SendMessage(string message, GetClientInfo targetClient) + public Task SendMessageAsync(string message, GetClientInfo targetClient) { if (targetClient == null) throw new ArgumentNullException(nameof(targetClient)); - return SendMessage(message, MessageTarget.Private, targetClient.Id); + return SendMessageAsync(message, MessageTarget.Private, targetClient.Id); } - public Task SendMessage(string message, MessageTarget target, int targetId) + public Task SendMessageAsync(string message, MessageTarget target, int targetId) { message = message ?? string.Empty; - return Client.Send("sendtextmessage", + return Client.SendAsync("sendtextmessage", new Parameter("targetmode", (int)target), new Parameter("target", targetId), new Parameter("msg", message)); @@ -580,35 +641,35 @@ public Task SendMessage(string message, MessageTarget target, int targetId) #endregion #region SendGlobalMessage - public Task SendGlobalMessage(string message) + public Task SendGlobalMessageAsync(string message) { - return Client.Send("gm", + return Client.SendAsync("gm", new Parameter("msg", message ?? string.Empty)); } #endregion #region PokeClient - public Task PokeClient(GetClientInfo client) + public Task PokeClientAsync(GetClientInfo client) { if (client == null) throw new ArgumentNullException(nameof(client)); - return PokeClient(client.Id); + return PokeClientAsync(client.Id); } - public Task PokeClient(int clientId) + public Task PokeClientAsync(int clientId) { - return PokeClient(clientId, string.Empty); + return PokeClientAsync(clientId, string.Empty); } - public Task PokeClient(GetClientInfo client, string message) + public Task PokeClientAsync(GetClientInfo client, string message) { if (client == null) throw new ArgumentNullException(nameof(client)); - return PokeClient(client.Id, message); + return PokeClientAsync(client.Id, message); } - public Task PokeClient(int clientId, string message) + public Task PokeClientAsync(int clientId, string message) { - return Client.Send("clientpoke", + return Client.SendAsync("clientpoke", new Parameter("msg", message ?? string.Empty), new Parameter("clid", clientId)); } @@ -616,13 +677,13 @@ public Task PokeClient(int clientId, string message) #endregion #region ChangeNickName - public Task ChangeNickName(string nickName) => ChangeNickName(nickName, default); + public Task ChangeNickNameAsync(string nickName) => ChangeNickNameAsync(nickName, default); - public Task ChangeNickName(string nickName, WhoAmI whoAmI) + public Task ChangeNickNameAsync(string nickName, WhoAmI whoAmI) { if (whoAmI != null) whoAmI.NickName = nickName; - return Client.Send("clientupdate", + return Client.SendAsync("clientupdate", new Parameter("client_nickname", nickName)); } #endregion @@ -633,11 +694,11 @@ public Task ChangeNickName(string nickName, WhoAmI whoAmI) #region CreateDirectory - public Task CreateDirectory(int channelId, string dirPath) => CreateDirectory(channelId, string.Empty, dirPath); + public Task CreateDirectoryAsync(int channelId, string dirPath) => CreateDirectoryAsync(channelId, string.Empty, dirPath); - public Task CreateDirectory(int channelId, string channelPassword, string dirPath) + public Task CreateDirectoryAsync(int channelId, string channelPassword, string dirPath) { - return Client.Send("ftcreatedir", + return Client.SendAsync("ftcreatedir", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("dirname", NormalizePath(dirPath))); @@ -647,15 +708,15 @@ public Task CreateDirectory(int channelId, string channelPassword, string dirPat #region DeleteFile - public Task DeleteFile(int channelId, string filePath) => DeleteFile(channelId, string.Empty, new string[] { filePath }); + public Task DeleteFileAsync(int channelId, string filePath) => DeleteFileAsync(channelId, string.Empty, new string[] { filePath }); - public Task DeleteFile(int channelId, string channelPassword, string filePath) => DeleteFile(channelId, channelPassword, new string[] { filePath }); + public Task DeleteFileAsync(int channelId, string channelPassword, string filePath) => DeleteFileAsync(channelId, channelPassword, new string[] { filePath }); - public Task DeleteFile(int channelId, IEnumerable filePaths) => DeleteFile(channelId, string.Empty, filePaths); + public Task DeleteFileAsync(int channelId, IEnumerable filePaths) => DeleteFileAsync(channelId, string.Empty, filePaths); - public Task DeleteFile(int channelId, string channelPassword, IEnumerable filePaths) + public Task DeleteFileAsync(int channelId, string channelPassword, IEnumerable filePaths) { - return Client.Send("ftdeletefile", + return Client.SendAsync("ftdeletefile", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("name", filePaths.Select(path => new ParameterValue(NormalizePath(path))).ToArray())); @@ -665,11 +726,11 @@ public Task DeleteFile(int channelId, string channelPassword, IEnumerable GetFileInfo(int channelId, string filePath) => GetFileInfo(channelId, string.Empty, filePath); + public Task GetFileInfoAsync(int channelId, string filePath) => GetFileInfoAsync(channelId, string.Empty, filePath); - public async Task GetFileInfo(int channelId, string channelPassword, string filePath) + public async Task GetFileInfoAsync(int channelId, string channelPassword, string filePath) { - var res = await Client.Send("ftgetfileinfo", + var res = await Client.SendAsync("ftgetfileinfo", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("name", NormalizePath(filePath))).ConfigureAwait(false); @@ -681,13 +742,13 @@ public async Task GetFileInfo(int channelId, string channelPassword #region GetFileList - public Task> GetFiles(int channelId) => GetFiles(channelId, string.Empty, "/"); + public Task> GetFilesAsync(int channelId) => GetFilesAsync(channelId, string.Empty, "/"); - public Task> GetFiles(int channelId, string dirPath) => GetFiles(channelId, string.Empty, dirPath); + public Task> GetFilesAsync(int channelId, string dirPath) => GetFilesAsync(channelId, string.Empty, dirPath); - public async Task> GetFiles(int channelId, string channelPassword, string dirPath) + public async Task> GetFilesAsync(int channelId, string channelPassword, string dirPath) { - var res = await Client.Send("ftgetfilelist", + var res = await Client.SendAsync("ftgetfilelist", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("path", NormalizePath(dirPath))).ConfigureAwait(false); @@ -701,11 +762,11 @@ public async Task> GetFiles(int channelId, string channe #region Same Channel - public Task MoveFile(int channelId, string oldFilePath, string newFilePath) => MoveFile(channelId, string.Empty, oldFilePath, newFilePath); + public Task MoveFileAsync(int channelId, string oldFilePath, string newFilePath) => MoveFileAsync(channelId, string.Empty, oldFilePath, newFilePath); - public Task MoveFile(int channelId, string channelPassword, string oldFilePath, string newFilePath) + public Task MoveFileAsync(int channelId, string channelPassword, string oldFilePath, string newFilePath) { - return Client.Send("ftrenamefile", + return Client.SendAsync("ftrenamefile", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("oldname", NormalizePath(oldFilePath)), @@ -716,15 +777,15 @@ public Task MoveFile(int channelId, string channelPassword, string oldFilePath, #region Other Channel - public Task MoveFile(int channelId, string oldFilePath, int targetChannelId, string newFilePath) => MoveFile(channelId, string.Empty, oldFilePath, targetChannelId, string.Empty, newFilePath); + public Task MoveFileAsync(int channelId, string oldFilePath, int targetChannelId, string newFilePath) => MoveFileAsync(channelId, string.Empty, oldFilePath, targetChannelId, string.Empty, newFilePath); - public Task MoveFile(int channelId, string channelPassword, string oldFilePath, int targetChannelId, string newFilePath) => MoveFile(channelId, channelPassword, oldFilePath, targetChannelId, string.Empty, newFilePath); + public Task MoveFileAsync(int channelId, string channelPassword, string oldFilePath, int targetChannelId, string newFilePath) => MoveFileAsync(channelId, channelPassword, oldFilePath, targetChannelId, string.Empty, newFilePath); - public Task MoveFile(int channelId, string oldFilePath, int targetChannelId, string targetChannelPassword, string newFilePath) => MoveFile(channelId, string.Empty, oldFilePath, targetChannelId, targetChannelPassword, newFilePath); + public Task MoveFileAsync(int channelId, string oldFilePath, int targetChannelId, string targetChannelPassword, string newFilePath) => MoveFileAsync(channelId, string.Empty, oldFilePath, targetChannelId, targetChannelPassword, newFilePath); - public Task MoveFile(int channelId, string channelPassword, string oldFilePath, int targetChannelId, string targetChannelPassword, string newFilePath) + public Task MoveFileAsync(int channelId, string channelPassword, string oldFilePath, int targetChannelId, string targetChannelPassword, string newFilePath) { - return Client.Send("ftrenamefile", + return Client.SendAsync("ftrenamefile", new Parameter("cid", channelId), new Parameter("cpw", channelPassword), new Parameter("tcid", targetChannelId), @@ -739,11 +800,11 @@ public Task MoveFile(int channelId, string channelPassword, string oldFilePath, #region UploadFile - public Task UploadFile(int channelId, string filePath, byte[] data, bool overwrite = true, bool verify = true) => UploadFile(channelId, string.Empty, filePath, data, overwrite, verify); + public Task UploadFileAsync(int channelId, string filePath, byte[] data, bool overwrite = true, bool verify = true) => UploadFileAsync(channelId, string.Empty, filePath, data, overwrite, verify); - public async Task UploadFile(int channelId, string channelPassword, string filePath, byte[] data, bool overwrite = true, bool verify = true) + public async Task UploadFileAsync(int channelId, string channelPassword, string filePath, byte[] data, bool overwrite = true, bool verify = true) { - var res = await Client.Send("ftinitupload", + var res = await Client.SendAsync("ftinitupload", new Parameter("clientftfid", _fileTransferClient.GetFileTransferId()), new Parameter("cid", channelId), new Parameter("cpw", channelPassword), @@ -754,19 +815,19 @@ public async Task UploadFile(int channelId, string channelPassword, string fileP var parsedRes = DataProxy.SerializeGeneric(res).First(); - await _fileTransferClient.SendFile(data, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); + await _fileTransferClient.SendFileAsync(data, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); if (verify) { - await VerifyUpload(parsedRes.ServerFileTransferId).ConfigureAwait(false); + await VerifyUploadAsync(parsedRes.ServerFileTransferId).ConfigureAwait(false); } } - public Task UploadFile(int channelId, string filePath, Stream dataStream, long size, bool overwrite = true, bool verify = true) => UploadFile(channelId, string.Empty, filePath, dataStream, size, overwrite, verify); + public Task UploadFileAsync(int channelId, string filePath, Stream dataStream, long size, bool overwrite = true, bool verify = true) => UploadFileAsync(channelId, string.Empty, filePath, dataStream, size, overwrite, verify); - public async Task UploadFile(int channelId, string channelPassword, string filePath, Stream dataStream, long size, bool overwrite = true, bool verify = true) + public async Task UploadFileAsync(int channelId, string channelPassword, string filePath, Stream dataStream, long size, bool overwrite = true, bool verify = true) { - var res = await Client.Send("ftinitupload", + var res = await Client.SendAsync("ftinitupload", new Parameter("clientftfid", _fileTransferClient.GetFileTransferId()), new Parameter("cid", channelId), new Parameter("cpw", channelPassword), @@ -777,16 +838,16 @@ public async Task UploadFile(int channelId, string channelPassword, string fileP var parsedRes = DataProxy.SerializeGeneric(res).First(); - await _fileTransferClient.SendFile(dataStream, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); + await _fileTransferClient.SendFileAsync(dataStream, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); if (verify) { - await VerifyUpload(parsedRes.ServerFileTransferId).ConfigureAwait(false); + await VerifyUploadAsync(parsedRes.ServerFileTransferId).ConfigureAwait(false); } } /// Waits until the server fully receives the file or throws an exception when the upload times out. - private async Task VerifyUpload(int serverFileTransferId) + private async Task VerifyUploadAsync(int serverFileTransferId) { long arrivedBytes = 0; var intervalMillis = 100; @@ -795,7 +856,7 @@ private async Task VerifyUpload(int serverFileTransferId) while (true) { - var transfers = await GetCurrentFileTransfers(); + var transfers = await GetCurrentFileTransfersAsync(); var currentTransfer = transfers.Where(transfer => transfer.ServerFileTransferId == serverFileTransferId).FirstOrDefault(); if (currentTransfer == null) @@ -813,7 +874,7 @@ private async Task VerifyUpload(int serverFileTransferId) { try { - await StopFileTransfer(serverFileTransferId).ConfigureAwait(false); + await StopFileTransferAsync(serverFileTransferId).ConfigureAwait(false); } catch { } @@ -836,11 +897,11 @@ private async Task VerifyUpload(int serverFileTransferId) #region DownloadFile - public Task DownloadFile(int channelId, string filePath) => DownloadFile(channelId, string.Empty, filePath); + public Task DownloadFileAsync(int channelId, string filePath) => DownloadFileAsync(channelId, string.Empty, filePath); - public async Task DownloadFile(int channelId, string channelPassword, string filePath) + public async Task DownloadFileAsync(int channelId, string channelPassword, string filePath) { - var res = await Client.Send("ftinitdownload", + var res = await Client.SendAsync("ftinitdownload", new Parameter("clientftfid", _fileTransferClient.GetFileTransferId()), new Parameter("cid", channelId), new Parameter("cpw", channelPassword), @@ -854,18 +915,18 @@ public async Task DownloadFile(int channelId, string channelPassword, st throw new FileTransferException("The file is too big for a single byte array."); } - return await _fileTransferClient.ReceiveFile((int)parsedRes.Size, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); + return await _fileTransferClient.ReceiveFileAsync((int)parsedRes.Size, parsedRes.Port, parsedRes.FileTransferKey).ConfigureAwait(false); } #endregion #region GetCurrentFileTransfers - public async Task> GetCurrentFileTransfers() + public async Task> GetCurrentFileTransfersAsync() { try { - var res = await Client.Send("ftlist").ConfigureAwait(false); + var res = await Client.SendAsync("ftlist").ConfigureAwait(false); return DataProxy.SerializeGeneric(res); } @@ -885,9 +946,9 @@ public async Task> GetCurrentFileTransfers #endregion - private Task StopFileTransfer(int serverFileTransferId, bool delete = true) + private Task StopFileTransferAsync(int serverFileTransferId, bool delete = true) { - return Client.Send("ftstop", + return Client.SendAsync("ftstop", new Parameter("serverftfid", serverFileTransferId), new Parameter("delete", delete)); } diff --git a/src/TeamSpeak3QueryApi/ValidationHelper.cs b/src/TeamSpeak3QueryApi/ValidationHelper.cs index 74a1a7a..9b87eac 100644 --- a/src/TeamSpeak3QueryApi/ValidationHelper.cs +++ b/src/TeamSpeak3QueryApi/ValidationHelper.cs @@ -1,17 +1,17 @@ using System; using System.Collections.Generic; -using System.Net; +using System.Net; using System.Text; namespace TeamSpeak3QueryApi { internal class ValidationHelper - { + { /// /// on false, API should throw new ArgumentOutOfRangeException("port"); /// /// - /// + /// public static bool ValidateTcpPort(int port) => port >= IPEndPoint.MinPort && port <= IPEndPoint.MaxPort; } }