diff --git a/src/KFlearning.Core/Services/RemoteServer.cs b/src/KFlearning.Core/Services/RemoteServer.cs deleted file mode 100644 index 6da4798..0000000 --- a/src/KFlearning.Core/Services/RemoteServer.cs +++ /dev/null @@ -1,149 +0,0 @@ -// SOLUTION : KFlearning -// PROJECT : KFlearning.Core -// FILENAME : RemoteServer.cs -// AUTHOR : Fahmi Noor Fiqri, Kodesiana.com -// WEBSITE : https://kodesiana.com -// REPO : https://github.com/Kodesiana or https://github.com/fahminlb33 -// -// This file is part of KFlearning, see LICENSE. -// See this code in repository URL above! - -using System; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace KFlearning.Core.Services -{ - public interface IRemoteServer : IDisposable - { - void Start(); - void SendShutdown(); - void StartServeFile(string path); - void StopServeFile(); - - event EventHandler ShutdownRequested; - event EventHandler FileBroadcast; - } - - public class RemoteServer : IRemoteServer - { - public const int ServicePort = 2021; - public const int FilePort = 2022; - - private const string MessageShutdown = "SDWN"; - private const string MessageFile = "FILE"; - - private static readonly IPEndPoint ServiceEndpoint = new IPEndPoint(IPAddress.Any, ServicePort); - - private readonly HttpListener _httpListener = new HttpListener(); - private readonly UdpClient _socket = new UdpClient(); - private MemoryStream _uploadStream; - - public event EventHandler ShutdownRequested; - public event EventHandler FileBroadcast; - - public RemoteServer() - { - _socket.Client.Bind(ServiceEndpoint); - _httpListener.Prefixes.Add($"http://*:{FilePort}/serve/"); - } - - #region Public Methods - - public void Start() - { - _socket.BeginReceive(ReceiveCallback, null); - } - - public void SendShutdown() - { - Send(MessageShutdown); - } - - public void StartServeFile(string path) - { - _uploadStream = new MemoryStream(File.ReadAllBytes(path)); - _httpListener.Start(); - _httpListener.BeginGetContext(GetContextCallback, null); - - Send(MessageFile); - } - - public void StopServeFile() - { - _httpListener.Stop(); - _uploadStream?.Dispose(); - } - - #endregion - - #region Private Methods (Callbacks) - - private void Send(string text) - { - var data = Encoding.ASCII.GetBytes(text); - _socket.BeginSend(data, data.Length, ServiceEndpoint, SendCallback, null); - } - - private void SendCallback(IAsyncResult ar) - { - _socket.EndSend(ar); - } - - private void ReceiveCallback(IAsyncResult ar) - { - var epFrom = new IPEndPoint(IPAddress.Any, ServicePort); - var bytes = _socket.EndReceive(ar, ref epFrom); - var message = Encoding.ASCII.GetString(bytes); - ProcessMessage(message, epFrom.Address); - - _socket.BeginReceive(ReceiveCallback, null); - } - - private void GetContextCallback(IAsyncResult ar) - { - var context = _httpListener.EndGetContext(ar); - var response = context.Response; - response.StatusCode = 200; - response.SendChunked = true; - response.ContentType = "application/octet-stream"; - - using (var networkStream = response.OutputStream) - { - _uploadStream.Seek(0, SeekOrigin.Begin); - _uploadStream.CopyTo(networkStream); - } - - _httpListener.BeginGetContext(GetContextCallback, null); - } - - private void ProcessMessage(string message, IPAddress server) - { - switch (message) - { - case MessageShutdown: - ShutdownRequested?.Invoke(this, new RemoteEventArgs {Address = server}); - break; - - case MessageFile: - FileBroadcast?.Invoke(this, new RemoteEventArgs {Address = server}); - break; - } - } - - #endregion - - #region IDisposable - - public void Dispose() - { - ((IDisposable)_httpListener)?.Dispose(); - ((IDisposable)_socket)?.Dispose(); - ((IDisposable)_uploadStream)?.Dispose(); - } - - #endregion - } -} diff --git a/src/KFlearning.Core/Services/RemoteShutdownServer.cs b/src/KFlearning.Core/Services/RemoteShutdownServer.cs new file mode 100644 index 0000000..ffd8ac3 --- /dev/null +++ b/src/KFlearning.Core/Services/RemoteShutdownServer.cs @@ -0,0 +1,101 @@ +// SOLUTION : KFlearning +// PROJECT : KFlearning.Core +// FILENAME : RemoteServer.cs +// AUTHOR : Fahmi Noor Fiqri, Kodesiana.com +// WEBSITE : https://kodesiana.com +// REPO : https://github.com/Kodesiana or https://github.com/fahminlb33 +// +// This file is part of KFlearning, see LICENSE. +// See this code in repository URL above! + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace KFlearning.Core.Services +{ + public interface IRemoteShutdownServer : IDisposable + { + void Listen(); + void SendShutdown(string cluster); + + event EventHandler ShutdownRequested; + } + + public class RemoteShutdownServer : IRemoteShutdownServer + { + public const int ServicePort = 2021; + private const string MessageShutdown = "SDWN"; + + private static readonly IPEndPoint ServiceEndpoint = new IPEndPoint(IPAddress.Any, ServicePort); + + private readonly UdpClient _socket = new UdpClient(); + private MemoryStream _uploadStream; + + public event EventHandler ShutdownRequested; + public event EventHandler FileBroadcast; + + public RemoteShutdownServer() + { + _socket.Client.Bind(ServiceEndpoint); + } + + #region Public Methods + + public void Listen() + { + _socket.BeginReceive(ReceiveCallback, null); + } + + public void SendShutdown(string cluster) + { + Send(MessageShutdown, cluster); + } + + #endregion + + #region Private Methods (Callbacks) + + private void Send(string message, string body) + { + var data = Encoding.ASCII.GetBytes($"{message}|{body}"); + _socket.BeginSend(data, data.Length, ServiceEndpoint, SendCallback, null); + } + + private void SendCallback(IAsyncResult ar) + { + _socket.EndSend(ar); + } + + private void ReceiveCallback(IAsyncResult ar) + { + var epFrom = new IPEndPoint(IPAddress.Any, ServicePort); + var bytes = _socket.EndReceive(ar, ref epFrom); + var message = Encoding.ASCII.GetString(bytes); + ProcessMessage(message, epFrom.Address); + + _socket.BeginReceive(ReceiveCallback, null); + } + + private void ProcessMessage(string message, IPAddress server) + { + if (!message.StartsWith(MessageShutdown)) return; + var cluster = message.Split('|')[1]; + ShutdownRequested?.Invoke(this, new ShutdownRequestedEventArgs { Address = server, Clusster = cluster }); + } + + #endregion + + #region IDisposable + + public void Dispose() + { + ((IDisposable)_socket)?.Dispose(); + ((IDisposable)_uploadStream)?.Dispose(); + } + + #endregion + } +} diff --git a/src/KFlearning.Core/Services/RemoteEventArgs.cs b/src/KFlearning.Core/Services/ShutdownRequestedEventArgs.cs similarity index 82% rename from src/KFlearning.Core/Services/RemoteEventArgs.cs rename to src/KFlearning.Core/Services/ShutdownRequestedEventArgs.cs index 9a2e122..9cb4b58 100644 --- a/src/KFlearning.Core/Services/RemoteEventArgs.cs +++ b/src/KFlearning.Core/Services/ShutdownRequestedEventArgs.cs @@ -13,8 +13,9 @@ namespace KFlearning.Core.Services { - public class RemoteEventArgs : EventArgs + public class ShutdownRequestedEventArgs : EventArgs { public IPAddress Address { get; set; } + public string Clusster { get; set; } } } \ No newline at end of file