Send messages to the client
This commit is contained in:
parent
9ee271559f
commit
5daecdd445
|
@ -12,5 +12,5 @@ socket.addEventListener('open', function (event) {
|
||||||
|
|
||||||
// Listen for messages
|
// Listen for messages
|
||||||
socket.addEventListener('message', function (event) {
|
socket.addEventListener('message', function (event) {
|
||||||
console.log('Message from server', event.data);
|
console.log('Message from server', JSON.parse (event.data));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
using System;
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
namespace Ooui
|
namespace Ooui
|
||||||
{
|
{
|
||||||
public class Message
|
public class Message
|
||||||
{
|
{
|
||||||
|
[JsonProperty("t")]
|
||||||
|
[JsonConverter (typeof (MillisecondEpochConverter))]
|
||||||
public DateTime CreatedTime = DateTime.UtcNow;
|
public DateTime CreatedTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
[JsonProperty("m")]
|
||||||
|
[JsonConverter (typeof (StringEnumConverter))]
|
||||||
public MessageType MessageType = MessageType.Nop;
|
public MessageType MessageType = MessageType.Nop;
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
public string TargetId = "";
|
public string TargetId = "";
|
||||||
public string Member = "";
|
|
||||||
|
[JsonProperty("k")]
|
||||||
|
public string Key = "";
|
||||||
|
|
||||||
|
[JsonProperty("v")]
|
||||||
public string Value = "";
|
public string Value = "";
|
||||||
|
|
||||||
public void SetValue (object value)
|
public void SetValue (object value)
|
||||||
|
@ -20,7 +33,7 @@ namespace Ooui
|
||||||
Value = EncodeString (s);
|
Value = EncodeString (s);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Value = String.Format (System.Globalization.CultureInfo.InvariantCulture, "{0}", value);
|
Value = JsonConvert.SerializeObject (value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,4 +55,20 @@ namespace Ooui
|
||||||
Set,
|
Set,
|
||||||
Call,
|
Call,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MillisecondEpochConverter : DateTimeConverterBase
|
||||||
|
{
|
||||||
|
private static readonly DateTime epoch = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteRawValue (((DateTime)value - epoch).TotalMilliseconds.ToString (System.Globalization.CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.Value == null) return null;
|
||||||
|
return epoch.AddMilliseconds ((double)reader.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
Ooui/Node.cs
17
Ooui/Node.cs
|
@ -14,6 +14,13 @@ namespace Ooui
|
||||||
readonly List<Message> messages = new List<Message> ();
|
readonly List<Message> messages = new List<Message> ();
|
||||||
readonly List<Message> stateMessages = new List<Message> ();
|
readonly List<Message> stateMessages = new List<Message> ();
|
||||||
|
|
||||||
|
public event Action<Message> MessageLogged;
|
||||||
|
|
||||||
|
public IEnumerable<Message> AllMessages =>
|
||||||
|
messages
|
||||||
|
.Concat (from c in children from m in c.AllMessages select m)
|
||||||
|
.OrderBy (x => x.CreatedTime);
|
||||||
|
|
||||||
public Node ()
|
public Node ()
|
||||||
{
|
{
|
||||||
Mapping = Mapping.Get (GetType ());
|
Mapping = Mapping.Get (GetType ());
|
||||||
|
@ -66,7 +73,7 @@ namespace Ooui
|
||||||
{
|
{
|
||||||
var old = stateMessages.FirstOrDefault (
|
var old = stateMessages.FirstOrDefault (
|
||||||
x => x.MessageType == MessageType.Set &&
|
x => x.MessageType == MessageType.Set &&
|
||||||
x.Member == message.Member);
|
x.Key == message.Key);
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
stateMessages.Remove (old);
|
stateMessages.Remove (old);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +81,8 @@ namespace Ooui
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageLogged?.Invoke (message);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void LogCreate ()
|
protected void LogCreate ()
|
||||||
|
@ -90,7 +99,7 @@ namespace Ooui
|
||||||
Log (new Message {
|
Log (new Message {
|
||||||
MessageType = MessageType.Call,
|
MessageType = MessageType.Call,
|
||||||
TargetId = Id,
|
TargetId = Id,
|
||||||
Member = methodName,
|
Key = methodName,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,13 +108,13 @@ namespace Ooui
|
||||||
var m = new Message {
|
var m = new Message {
|
||||||
MessageType = MessageType.Set,
|
MessageType = MessageType.Set,
|
||||||
TargetId = Id,
|
TargetId = Id,
|
||||||
Member = Mapping.GetMemberPath (propertyName),
|
Key = Mapping.GetMemberPath (propertyName),
|
||||||
};
|
};
|
||||||
m.SetValue (value);
|
m.SetValue (value);
|
||||||
Log (m);
|
Log (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool SetProperty<T> (ref T backingStore, T newValue, string propertyName = "")
|
protected bool SetProperty<T> (ref T backingStore, T newValue, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
|
||||||
{
|
{
|
||||||
if (!backingStore.Equals (newValue)) {
|
if (!backingStore.Equals (newValue)) {
|
||||||
backingStore = newValue;
|
backingStore = newValue;
|
||||||
|
|
|
@ -129,6 +129,9 @@ namespace Ooui
|
||||||
|
|
||||||
async void ProcessWebSocketRequest (HttpListenerContext listenerContext, CancellationToken token)
|
async void ProcessWebSocketRequest (HttpListenerContext listenerContext, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Find the element
|
||||||
|
//
|
||||||
var url = listenerContext.Request.Url;
|
var url = listenerContext.Request.Url;
|
||||||
var path = url.LocalPath;
|
var path = url.LocalPath;
|
||||||
|
|
||||||
|
@ -150,9 +153,14 @@ namespace Ooui
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Connect the web socket
|
||||||
|
//
|
||||||
WebSocketContext webSocketContext = null;
|
WebSocketContext webSocketContext = null;
|
||||||
|
WebSocket webSocket = null;
|
||||||
try {
|
try {
|
||||||
webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: "ooui-1.0").ConfigureAwait (false);
|
webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: "ooui-1.0").ConfigureAwait (false);
|
||||||
|
webSocket = webSocketContext.WebSocket;
|
||||||
Console.WriteLine ("WEBSOCKET {0}", listenerContext.Request.Url.LocalPath);
|
Console.WriteLine ("WEBSOCKET {0}", listenerContext.Request.Url.LocalPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
|
@ -162,9 +170,30 @@ namespace Ooui
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocket webSocket = null;
|
|
||||||
|
//
|
||||||
|
// Preparse handlers for the element
|
||||||
|
//
|
||||||
|
Action<Message> onElementMessage = async m => {
|
||||||
|
if (webSocket == null) return;
|
||||||
try {
|
try {
|
||||||
webSocket = webSocketContext.WebSocket;
|
await SendMessageAsync (webSocket, m, token);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
Error ("Failed to handled element message", ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Communicate!
|
||||||
|
//
|
||||||
|
try {
|
||||||
|
foreach (var m in element.AllMessages) {
|
||||||
|
if (webSocket.State == WebSocketState.Open) {
|
||||||
|
await SendMessageAsync (webSocket, m, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.MessageLogged += onElementMessage;
|
||||||
|
|
||||||
var receiveBuffer = new byte[1024];
|
var receiveBuffer = new byte[1024];
|
||||||
|
|
||||||
|
@ -190,8 +219,8 @@ namespace Ooui
|
||||||
var receivedString = Encoding.UTF8.GetString (receiveBuffer, 0, size);
|
var receivedString = Encoding.UTF8.GetString (receiveBuffer, 0, size);
|
||||||
Console.WriteLine ("RECEIVED: {0}", receivedString);
|
Console.WriteLine ("RECEIVED: {0}", receivedString);
|
||||||
|
|
||||||
var outputBuffer = new ArraySegment<byte> (Encoding.UTF8.GetBytes ($"You said: {receivedString}"));
|
// var outputBuffer = new ArraySegment<byte> (Encoding.UTF8.GetBytes ($"You said: {receivedString}"));
|
||||||
await webSocket.SendAsync (outputBuffer, WebSocketMessageType.Text, true, token).ConfigureAwait (false);
|
// await webSocket.SendAsync (outputBuffer, WebSocketMessageType.Text, true, token).ConfigureAwait (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,10 +231,18 @@ namespace Ooui
|
||||||
Error ("Failed to process web socket", ex);
|
Error ("Failed to process web socket", ex);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
element.MessageLogged -= onElementMessage;
|
||||||
webSocket?.Dispose ();
|
webSocket?.Dispose ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Task SendMessageAsync (WebSocket webSocket, Message message, CancellationToken token)
|
||||||
|
{
|
||||||
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject (message);
|
||||||
|
var outputBuffer = new ArraySegment<byte> (Encoding.UTF8.GetBytes (json));
|
||||||
|
return webSocket.SendAsync (outputBuffer, WebSocketMessageType.Text, true, token);
|
||||||
|
}
|
||||||
|
|
||||||
void Error (string message, Exception ex)
|
void Error (string message, Exception ex)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Samples
|
||||||
{
|
{
|
||||||
var server = new Server ();
|
var server = new Server ();
|
||||||
var button = new Button();
|
var button = new Button();
|
||||||
|
button.Name = "TestButton";
|
||||||
server.Publish ("/button", button);
|
server.Publish ("/button", button);
|
||||||
server.RunAsync ("http://*:8080/").Wait ();
|
server.RunAsync ("http://*:8080/").Wait ();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue