mirror of
https://github.com/sbrl/Nibriboard.git
synced 2018-01-10 21:33:49 +00:00
Implement more of the server-side message handling logic.
This commit is contained in:
parent
504f8daed2
commit
4336f1e38c
4 changed files with 146 additions and 16 deletions
|
@ -9,10 +9,11 @@ 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>
|
||||||
public Rectangle InitialViewport = new Rectangle(
|
public Rectangle InitialViewport = Rectangle.Empty;
|
||||||
0, 0,
|
/// <summary>
|
||||||
1366, 768
|
/// The initial position of the user's cursor.
|
||||||
);
|
/// </summary>
|
||||||
|
public Point InitialAbsCursorPosition = Point.Empty;
|
||||||
|
|
||||||
public HandshakeRequestMessage()
|
public HandshakeRequestMessage()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,22 +2,63 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
using IotWeb.Common.Http;
|
using IotWeb.Common.Http;
|
||||||
using SBRL.Utilities;
|
using SBRL.Utilities;
|
||||||
|
using Nibriboard.Client.Messages;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Reflection;
|
||||||
|
using RippleSpace;
|
||||||
|
|
||||||
namespace Nibriboard.Client
|
namespace Nibriboard.Client
|
||||||
{
|
{
|
||||||
public class NibriClient
|
public class NibriClient
|
||||||
{
|
{
|
||||||
|
private static int nextId = 1;
|
||||||
|
private static int getNextId() { return nextId++; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This client's unique id.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Id = getNextId();
|
||||||
|
/// <summary>
|
||||||
|
/// The nibri client manager
|
||||||
|
/// </summary>
|
||||||
private readonly NibriClientManager manager;
|
private readonly NibriClientManager manager;
|
||||||
|
/// <summary>
|
||||||
|
/// 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 WebSocket client;
|
||||||
|
|
||||||
private Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>()
|
private static readonly Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>()
|
||||||
{
|
{
|
||||||
["handshake"] =
|
["handshakeRequest"] = typeof(HandshakeRequestMessage)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this client has completed the handshake yet or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool HandshakeCompleted = false;
|
||||||
|
/// <summary>
|
||||||
|
/// The name this client has assignedto themselves.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The current area that this client is looking at.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The current view port.</value>
|
||||||
|
public Rectangle CurrentViewPort { get; private set; } = Rectangle.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// The absolute position in plane-space of this client's cursor.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The absolute cursor position.</value>
|
||||||
|
public Point AbsoluteCursorPosition { get; private set; } = Point.Empty;
|
||||||
|
|
||||||
|
#region Core Setup & Message Routing Logic
|
||||||
|
|
||||||
public NibriClient(NibriClientManager inManager, WebSocket inClient)
|
public NibriClient(NibriClientManager inManager, WebSocket inClient)
|
||||||
{
|
{
|
||||||
manager = inManager;
|
manager = inManager;
|
||||||
|
@ -40,16 +81,101 @@ namespace Nibriboard.Client
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(string message)
|
private async Task handleMessage(string frame)
|
||||||
|
{
|
||||||
|
string eventName = JsonUtilities.DeserializeProperty<string>(frame, "event");
|
||||||
|
|
||||||
|
if (!messageEventTypes.ContainsKey(eventName))
|
||||||
|
Log.WriteLine("Received message with invalid event {1} from Client #{0}", Id, eventName);
|
||||||
|
|
||||||
|
Type messageType = messageEventTypes[eventName];
|
||||||
|
Type jsonNet = typeof(JsonConvert);
|
||||||
|
MethodInfo deserialiserInfo = jsonNet.GetMethod("DeserailizeObject");
|
||||||
|
MethodInfo genericInfo = deserialiserInfo.MakeGenericMethod(messageType);
|
||||||
|
var decodedMessage = genericInfo.Invoke(null, new object[] { frame });
|
||||||
|
|
||||||
|
string handlerMethodName = "handle" + decodedMessage.GetType().Name;
|
||||||
|
Type clientType = this.GetType();
|
||||||
|
MethodInfo handlerInfo = clientType.GetMethod(handlerMethodName);
|
||||||
|
await (Task)handlerInfo.Invoke(this, new object[] { decodedMessage });
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a <see cref="Nibriboard.Client.Messages.Message"/> to the client.
|
||||||
|
/// If you *really* need to send a raw message to the client, you can do so with the SendRawa() method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to send.</param>
|
||||||
|
public void Send(Message message)
|
||||||
|
{
|
||||||
|
SendRaw(JsonConvert.SerializeObject(message));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a raw string to the client. Don't use unnless you know what you're doing!
|
||||||
|
/// Use the regular Send() method if you can possibly help it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to send.</param>
|
||||||
|
public void SendRaw(string message)
|
||||||
{
|
{
|
||||||
client.Send(Encoding.UTF8.GetBytes(message));
|
client.Send(Encoding.UTF8.GetBytes(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task handleMessage(string frame)
|
/// <summary>
|
||||||
|
/// Generates a new ClientState object representing this client's state at the current time.
|
||||||
|
/// </summary>
|
||||||
|
public ClientState GenerateStateSnapshot()
|
||||||
{
|
{
|
||||||
string eventName = JsonUtilities.DeserializeProperty(frame, "event");
|
ClientState result = new ClientState();
|
||||||
|
result.Id = Id;
|
||||||
|
result.Name = Name;
|
||||||
|
result.AbsCursorPosition = AbsoluteCursorPosition;
|
||||||
|
result.Viewport = CurrentViewPort;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Message Handlers
|
||||||
|
/// <summary>
|
||||||
|
/// Handles an incoming handshake request. We should only receive one of these!
|
||||||
|
/// </summary>
|
||||||
|
protected Task handleHandshakeRequestMessage(HandshakeRequestMessage message)
|
||||||
|
{
|
||||||
|
CurrentViewPort = message.InitialViewport;
|
||||||
|
AbsoluteCursorPosition = message.InitialAbsCursorPosition;
|
||||||
|
|
||||||
|
Send(GenerateClientStateUpdate());
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles an incoming cursor position message from the client..
|
||||||
|
/// </summary>
|
||||||
|
protected Task handleCursorPositionMessage(CursorPositionMessage message) {
|
||||||
|
AbsoluteCursorPosition = message.AbsCursorPosition;
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates an update message that contains information about the locations and states of all connected clients.
|
||||||
|
/// Automatically omits information about the current client.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The client state update message.</returns>
|
||||||
|
protected ClientStateMessage GenerateClientStateUpdate()
|
||||||
|
{
|
||||||
|
ClientStateMessage result = new ClientStateMessage();
|
||||||
|
foreach (NibriClient client in manager.Clients)
|
||||||
|
{
|
||||||
|
// Don't include ourselves in the update message!
|
||||||
|
if (client == this)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result.ClientStates.Add(client.GenerateStateSnapshot());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,14 @@ namespace Nibriboard.Client
|
||||||
public class NibriClientManager : IWebSocketRequestHandler
|
public class NibriClientManager : IWebSocketRequestHandler
|
||||||
{
|
{
|
||||||
private ClientSettings clientSettings;
|
private ClientSettings clientSettings;
|
||||||
private List<NibriClient> clients = new List<NibriClient>();
|
public List<NibriClient> Clients = new List<NibriClient>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of clients currently connected to this Nibriboard.
|
/// The number of clients currently connected to this Nibriboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ClientCount {
|
public int ClientCount {
|
||||||
get {
|
get {
|
||||||
return clients.Count;
|
return Clients.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,18 +45,18 @@ 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);
|
||||||
clients.Add(client);
|
Clients.Add(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Broadcast(NibriClient sendingClient, string message)
|
public void Broadcast(NibriClient sendingClient, string message)
|
||||||
{
|
{
|
||||||
foreach(NibriClient client in clients)
|
foreach(NibriClient client in Clients)
|
||||||
{
|
{
|
||||||
// Don't send the message to the sender
|
// Don't send the message to the sender
|
||||||
if (client == sendingClient)
|
if (client == sendingClient)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
client.Send(message);
|
client.SendRaw(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>Nibriboard</RootNamespace>
|
<RootNamespace>Nibriboard</RootNamespace>
|
||||||
<AssemblyName>Nibriboard</AssemblyName>
|
<AssemblyName>Nibriboard</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -74,6 +74,9 @@
|
||||||
<Compile Include="Utilities\JsonUtilities.cs" />
|
<Compile Include="Utilities\JsonUtilities.cs" />
|
||||||
<Compile Include="Client\Messages\Message.cs" />
|
<Compile Include="Client\Messages\Message.cs" />
|
||||||
<Compile Include="Client\Messages\HandshakeRequestMessage.cs" />
|
<Compile Include="Client\Messages\HandshakeRequestMessage.cs" />
|
||||||
|
<Compile Include="Client\Messages\CursorPositionMessage.cs" />
|
||||||
|
<Compile Include="Client\Messages\ClientStateMessage.cs" />
|
||||||
|
<Compile Include="RippleSpace\ClientState.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="ClientFiles\index.html" />
|
<EmbeddedResource Include="ClientFiles\index.html" />
|
||||||
|
@ -97,7 +100,7 @@
|
||||||
<MonoDevelop>
|
<MonoDevelop>
|
||||||
<Properties>
|
<Properties>
|
||||||
<Policies>
|
<Policies>
|
||||||
<DotNetNamingPolicy DirectoryNamespaceAssociation="Hierarchical" ResourceNamePolicy="FileFormatDefault" />
|
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="FileFormatDefault" />
|
||||||
</Policies>
|
</Policies>
|
||||||
</Properties>
|
</Properties>
|
||||||
</MonoDevelop>
|
</MonoDevelop>
|
||||||
|
|
Loading…
Reference in a new issue