BIG TCP Overhaul and passcode start

- Switch to Serilog for console logging
- TCPSender is now persistent (let's hope) so can be used with passcode protected workspaces
- UDP connection works with passcodes just can't timeout
- Passcode prompt is automatic for workspaces that are password protected
This commit is contained in:
2020-06-05 23:53:16 -05:00
parent 4eb84939ca
commit 9899a6d33e
25 changed files with 245 additions and 191 deletions
@@ -130,7 +130,7 @@ namespace qController
{
string workspace_prefix = "/workspace/" + qController.qWorkspace.workspace_id;
string command = workspace_prefix + ((QButton)sender).qCommand.osc;
qController.qClient.sendStringUDP(command);
qController.qClient.sendUDP(command);
}
}
}
@@ -1,5 +1,6 @@
using System;
using Xamarin.Forms;
using Serilog;
namespace qController
{
@@ -102,7 +103,7 @@ namespace qController
void Delete(object sender, EventArgs e)
{
Console.WriteLine("QINSTANCECELL - Delete " + nameLabel.Text + "," + addressLabel.Text + " Pressed");
Log.Debug("QINSTANCECELL - Delete " + nameLabel.Text + "," + addressLabel.Text + " Pressed");
QStorage.RemoveInstance(nameLabel.Text,addressLabel.Text);
}
@@ -110,7 +111,7 @@ namespace qController
void Connect(object sender, EventArgs e)
{
App.NavigationPage.Navigation.PushAsync(new ControlPage(nameLabel.Text,addressLabel.Text));
Console.WriteLine("QINSTANCECELL - Connect To " + nameLabel.Text + " Pressed");
Log.Debug("QINSTANCECELL - Connect To " + nameLabel.Text + " Pressed");
}
}
}
@@ -1,8 +1,9 @@
//Class used to facilitate communication with a QInstance
//Listens for incoming messages via qReceiver (UDP) and tcpSender (TCP)
//WEIRD MESSAGE PARSING RULES NEED FIXED
//TODO: WEIRD MESSAGE PARSING RULES NEED FIXED
using System;
using SharpOSC;
using Serilog;
namespace qController
{
@@ -22,7 +23,8 @@ namespace qController
qParser = new QParser();
qReceiver = new QReceiver(Port + 1);
tcpSender = new TCPSender(Address, Port);
//udpSender = new UDPSender(Address, Port);
tcpSender.Connect();
udpSender = new UDPSender(Address, Port);
tcpSender.MessageReceived += OnMessageReceived;
qReceiver.UpdateMessageReceived += OnMessageReceived;
@@ -32,8 +34,10 @@ namespace qController
//one method for messages received whether from TCP or UDP (SAME MSG FORMAT)
private void OnMessageReceived(object source, MessageEventArgs args)
{
Console.WriteLine("QCLIENT - Message Received: " + args.Message.Address);
//try to find a better filtering process
Log.Debug("QCLIENT - Message Received: " + args.Message.Address);
//TODO: find a better filtering process
if (!args.Message.Address.Contains("update"))
qParser.ParseMessage(args.Message);
else if (args.Message.Address.Contains("playbackPosition") || args.Message.Address.Contains("cueList") || args.Message.Address.Contains("dashboard"))
@@ -55,61 +59,54 @@ namespace qController
}
catch (Exception ex)
{
Console.WriteLine("QCLIENT - Send Exception: " + ex.Message);
Log.Debug("QCLIENT - Send Exception: " + ex.Message);
}
}
public void sendArgs(string address, object args)
public void sendUDP(string address)
{
Log.Debug($"QCLIENT - UDP Sent with address: {address}");
udpSender = new UDPSender(Address,Port);
udpSender.Send(new OscMessage(address));
udpSender.Close();
}
public void sendUDP(string address, params object[] args)
{
Log.Debug($"QCLIENT - UDP Sent with address: {address}");
udpSender = new UDPSender(Address, Port);
udpSender.Send(new OscMessage(address, args));
udpSender.Close();
}
public void sendTCP(string address)
{
Log.Debug($"QCLIENT - TCP Sent with address: {address}");
try
{
tcpSender.Send(new OscMessage(address));
}
catch (Exception ex)
{
Log.Debug("QCLIENT - Send and Receive Exception: " + ex.Message);
}
}
public void sendTCP(string address, params object[] args)
{
Log.Debug($"QCLIENT - TCP Sent with address: {address}");
try
{
tcpSender.Send(new OscMessage(address, args));
}
catch (Exception ex)
{
Console.WriteLine("QCLIENT - Send w/Args Exception: " + ex.Message);
}
}
public void sendStringUDP(string address)
{
udpSender = new UDPSender(Address,Port);
udpSender.Send(new OscMessage(address));
udpSender.Close();
}
public void sendArgsUDP(string address, params object[] args)
{
udpSender = new UDPSender(Address, Port);
udpSender.Send(new OscMessage(address, args));
udpSender.Close();
}
public void sendAndReceiveString(string address)
{
try
{
tcpSender.SendAndReceive(new OscMessage(address));
}
catch (Exception ex)
{
Console.WriteLine("QCLIENT - Send and Receive Exception: " + ex.Message);
}
}
public void sendAndReceiveStringArgs(string address, params object[] args)
{
try
{
tcpSender.SendAndReceive(new OscMessage(address, args));
}
catch (Exception ex)
{
Console.WriteLine("QCLIENT - Send and Receive w/Args Exception: " + ex.Message);
Log.Debug("QCLIENT - Send and Receive w/Args Exception: " + ex.Message);
}
}
public void ProcessUpdate(OscMessage msg)
{
Console.WriteLine("QCLIENT - Process Update: " + msg.Address);
Log.Debug("QCLIENT - Process Update: " + msg.Address);
if (msg.Address.Contains("workspace"))
{
UpdateWorkspace("not yet implemented");
@@ -120,19 +117,19 @@ namespace qController
{
string valuesForKeys = "[\"number\",\"uniqueID\",\"flagged\",\"listName\",\"type\",\"colorName\",\"name\",\"armed\",\"displayName\",\"isBroken\",\"isLoaded\",\"isPaused\",\"isRunning\",\"preWait\",\"duration\",\"postWait\",\"translationX\",\"translationY\",\"opacity\",\"scaleX\",\"scaleY\",\"notes\",\"levels\"]";
string address = "/workspace/" + workspace_id + "/cue_id/" + cue_id + "/valuesForKeys";
sendAndReceiveStringArgs(address, valuesForKeys);
sendTCP(address, valuesForKeys);
}
public void UpdateSelectedCue(string workspace_id)
{
string valuesForKeys = "[\"number\",\"uniqueID\",\"flagged\",\"listName\",\"type\",\"colorName\",\"name\",\"armed\",\"displayName\",\"isBroken\",\"isLoaded\",\"isPaused\",\"isRunning\",\"preWait\",\"duration\",\"postWait\",\"translationX\",\"translationY\",\"opacity\",\"scaleX\",\"scaleY\",\"notes\",\"levels\"]";
string address = "/workspace/" + workspace_id + "/cue/selected/valuesForKeys";
sendAndReceiveStringArgs(address, valuesForKeys);
sendTCP(address, valuesForKeys);
}
public void UpdateWorkspace(string ws_id)
{
Console.WriteLine("QCLIENT - Workspace needs to be updated: " + ws_id);
Log.Debug("QCLIENT - Workspace needs to be updated: " + ws_id);
}
public void Close()
@@ -1,9 +1,9 @@
//Class used for overall Workspace control (ONLY REPRESENTS ONE WORKSPACE)
//Contains all necessary items to facilitate communication (sending, receiving) to a QLab workspace
//Also contains the local QWorkspace object which stores all the information that is used in displaying
//STILL NEED TO WORK ON PASSWORD PROTECTED WORKSPACES
//TODO: STILL NEED TO WORK ON PASSWORD PROTECTED WORKSPACES
using System;
using System.Diagnostics;
using Serilog;
namespace qController
{
@@ -29,27 +29,28 @@ namespace qController
public void Connect(string workspace_id)
{
Console.WriteLine("QCONTROLLER - Connect Called: " + workspace_id);
Log.Debug($"QCONTROLLER - Connect Called: {workspace_id}");
qWorkspace = new QWorkspace(workspace_id);
qUpdater.Start();
qClient.sendArgsUDP("/workspace/"+workspace_id+"/connect");
qClient.sendArgsUDP("/workspace/"+workspace_id+"/updates", 1);
qClient.sendAndReceiveString("/workspace/"+workspace_id+"/cueLists");
qClient.sendUDP("/workspace/"+workspace_id+"/connect");
}
public void Connect(string workspace_id, string passcode)
{
Log.Debug($"QCONTROLLER - Connect with Passcode Called: {workspace_id}:{passcode}");
qWorkspace = new QWorkspace(workspace_id);
qClient.sendUDP("/workspace/" + workspace_id + "/connect", passcode);
qClient.sendTCP("/workspace/" + workspace_id + "/connect", passcode);
}
public void KickOff()
{
qClient.sendArgsUDP("/workspaces");
qClient.sendUDP("/workspaces");
}
public void Disconnect()
{
qClient.sendStringUDP("/workspace/"+qWorkspace.workspace_id+"/disconnect");
}
public void ConnectWithPass(string pass)
{
qClient.sendArgsUDP("/workspace/" + qWorkspace.workspace_id + "/connect", pass);
qClient.sendUDP("/workspace/"+qWorkspace.workspace_id+"/disconnect");
}
public void Resume()
@@ -58,7 +59,7 @@ namespace qController
//qUpdater = new QUpdater(this);
if(qWorkspace != null)
{
Console.WriteLine("QCONTROLLER - Resuming: " + qWorkspace.workspace_id);
Log.Debug($"QCONTROLLER - Resuming: {qWorkspace.workspace_id}");
}
}
@@ -1,6 +1,6 @@
//Currently unused would like to reimplement eventually
//Currently being done in qConnectionPage.xaml.cs Scan() method
using System;
using Serilog;
using System.Collections.Generic;
using Zeroconf;
@@ -14,9 +14,9 @@ namespace qController
public async void SearchForWorkspaces()
{
Console.WriteLine("QFINDER - Scanning Started");
Log.Debug("QFINDER - Scanning Started");
IReadOnlyList<IZeroconfHost> results = await ZeroconfResolver.ResolveAsync("_qlab._udp.local.");
Console.WriteLine("QFINDER - Scanning Done");
Log.Debug("QFINDER - Scanning Done");
}
}
}
@@ -3,6 +3,8 @@ using SharpOSC;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Collections.Generic;
using Serilog;
namespace qController
{
public class CueEventArgs : EventArgs
@@ -39,6 +41,12 @@ namespace qController
get;
set;
}
public string WorkspaceId
{
get;
set;
}
}
public class WorkspaceInfoArgs : EventArgs
@@ -102,7 +110,7 @@ namespace qController
else if (msg.Address.Contains("playbackPosition"))
ParsePositionUpdateInfo(msg);
else if (msg.Address.Contains("thump"))
Console.WriteLine("QPARSER - Heartbeat Received");
Log.Debug("QPARSER - Heartbeat Received");
else if (msg.Address.Contains("disconnect"))
OnWorkspaceDisconnect();
else if (msg.Address.Contains("connect"))
@@ -113,10 +121,10 @@ namespace qController
ParseQInfo(msg);
else
{
Console.WriteLine("QPARSER - Unkown message type: " + msg.Address);
Log.Debug("QPARSER - Unkown message type: " + msg.Address);
foreach (var item in msg.Arguments)
{
Console.WriteLine(item);
Log.Debug(item.ToString());
}
}
}
@@ -127,7 +135,8 @@ namespace qController
if (msg.Arguments.Count > 0)
{
JToken connectStatus = OSC2JSON(msg);
OnConnectionStatusChanged(connectStatus.ToString());
;
OnConnectionStatusChanged(connectStatus.ToString(), msg.Address.Split('/')[3]);
}
}
@@ -223,10 +232,10 @@ namespace qController
if (PlaybackPositionUpdated != null)
PlaybackPositionUpdated(this, new PlaybackPositionArgs() { PlaybackPosition = id });
}
protected virtual void OnConnectionStatusChanged(string status)
protected virtual void OnConnectionStatusChanged(string status, string workspace_id)
{
if (ConnectionStatusChanged != null)
ConnectionStatusChanged(this, new ConnectEventArgs() { Status = status });
ConnectionStatusChanged(this, new ConnectEventArgs() { Status = status, WorkspaceId = workspace_id });
}
protected virtual void OnChildrenUpdated(string id, List<QCue> cues)
{
@@ -1,6 +1,7 @@
//Class used for receiving workspace update messages (UDP)
using SharpOSC;
using System.Threading;
using Serilog;
namespace qController
{
@@ -31,7 +32,7 @@ namespace qController
if (messageReceived != null)
OnUpdateMessageReceived(messageReceived);
else
Console.WriteLine("Message came back null");
Log.Debug("Message came back null");
};
udpListener = new UDPListener(Port, callback);
@@ -1,7 +1,9 @@
//Class used for updating local "copy" of workspace info, cue-lists, cues, etc.
using System;
using System.Threading;
using Serilog;
using Xamarin.Forms;
using Serilog;
namespace qController
{
@@ -10,7 +12,8 @@ namespace qController
private bool active = true;
private QController qController;
private Thread updateThread;
private Thread updateThread;
public QUpdater(QController controller)
{
qController = controller;
@@ -19,19 +22,31 @@ namespace qController
qController.qClient.qParser.WorkspaceUpdated += OnWorkspaceUpdated;
qController.qClient.qParser.PlaybackPositionUpdated += OnPlaybackPositionUpdated;
qController.qClient.qParser.WorkspaceLoadError += OnWorkspaceLoadError;
qController.qClient.qParser.ConnectionStatusChanged += OnConnectionStatusChanged;
}
private void OnConnectionStatusChanged(object source, ConnectEventArgs args)
{
Log.Debug("QUPDATER - Connection Status Changed: " + args.Status);
if (args.Status == "ok")
{
qController.qClient.sendTCP("/workspace/" + qController.qWorkspace.workspace_id + "/updates", 1);
qController.qClient.sendTCP("/workspace/" + qController.qWorkspace.workspace_id + "/cueLists");
}
}
private void OnWorkspaceLoadError(object source, WorkspaceEventArgs args)
{
Console.WriteLine("QUPDATER - Loading cuelists has failed for some reason retrying");
qController.qClient.sendArgsUDP("/workspace/" + args.UpdatedWorkspace.workspace_id + "/connect");
qController.qClient.sendArgsUDP("/workspace/" + args.UpdatedWorkspace.workspace_id + "/updates", 1);
qController.qClient.sendAndReceiveString("/workspace/" + args.UpdatedWorkspace.workspace_id + "/cueLists");
Log.Debug("QUPDATER - Loading cuelists has failed for some reason retrying");
//qController.qClient.sendArgsUDP("/workspace/" + args.UpdatedWorkspace.workspace_id + "/connect");
//qController.qClient.sendArgsUDP("/workspace/" + args.UpdatedWorkspace.workspace_id + "/updates", 1);
//qController.qClient.sendTCP("/workspace/" + args.UpdatedWorkspace.workspace_id + "/cueLists");
}
public void Start(){
Log.Debug("QUPDATER - Start() method called");
updateThread.Start();
}
@@ -51,8 +66,8 @@ namespace qController
if (args.Cue.type == "Group")
{
//Console.WriteLine("QUpdater/Updated cue was group cue, sending children request");
qController.qClient.sendStringUDP("/workspace/"+qController.qWorkspace.workspace_id+"/cue_id/" + args.Cue.uniqueID + "/children");
//Log.Debug("QUpdater/Updated cue was group cue, sending children request");
qController.qClient.sendUDP("/workspace/"+qController.qWorkspace.workspace_id+"/cue_id/" + args.Cue.uniqueID + "/children");
}
}
@@ -63,7 +78,7 @@ namespace qController
qController.qWorkspace.CheckPopulated();
if (qController.qWorkspace.IsPopulated)
{
Console.WriteLine("QUPDATER - Workspace group cues are already populated");
Log.Debug("QUPDATER - Workspace group cues are already populated");
App.showToast("Workspace cues have been loaded....");
//get selected cue
qController.qClient.UpdateSelectedCue(qController.qWorkspace.workspace_id);
@@ -74,14 +89,14 @@ namespace qController
public void OnPlaybackPositionUpdated(object source, PlaybackPositionArgs args)
{
qController.playbackPosition = args.PlaybackPosition;
Console.WriteLine("QUPDATER - Update Specific Cue Called because of Playback Position Updated");
Log.Debug("QUPDATER - Update Specific Cue Called because of Playback Position Updated");
qController.qClient.UpdateSpecificCue(qController.qWorkspace.workspace_id,args.PlaybackPosition);
}
public void SendThump()
{
qController.qClient.sendStringUDP("/workspace/" + qController.qWorkspace.workspace_id + "/thump");
qController.qClient.sendUDP("/workspace/" + qController.qWorkspace.workspace_id + "/thump");
}
public void Kill(){
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Serilog;
namespace SharpOSC
{
@@ -27,8 +27,8 @@ namespace SharpOSC
private static OscMessage parseMessage(byte[] msg)
{
int index = 0;
//Console.WriteLine("Raw ASCII DATA: " + System.Text.Encoding.ASCII.GetString(msg));
//Console.WriteLine("Raw UTF-8 DATA: " + System.Text.Encoding.UTF8.GetString(msg));
//Log.Debug("Raw ASCII DATA: " + System.Text.Encoding.ASCII.GetString(msg));
//Log.Debug("Raw UTF-8 DATA: " + System.Text.Encoding.UTF8.GetString(msg));
string address = null;
char[] types = new char[0];
List<object> arguments = new List<object>();
@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using Serilog;
namespace SharpOSC
{
@@ -46,20 +47,40 @@ namespace SharpOSC
_address = address;
}
public void Send(byte[] message)
public void Connect()
{
client = new TcpClient(Address, Port);
Log.Debug($"TCPSender - connect called for <{Address}:{Port}>");
Thread receivingThread = new Thread(ReceiveLoop);
receivingThread.Start();
}
public void Send(byte[] message)
{
byte[] slipData = SlipEncode(message);
NetworkStream netStream = client.GetStream();
netStream.Write(slipData.ToArray(), 0, slipData.ToArray().Length);
}
public async void Receive()
public void Send(OscPacket packet)
{
byte[] data = packet.GetBytes();
Send(data);
}
public void ReceiveLoop()
{
while (client.Connected)
{
Receive();
}
Log.Debug("TCPSender - Receive Loop has exited for some reason");
}
public void Receive()
{
Random random = new Random();
int num = random.Next(1000);
OscMessage response = new OscMessage("/null");
NetworkStream netStream = client.GetStream();
try
{
@@ -67,49 +88,25 @@ namespace SharpOSC
List<byte> responseData = new List<byte>();
if (netStream.CanRead)
{
byte[] buffer = new byte[1024];
byte[] buffer = new byte[256];
int bytesRead = 0;
do
{
bytesRead = await netStream.ReadAsync(buffer, 0, buffer.Length);
bytesRead = netStream.Read(buffer, 0, buffer.Length);
responseData.AddRange(buffer);
Thread.Sleep(1);
//Console.WriteLine( "Thread " + num + ": Bytes read: " + bytesRead + " - " + Encoding.UTF8.GetString(buffer));
Thread.Sleep(30);
//Log.Debug("Thread " + num + ": Bytes read: " + bytesRead + " - " + Encoding.UTF8.GetString(buffer));
} while (netStream.DataAvailable);
//Console.WriteLine("Raw TCP In: " + System.Text.Encoding.UTF8.GetString(responseData.ToArray()));
response = (OscMessage)OscPacket.GetPacket(responseData.Skip(1).ToArray());
//Log.Debug("Raw TCP In: " + System.Text.Encoding.UTF8.GetString(responseData.ToArray()));
OscMessage response = (OscMessage)OscPacket.GetPacket(responseData.Skip(1).ToArray());
OnMessageReceived(response);
}
} catch(Exception e)
{
Console.WriteLine("TCPSENDER - Receive Exception: " + e.ToString());
//Log.Debug("TCPSENDER - Receive Exception: " + e.ToString());
}
OnMessageReceived(response);
}
public void SendAndReceive(byte[] message)
{
client = new TcpClient(Address, Port);
byte[] slipData = SlipEncode(message);
NetworkStream netStream = client.GetStream();
netStream.Write(slipData.ToArray(), 0, slipData.ToArray().Length);
Receive();
}
public void SendAndReceive(OscPacket packet)
{
OscMessage msg = (OscMessage)packet;
//Console.WriteLine("TCPSENDER - TCP Message Sent: " + msg.Address);
byte[] data = packet.GetBytes();
SendAndReceive(data);
}
public void Send(OscPacket packet)
{
byte[] data = packet.GetBytes();
Send(data);
}
public byte[] SlipEncode(byte[] data)
@@ -4,6 +4,7 @@ using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using Serilog;
namespace SharpOSC
{
@@ -96,10 +97,10 @@ namespace SharpOSC
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Log.Debug(e.ToString());
// If there is an error reading the packet, null is sent to the callback
}
//Console.WriteLine("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
OscPacketCallback(packet);
}
else
@@ -150,7 +151,7 @@ namespace SharpOSC
{
byte[] bytes = queue.Dequeue();
var packet = OscPacket.GetPacket(bytes);
//Console.WriteLine("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
return packet;
}
else
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using Serilog;
namespace qController
{
@@ -54,7 +55,7 @@ namespace qController
{
if(data[i].cues[j].uniqueID == cue.uniqueID)
{
//Console.WriteLine("Cue found and updated in workspace: " + cue.uniqueID);
//Log.Debug("Cue found and updated in workspace: " + cue.uniqueID);
data[i].cues[j] = cue;
return;
}
@@ -101,7 +102,7 @@ namespace qController
{
foreach (var cueList in data)
{
Console.WriteLine(cueList.listName + "("+ cueList.cues.Count + " cues)");
Log.Debug(cueList.listName + "("+ cueList.cues.Count + " cues)");
}
}
}
@@ -1,4 +1,4 @@
using System;
using Serilog;
using System.Collections.ObjectModel;
using Acr.Settings;
@@ -13,7 +13,7 @@ namespace qController
if (qInstances == null)
{
Console.WriteLine("QSTORAGE - No qInstance exists creating one");
Log.Debug("QSTORAGE - No qInstance exists creating one");
qInstances = new ObservableCollection<QInstance>();
updateStorage();
}
@@ -54,7 +54,7 @@ namespace qController
public static bool Contains(string name, string address){
foreach (var item in qInstances)
{
//Console.WriteLine("Item name: " + item.name + " Found Name: " + name);
//Log.Debug("Item name: " + item.name + " Found Name: " + name);
if (item.address == address)
{
return true;