diff --git a/PixelServer/DiscoveryBeacon.cs b/PixelServer/DiscoveryBeacon.cs
index 46ea2c7..13ed641 100644
--- a/PixelServer/DiscoveryBeacon.cs
+++ b/PixelServer/DiscoveryBeacon.cs
@@ -19,13 +19,19 @@ namespace PixelServer.Net
{
TextWriter logger;
UdpClient beacon;
+ int emitFrequency = 2000;
+ string role = "server";
+
///
/// Whether the beacon is currently active.
/// If true then the beacon needs disposing of properly by calling the Dispose() method before the program ends.
///
public bool Active { get; private set; } = true;
+ ///
+ /// Whether the logging output should be verbose.
+ ///
+ public bool Verbose { get; private set; } = false;
- string role = "server";
///
/// The current IP address of the local machine.
@@ -47,7 +53,9 @@ namespace PixelServer.Net
/// The port that the beacon should broadcast on.
///
public int Port { get; set; } = 5050;
-
+ ///
+ /// The role that the program hosted at this beacon plays. Default: server.
+ ///
public string Role {
get{
return role;
@@ -60,9 +68,17 @@ namespace PixelServer.Net
}
///
- /// The frequency at which the beacon should emit broadcasts.
+ /// The time, in milliseconds, that the beacon should wait between broadcasts.
///
- 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);
+ }
+ }
///
/// Initializes a new instance of the class.
@@ -103,7 +119,7 @@ namespace PixelServer.Net
public async Task Emit()
{
connect();
-
+ logger.WriteLine("Beacon activated with broadcast interval of {0}ms.", EmitFrequency);
while(true)
{
await emitOnce();
@@ -129,6 +145,7 @@ namespace PixelServer.Net
beacon = new UdpClient(Port);
Active = true;
beacon.JoinMulticastGroup(DestinationAddress);
+ logger.WriteLine("One way beacon set up pointing at {0}.", MulticastChannel);
}
///
@@ -154,7 +171,7 @@ namespace PixelServer.Net
/// The message payload.
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);
await Send(destination, payload);
}
@@ -182,7 +199,12 @@ namespace PixelServer.Net
/// was occupying.
public void Dispose()
{
- beacon.Close();
+ if(Active)
+ {
+ beacon.Close();
+ Active = false;
+ }
+
}
}
}
diff --git a/PixelServer/PixelServer.cs b/PixelServer/PixelServer.cs
new file mode 100644
index 0000000..a595eb5
--- /dev/null
+++ b/PixelServer/PixelServer.cs
@@ -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
+{
+ ///
+ /// Provides the server component of the Hull Pixelbot server that can be used to control any number of pixel bots at once.
+ ///
+ public class PixelServer
+ {
+ TextWriter logger;
+ IPAddress bindAddress = IPAddress.Any;
+ int port;
+
+ TcpListener server;
+ ///
+ /// Whether the Hull Pixelbot serve is currently active and listening.
+ ///
+ 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);
+ }
+ }
+}
+
diff --git a/PixelServer/PixelServer.csproj b/PixelServer/PixelServer.csproj
index 66a53b8..9052bb6 100644
--- a/PixelServer/PixelServer.csproj
+++ b/PixelServer/PixelServer.csproj
@@ -38,6 +38,8 @@
+
+
\ No newline at end of file
diff --git a/PixelServer/PrefixedWriter.cs b/PixelServer/PrefixedWriter.cs
new file mode 100644
index 0000000..9c6b623
--- /dev/null
+++ b/PixelServer/PrefixedWriter.cs
@@ -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 });
+ }
+ }
+}
+
diff --git a/PixelServer/Program.cs b/PixelServer/Program.cs
index bf50619..92e711c 100644
--- a/PixelServer/Program.cs
+++ b/PixelServer/Program.cs
@@ -1,22 +1,34 @@
using System;
-using PixelServer.Net;
using System.Net;
using System.Threading.Tasks;
using SBRL.Utilities;
-using System.Net.NetworkInformation;
-using System.Net.Sockets;
+using PixelServer.Net;
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)
{
- 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());
- beacon.Emit().Wait();
+ Task.WaitAll(new Task[] {
+ beacon.Emit(),
+ server.Listen()
+ });
}
}
}