diff --git a/src/client/NP/NPClient.cs b/src/client/NP/NPClient.cs index 347cedd..4eb8485 100644 --- a/src/client/NP/NPClient.cs +++ b/src/client/NP/NPClient.cs @@ -1,147 +1,147 @@ -using System; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using log4net; -using NPSharp.RPC; -using NPSharp.RPC.Messages.Client; -using NPSharp.RPC.Messages.Server; - -namespace NPSharp.NP -{ - /// - /// Represents a high-level network platform client. - /// - public class NPClient - { - private readonly string _host; - private readonly ILog _log; - private readonly ushort _port; - private CancellationToken _cancellationToken; - private CancellationTokenSource _cancellationTokenSource; - private RPCClientStream _rpc; - - /// - /// Initializes the NP client with a specified host and port. - /// - /// The host to connect to. - /// The port to use. Default: 3025. - public NPClient(string host, ushort port = 3025) - { - _host = host; - _port = port; - _log = LogManager.GetLogger("NPClient"); - } - - /// - /// The internal RPC client. +using System; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using log4net; +using NPSharp.RPC; +using NPSharp.RPC.Messages.Client; +using NPSharp.RPC.Messages.Server; + +namespace NPSharp.NP +{ + /// + /// Represents a high-level network platform client. + /// + public class NPClient + { + private readonly string _host; + private readonly ILog _log; + private readonly ushort _port; + private CancellationToken _cancellationToken; + private CancellationTokenSource _cancellationTokenSource; + private RPCClientStream _rpc; + + /// + /// Initializes the NP client with a specified host and port. /// - public RPCClientStream RPCClient { get { return _rpc; } } - - /// - /// The assigned NP user ID. Will be set on successful authentication. - /// - public ulong LoginId { get; private set; } - - /// - /// The assigned session token for this client. Will be set on successful authentication. - /// - public string SessionToken { get; private set; } - - // TODO: Handle connection failures via exception - /// - /// Connects the client to the NP server. - /// - /// True if the connection succeeded, otherwise false. - public bool Connect() - { - _log.Debug("Connect() start"); - - _cancellationTokenSource = new CancellationTokenSource(); - _cancellationToken = _cancellationTokenSource.Token; - - try - { - _rpc = RPCClientStream.Open(_host, _port); - } - catch (Exception err) - { -#if DEBUG - _log.ErrorFormat(@"Could not initialize RPC: {0}", err); -#else - _log.ErrorFormat(@"Could not initialize RPC: {0}", err.Message); -#endif - return false; - } - - Task.Factory.StartNew(() => - { - _log.Debug("Now receiving RPC messages"); - try - { - while (true) - { - if (_rpc.Read() == null) - break; - } - } - catch (ProtocolViolationException error) - { - _log.ErrorFormat("Protocol violation: {0}. Disconnect imminent.", error.Message); - Disconnect(); - } - - _log.Debug("Now not receiving RPC messages anymore"); - }, _cancellationToken); - - _log.Debug("Connect() done"); - return true; - } - - /// - /// Disconnects the client from the NP server. - /// - public void Disconnect() - { - _log.Debug("Disconnect() start"); - - _cancellationTokenSource.Cancel(true); - // TODO: Find a cleaner way to cancel _processingTask (focus: _rpc.Read) - //_procTask.Wait(_cancellationToken); - _rpc.Close(); - - LoginId = 0; - - _log.Debug("Disconnect() done"); - } - - // TODO: Try to use an exception for failed action instead - /// - /// Authenticates this connection via a token. This token has to be requested via an external interface like - /// remauth.php. - /// - /// The token to use for authentication - /// True if the login succeeded, otherwise false. - public async Task AuthenticateWithToken(string token) - { - var tcs = new TaskCompletionSource(); - - _rpc.AttachHandlerForNextMessage(packet => - { - var result = packet as AuthenticateResultMessage; - if (result == null) - return; - - if (result.Result != 0) - tcs.SetResult(false); - LoginId = result.NPID; - SessionToken = result.SessionToken; - tcs.SetResult(true); - }); - _rpc.Send(new AuthenticateWithTokenMessage {Token = token}); - - return await tcs.Task; + /// The host to connect to. + /// The port to use. Default: 3025. + public NPClient(string host, ushort port = 3025) + { + _host = host; + _port = port; + _log = LogManager.GetLogger("NPClient"); + } + + /// + /// The internal RPC client. + /// + public RPCClientStream RPCClient { get { return _rpc; } } + + /// + /// The assigned NP user ID. Will be set on successful authentication. + /// + public ulong LoginId { get; private set; } + + /// + /// The assigned session token for this client. Will be set on successful authentication. + /// + public string SessionToken { get; private set; } + + // TODO: Handle connection failures via exception + /// + /// Connects the client to the NP server. + /// + /// True if the connection succeeded, otherwise false. + public bool Connect() + { + _log.Debug("Connect() start"); + + _cancellationTokenSource = new CancellationTokenSource(); + _cancellationToken = _cancellationTokenSource.Token; + + try + { + _rpc = RPCClientStream.Open(_host, _port); + } + catch (Exception err) + { +#if DEBUG + _log.ErrorFormat(@"Could not initialize RPC: {0}", err); +#else + _log.ErrorFormat(@"Could not initialize RPC: {0}", err.Message); +#endif + return false; + } + + Task.Factory.StartNew(() => + { + _log.Debug("Now receiving RPC messages"); + try + { + while (true) + { + if (_rpc.Read() == null) + break; + } + } + catch (ProtocolViolationException error) + { + _log.ErrorFormat("Protocol violation: {0}. Disconnect imminent.", error.Message); + Disconnect(); + } + + _log.Debug("Now not receiving RPC messages anymore"); + }, _cancellationToken); + + _log.Debug("Connect() done"); + return true; + } + + /// + /// Disconnects the client from the NP server. + /// + public void Disconnect() + { + _log.Debug("Disconnect() start"); + + _cancellationTokenSource.Cancel(true); + // TODO: Find a cleaner way to cancel _processingTask (focus: _rpc.Read) + //_procTask.Wait(_cancellationToken); + _rpc.Close(); + + LoginId = 0; + + _log.Debug("Disconnect() done"); + } + + // TODO: Try to use an exception for failed action instead + /// + /// Authenticates this connection via a token. This token has to be requested via an external interface like + /// remauth.php. + /// + /// The token to use for authentication + /// True if the login succeeded, otherwise false. + public async Task AuthenticateWithToken(string token) + { + var tcs = new TaskCompletionSource(); + + _rpc.AttachHandlerForNextMessage(packet => + { + var result = packet as AuthenticateResultMessage; + if (result == null) + return; + + if (result.Result != 0) + tcs.SetResult(false); + LoginId = result.NPID; + SessionToken = result.SessionToken; + tcs.SetResult(true); + }); + _rpc.Send(new AuthenticateWithTokenMessage {Token = token}); + + return await tcs.Task; } /// @@ -161,7 +161,12 @@ namespace NPSharp.NP return; if (result.Result != 0) + { tcs.SetResult(false); + + return; + } + LoginId = result.NPID; SessionToken = result.SessionToken; tcs.SetResult(true); @@ -169,108 +174,132 @@ namespace NPSharp.NP _rpc.Send(new AuthenticateWithKeyMessage { LicenseKey = key }); return await tcs.Task; - } - - // TODO: Try to use an exception for failed action instead - /// - /// Uploads a user file. - /// - /// The file name to save the contents to on the server - /// The raw byte contents - /// True if the upload succeeded, otherwise false. - public async Task UploadUserFile(string filename, byte[] contents) - { - var tcs = new TaskCompletionSource(); - - _rpc.AttachHandlerForNextMessage(packet => - { - var result = (StorageWriteUserFileResultMessage) packet; - if (result.Result != 0) - tcs.SetResult(false); - tcs.SetResult(true); - }); - _rpc.Send(new StorageWriteUserFileMessage {FileData = contents, FileName = filename, NPID = LoginId}); - - return await tcs.Task; - } - - /// - /// Downloads a user file and returns its contents. - /// - /// The file to download - /// File contents as byte array - public async Task GetUserFile(string filename) - { - var tcs = new TaskCompletionSource(); - - _rpc.AttachHandlerForNextMessage(packet => - { - var result = (StorageUserFileMessage) packet; - if (result.Result != 0) - { - tcs.SetException(new NpFileException(result.Result)); - return; - } - tcs.SetResult(result.FileData); - }); - _rpc.Send(new StorageGetUserFileMessage {FileName = filename, NPID = LoginId}); - - return await tcs.Task; - } - - - /// - /// Downloads a user file onto the harddisk. - /// - /// The file to download - /// Path where to save the file - public async void DownloadUserFileTo(string filename, string targetpath) - { - var contents = await GetUserFile(filename); - - File.WriteAllBytes(targetpath, contents); - } - - - /// - /// Downloads a publisher file and returns its contents. - /// - /// The file to download - /// File contents as byte array - public async Task GetPublisherFile(string filename) - { - var tcs = new TaskCompletionSource(); - - _rpc.AttachHandlerForNextMessage(packet => - { - var result = (StoragePublisherFileMessage) packet; - if (result.Result != 0) - { - tcs.SetException(new NpFileException(result.Result)); - return; - } - tcs.SetResult(result.FileData); - }); - _rpc.Send(new StorageGetPublisherFileMessage {FileName = filename}); - - return await tcs.Task; - } - - /// - /// Downloads a publisher file onto the harddisk. - /// - /// The file to download - /// Path where to save the file - public async void DownloadPublisherFileTo(string filename, string targetpath) - { - var contents = await GetPublisherFile(filename); - - File.WriteAllBytes(targetpath, contents); - } - - public void SendRandomString(string data) - { - _rpc.Send(new StorageSendRandomStringMessage {RandomString = data}); - } - } + } + + public async Task ValidateTicket(uint clientIP, ulong npID, byte[] ticket) + { + var tcs = new TaskCompletionSource(); + + _rpc.AttachHandlerForNextMessage(packet => + { + var result = packet as AuthenticateValidateTicketResultMessage; + if (result == null) + return; + + if (result.Result != 0) + { + tcs.SetResult(false); + } + else + { + tcs.SetResult(true); + } + }); + _rpc.Send(new AuthenticateValidateTicketMessage { ClientIP = clientIP, Ticket = ticket, NPID = npID }); + + return await tcs.Task; + } + + // TODO: Try to use an exception for failed action instead + /// + /// Uploads a user file. + /// + /// The file name to save the contents to on the server + /// The raw byte contents + /// True if the upload succeeded, otherwise false. + public async Task UploadUserFile(string filename, byte[] contents) + { + var tcs = new TaskCompletionSource(); + + _rpc.AttachHandlerForNextMessage(packet => + { + var result = (StorageWriteUserFileResultMessage) packet; + if (result.Result != 0) + tcs.SetResult(false); + tcs.SetResult(true); + }); + _rpc.Send(new StorageWriteUserFileMessage {FileData = contents, FileName = filename, NPID = LoginId}); + + return await tcs.Task; + } + + /// + /// Downloads a user file and returns its contents. + /// + /// The file to download + /// File contents as byte array + public async Task GetUserFile(string filename) + { + var tcs = new TaskCompletionSource(); + + _rpc.AttachHandlerForNextMessage(packet => + { + var result = (StorageUserFileMessage) packet; + if (result.Result != 0) + { + tcs.SetException(new NpFileException(result.Result)); + return; + } + tcs.SetResult(result.FileData); + }); + _rpc.Send(new StorageGetUserFileMessage {FileName = filename, NPID = LoginId}); + + return await tcs.Task; + } + + + /// + /// Downloads a user file onto the harddisk. + /// + /// The file to download + /// Path where to save the file + public async void DownloadUserFileTo(string filename, string targetpath) + { + var contents = await GetUserFile(filename); + + File.WriteAllBytes(targetpath, contents); + } + + + /// + /// Downloads a publisher file and returns its contents. + /// + /// The file to download + /// File contents as byte array + public async Task GetPublisherFile(string filename) + { + var tcs = new TaskCompletionSource(); + + _rpc.AttachHandlerForNextMessage(packet => + { + var result = (StoragePublisherFileMessage) packet; + if (result.Result != 0) + { + tcs.SetException(new NpFileException(result.Result)); + return; + } + tcs.SetResult(result.FileData); + }); + _rpc.Send(new StorageGetPublisherFileMessage {FileName = filename}); + + return await tcs.Task; + } + + /// + /// Downloads a publisher file onto the harddisk. + /// + /// The file to download + /// Path where to save the file + public async void DownloadPublisherFileTo(string filename, string targetpath) + { + var contents = await GetPublisherFile(filename); + + File.WriteAllBytes(targetpath, contents); + } + + public void SendRandomString(string data) + { + _rpc.Send(new StorageSendRandomStringMessage {RandomString = data}); + } + } } \ No newline at end of file