Write initial DiscoveryBeacon and PixelServer implementation.
This commit is contained in:
parent
9ae5d2c97a
commit
9c545a6d2a
5 changed files with 210 additions and 13 deletions
|
@ -19,13 +19,19 @@ namespace PixelServer.Net
|
||||||
{
|
{
|
||||||
TextWriter logger;
|
TextWriter logger;
|
||||||
UdpClient beacon;
|
UdpClient beacon;
|
||||||
|
int emitFrequency = 2000;
|
||||||
|
string role = "server";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the beacon is currently active.
|
/// Whether the beacon is currently active.
|
||||||
/// If true then the beacon needs disposing of properly by calling the Dispose() method before the program ends.
|
/// If true then the beacon needs disposing of properly by calling the Dispose() method before the program ends.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Active { get; private set; } = true;
|
public bool Active { get; private set; } = true;
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the logging output should be verbose.
|
||||||
|
/// </summary>
|
||||||
|
public bool Verbose { get; private set; } = false;
|
||||||
|
|
||||||
string role = "server";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current IP address of the local machine.
|
/// The current IP address of the local machine.
|
||||||
|
@ -47,7 +53,9 @@ namespace PixelServer.Net
|
||||||
/// The port that the beacon should broadcast on.
|
/// The port that the beacon should broadcast on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Port { get; set; } = 5050;
|
public int Port { get; set; } = 5050;
|
||||||
|
/// <summary>
|
||||||
|
/// The role that the program hosted at this beacon plays. Default: server.
|
||||||
|
/// </summary>
|
||||||
public string Role {
|
public string Role {
|
||||||
get{
|
get{
|
||||||
return role;
|
return role;
|
||||||
|
@ -60,9 +68,17 @@ namespace PixelServer.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The frequency at which the beacon should emit broadcasts.
|
/// The time, in milliseconds, that the beacon should wait between broadcasts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int EmitFrequency { get; set; } = 2000;
|
public int EmitFrequency {
|
||||||
|
get {
|
||||||
|
return emitFrequency;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
emitFrequency = value;
|
||||||
|
logger.WriteLine("Beacon broadcast frequency changed to {0}ms.", EmitFrequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PixelServer.Net.DiscoveryBeacon"/> class.
|
/// Initializes a new instance of the <see cref="PixelServer.Net.DiscoveryBeacon"/> class.
|
||||||
|
@ -103,7 +119,7 @@ namespace PixelServer.Net
|
||||||
public async Task Emit()
|
public async Task Emit()
|
||||||
{
|
{
|
||||||
connect();
|
connect();
|
||||||
|
logger.WriteLine("Beacon activated with broadcast interval of {0}ms.", EmitFrequency);
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
await emitOnce();
|
await emitOnce();
|
||||||
|
@ -129,6 +145,7 @@ namespace PixelServer.Net
|
||||||
beacon = new UdpClient(Port);
|
beacon = new UdpClient(Port);
|
||||||
Active = true;
|
Active = true;
|
||||||
beacon.JoinMulticastGroup(DestinationAddress);
|
beacon.JoinMulticastGroup(DestinationAddress);
|
||||||
|
logger.WriteLine("One way beacon set up pointing at {0}.", MulticastChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -154,7 +171,7 @@ namespace PixelServer.Net
|
||||||
/// <param name="data">The message payload.</param>
|
/// <param name="data">The message payload.</param>
|
||||||
private async Task Send(IPEndPoint destination, string data)
|
private async Task Send(IPEndPoint destination, string data)
|
||||||
{
|
{
|
||||||
logger.WriteLine("Sending '{0}' to {1}.", Utilities.EscapeString(data), destination);
|
if(Verbose) logger.WriteLine("Sending '{0}' to {1}.", Utilities.EscapeString(data), destination);
|
||||||
byte[] payload = Encoding.UTF8.GetBytes(data);
|
byte[] payload = Encoding.UTF8.GetBytes(data);
|
||||||
await Send(destination, payload);
|
await Send(destination, payload);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +199,12 @@ namespace PixelServer.Net
|
||||||
/// <see cref="PixelServer.Net.DiscoveryBeacon"/> was occupying.</remarks>
|
/// <see cref="PixelServer.Net.DiscoveryBeacon"/> was occupying.</remarks>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
beacon.Close();
|
if(Active)
|
||||||
|
{
|
||||||
|
beacon.Close();
|
||||||
|
Active = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
94
PixelServer/PixelServer.cs
Normal file
94
PixelServer/PixelServer.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using SBRL.Utilities;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace PixelServer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the server component of the Hull Pixelbot server that can be used to control any number of pixel bots at once.
|
||||||
|
/// </summary>
|
||||||
|
public class PixelServer
|
||||||
|
{
|
||||||
|
TextWriter logger;
|
||||||
|
IPAddress bindAddress = IPAddress.Any;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
TcpListener server;
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the Hull Pixelbot serve is currently active and listening.
|
||||||
|
/// </summary>
|
||||||
|
public bool Active { get; private set; } = false;
|
||||||
|
public IPAddress BindAddress
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return bindAddress;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if (Active == true)
|
||||||
|
throw new InvalidOperationException("Error: The bind address can't be changed once the server has started listening!");
|
||||||
|
bindAddress = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int Port
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if (Active == true)
|
||||||
|
throw new InvalidOperationException("Error: The port can't be changed once the server has started listening!");
|
||||||
|
port = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IPEndPoint Endpoint
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return new IPEndPoint(BindAddress, Port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PixelServer(int inPort, TextWriter inLogger)
|
||||||
|
{
|
||||||
|
Port = inPort;
|
||||||
|
logger = inLogger;
|
||||||
|
}
|
||||||
|
public PixelServer(int inPort) : this(inPort, Console.Out)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Listen()
|
||||||
|
{
|
||||||
|
server = new TcpListener(Endpoint);
|
||||||
|
logger.WriteLine("TCP Listener set up on {0}.", Endpoint);
|
||||||
|
Active = true;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
TcpClient nextClient = await server.AcceptTcpClientAsync();
|
||||||
|
AsyncTools.ForgetTask(Handle(nextClient));
|
||||||
|
}
|
||||||
|
// TODO: Add an shutdown CancellationToken thingy here
|
||||||
|
//Active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Handle(TcpClient client)
|
||||||
|
{
|
||||||
|
logger.WriteLine("Accepted connection from {0}.", client.Client.RemoteEndPoint);
|
||||||
|
|
||||||
|
using (StreamReader incoming = new StreamReader(client.GetStream()))
|
||||||
|
using (StreamWriter outgoing = new StreamWriter(client.GetStream()) { AutoFlush = true })
|
||||||
|
{
|
||||||
|
string nextLine;
|
||||||
|
while((nextLine = await incoming.ReadLineAsync()) != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Got message from client: '{0}'", nextLine.Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Lost connection from {0}.", client.Client.RemoteEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@
|
||||||
<Compile Include="DiscoveryBeacon.cs" />
|
<Compile Include="DiscoveryBeacon.cs" />
|
||||||
<Compile Include="Utilities.cs" />
|
<Compile Include="Utilities.cs" />
|
||||||
<Compile Include="ForgetTask.cs" />
|
<Compile Include="ForgetTask.cs" />
|
||||||
|
<Compile Include="PixelServer.cs" />
|
||||||
|
<Compile Include="PrefixedWriter.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
67
PixelServer/PrefixedWriter.cs
Normal file
67
PixelServer/PrefixedWriter.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SBRL.Utilities
|
||||||
|
{
|
||||||
|
public class PrefixedWriter : TextWriter, IDisposable
|
||||||
|
{
|
||||||
|
private TextWriter destination;
|
||||||
|
public string Prefix { get; set; } = "";
|
||||||
|
|
||||||
|
public override Encoding Encoding {
|
||||||
|
get {
|
||||||
|
return Encoding.UTF8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrefixedWriter(TextWriter inDestination)
|
||||||
|
{
|
||||||
|
destination = inDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(string str, params object[] args)
|
||||||
|
{
|
||||||
|
destination.Write(Prefix + str, args);
|
||||||
|
}
|
||||||
|
public override void Write(string str)
|
||||||
|
{
|
||||||
|
Write(str, new object[] {});
|
||||||
|
}
|
||||||
|
public override void Write(string str, object arg1)
|
||||||
|
{
|
||||||
|
Write(str, new object[] { arg1 });
|
||||||
|
}
|
||||||
|
public override void Write(string str, object arg1, object arg2)
|
||||||
|
{
|
||||||
|
Write(str, new object[] { arg1, arg2 });
|
||||||
|
}
|
||||||
|
public override void Write(string str, object arg1, object arg2, object arg3)
|
||||||
|
{
|
||||||
|
Write(str, new object[] { arg1, arg2, arg3 });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void WriteLine(string str, params object[] args)
|
||||||
|
{
|
||||||
|
Write(str + Environment.NewLine, args);
|
||||||
|
}
|
||||||
|
public override void WriteLine(string str)
|
||||||
|
{
|
||||||
|
WriteLine(str, new object[] {});
|
||||||
|
}
|
||||||
|
public override void WriteLine(string str, object arg1)
|
||||||
|
{
|
||||||
|
WriteLine(str, new object[] { arg1 });
|
||||||
|
}
|
||||||
|
public override void WriteLine(string str, object arg1, object arg2)
|
||||||
|
{
|
||||||
|
WriteLine(str, new object[] { arg1, arg2 });
|
||||||
|
}
|
||||||
|
public override void WriteLine(string str, object arg1, object arg2, object arg3)
|
||||||
|
{
|
||||||
|
WriteLine(str, new object[] { arg1, arg2, arg3 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,34 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using PixelServer.Net;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using SBRL.Utilities;
|
using SBRL.Utilities;
|
||||||
using System.Net.NetworkInformation;
|
using PixelServer.Net;
|
||||||
using System.Net.Sockets;
|
|
||||||
|
|
||||||
namespace PixelServer
|
namespace PixelServer
|
||||||
{
|
{
|
||||||
class MainClass
|
static class Program
|
||||||
{
|
{
|
||||||
|
private static int port = 5050;
|
||||||
|
private static PrefixedWriter systemWriter = new PrefixedWriter(Console.Out) { Prefix = "[System] " };
|
||||||
|
private static PrefixedWriter beaconWriter = new PrefixedWriter(Console.Out) { Prefix = "[Beacon] " };
|
||||||
|
private static PrefixedWriter serverWriter = new PrefixedWriter(Console.Out) { Prefix = "[Server] " };
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
DiscoveryBeacon beacon = new DiscoveryBeacon(IPAddress.Parse("239.62.148.30"));
|
systemWriter.WriteLine("Booting server.");
|
||||||
|
DiscoveryBeacon beacon = new DiscoveryBeacon(
|
||||||
|
IPAddress.Parse("239.62.148.30"), port,
|
||||||
|
beaconWriter
|
||||||
|
);
|
||||||
|
PixelServer server = new PixelServer(port, serverWriter);
|
||||||
|
systemWriter.WriteLine("Server booting complete. Beginning async loop.");
|
||||||
//AsyncTools.ForgetTask(beacon.Emit());
|
//AsyncTools.ForgetTask(beacon.Emit());
|
||||||
beacon.Emit().Wait();
|
Task.WaitAll(new Task[] {
|
||||||
|
beacon.Emit(),
|
||||||
|
server.Listen()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue