mirror of
https://github.com/sbrl/Nibriboard.git
synced 2018-01-10 21:33:49 +00:00
It sure does feel strangely both good and scary to be completely refactoring so many core classes.
This commit is contained in:
parent
afb6eb8dca
commit
be258f63dc
8 changed files with 246 additions and 370 deletions
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using SBRL.GlidingSquirrel.Http;
|
||||
using SBRL.GlidingSquirrel.Websocket;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Nibriboard.Client
|
||||
{
|
||||
public class HttpClientSettingsHandler : WebsocketServer
|
||||
{
|
||||
private ClientSettings settings;
|
||||
|
||||
public HttpClientSettingsHandler(ClientSettings inSettings)
|
||||
{
|
||||
settings = inSettings;
|
||||
}
|
||||
|
||||
public void HandleRequest(string uri, HttpRequest request, HttpResponse response, HttpContext context) {
|
||||
StreamWriter responseData = new StreamWriter(response.Content) { AutoFlush = true };
|
||||
|
||||
string settingsJson = JsonConvert.SerializeObject(settings);
|
||||
response.ContentLength = settingsJson.Length;
|
||||
response.Headers.Add("content-type", "application/json");
|
||||
|
||||
responseData.Write(settingsJson);
|
||||
|
||||
Log.WriteLine("[Http/ClientSettings] Sent settings");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using MimeSharp;
|
||||
|
||||
using SBRL.GlidingSquirrel.Websocket;
|
||||
|
||||
using SBRL.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Nibriboard.Client
|
||||
{
|
||||
public class HttpEmbeddedFileHandler : WebsocketsServer
|
||||
{
|
||||
private string filePrefix;
|
||||
|
||||
private Mime mimeTypeFinder = new Mime();
|
||||
private Dictionary<string, string> mimeTypeOverrides = new Dictionary<string, string>() {
|
||||
["application/xhtml+xml"] = "text/html",
|
||||
["application/tei+xml"] = "image/x-icon"
|
||||
};
|
||||
|
||||
private List<string> embeddedFiles = new List<string>(EmbeddedFiles.ResourceList);
|
||||
|
||||
public HttpEmbeddedFileHandler(string inFilePrefix)
|
||||
{
|
||||
filePrefix = inFilePrefix;
|
||||
}
|
||||
|
||||
public void HandleRequest(string uri, HttpRequest request, HttpResponse response, HttpContext context) {
|
||||
StreamWriter responseData = new StreamWriter(response.Content) { AutoFlush = true };
|
||||
if (request.Method != HttpMethod.Get) {
|
||||
response.ResponseCode = HttpResponseCode.MethodNotAllowed;
|
||||
response.ContentType = "text/plain";
|
||||
responseData.WriteLine("Error: That method isn't supported yet.");
|
||||
logRequest(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string expandedFilePath = getEmbeddedFileReference(request.URI);
|
||||
if (!embeddedFiles.Contains(expandedFilePath)) {
|
||||
expandedFilePath += "index.html";
|
||||
}
|
||||
if (!embeddedFiles.Contains(expandedFilePath)) {
|
||||
response.ResponseCode = HttpResponseCode.NotFound;
|
||||
response.ContentType = "text/plain";
|
||||
responseData.WriteLine("Can't find {0}.", expandedFilePath);
|
||||
logRequest(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
response.ContentType = getMimeType(expandedFilePath);
|
||||
response.Headers.Add("content-type", response.ContentType);
|
||||
|
||||
byte[] embeddedFile = EmbeddedFiles.ReadAllBytes(expandedFilePath);
|
||||
response.ContentLength = embeddedFile.Length;
|
||||
|
||||
try
|
||||
{
|
||||
response.Content.Write(embeddedFile, 0, embeddedFile.Length);
|
||||
}
|
||||
catch(Exception error)
|
||||
{
|
||||
Log.WriteLine($"[Nibriboard/EmbeddedFileHandler] Error: {error.Message} Details:");
|
||||
Log.WriteLine(error.ToString());
|
||||
}
|
||||
logRequest(request, response);
|
||||
}
|
||||
|
||||
protected string getEmbeddedFileReference(string uri) {
|
||||
return filePrefix + "." + uri.TrimStart("/".ToCharArray()).Replace('/', '.');
|
||||
}
|
||||
|
||||
protected string getMimeType(string uri) {
|
||||
string mimeType = mimeTypeFinder.Lookup(uri);
|
||||
foreach (KeyValuePair<string, string> mimeMapping in mimeTypeOverrides) {
|
||||
if (mimeType == mimeMapping.Key)
|
||||
mimeType = mimeMapping.Value;
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
private void logRequest(HttpRequest request, HttpResponse response) {
|
||||
Log.WriteLine("[Http/FileHandler] {0} {1} {2} {3}", response.ResponseCode.ResponseCode(), response.ContentType, request.Method.ToString().ToUpper(), request.URI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,12 +5,13 @@ using System.Text;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using IotWeb.Common.Http;
|
||||
using Newtonsoft.Json;
|
||||
using SBRL.Utilities;
|
||||
using Nibriboard.Client.Messages;
|
||||
using Nibriboard.RippleSpace;
|
||||
|
||||
using SBRL.GlidingSquirrel.Websocket;
|
||||
|
||||
namespace Nibriboard.Client
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -38,7 +39,7 @@ namespace Nibriboard.Client
|
|||
/// <summary>
|
||||
/// The nibri client manager
|
||||
/// </summary>
|
||||
private readonly NibriClientManager manager;
|
||||
private readonly NibriboardApp manager;
|
||||
/// <summary>
|
||||
/// The plane that this client is currently on.
|
||||
/// </summary>
|
||||
|
@ -48,7 +49,7 @@ namespace Nibriboard.Client
|
|||
/// The underlying websocket connection to the client.
|
||||
/// Please try not to call the send method on here - use the NibriClient Send() method instead.
|
||||
/// </summary>
|
||||
private readonly WebSocket client;
|
||||
private readonly WebsocketClient connection;
|
||||
|
||||
private static readonly Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>() {
|
||||
["HandshakeRequest"] = typeof(HandshakeRequestMessage),
|
||||
|
@ -64,7 +65,11 @@ namespace Nibriboard.Client
|
|||
/// <summary>
|
||||
/// Whether this nibri client is still connected.
|
||||
/// </summary>
|
||||
public bool Connected = true;
|
||||
public bool Connected {
|
||||
get {
|
||||
return connection.IsClosing;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Fires when this nibri client disconnects.
|
||||
/// </summary>
|
||||
|
@ -117,41 +122,26 @@ namespace Nibriboard.Client
|
|||
|
||||
#region Core Setup & Message Routing Logic
|
||||
|
||||
public NibriClient(NibriClientManager inManager, WebSocket inClient)
|
||||
public NibriClient(NibriboardApp inManager, WebsocketClient inClient)
|
||||
{
|
||||
Log.WriteLine("[Nibriboard/WebSocket] New NibriClient connected with id #{0}.", Id);
|
||||
|
||||
manager = inManager;
|
||||
client = inClient;
|
||||
connection = inClient;
|
||||
|
||||
client.DataReceived += async (WebSocket clientSocket, string frame) => {
|
||||
try
|
||||
{
|
||||
await handleMessage(frame);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
await Console.Error.WriteLineAsync(error.ToString());
|
||||
throw;
|
||||
}
|
||||
// Attach a few events
|
||||
connection.OnDisconnection += handleDisconnection;
|
||||
connection.OnTextMessage += handleMessage;
|
||||
|
||||
//Task.Run(async () => await onMessage(frame)).Wait();
|
||||
};
|
||||
// Store whether this NibriClient is still connected or not
|
||||
client.ConnectionClosed += (WebSocket socket) => {
|
||||
Connected = false;
|
||||
Disconnected(this);
|
||||
Log.WriteLine("[NibriClient] Client #{0} disconnected.", Id);
|
||||
};
|
||||
}
|
||||
|
||||
private async Task handleMessage(string frame)
|
||||
private async Task handleMessage(object sender, TextMessageEventArgs eventArgs)
|
||||
{
|
||||
// Update the last time we received a message from the client
|
||||
LastMessageTime = DateTime.Now;
|
||||
|
||||
// Extract the event name from the message that the client sent.
|
||||
string eventName = JsonUtilities.DeserializeProperty<string>(frame, "Event");
|
||||
string eventName = JsonUtilities.DeserializeProperty<string>(eventArgs.Payload, "Event");
|
||||
|
||||
if(eventName == null) {
|
||||
Log.WriteLine("[NibriClient#{0}] Received message that didn't have an event.", Id);
|
||||
|
@ -170,7 +160,7 @@ namespace Nibriboard.Client
|
|||
Type jsonNet = typeof(JsonConvert);
|
||||
MethodInfo deserialiserInfo = jsonNet.GetMethods().First(method => method.Name == "DeserializeObject" && method.IsGenericMethod);
|
||||
MethodInfo genericInfo = deserialiserInfo.MakeGenericMethod(messageType);
|
||||
var decodedMessage = genericInfo.Invoke(null, new object[] { frame });
|
||||
var decodedMessage = genericInfo.Invoke(null, new object[] { eventArgs.Payload });
|
||||
|
||||
string handlerMethodName = "handle" + decodedMessage.GetType().Name;
|
||||
Type clientType = this.GetType();
|
||||
|
@ -180,11 +170,19 @@ namespace Nibriboard.Client
|
|||
catch(Exception error)
|
||||
{
|
||||
Log.WriteLine("[NibriClient#{0}] Error decoding and / or handling message.", Id);
|
||||
Log.WriteLine("[NibriClient#{0}] Raw frame content: {1}", Id, frame);
|
||||
Log.WriteLine("[NibriClient#{0}] Raw frame content: {1}", Id, eventArgs.Payload);
|
||||
Log.WriteLine("[NibriClient#{0}] Exception details: {1}", Id, error);
|
||||
}
|
||||
}
|
||||
|
||||
private Task handleDisconnection(object sender, ClientDisconnectedEventArgs eventArgs)
|
||||
{
|
||||
Disconnected?.Invoke(this);
|
||||
Log.WriteLine("[NibriClient] Client #{0} disconnected.", Id);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
@ -222,7 +220,7 @@ namespace Nibriboard.Client
|
|||
|
||||
Log.WriteLine("[NibriClient/#{0}] Sending message with length {1}.", Id, message.Length);
|
||||
|
||||
client.Send(message);
|
||||
connection.Send(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -239,7 +237,7 @@ namespace Nibriboard.Client
|
|||
/// <summary>
|
||||
/// Closes the connection to the client gracefully.
|
||||
/// </summary>
|
||||
public void CloseConnection(Message lastMessage)
|
||||
public async Task CloseConnection(Message lastMessage)
|
||||
{
|
||||
if (!Connected)
|
||||
return;
|
||||
|
@ -247,7 +245,7 @@ namespace Nibriboard.Client
|
|||
// Tell the client that we're shutting down
|
||||
Send(lastMessage);
|
||||
|
||||
client.Close();
|
||||
await connection.Close(WebsocketCloseReason.Normal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -514,7 +512,7 @@ namespace Nibriboard.Client
|
|||
protected ClientStatesMessage GenerateClientStateUpdate()
|
||||
{
|
||||
ClientStatesMessage result = new ClientStatesMessage();
|
||||
foreach (NibriClient otherClient in manager.Clients)
|
||||
foreach (NibriClient otherClient in manager.NibriClients)
|
||||
{
|
||||
// Don't include ourselves in the update message!
|
||||
if (otherClient == this)
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
using System;
|
||||
using IotWeb.Common.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Nibriboard.Client.Messages;
|
||||
using System.Threading;
|
||||
using Nibriboard.RippleSpace;
|
||||
|
||||
namespace Nibriboard.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a group of <see cref="Nibriboard.Client.NibriClient"/>s.
|
||||
/// </summary>
|
||||
public class NibriClientManager : IWebSocketRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// The ripple space manager that this client manager is connected to.
|
||||
/// </summary>
|
||||
public RippleSpaceManager SpaceManager { get; private set; }
|
||||
|
||||
private ClientSettings clientSettings;
|
||||
public List<NibriClient> Clients = new List<NibriClient>();
|
||||
|
||||
public LineIncubator LineIncubator = new LineIncubator();
|
||||
|
||||
/// <summary>
|
||||
/// The cancellation token that's used by the main server to tell us when we should shut down.
|
||||
/// </summary>
|
||||
protected CancellationToken canceller;
|
||||
|
||||
/// <summary>
|
||||
/// The interval at which heatbeats should be sent to the client.
|
||||
/// </summary>
|
||||
public readonly int HeatbeatInterval = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// The number of clients currently connected to this Nibriboard.
|
||||
/// </summary>
|
||||
public int ClientCount {
|
||||
get {
|
||||
return Clients.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public NibriClientManager(ClientSettings inClientSettings, RippleSpaceManager inSpaceManager, CancellationToken inCancellationToken)
|
||||
{
|
||||
clientSettings = inClientSettings;
|
||||
canceller = inCancellationToken;
|
||||
|
||||
SpaceManager = inSpaceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether we will accept a given new WebSocket connection or not.
|
||||
/// </summary>
|
||||
/// <param name="uri">The uri the user connected to.</param>
|
||||
/// <param name="protocol">The protocol the user is connecting with.</param>
|
||||
/// <returns>Whether we want to accept the WebSocket connection attempt or not.</returns>
|
||||
public bool WillAcceptRequest(string uri, string protocol)
|
||||
{
|
||||
//Log.WriteLine("[Nibriboard/Websocket] Accepting new {0} connection.", protocol);
|
||||
return clientSettings.WebsocketProtocol == protocol;
|
||||
}
|
||||
/// <summary>
|
||||
/// Handles WebSocket clients when they first connect, wrapping them in
|
||||
/// a <see cref="Nibriboard.Client.NibriClient" /> instance and adding them to
|
||||
/// the client list.
|
||||
/// </summary>
|
||||
/// <param name="newSocket">New socket.</param>
|
||||
public void Connected(WebSocket newSocket)
|
||||
{
|
||||
NibriClient client = new NibriClient(this, newSocket);
|
||||
client.Disconnected += handleDisconnection; // Clean up when the client disconnects
|
||||
|
||||
Clients.Add(client);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to all the connected clients, except the one who's sending it.
|
||||
/// </summary>
|
||||
/// <param name="sendingClient">The client sending the message.</param>
|
||||
/// <param name="message">The message that is to bee sent.</param>
|
||||
public void Broadcast(NibriClient sendingClient, Message message)
|
||||
{
|
||||
foreach(NibriClient client in Clients)
|
||||
{
|
||||
// Don't send the message to the sender
|
||||
if (client == sendingClient)
|
||||
continue;
|
||||
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on the same plane as the sender, except the sender themselves.
|
||||
/// </summary>
|
||||
/// <param name="sendingClient">The sending client.</param>
|
||||
/// <param name="message">The message to send.</param>
|
||||
public void BroadcastPlane(NibriClient sendingClient, Message message)
|
||||
{
|
||||
foreach(NibriClient client in Clients)
|
||||
{
|
||||
// Don't send the message to the sender
|
||||
if(client == sendingClient)
|
||||
continue;
|
||||
// Only send the message to others on the same plane
|
||||
if(client.CurrentPlane != sendingClient.CurrentPlane)
|
||||
continue;
|
||||
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on a specified plane.
|
||||
/// </summary>
|
||||
/// <param name="plane">The plane to send the message to.</param>
|
||||
/// <param name="message">The message to send.</param>
|
||||
public void ReflectPlane(Plane plane, Message message)
|
||||
{
|
||||
foreach(NibriClient client in Clients)
|
||||
{
|
||||
if(client.CurrentPlane != plane)
|
||||
continue;
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Periodically tidies up the client list, disconnecting old clients.
|
||||
/// </summary>
|
||||
private async Task ClientMaintenanceMonkey()
|
||||
{
|
||||
while (true) {
|
||||
// Exit if we've been asked to shut down
|
||||
if (canceller.IsCancellationRequested) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Disconnect unresponsive clients.
|
||||
foreach (NibriClient client in Clients) {
|
||||
// If we haven't heard from this client in a little while, send a heartbeat message
|
||||
if(client.MillisecondsSinceLastMessage > HeatbeatInterval)
|
||||
client.SendHeartbeat();
|
||||
|
||||
// If the client hasn't sent us a message in a while (even though we sent
|
||||
// them a heartbeat to check on them on the last loop), disconnect them
|
||||
if (client.MillisecondsSinceLastMessage > HeatbeatInterval * 2)
|
||||
client.CloseConnection(new IdleDisconnectMessage());
|
||||
}
|
||||
|
||||
await Task.Delay(HeatbeatInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up this NibriClient manager ready for shutdown.
|
||||
/// </summary>
|
||||
private void close()
|
||||
{
|
||||
// Close the connection to all the remaining nibri clients, telling them that the server is about to shut down
|
||||
foreach (NibriClient client in Clients)
|
||||
client.CloseConnection(new ShutdownMessage());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up after a client disconnects from the server.
|
||||
/// </summary>
|
||||
/// <param name="disconnectedClient">The client that has disconnected.</param>
|
||||
private void handleDisconnection(NibriClient disconnectedClient)
|
||||
{
|
||||
Clients.Remove(disconnectedClient);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,11 +69,8 @@
|
|||
<Compile Include="Utilities\EmbeddedFiles.cs" />
|
||||
<Compile Include="Env.cs" />
|
||||
<Compile Include="RippleSpace\RippleSpaceManager.cs" />
|
||||
<Compile Include="Client\HttpEmbeddedFileHandler.cs" />
|
||||
<Compile Include="Client\NibriClient.cs" />
|
||||
<Compile Include="Client\NibriClientManager.cs" />
|
||||
<Compile Include="Client\ClientSettings.cs" />
|
||||
<Compile Include="Client\HttpClientSettingsHandler.cs" />
|
||||
<Compile Include="Utilities\PointExtensions.cs" />
|
||||
<Compile Include="Utilities\JsonUtilities.cs" />
|
||||
<Compile Include="Client\Messages\Message.cs" />
|
||||
|
@ -109,6 +106,7 @@
|
|||
<Compile Include="RippleSpace\PlaneInfo.cs" />
|
||||
<Compile Include="Utilities\BinaryIO.cs" />
|
||||
<Compile Include="Client\Messages\ViewportUpdateMessage.cs" />
|
||||
<Compile Include="NibriboardApp.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ClientFiles\index.html" />
|
||||
|
|
202
Nibriboard/NibriboardApp.cs
Normal file
202
Nibriboard/NibriboardApp.cs
Normal file
|
@ -0,0 +1,202 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Nibriboard.Client;
|
||||
using Nibriboard.Client.Messages;
|
||||
using Nibriboard.RippleSpace;
|
||||
using SBRL.GlidingSquirrel.Http;
|
||||
using SBRL.GlidingSquirrel.Websocket;
|
||||
using SBRL.Utilities;
|
||||
|
||||
namespace Nibriboard
|
||||
{
|
||||
public class NibriboardAppStartInfo
|
||||
{
|
||||
public string FilePrefix { get; set; }
|
||||
|
||||
public ClientSettings ClientSettings { get; set; }
|
||||
public RippleSpaceManager SpaceManager { get; set; }
|
||||
}
|
||||
|
||||
public class NibriboardApp : WebsocketServer
|
||||
{
|
||||
private string filePrefix;
|
||||
private List<string> embeddedFiles = new List<string>(EmbeddedFiles.ResourceList);
|
||||
|
||||
/// <summary>
|
||||
/// The ripple space manager that this client manager is connected to.
|
||||
/// </summary>
|
||||
public RippleSpaceManager SpaceManager { get; private set; }
|
||||
|
||||
public LineIncubator LineIncubator = new LineIncubator();
|
||||
|
||||
private ClientSettings clientSettings;
|
||||
|
||||
public List<NibriClient> NibriClients = new List<NibriClient>();
|
||||
|
||||
/// <summary>
|
||||
/// The number of clients currently connected to this Nibriboard.
|
||||
/// </summary>
|
||||
public int ClientCount {
|
||||
get {
|
||||
return Clients.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public NibriboardApp(NibriboardAppStartInfo startInfo, IPAddress inBindAddress, int inPort) : base(inBindAddress, inPort)
|
||||
{
|
||||
clientSettings = startInfo.ClientSettings;
|
||||
SpaceManager = startInfo.SpaceManager;
|
||||
|
||||
filePrefix = startInfo.FilePrefix;
|
||||
MimeTypeOverrides.Add(".ico", "image/x-icon");
|
||||
}
|
||||
|
||||
|
||||
public override Task HandleClientConnected(object sender, ClientConnectedEventArgs eventArgs)
|
||||
{
|
||||
NibriClient client = new NibriClient(this, eventArgs.ConnectingClient);
|
||||
|
||||
client.Disconnected += (NibriClient disconnectedClient) => NibriClients.Remove(disconnectedClient);
|
||||
NibriClients.Add(client);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task HandleClientDisconnected(object sender, ClientDisconnectedEventArgs eventArgs)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task HandleHttpRequest(HttpRequest request, HttpResponse response)
|
||||
{
|
||||
if(request.Method != HttpMethod.GET)
|
||||
{
|
||||
response.ResponseCode = HttpResponseCode.MethodNotAllowed;
|
||||
response.ContentType = "text/plain";
|
||||
await response.SetBody("Error: That method isn't supported yet.");
|
||||
logRequest(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if(request.Url == "/Settings.json")
|
||||
{
|
||||
|
||||
string settingsJson = JsonConvert.SerializeObject(clientSettings);
|
||||
response.ContentLength = settingsJson.Length;
|
||||
response.ContentType = "application/json";
|
||||
await response.SetBody(settingsJson);
|
||||
|
||||
Log.WriteLine("[Http/ClientSettings] Sent settings to {0}", request.ClientAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string expandedFilePath = getEmbeddedFileReference(request.Url);
|
||||
if(!embeddedFiles.Contains(expandedFilePath))
|
||||
{
|
||||
expandedFilePath += "index.html";
|
||||
}
|
||||
if(!embeddedFiles.Contains(expandedFilePath))
|
||||
{
|
||||
response.ResponseCode = HttpResponseCode.NotFound;
|
||||
response.ContentType = "text/plain";
|
||||
await response.SetBody($"Can't find expandedFilePath.");
|
||||
logRequest(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
response.ContentType = LookupMimeType(expandedFilePath);
|
||||
|
||||
string embeddedFile = EmbeddedFiles.ReadAllText(expandedFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
await response.SetBody(embeddedFile);
|
||||
}
|
||||
catch(Exception error)
|
||||
{
|
||||
Log.WriteLine($"[Nibriboard/EmbeddedFileHandler] Error: {error.Message} Details:");
|
||||
Log.WriteLine(error.ToString());
|
||||
}
|
||||
logRequest(request, response);
|
||||
}
|
||||
|
||||
#region Interface Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to all the connected clients, except the one who's sending it.
|
||||
/// </summary>
|
||||
/// <param name="sendingClient">The client sending the message.</param>
|
||||
/// <param name="message">The message that is to bee sent.</param>
|
||||
public void Broadcast(NibriClient sendingClient, Message message)
|
||||
{
|
||||
foreach(NibriClient client in NibriClients)
|
||||
{
|
||||
// Don't send the message to the sender
|
||||
if(client == sendingClient)
|
||||
continue;
|
||||
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on the same plane as the sender, except the sender themselves.
|
||||
/// </summary>
|
||||
/// <param name="sendingClient">The sending client.</param>
|
||||
/// <param name="message">The message to send.</param>
|
||||
public void BroadcastPlane(NibriClient sendingClient, Message message)
|
||||
{
|
||||
foreach(NibriClient client in NibriClients)
|
||||
{
|
||||
// Don't send the message to the sender
|
||||
if(client == sendingClient)
|
||||
continue;
|
||||
// Only send the message to others on the same plane
|
||||
if(client.CurrentPlane != sendingClient.CurrentPlane)
|
||||
continue;
|
||||
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to everyone on a specified plane.
|
||||
/// </summary>
|
||||
/// <param name="plane">The plane to send the message to.</param>
|
||||
/// <param name="message">The message to send.</param>
|
||||
public void ReflectPlane(Plane plane, Message message)
|
||||
{
|
||||
foreach(NibriClient client in NibriClients)
|
||||
{
|
||||
if(client.CurrentPlane != plane)
|
||||
continue;
|
||||
client.Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
protected string getEmbeddedFileReference(string uri)
|
||||
{
|
||||
return filePrefix + "." + uri.TrimStart("/".ToCharArray()).Replace('/', '.');
|
||||
}
|
||||
|
||||
private void logRequest(HttpRequest request, HttpResponse response)
|
||||
{
|
||||
Log.WriteLine(
|
||||
"[Http/FileHandler] {0} {1} {2} {3}",
|
||||
response.ResponseCode,
|
||||
response.ContentType,
|
||||
request.Method,
|
||||
request.Url
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,14 +1,15 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
using Nibriboard.RippleSpace;
|
||||
using Nibriboard.Client;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
using SBRL.GlidingSquirrel.Websocket;
|
||||
|
||||
using Nibriboard.RippleSpace;
|
||||
using Nibriboard.Client;
|
||||
|
||||
namespace Nibriboard
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -18,14 +19,11 @@ namespace Nibriboard
|
|||
public class NibriboardServer
|
||||
{
|
||||
private TcpListener commandServer;
|
||||
private WebsocketsServer httpServer;
|
||||
private NibriboardApp appServer;
|
||||
|
||||
private ClientSettings clientSettings;
|
||||
private RippleSpaceManager planeManager;
|
||||
|
||||
private readonly CancellationTokenSource clientManagerCanceller = new CancellationTokenSource();
|
||||
private NibriClientManager clientManager;
|
||||
|
||||
public readonly int CommandPort = 31587;
|
||||
public readonly int Port = 31586;
|
||||
|
||||
|
@ -49,37 +47,16 @@ namespace Nibriboard
|
|||
};
|
||||
|
||||
// HTTP Server setup
|
||||
httpServer = new HttpServer(Port);
|
||||
httpServer.AddHttpRequestHandler(
|
||||
"/",
|
||||
new HttpEmbeddedFileHandler("Nibriboard.ClientFiles")
|
||||
/*new HttpResourceHandler(
|
||||
Assembly.GetExecutingAssembly(),
|
||||
"ClientFiles",
|
||||
"index.html"
|
||||
)*/
|
||||
);
|
||||
httpServer.AddHttpRequestHandler(
|
||||
"/Settings.json",
|
||||
new HttpClientSettingsHandler(clientSettings)
|
||||
);
|
||||
|
||||
// Websocket setup
|
||||
clientManager = new NibriClientManager(
|
||||
clientSettings,
|
||||
planeManager,
|
||||
clientManagerCanceller.Token
|
||||
);
|
||||
httpServer.AddWebSocketRequestHandler(
|
||||
clientSettings.WebSocketPath,
|
||||
|
||||
clientManager
|
||||
);
|
||||
appServer = new NibriboardApp(new NibriboardAppStartInfo() {
|
||||
FilePrefix = "Nibriboard.ClientFiles",
|
||||
ClientSettings = clientSettings,
|
||||
SpaceManager = planeManager
|
||||
}, IPAddress.IPv6Any, Port);
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
httpServer.Start();
|
||||
await appServer.Start();
|
||||
Log.WriteLine("[NibriboardServer] Started on port {0}", Port);
|
||||
|
||||
await planeManager.StartMaintenanceMonkey();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e219ad112d256e00563eca76f13691ebe486e3bd
|
||||
Subproject commit e59dd72dd475b685ede1a05258ea0369bdcbc8c1
|
Loading…
Reference in a new issue