Removed all HTTP Post logic from CotijaSystemController and switched to websockets for sending data to server

This commit is contained in:
Neil Dorin
2018-03-21 12:59:41 -06:00
parent 8d03e81431
commit 82fad55c1e
5 changed files with 142 additions and 208 deletions

View File

@@ -21,12 +21,8 @@ namespace PepperDash.Essentials
{ {
public class CotijaSystemController : Device public class CotijaSystemController : Device
{ {
int SseMessageLengthBeforeFailureCount;
WebSocketClient WSClient; WebSocketClient WSClient;
//GenericHttpSseClient SseClient;
/// <summary> /// <summary>
/// Prevents post operations from stomping on each other and getting lost /// Prevents post operations from stomping on each other and getting lost
/// </summary> /// </summary>
@@ -36,8 +32,6 @@ namespace PepperDash.Essentials
public CotijaConfig Config { get; private set; } public CotijaConfig Config { get; private set; }
HttpClient Client;
Dictionary<string, Object> ActionDictionary = new Dictionary<string, Object>(StringComparer.InvariantCultureIgnoreCase); Dictionary<string, Object> ActionDictionary = new Dictionary<string, Object>(StringComparer.InvariantCultureIgnoreCase);
Dictionary<string, CTimer> PushedActions = new Dictionary<string, CTimer>(); Dictionary<string, CTimer> PushedActions = new Dictionary<string, CTimer>();
@@ -56,13 +50,6 @@ namespace PepperDash.Essentials
long ButtonHeartbeatInterval = 1000; long ButtonHeartbeatInterval = 1000;
bool NeedNewClient;
/// <summary>
/// Used to count retries in PostToServer
/// </summary>
int RetryCounter;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -278,88 +265,21 @@ namespace PepperDash.Essentials
} }
/// <summary> /// <summary>
/// Posts a message to the server from a room /// Sends a message to the server from a room
/// </summary> /// </summary>
/// <param name="room">room from which the message originates</param> /// <param name="room">room from which the message originates</param>
/// <param name="o">object to be serialized and sent in post body</param> /// <param name="o">object to be serialized and sent in post body</param>
public void PostToServer(JObject o) public void SendMessageToServer(JObject o)
{ {
CrestronInvoke.BeginInvoke(oo =>
{
if (string.IsNullOrEmpty(SystemUuid))
{
Debug.Console(1, this, "Status post attempt before UUID is set. Ignoring.");
return;
}
var ready = PostLockEvent.Wait(2000);
if (!ready)
{
Debug.Console(1, this, "PostToServer failed to enter after 2 seconds. Ignoring");
return;
}
PostLockEvent.Reset(); if (WSClient != null && WSClient.Connected)
try
{ {
if (Client == null || NeedNewClient) string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
{
NeedNewClient = false;
Client = new HttpClient();
}
Client.Verbose = false;
Client.KeepAlive = true;
HttpClientRequest request = new HttpClientRequest(); var messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
request.RequestType = RequestType.Post;
string url = string.Format("http://{0}/api/system/{1}/status", Config.ServerUrl, SystemUuid);
request.Url.Parse(url);
request.KeepAlive = true;
request.Header.ContentType = "application/json";
// Ignore any null objects when serializing and remove formatting
string ignored = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
Debug.Console(1, this, "Posting to '{0}':\n{1}", url, ignored);
request.ContentString = ignored;
request.FinalizeHeader();
Client.DispatchAsync(request, (r, err) =>
{
Debug.Console(1, this, "POST result: {0}", err);
if (err == HTTP_CALLBACK_ERROR.COMPLETED) WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME);
{
Debug.Console(1, this, "Status Response Code: {0}", r.Code);
PostLockEvent.Set();
RetryCounter = 0;
} }
else
{
// Try again. This client is hosed.
NeedNewClient = true;
RetryCounter++;
// instant retry on first try.
if (RetryCounter >= 2 && RetryCounter < 5)
CrestronEnvironment.Sleep(1000);
else if (RetryCounter >= 5 && RetryCounter <= 10)
CrestronEnvironment.Sleep(5000);
// give up
else if (RetryCounter > 10)
{
Debug.Console(1, this, "Giving up on server POST");
RetryCounter = 0;
return;
}
Debug.Console(1, this, "POST retry #{0}", RetryCounter);
PostLockEvent.Set();
PostToServer(o);
}
});
}
catch (Exception e)
{
Debug.Console(1, this, "Error Posting to Server: {0}", e);
PostLockEvent.Set();
}
});
} }
@@ -410,7 +330,6 @@ namespace PepperDash.Essentials
else else
{ {
Debug.Console(1, this, "Null response received from server."); Debug.Console(1, this, "Null response received from server.");
NeedNewClient = true;
} }
} }
} }
@@ -485,7 +404,8 @@ namespace PepperDash.Essentials
WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid);
WSClient.Connect(); WSClient.Connect();
Debug.Console(0, this, "Websocket connected"); Debug.Console(0, this, "Websocket connected");
WSClient.ReceiveCallBack = WebsocketReceive; WSClient.ReceiveCallBack = WebsocketReceiveCallback;
WSClient.SendCallBack = WebsocketSendCallback;
WSClient.ReceiveAsync(); WSClient.ReceiveAsync();
@@ -516,7 +436,6 @@ namespace PepperDash.Essentials
// *********************************** // ***********************************
} }
/// <summary> /// <summary>
/// Resets reconnect timer and updates usercode /// Resets reconnect timer and updates usercode
/// </summary> /// </summary>
@@ -541,7 +460,7 @@ namespace PepperDash.Essentials
/// <param name="length"></param> /// <param name="length"></param>
/// <param name="opcode"></param> /// <param name="opcode"></param>
/// <param name="err"></param> /// <param name="err"></param>
int WebsocketReceive(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, int WebsocketReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode,
WebSocketClient.WEBSOCKET_RESULT_CODES err) WebSocketClient.WEBSOCKET_RESULT_CODES err)
{ {
var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length); var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length);
@@ -551,6 +470,18 @@ namespace PepperDash.Essentials
return 1; return 1;
} }
/// <summary>
/// Callback to catch possible errors in sending via the websocket
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
int WebsocketSendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result)
{
Debug.Console(2, "SendCallback result: {0}", result);
return 1;
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -558,6 +489,9 @@ namespace PepperDash.Essentials
/// <param name="e"></param> /// <param name="e"></param>
void ParseStreamRx(string message) void ParseStreamRx(string message)
{ {
if(string.IsNullOrEmpty(message))
return;
Debug.Console(1, this, "Message RX: '{0}'", message); Debug.Console(1, this, "Message RX: '{0}'", message);
try try
{ {
@@ -667,8 +601,8 @@ namespace PepperDash.Essentials
} }
catch (Exception err) catch (Exception err)
{ {
Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount); //Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount);
SseMessageLengthBeforeFailureCount = 0; //SseMessageLengthBeforeFailureCount = 0;
Debug.Console(1, this, "Unable to parse message: {0}", err); Debug.Console(1, this, "Unable to parse message: {0}", err);
} }
} }

View File

@@ -456,7 +456,7 @@ namespace PepperDash.Essentials.Room.Cotija
/// <param name="contentObject">The contents of the content object</param> /// <param name="contentObject">The contents of the content object</param>
void PostStatusMessage(object contentObject) void PostStatusMessage(object contentObject)
{ {
Parent.PostToServer(JObject.FromObject(new Parent.SendMessageToServer(JObject.FromObject(new
{ {
type = "/room/status/", type = "/room/status/",
content = contentObject content = contentObject
@@ -470,7 +470,7 @@ namespace PepperDash.Essentials.Room.Cotija
/// <param name="contentObject"></param> /// <param name="contentObject"></param>
void PostMessage(string messageType, object contentObject) void PostMessage(string messageType, object contentObject)
{ {
Parent.PostToServer(JObject.FromObject(new Parent.SendMessageToServer(JObject.FromObject(new
{ {
type = messageType, type = messageType,
content = contentObject content = contentObject

View File

@@ -102,7 +102,7 @@ namespace PepperDash.Essentials
JObject message = new JObject(); JObject message = new JObject();
message.Add("type", "/room/shutdown/"); message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
/// <summary> /// <summary>
@@ -117,7 +117,7 @@ namespace PepperDash.Essentials
JObject message = new JObject(); JObject message = new JObject();
message.Add("type", "/room/shutdown/"); message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
/// <summary> /// <summary>
@@ -133,7 +133,7 @@ namespace PepperDash.Essentials
JObject message = new JObject(); JObject message = new JObject();
message.Add("type", "/room/shutdown/"); message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
// equivalent JS message: // equivalent JS message:
// Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount }) // Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount })
} }
@@ -150,7 +150,7 @@ namespace PepperDash.Essentials
JObject message = new JObject(); JObject message = new JObject();
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
/// <summary> /// <summary>
@@ -165,7 +165,7 @@ namespace PepperDash.Essentials
JObject message = new JObject(); JObject message = new JObject();
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
/// <summary> /// <summary>
@@ -193,7 +193,7 @@ namespace PepperDash.Essentials
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e)
@@ -245,7 +245,7 @@ namespace PepperDash.Essentials
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
} }
@@ -297,7 +297,7 @@ namespace PepperDash.Essentials
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }
else else
{ {
@@ -362,7 +362,7 @@ namespace PepperDash.Essentials
message.Add("type", "/room/status/"); message.Add("type", "/room/status/");
message.Add("content", roomStatus); message.Add("content", roomStatus);
Parent.PostToServer(message); Parent.SendMessageToServer(message);
} }