1
0
Fork 0
mirror of https://github.com/sbrl/Nibriboard.git synced 2018-01-10 21:33:49 +00:00

Finish fixing bugs in the core message handling system. It works, more or less! :D

This commit is contained in:
Starbeamrainbowlabs 2017-02-05 14:46:40 +00:00
parent 690abc6445
commit e71ff31ef2
12 changed files with 244 additions and 27 deletions

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Drawing;
using SBRL.Utilities;
namespace Nibriboard.Client.Messages namespace Nibriboard.Client.Messages
{ {
@ -11,7 +12,7 @@ namespace Nibriboard.Client.Messages
/// <summary> /// <summary>
/// The absolute cursor position. /// The absolute cursor position.
/// </summary> /// </summary>
public Point AbsCursorPosition; public Vector2 AbsCursorPosition;
public CursorPositionMessage() public CursorPositionMessage()
{ {

View file

@ -1,9 +1,9 @@
using System; using System;
using System.Drawing;
using Newtonsoft.Json; using Newtonsoft.Json;
// TODO: In C# you can either have namespaces or types in a namespace - not both.
using Nibriboard.Utilities.JsonConverters; using SBRL.Utilities;
using SBRL.Utilities.JsonConverters;
namespace Nibriboard.Client.Messages namespace Nibriboard.Client.Messages
{ {
@ -13,13 +13,12 @@ namespace Nibriboard.Client.Messages
/// The initial visible area on the client's screen. /// The initial visible area on the client's screen.
/// Very useful for determining which chunks we should send a client when they first connect. /// Very useful for determining which chunks we should send a client when they first connect.
/// </summary> /// </summary>
[JsonConverter(typeof(RectangleConverter))] public Rectangle InitialViewport = Rectangle.Zero;
public Rectangle InitialViewport = Rectangle.Empty;
/// <summary> /// <summary>
/// The initial position of the user's cursor. /// The initial position of the user's cursor.
/// </summary> /// </summary>
[JsonConverter(typeof(RectangleConverter))] public Vector2 InitialAbsCursorPosition = Vector2.Zero;
public Point InitialAbsCursorPosition = Point.Empty;
public HandshakeRequestMessage() public HandshakeRequestMessage()
{ {

View file

@ -1,19 +1,23 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Text; using System.Text;
using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Reflection;
using IotWeb.Common.Http; using IotWeb.Common.Http;
using Newtonsoft.Json;
using SBRL.Utilities; using SBRL.Utilities;
using Nibriboard.Client.Messages; using Nibriboard.Client.Messages;
using Newtonsoft.Json;
using System.Reflection;
using RippleSpace; using RippleSpace;
namespace Nibriboard.Client namespace Nibriboard.Client
{ {
/// <summary>
/// A delegate that is used in the event that is fired when a nibri client disconnects.
/// </summary>
public delegate void NibriDisconnectedEvent(NibriClient disconnectedClient);
/// <summary> /// <summary>
/// Represents a single client connected to the ripple-space on this Nibriboard server. /// Represents a single client connected to the ripple-space on this Nibriboard server.
/// </summary> /// </summary>
@ -41,6 +45,12 @@ namespace Nibriboard.Client
["handshakeRequest"] = typeof(HandshakeRequestMessage) ["handshakeRequest"] = typeof(HandshakeRequestMessage)
}; };
/// <summary>
/// Whether this nibri client is still connected.
/// </summary>
public bool Connected = true;
public event NibriDisconnectedEvent Disconnected;
/// <summary> /// <summary>
/// Whether this client has completed the handshake yet or not. /// Whether this client has completed the handshake yet or not.
/// </summary> /// </summary>
@ -54,12 +64,12 @@ namespace Nibriboard.Client
/// The current area that this client is looking at. /// The current area that this client is looking at.
/// </summary> /// </summary>
/// <value>The current view port.</value> /// <value>The current view port.</value>
public Rectangle CurrentViewPort { get; private set; } = Rectangle.Empty; public Rectangle CurrentViewPort { get; private set; } = Rectangle.Zero;
/// <summary> /// <summary>
/// The absolute position in plane-space of this client's cursor. /// The absolute position in plane-space of this client's cursor.
/// </summary> /// </summary>
/// <value>The absolute cursor position.</value> /// <value>The absolute cursor position.</value>
public Point AbsoluteCursorPosition { get; private set; } = Point.Empty; public Vector2 AbsoluteCursorPosition { get; private set; } = Vector2.Zero;
#region Core Setup & Message Routing Logic #region Core Setup & Message Routing Logic
@ -81,8 +91,8 @@ namespace Nibriboard.Client
//Task.Run(async () => await onMessage(frame)).Wait(); //Task.Run(async () => await onMessage(frame)).Wait();
}; };
// Store whether this NibriClient is still connected or not
client.ConnectionClosed += (WebSocket socket) => Connected = false;
} }
private async Task handleMessage(string frame) private async Task handleMessage(string frame)
@ -107,7 +117,7 @@ namespace Nibriboard.Client
string handlerMethodName = "handle" + decodedMessage.GetType().Name; string handlerMethodName = "handle" + decodedMessage.GetType().Name;
Type clientType = this.GetType(); Type clientType = this.GetType();
MethodInfo handlerInfo = clientType.GetMethod(handlerMethodName); MethodInfo handlerInfo = clientType.GetMethod(handlerMethodName, BindingFlags.Instance | BindingFlags.NonPublic);
await (Task)handlerInfo.Invoke(this, new object[] { decodedMessage }); await (Task)handlerInfo.Invoke(this, new object[] { decodedMessage });
} }
@ -129,7 +139,10 @@ namespace Nibriboard.Client
/// <param name="message">The message to send.</param> /// <param name="message">The message to send.</param>
public void SendRaw(string message) public void SendRaw(string message)
{ {
client.Send(Encoding.UTF8.GetBytes(message)); if (!Connected)
throw new InvalidOperationException($"[NibriClient]{Id}] Can't send a message as the client has disconnected.");
client.Send(message);
} }
/// <summary> /// <summary>

View file

@ -49,10 +49,16 @@ namespace Nibriboard.Client
public void Connected(WebSocket newSocket) public void Connected(WebSocket newSocket)
{ {
NibriClient client = new NibriClient(this, newSocket); NibriClient client = new NibriClient(this, newSocket);
client.Disconnected += handleDisconnection; // Clean up when the client disconnects
Clients.Add(client); 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) public void Broadcast(NibriClient sendingClient, Message message)
{ {
foreach(NibriClient client in Clients) foreach(NibriClient client in Clients)
@ -64,5 +70,14 @@ namespace Nibriboard.Client
client.Send(message); client.Send(message);
} }
} }
/// <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);
}
} }
} }

View file

@ -46,6 +46,10 @@ class RippleLink extends EventEmitter$1
this.websocket.addEventListener("message", this.handleMessage.bind(this)); this.websocket.addEventListener("message", this.handleMessage.bind(this));
this.websocket.addEventListener("close", this.handleDisconnection.bind(this)); this.websocket.addEventListener("close", this.handleDisconnection.bind(this));
// Close the socket correctly
window.addEventListener("beforeunload", (function(event) {
this.websocket.close();
}).bind(this));
} }
handleConnection(event) { handleConnection(event) {

View file

@ -20,6 +20,10 @@ class RippleLink extends EventEmitter
this.websocket.addEventListener("message", this.handleMessage.bind(this)); this.websocket.addEventListener("message", this.handleMessage.bind(this));
this.websocket.addEventListener("close", this.handleDisconnection.bind(this)); this.websocket.addEventListener("close", this.handleDisconnection.bind(this));
// Close the socket correctly
window.addEventListener("beforeunload", (function(event) {
this.websocket.close();
}).bind(this));
} }
handleConnection(event) { handleConnection(event) {

View file

@ -77,8 +77,10 @@
<Compile Include="Client\Messages\CursorPositionMessage.cs" /> <Compile Include="Client\Messages\CursorPositionMessage.cs" />
<Compile Include="Client\Messages\ClientStateMessage.cs" /> <Compile Include="Client\Messages\ClientStateMessage.cs" />
<Compile Include="RippleSpace\ClientState.cs" /> <Compile Include="RippleSpace\ClientState.cs" />
<Compile Include="Utilities\JsonConverters\RectangleConverter.cs" />
<Compile Include="Utilities\JsonConverters\PointConverter.cs" /> <Compile Include="Utilities\JsonConverters\PointConverter.cs" />
<Compile Include="Utilities\JsonConverters\RectangleJsonConverter.cs" />
<Compile Include="Utilities\Rectangle.cs" />
<Compile Include="Utilities\Vector2.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="ClientFiles\index.html" /> <EmbeddedResource Include="ClientFiles\index.html" />

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Drawing;
using SBRL.Utilities;
namespace RippleSpace namespace RippleSpace
{ {
@ -26,11 +27,11 @@ namespace RippleSpace
/// <summary> /// <summary>
/// The size and position of the client's viewport. /// The size and position of the client's viewport.
/// </summary> /// </summary>
public Rectangle Viewport = Rectangle.Empty; public Rectangle Viewport = Rectangle.Zero;
/// <summary> /// <summary>
/// The absolute position of the client's cursor. /// The absolute position of the client's cursor.
/// </summary> /// </summary>
public Point AbsCursorPosition = Point.Empty; public Vector2 AbsCursorPosition = Vector2.Zero;
public ClientState() public ClientState()
{ {

View file

@ -4,7 +4,7 @@ using System.Drawing;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Nibriboard.Utilities.JsonConverters namespace SBRL.Utilities.JsonConverters
{ {
/// <summary> /// <summary>
/// Deserialises objects into points from the System.Drawing namespace. /// Deserialises objects into points from the System.Drawing namespace.

View file

@ -4,12 +4,12 @@ using System.Drawing;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Nibriboard.Utilities.JsonConverters namespace SBRL.Utilities.JsonConverters
{ {
/// <summary> /// <summary>
/// Deserialises objects into rectangles from the System.Drawing namespace. /// Deserialises objects into rectangles from the System.Drawing namespace.
/// </summary> /// </summary>
public class RectangleConverter : JsonConverter public class RectangleJsonConverter : JsonConverter
{ {
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ {

View file

@ -0,0 +1,115 @@
using System;
using System.Drawing;
namespace SBRL.Utilities
{
/// <summary>
/// Represents a rectangle in 2D space.
/// </summary>
public struct Rectangle
{
/// <summary>
/// A rectangle with all it's properties initialised to zero.
/// </summary>
public static Rectangle Zero = new Rectangle() { X = 0, Y = 0, Width = 0, Height = 0 };
#region Core Data
/// <summary>
/// The X coordinate of the rectangle.
/// </summary>
public int X { get; set; }
/// <summary>
/// The Ycoordinateof the rectangle.
/// </summary>
/// <value>The y.</value>
public int Y { get; set; }
/// <summary>
/// The width of the rectangle.
/// </summary>
public int Width { get; set; }
/// <summary>
/// The height of the rectangle.
/// </summary>
public int Height { get; set; }
#endregion
#region Corners
/// <summary>
/// The top-left corner of the rectangle.
/// </summary>
public Point TopLeft {
get {
return new Point(X, Y);
}
}
/// <summary>
/// The top-right corner of the rectangle.
/// </summary>
public Point TopRight {
get {
return new Point(X + Width, Y);
}
}
/// <summary>
/// The bottom-left corner of the rectangle.
/// </summary>
public Point BottomLeft {
get {
return new Point(X, Y + Height);
}
}
/// <summary>
/// The bottom-right corner of the rectangle.
/// </summary>
public Point BottomRight {
get {
return new Point(X + Width, Y + Height);
}
}
#endregion
#region Edges
/// <summary>
/// The Y coordinate of the top of the rectangle.
/// </summary>
public int Top {
get {
return Y;
}
}
/// <summary>
/// The Y coordinate of the bottom of the rectangle.
/// </summary>
public int Bottom {
get {
return Y + Width;
}
}
/// <summary>
/// The X coordinate of the left side of the rectangle.
/// </summary>
public int Left {
get {
return X;
}
}
/// <summary>
/// The X coordinate of the right side of the rectangle.
/// </summary>
public int Right {
get {
return X + Width;
}
}
#endregion
public Rectangle(int x, int y, int width, int height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
}
}

View file

@ -0,0 +1,63 @@
using System;
namespace SBRL.Utilities
{
/// <summary>
/// Represents a single point in 2D space.
/// May also be used to represent a direction with a magnitude.
/// </summary>
public struct Vector2
{
/// <summary>
/// A Vector 2 with all it's proeprties initialised to zero.
/// </summary>
public static Vector2 Zero = new Vector2() { X = 0, Y = 0 };
/// <summary>
/// The X coordinate.
/// </summary>
public int X { get; set; }
/// <summary>
/// The Y coordinate.
/// </summary>
public int Y { get; set; }
public Vector2(int x, int y)
{
X = x;
Y = y;
}
public Vector2 Add(Vector2 b)
{
return new Vector2(
X + b.X,
Y + b.X
);
}
public Vector2 Subtract(Vector2 b)
{
return new Vector2(
X - b.X,
Y - b.X
);
}
public Vector2 Divide(int b)
{
return new Vector2(
X / b,
Y / b
);
}
public Vector2 Multiply(int b)
{
return new Vector2(
X * b,
Y * b
);
}
}
}