Ooui-tws-port/Ooui/WebSocketSession.cs

150 lines
5.0 KiB
C#
Raw Normal View History

2018-03-14 00:56:11 +00:00
using System;
2018-03-09 23:14:51 +00:00
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;
2023-03-17 08:08:32 +00:00
using Tesses.WebServer.WebSocket;
2018-03-09 23:14:51 +00:00
namespace Ooui
{
public class WebSocketSession : Session
{
2023-03-17 08:08:32 +00:00
2018-03-09 23:14:51 +00:00
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);
2023-03-17 08:08:32 +00:00
public WebSocketSession (Element element, bool disposeElementAfterSession, double initialWidth, double initialHeight, Action<string, Exception> errorLogger, CancellationToken serverToken)
: base (element, disposeElementAfterSession, initialWidth, initialHeight, errorLogger)
2018-03-09 23:14:51 +00:00
{
2023-03-17 08:08:32 +00:00
2018-03-09 23:14:51 +00:00
//
// 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 ();
}
};
}
2023-03-17 08:08:32 +00:00
public void Init()
2018-03-09 23:14:51 +00:00
{
//
// 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));
2023-03-17 08:08:32 +00:00
}catch(Exception ex)
{
_=ex;
2018-03-09 23:14:51 +00:00
}
2023-03-17 08:08:32 +00:00
2018-03-09 23:14:51 +00:00
}
protected override void QueueMessage (Message message)
{
base.QueueMessage (message);
sendThrottle.Enabled = true;
}
2023-03-17 08:08:32 +00:00
void TransmitQueuedMessages ()
2018-03-09 23:14:51 +00:00
{
try {
//
// Dequeue as many messages as we can
//
var messagesToSend = new List<Message> ();
2023-03-17 08:08:32 +00:00
2018-03-09 23:14:51 +00:00
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);
2023-03-17 08:08:32 +00:00
//Console.WriteLine ("TRANSMIT " + json);
sendMsg?.Invoke(WebSocketMessage.Create(json));
//task = webSocket.SendAsync (outputBuffer, WebSocketMessageType.Text, true, token).ConfigureAwait (false);
2018-03-09 23:14:51 +00:00
}
2023-03-17 08:08:32 +00:00
2018-03-09 23:14:51 +00:00
}
catch (Exception ex) {
Error ("Failed to send queued messages, aborting session", ex);
element.MessageSent -= handleElementMessageSent;
sessionCts.Cancel ();
}
}
2023-03-17 08:08:32 +00:00
Action<WebSocketMessage> sendMsg;
internal void Opened(Action<WebSocketMessage> arg1, Action<byte[]> arg2, CancellationToken arg3)
{
sendMsg = arg1;
Init();
}
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);
}
}
}
2018-03-09 23:14:51 +00:00
}
}