Ooui-tws-port/Ooui/WebSocketSession.cs

164 lines
5.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.WebSockets;
using Tesses.WebServer.WebSocket;
namespace Ooui
{
public class WebSocketSession : Session
{
readonly Action<Message> handleElementMessageSent;
readonly CancellationTokenSource sessionCts = new CancellationTokenSource ();
readonly CancellationTokenSource linkedCts;
readonly CancellationToken token;
readonly System.Timers.Timer sendThrottle;
DateTime lastTransmitTime = DateTime.MinValue;
readonly TimeSpan throttleInterval = TimeSpan.FromSeconds (1.0 / UI.MaxFps);
public WebSocketSession (UI ui,Element element, bool disposeElementAfterSession, double initialWidth, double initialHeight, Action<string, Exception> errorLogger, CancellationToken serverToken)
: base (element, disposeElementAfterSession, initialWidth, initialHeight, errorLogger)
{
this.ui = ui;
//
// Create a new session cancellation token that will trigger
// automatically if the server shutsdown or the session shutsdown.
//
linkedCts = CancellationTokenSource.CreateLinkedTokenSource (serverToken, sessionCts.Token);
token = linkedCts.Token;
//
// Preparse handlers for the element
//
handleElementMessageSent = QueueMessage;
//
// Create a timer to use as a throttle when sending messages
//
sendThrottle = new System.Timers.Timer (throttleInterval.TotalMilliseconds);
sendThrottle.Elapsed += (s, e) => {
// System.Console.WriteLine ("TICK SEND THROTTLE FOR {0}", element);
if ((e.SignalTime - lastTransmitTime) >= throttleInterval) {
sendThrottle.Enabled = false;
lastTransmitTime = e.SignalTime;
TransmitQueuedMessages ();
}
};
}
public void Init()
{
//
// Start watching for changes in the element
//
element.MessageSent += handleElementMessageSent;
try {
//
// Add it to the document body
//
if (element.WantsFullScreen) {
element.Style.Width = initialWidth;
element.Style.Height = initialHeight;
}
QueueMessage (Message.Call ("document.body", "appendChild", element));
}catch(Exception ex)
{
_=ex;
}
}
protected override void QueueMessage (Message message)
{
base.QueueMessage (message);
sendThrottle.Enabled = true;
}
void TransmitQueuedMessages ()
{
try {
//
// Dequeue as many messages as we can
//
var messagesToSend = new List<Message> ();
lock (queuedMessages) {
messagesToSend.AddRange (queuedMessages);
queuedMessages.Clear ();
if (messagesToSend.Count == 0)
return;
//
// Now actually send this message
// Do this while locked to make sure SendAsync is called in the right order
//
var json = Newtonsoft.Json.JsonConvert.SerializeObject (messagesToSend);
//Console.WriteLine ("TRANSMIT " + json);
sendMsg?.Invoke(WebSocketMessage.Create(json));
//task = webSocket.SendAsync (outputBuffer, WebSocketMessageType.Text, true, token).ConfigureAwait (false);
}
}
catch ( System.AggregateException ex)
{
if(ex.ToString().Replace(" ","").ToLower().Contains("mutexisnotowned"))
{
if(ui.Verbose)
Console.WriteLine("Mutex is not owned error, continue going");
}else{
Error ("Failed to send queued messages, aborting session", ex);
element.MessageSent -= handleElementMessageSent;
sessionCts.Cancel ();
}
_=ex;
}
catch (Exception ex) {
Error ("Failed to send queued messages, aborting session", ex);
element.MessageSent -= handleElementMessageSent;
sessionCts.Cancel ();
}
}
Action<WebSocketMessage> sendMsg;
internal void Opened(Action<WebSocketMessage> arg1, Action<byte[]> arg2, CancellationToken arg3)
{
sendMsg = arg1;
Init();
}
internal UI ui;
internal void Arrived(WebSocketMessage obj)
{
element.Receive(obj.DecodeJson<Message>());
}
internal void Closed(bool obj)
{
linkedCts.Cancel();
element.MessageSent -= handleElementMessageSent;
if (disposeElementAfterSession && (element is IDisposable disposable)) {
try {
disposable.Dispose ();
}
catch (Exception ex) {
Error ("Failed to dispose of element", ex);
}
}
}
}
}