164 lines
5.6 KiB
C#
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> ();
|
|
|
|
LockQueue();
|
|
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);
|
|
UnlockQueue();
|
|
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|