diff --git a/Client/Client.cs b/Client/Client.cs new file mode 100644 index 0000000..123d222 --- /dev/null +++ b/Client/Client.cs @@ -0,0 +1,149 @@ +using System; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using ProftaakRH; + +namespace Client +{ + class Client : IDataReceiver + { + private TcpClient client; + private NetworkStream stream; + private byte[] buffer = new byte[1024]; + private bool connected; + private byte[] totalBuffer = new byte[1024]; + private int totalBufferReceived = 0; + + + public Client() : this("localhost", 5555) + { + + } + + public Client(string adress, int port) + { + this.client = new TcpClient(); + this.connected = false; + client.BeginConnect(adress, port, new AsyncCallback(OnConnect), null); + } + + private void OnConnect(IAsyncResult ar) + { + this.client.EndConnect(ar); + Console.WriteLine("Verbonden!"); + + + this.stream = this.client.GetStream(); + + tryLogin(); + + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + } + + private void OnRead(IAsyncResult ar) + { + int receivedBytes = this.stream.EndRead(ar); + + if (totalBufferReceived + receivedBytes > 1024) + { + throw new OutOfMemoryException("buffer too small"); + } + Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, receivedBytes); + totalBufferReceived += receivedBytes; + + int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + while (totalBufferReceived >= expectedMessageLength) + { + //volledig packet binnen + byte[] messageBytes = new byte[expectedMessageLength]; + Array.Copy(totalBuffer, 0, messageBytes, 0, expectedMessageLength); + + + byte[] payloadbytes = new byte[BitConverter.ToInt32(messageBytes, 0) - 5]; + + Array.Copy(messageBytes, 5, payloadbytes, 0, payloadbytes.Length); + + string identifier; + bool isJson = DataParser.getJsonIdentifier(messageBytes, out identifier); + if (isJson) + { + switch (identifier) + { + case DataParser.LOGIN_RESPONSE: + string responseStatus = DataParser.getResponseStatus(payloadbytes); + if (responseStatus == "OK") + { + this.connected = true; + } + else + { + Console.WriteLine($"login failed \"{responseStatus}\""); + tryLogin(); + } + break; + default: + Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}"); + break; + } + } + else if (DataParser.isRawData(messageBytes)) + { + Console.WriteLine($"Received data: {BitConverter.ToString(payloadbytes)}"); + } + + totalBufferReceived -= expectedMessageLength; + expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + } + + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + + } + + private void OnWrite(IAsyncResult ar) + { + this.stream.EndWrite(ar); + } + + #region interface + //maybe move this to other place + public void BPM(byte[] bytes) + { + if (bytes == null) + { + throw new ArgumentNullException("no bytes"); + } + byte[] message = DataParser.GetRawDataMessage(bytes); + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + } + + public void Bike(byte[] bytes) + { + if (bytes == null) + { + throw new ArgumentNullException("no bytes"); + } + byte[] message = DataParser.GetRawDataMessage(bytes); + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + } + + #endregion + + public bool IsConnected() + { + return this.connected; + } + private void tryLogin() + { + //TODO File in lezen + Console.WriteLine("enter username"); + string username = Console.ReadLine(); + Console.WriteLine("enter password"); + string password = Console.ReadLine(); + + byte[] message = DataParser.getJsonMessage(DataParser.GetLoginJson(username, password)); + + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + } + } +} diff --git a/Client/Client.csproj b/Client/Client.csproj new file mode 100644 index 0000000..dd9af6e --- /dev/null +++ b/Client/Client.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + diff --git a/Client/DataParser.cs b/Client/DataParser.cs new file mode 100644 index 0000000..c83b86a --- /dev/null +++ b/Client/DataParser.cs @@ -0,0 +1,166 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Client +{ + public class DataParser + { + public const string LOGIN = "LOGIN"; + public const string LOGIN_RESPONSE = "LOGIN_RESPONSE"; + /// + /// makes the json object with LOGIN identifier and username and password + /// + /// username + /// password + /// json object to ASCII to bytes + public static byte[] GetLoginJson(string mUsername, string mPassword) + { + dynamic json = new + { + identifier = LOGIN, + data = new + { + username = mUsername, + password = mPassword, + } + }; + + return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)); + } + + public static bool GetUsernamePassword(byte[] jsonbytes, out string username, out string password) + { + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(jsonbytes)); + try + { + username = json.data.username; + password = json.data.password; + return true; + } + catch + { + username = null; + password = null; + return false; + } + } + + private static byte[] getJsonMessage(string mIdentifier, dynamic data) + { + dynamic json = new + { + identifier = mIdentifier, + data + }; + return getMessage(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)), 0x01); + } + + public static byte[] getLoginResponse(string mStatus) + { + return getJsonMessage(LOGIN_RESPONSE, new { status = mStatus }); + } + + public static string getResponseStatus(byte[] json) + { + return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.status; + } + + /// + /// get the identifier from json + /// + /// json in ASCII + /// gets the identifier + /// if it sucseeded + public static bool getJsonIdentifier(byte[] bytes, out string identifier) + { + if (bytes.Length <= 5) + { + throw new ArgumentException("bytes to short"); + } + byte messageId = bytes[4]; + + if (messageId == 0x01) + { + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(bytes.Skip(5).ToArray())); + identifier = json.identifier; + return true; + } + else + { + identifier = ""; + return false; + } + } + + /// + /// checks if the de message is raw data according to the protocol + /// + /// message + /// if message contains raw data + public static bool isRawData(byte[] bytes) + { + if (bytes.Length <= 5) + { + throw new ArgumentException("bytes to short"); + } + return bytes[4] == 0x02; + } + + /// + /// constructs a message with the payload, messageId and clientId + /// + /// + /// + /// + /// the message ready for sending + private static byte[] getMessage(byte[] payload, byte messageId) + { + byte[] res = new byte[payload.Length + 5]; + + Array.Copy(BitConverter.GetBytes(payload.Length + 5), 0, res, 0, 4); + res[4] = messageId; + Array.Copy(payload, 0, res, 5, payload.Length); + + return res; + } + + /// + /// constructs a message with the payload and clientId and assumes the payload is raw data + /// + /// + /// + /// the message ready for sending + public static byte[] GetRawDataMessage(byte[] payload) + { + return getMessage(payload, 0x02); + } + + /// + /// constructs a message with the payload and clientId and assumes the payload is json + /// + /// + /// + /// the message ready for sending + public static byte[] getJsonMessage(byte[] payload) + { + return getMessage(payload, 0x01); + } + + /// + /// constructs a message with the message and clientId + /// + /// + /// + /// the message ready for sending + public static byte[] getJsonMessage(string message) + { + return getJsonMessage(Encoding.ASCII.GetBytes(message)); + } + + + } +} diff --git a/Client/Program.cs b/Client/Program.cs new file mode 100644 index 0000000..7b722f5 --- /dev/null +++ b/Client/Program.cs @@ -0,0 +1,35 @@ +using System; +using Hardware; +using Hardware.Simulators; + +namespace Client +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + //connect fiets? + + + Client client = new Client(); + + + while (!client.IsConnected()) + { + + } + //BLEHandler bLEHandler = new BLEHandler(client); + + //bLEHandler.Connect(); + + BikeSimulator bikeSimulator = new BikeSimulator(client); + + bikeSimulator.StartSimulation(); + + while (true) + { + } + } + } +} diff --git a/Message/Message.cs b/Message/Message.cs new file mode 100644 index 0000000..34c0ff5 --- /dev/null +++ b/Message/Message.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; +using System; + +namespace Message +{ + /// + /// Message class to handle traffic between clients and server + /// + public class Message + { + + public static void Main(string[] args) + { + + } + /// + /// identifier for the message + /// + public Identifier Identifier + { + get;set; + } + + /// + /// payload of the message, the actual text + /// + public string Payload + { + get;set; + } + + /// + /// constructs a new message with the given parameters + /// + /// the identifier + /// the payload + public Message(Identifier identifier, string payload) + { + this.Identifier = identifier; + this.Payload = payload; + } + + /// + /// serializes this object to a JSON string + /// + /// a JSON representation of this object + public string Serialize() + { + return JsonConvert.SerializeObject(this); + } + + /// + /// deserializes a JSON string into a new Message object + /// + /// the JSON string to deserialize + /// a new Message object from the JSON string + public static Message Deserialize(string json) + { + return (Message)JsonConvert.DeserializeObject(json); + } + } + + /// + /// Identifier enum for the Message objects + /// + public enum Identifier + { + LOGIN, + CHAT, + } +} diff --git a/Message/Message.csproj b/Message/Message.csproj new file mode 100644 index 0000000..0eaee1b --- /dev/null +++ b/Message/Message.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp3.1 + + + + + + + diff --git a/ProftaakRH/BLEHandler.cs b/ProftaakRH/BLEHandler.cs index da2d90a..6baf843 100644 --- a/ProftaakRH/BLEHandler.cs +++ b/ProftaakRH/BLEHandler.cs @@ -4,15 +4,16 @@ using System.Text; using Avans.TI.BLE; using System.Threading; using System.Security.Cryptography; +using ProftaakRH; namespace Hardware { /// /// BLEHandler class that handles connection and traffic to and from the bike /// - class BLEHandler + public class BLEHandler { - IDataConverter dataConverter; + List dataReceivers; private BLE bleBike; private BLE bleHeart; public bool Running { get; set; } @@ -20,11 +21,20 @@ namespace Hardware /// /// Makes a new BLEHandler object /// - /// the dataconverter object - public BLEHandler(IDataConverter dataConverter) + /// the dataconverter object + public BLEHandler(IDataReceiver dataReceiver) { - this.dataConverter = dataConverter; - bool running = false; + this.dataReceivers = new List { dataReceiver }; + } + + public BLEHandler(List dataReceivers) + { + this.dataReceivers = dataReceivers; + } + + public void addDataReceiver(IDataReceiver dataReceiver) + { + this.dataReceivers.Add(dataReceiver); } /// @@ -120,16 +130,22 @@ namespace Hardware /// the value changed event private void BleBike_SubscriptionValueChanged(object sender, BLESubscriptionValueChangedEventArgs e) { - + if (e.ServiceName == "6e40fec2-b5a3-f393-e0a9-e50e24dcca9e") { byte[] payload = new byte[8]; Array.Copy(e.Data, 4, payload, 0, 8); - this.dataConverter.Bike(payload); + foreach (IDataReceiver dataReceiver in this.dataReceivers) + { + dataReceiver.Bike(payload); + } } else if (e.ServiceName == "00002a37-0000-1000-8000-00805f9b34fb") { - this.dataConverter.BPM(e.Data); + foreach (IDataReceiver dataReceiver in this.dataReceivers) + { + dataReceiver.BPM(e.Data); + } } else { @@ -165,7 +181,7 @@ namespace Hardware antMessage[i] = 0xFF; } antMessage[11] = (byte)Math.Max(Math.Min(Math.Round(percentage / 0.5), 255), 0); - + byte checksum = 0; for (int i = 0; i < 12; i++) diff --git a/ProftaakRH/BikeSimulator.cs b/ProftaakRH/BikeSimulator.cs index 5664f9e..daea355 100644 --- a/ProftaakRH/BikeSimulator.cs +++ b/ProftaakRH/BikeSimulator.cs @@ -1,4 +1,5 @@ using LibNoise.Primitive; +using ProftaakRH; using System; using System.Collections.Generic; using System.Linq; @@ -9,9 +10,9 @@ using System.Threading; namespace Hardware.Simulators { - class BikeSimulator : IHandler + public class BikeSimulator : IHandler { - IDataConverter dataConverter; + List dataReceivers; private int elapsedTime = 0; private int eventCounter = 0; private double distanceTraveled = 0; @@ -29,10 +30,21 @@ namespace Hardware.Simulators - public BikeSimulator(IDataConverter dataConverter) + public BikeSimulator(IDataReceiver dataReceiver) { - this.dataConverter = dataConverter; + this.dataReceivers = new List { dataReceiver }; } + + public BikeSimulator(List dataReceivers) + { + this.dataReceivers = dataReceivers; + } + + public void addDataReceiver(IDataReceiver dataReceiver) + { + this.dataReceivers.Add(dataReceiver); + } + public void StartSimulation() { //Example BLE Message @@ -41,16 +53,19 @@ namespace Hardware.Simulators float x = 0.0f; //Perlin for Random values - ImprovedPerlin improvedPerlin = new ImprovedPerlin(0,LibNoise.NoiseQuality.Best); - + ImprovedPerlin improvedPerlin = new ImprovedPerlin(0, LibNoise.NoiseQuality.Best); + while (true) { - CalculateVariables(improvedPerlin.GetValue(x)+1); + CalculateVariables(improvedPerlin.GetValue(x) + 1); //Simulate sending data - dataConverter.Bike(GenerateBike0x19()); - dataConverter.Bike(GenerateBike0x10()); - dataConverter.BPM(GenerateHeart()); + foreach (IDataReceiver dataReceiver in this.dataReceivers) + { + dataReceiver.Bike(GenerateBike0x19()); + dataReceiver.Bike(GenerateBike0x10()); + dataReceiver.BPM(GenerateHeart()); + } Thread.Sleep(1000); @@ -65,21 +80,21 @@ namespace Hardware.Simulators private byte[] GenerateBike0x19() { byte statByte = (byte)(powerArray[1] >> 4); - byte[] bikeByte = { 0x19, Convert.ToByte(eventCounter%256), Convert.ToByte(cadence%254), accPowerArray[0], accPowerArray[1], powerArray[0], statByte, 0x20 }; + byte[] bikeByte = { 0x19, Convert.ToByte(eventCounter % 256), Convert.ToByte(cadence % 254), accPowerArray[0], accPowerArray[1], powerArray[0], statByte, 0x20 }; return bikeByte; } //Generate an ANT message for page 0x10 private byte[] GenerateBike0x10() { - byte[] bikeByte = { 0x10, Convert.ToByte(equipmentType), Convert.ToByte(elapsedTime*4%64), Convert.ToByte(distanceTraveled), speedArray[0], speedArray[1], Convert.ToByte(BPM), 0xFF }; + byte[] bikeByte = { 0x10, Convert.ToByte(equipmentType), Convert.ToByte(elapsedTime * 4 % 64), Convert.ToByte(distanceTraveled), speedArray[0], speedArray[1], Convert.ToByte(BPM), 0xFF }; return bikeByte; } //Generate an ANT message for BPM private byte[] GenerateHeart() { - byte[] hartByte = { 0x00, Convert.ToByte(BPM)}; + byte[] hartByte = { 0x00, Convert.ToByte(BPM) }; return hartByte; } @@ -114,13 +129,13 @@ namespace Hardware.Simulators //Input perlin value private void CalculateVariables(float perlin) { - this.speed = perlin * 5 / 0.01 ; + this.speed = perlin * 5 / 0.01; short sped = (short)speed; speedArray = BitConverter.GetBytes(sped); - this.distanceTraveled = (distanceTraveled+(speed*0.01)) % 256; - this.BPM = (int) (perlin * 80); - this.cadence = (int)speed/6; - this.power = ((1 + resistance) * speed)/14 % 4094; + this.distanceTraveled = (distanceTraveled + (speed * 0.01)) % 256; + this.BPM = (int)(perlin * 80); + this.cadence = (int)speed / 6; + this.power = ((1 + resistance) * speed) / 14 % 4094; this.accPower = (this.accPower + this.power) % 65536; // TO DO power to power LSB & MSN powerArray = BitConverter.GetBytes((short)this.power); @@ -131,9 +146,9 @@ namespace Hardware.Simulators public void setResistance(byte[] bytes) { //TODO check if message is correct - if(bytes.Length == 13) + if (bytes.Length == 13) { - this.resistance = Convert.ToDouble(bytes[11])/2; + this.resistance = Convert.ToDouble(bytes[11]) / 2; } } } diff --git a/ProftaakRH/DataConverter.cs b/ProftaakRH/DataConverter.cs index 7c93ff2..69eb49e 100644 --- a/ProftaakRH/DataConverter.cs +++ b/ProftaakRH/DataConverter.cs @@ -1,4 +1,5 @@ -using System; +using ProftaakRH; +using System; using System.Collections.Generic; using System.Text; @@ -7,7 +8,7 @@ namespace Hardware /// /// DataConverter class that handles all conversion of received data from the BLE bike. /// - class DataConverter : IDataConverter + class DataConverter : IDataReceiver { /// /// Receives, parses and displays any incoming data from the bike. @@ -22,7 +23,7 @@ namespace Hardware else if (bytes.Length == 8) { - + switch (bytes[0]) { case 0x10: @@ -37,7 +38,7 @@ namespace Hardware Console.WriteLine($"Speed is : {input * 0.01}m/s (Range 65.534m/4)"); if (bytes[6] != 0xFF) { - Console.WriteLine("Heart rate byte: {0}", Convert.ToString(bytes[6],2)); + Console.WriteLine("Heart rate byte: {0}", Convert.ToString(bytes[6], 2)); } break; case 0x19: @@ -45,17 +46,17 @@ namespace Hardware if (bytes[2] != 0xFF) { Console.WriteLine($"Instantaneous cadence: {bytes[2]} RPM (Range 0-254)"); - + } int accumPower = bytes[3] | (bytes[4] << 8); - + Console.WriteLine($"Accumulated power: {accumPower} watt (Rollover 65536)"); - int instantPower = (bytes[5]) | (bytes[6] & 0b00001111)<<8; - + int instantPower = (bytes[5]) | (bytes[6] & 0b00001111) << 8; + if (instantPower != 0xFFF) - Console.WriteLine($"Instant power: {instantPower} watt (Range 0-4094)"); + Console.WriteLine($"Instant power: {instantPower} watt (Range 0-4094)"); int trainerStatus = bytes[6] & 0b11110000; // bit 4-7 int flags = bytes[7] >> 4; @@ -103,13 +104,4 @@ namespace Hardware Console.WriteLine(); } } - - /// - /// Dataconverter interface for handling data received from the bike - /// - interface IDataConverter - { - void BPM(byte[] bytes); - void Bike(byte[] bytes); - } } diff --git a/ProftaakRH/IDataReceiver.cs b/ProftaakRH/IDataReceiver.cs new file mode 100644 index 0000000..7105c47 --- /dev/null +++ b/ProftaakRH/IDataReceiver.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProftaakRH +{ + public interface IDataReceiver + { + void BPM(byte[] bytes); + void Bike(byte[] bytes); + } +} diff --git a/ProftaakRH/Main.cs b/ProftaakRH/Main.cs index 0938089..5ffcab4 100644 --- a/ProftaakRH/Main.cs +++ b/ProftaakRH/Main.cs @@ -7,15 +7,15 @@ using Hardware.Simulators; namespace ProftaakRH { - class Program + class Program { static void Main(string[] agrs) { - IDataConverter dataConverter = new DataConverter(); - BLEHandler bLEHandler = new BLEHandler(dataConverter); - //BikeSimulator bikeSimulator = new BikeSimulator(dataConverter); - //bikeSimulator.setResistance(bikeSimulator.GenerateResistance(1f)); - //bikeSimulator.StartSimulation(); + IDataReceiver dataReceiver = new DataConverter(); + BLEHandler bLEHandler = new BLEHandler(dataReceiver); + BikeSimulator bikeSimulator = new BikeSimulator(dataReceiver); + bikeSimulator.setResistance(bikeSimulator.GenerateResistance(1f)); + bikeSimulator.StartSimulation(); bool running = true; @@ -24,7 +24,7 @@ namespace ProftaakRH string input = Console.ReadLine(); input.ToLower(); input.Trim(); - if(input == "quit") + if (input == "quit") { running = false; break; diff --git a/ProftaakRH/ProftaakRH.csproj b/ProftaakRH/ProftaakRH.csproj index 8f98a2c..d6280ab 100644 --- a/ProftaakRH/ProftaakRH.csproj +++ b/ProftaakRH/ProftaakRH.csproj @@ -7,6 +7,7 @@ + diff --git a/ProftaakRH/ProftaakRH.sln b/ProftaakRH/ProftaakRH.sln index a756a82..069a13b 100644 --- a/ProftaakRH/ProftaakRH.sln +++ b/ProftaakRH/ProftaakRH.sln @@ -3,7 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30413.136 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProftaakRH", "ProftaakRH.csproj", "{0F053CC5-D969-4970-9501-B3428EA3D777}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProftaakRH", "ProftaakRH.csproj", "{0F053CC5-D969-4970-9501-B3428EA3D777}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RH-Engine", "..\RH-Engine\RH-Engine.csproj", "{984E295E-47A2-41E7-90E5-50FDB9E67694}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "..\Server\Server.csproj", "{B1AB6F51-A20D-4162-9A7F-B3350B7510FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "..\Client\Client.csproj", "{5759DD20-7A4F-4D8D-B986-A70A7818C112}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Message", "..\Message\Message.csproj", "{9ED6832D-B0FB-4460-9BCD-FAA58863B0CE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +23,22 @@ Global {0F053CC5-D969-4970-9501-B3428EA3D777}.Debug|Any CPU.Build.0 = Debug|Any CPU {0F053CC5-D969-4970-9501-B3428EA3D777}.Release|Any CPU.ActiveCfg = Release|Any CPU {0F053CC5-D969-4970-9501-B3428EA3D777}.Release|Any CPU.Build.0 = Release|Any CPU + {984E295E-47A2-41E7-90E5-50FDB9E67694}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {984E295E-47A2-41E7-90E5-50FDB9E67694}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984E295E-47A2-41E7-90E5-50FDB9E67694}.Release|Any CPU.ActiveCfg = Release|Any CPU + {984E295E-47A2-41E7-90E5-50FDB9E67694}.Release|Any CPU.Build.0 = Release|Any CPU + {B1AB6F51-A20D-4162-9A7F-B3350B7510FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1AB6F51-A20D-4162-9A7F-B3350B7510FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1AB6F51-A20D-4162-9A7F-B3350B7510FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1AB6F51-A20D-4162-9A7F-B3350B7510FD}.Release|Any CPU.Build.0 = Release|Any CPU + {5759DD20-7A4F-4D8D-B986-A70A7818C112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5759DD20-7A4F-4D8D-B986-A70A7818C112}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5759DD20-7A4F-4D8D-B986-A70A7818C112}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5759DD20-7A4F-4D8D-B986-A70A7818C112}.Release|Any CPU.Build.0 = Release|Any CPU + {9ED6832D-B0FB-4460-9BCD-FAA58863B0CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9ED6832D-B0FB-4460-9BCD-FAA58863B0CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9ED6832D-B0FB-4460-9BCD-FAA58863B0CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9ED6832D-B0FB-4460-9BCD-FAA58863B0CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RH-Engine/Command.cs b/RH-Engine/Command.cs index 6491de4..3ef3bc1 100644 --- a/RH-Engine/Command.cs +++ b/RH-Engine/Command.cs @@ -1,10 +1,6 @@ using LibNoise.Primitive; using Newtonsoft.Json; using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading; namespace RH_Engine { @@ -16,9 +12,7 @@ namespace RH_Engine public const string STANDARD_LEFTHAND = "LeftHand"; public const string STANDARD_RIGHTHAND = "RightHand"; - - - string tunnelID; + private string tunnelID; public Command(string tunnelID) { @@ -35,10 +29,10 @@ namespace RH_Engine size = sizeArray, heights = heightsArray } - }; return JsonConvert.SerializeObject(Payload(payload)); } + public string AddLayer(string uid, string texture) { dynamic payload = new @@ -56,6 +50,7 @@ namespace RH_Engine }; return JsonConvert.SerializeObject(Payload(payload)); } + public string UpdateTerrain() { dynamic payload = new @@ -63,7 +58,6 @@ namespace RH_Engine id = "scene/terrain/update", data = new { - } }; return JsonConvert.SerializeObject(Payload(payload)); @@ -91,37 +85,135 @@ namespace RH_Engine public string DeleteNode(string uuid) { - dynamic payload = new { id = "scene/node/delete", data = new { id = uuid, - } - }; return JsonConvert.SerializeObject(Payload(payload)); - } - public string AddBikeModel() + public string addPanel(string serialToSend, string uuidBike) { - return AddModel("bike", "data\\NetworkEngine\\models\\bike\\bike.fbx"); + dynamic payload = new + { + id = "scene/node/add", + serial = serialToSend, + data = new + { + name = "dashboard", + parent = uuidBike, + components = new + { + panel = new + { + size = new int[] { 1, 1 }, + resolution = new int[] { 512, 512 }, + background = new int[] { 1, 0, 0, 0 }, + castShadow = false + } + } + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation) + public string ColorPanel(string uuidPanel) { - return AddModel(nodeName, fileLocation, null, new float[] { 0, 0, 0 }, 1, new float[] { 0, 0, 0 }); + dynamic payload = new + { + id = "scene/panel/setclearcolor", + data = new + { + id = uuidPanel, + color = new int[] { 1, 1, 1, 1 } + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation, float[] positionVector, float scalar, float[] rotationVector) + public string SwapPanel(string uuid) { - return AddModel(nodeName, fileLocation, null, positionVector, scalar, rotationVector); + dynamic payload = new + { + id = "scene/panel/swap", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation, string animationLocation, float[] positionVector, float scalar, float[] rotationVector) + public string bikeSpeed(string uuidPanel, double speed) + { + dynamic payload = new + { + id = "scene/panel/drawtext", + data = new + { + id = uuidPanel, + text = "Bike speed placeholder", + position = new int[] { 0, 0 }, + size = 32.0, + color = new int[] { 0, 0, 0, 1 }, + font = "segoeui" + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string SwapPanelCommand(string uuid) + { + dynamic payload = new + { + id = "scene/panel/swap", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string ClearPanel(string uuid) + { + dynamic payload = new + { + id = "scene/panel/clear", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string AddBikeModel(string serial) + { + return AddModel("bike", serial, "data\\NetworkEngine\\models\\bike\\bike.fbx"); + } + + public string AddModel(string nodeName, string serial, string fileLocation) + { + return AddModel(nodeName, serial, fileLocation, null, new float[] { 0, 0, 0 }, 1, new float[] { 0, 0, 0 }); + } + + public string AddModel(string nodeName, string serial, string fileLocation, float[] positionVector, float scalar, float[] rotationVector) + { + return AddModel(nodeName, serial, fileLocation, null, positionVector, scalar, rotationVector); + } + + public string AddModel(string nodeName, string serialToSend, string fileLocation, string animationLocation, float[] positionVector, float scalar, float[] rotationVector) { string namename = nodeName; bool animatedBool = false; @@ -133,6 +225,7 @@ namespace RH_Engine dynamic payload = new { id = "scene/node/add", + serial = serialToSend, data = new { name = namename, @@ -143,7 +236,6 @@ namespace RH_Engine position = positionVector, scale = scalar, rotation = rotationVector - }, model = new { @@ -154,7 +246,6 @@ namespace RH_Engine }, } } - }; return JsonConvert.SerializeObject(Payload(payload)); } @@ -184,14 +275,14 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } - - public string RouteCommand() + public string RouteCommand(string serialToSend) { ImprovedPerlin improvedPerlin = new ImprovedPerlin(4325, LibNoise.NoiseQuality.Best); Random r = new Random(); dynamic payload = new { id = "route/add", + serial = serialToSend, data = new { nodes = new dynamic[] @@ -241,13 +332,44 @@ namespace RH_Engine private int[] GetDir() { Random rng = new Random(); - int[] dir = {rng.Next(50), 0, rng.Next(50)}; + int[] dir = { rng.Next(50), 0, rng.Next(50) }; return dir; } - public string FollowRouteCommand() + public string RouteFollow(string routeID, string nodeID, float speedValue) { - return ""; + return RouteFollow(routeID, nodeID, speedValue, new float[] { 0, 0, 0 }); + } + + public string RouteFollow(string routeID, string nodeID, float speedValue, float[] rotateOffsetVector, float[] positionOffsetVector) + { + return RouteFollow(routeID, nodeID, speedValue, 0, "XYZ", 1, true, rotateOffsetVector, positionOffsetVector); + } + + public string RouteFollow(string routeID, string nodeID, float speedValue, float[] positionOffsetVector) + { + return RouteFollow(routeID, nodeID, speedValue, 0, "XYZ", 1, true, new float[] { 0, 0, 0 }, positionOffsetVector); + } + private string RouteFollow(string routeID, string nodeID, float speedValue, float offsetValue, string rotateValue, float smoothingValue, bool followHeightValue, float[] rotateOffsetVector, float[] positionOffsetVector) + { + dynamic payload = new + { + id = "route/follow", + data = new + { + route = routeID, + node = nodeID, + speed = speedValue, + offset = offsetValue, + rotate = rotateValue, + smoothing = smoothingValue, + followHeight = followHeightValue, + rotateOffset = rotateOffsetVector, + positionOffset = positionOffsetVector + + } + }; + return JsonConvert.SerializeObject(Payload(payload)); } public string RoadCommand(string uuid_route) @@ -268,11 +390,12 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } - public string GetSceneInfoCommand() + public string GetSceneInfoCommand(string serialToSend) { dynamic payload = new { - id = "scene/get" + id = "scene/get", + serial = serialToSend }; return JsonConvert.SerializeObject(Payload(payload)); @@ -282,7 +405,8 @@ namespace RH_Engine { dynamic payload = new { - id = "scene/reset" + id = "scene/reset", + serial = "reset" }; return JsonConvert.SerializeObject(Payload(payload)); @@ -295,7 +419,6 @@ namespace RH_Engine throw new Exception("The time must be between 0 and 24!"); } - dynamic payload = new { id = "scene/skybox/settime", @@ -303,13 +426,10 @@ namespace RH_Engine { time = timeToSet } - }; return JsonConvert.SerializeObject(Payload(payload)); - } - private object Payload(dynamic message) { return new @@ -322,8 +442,5 @@ namespace RH_Engine } }; } - - - } -} +} \ No newline at end of file diff --git a/RH-Engine/JSONParser.cs b/RH-Engine/JSONParser.cs index 2f1f903..8621aff 100644 --- a/RH-Engine/JSONParser.cs +++ b/RH-Engine/JSONParser.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Sockets; -using System.Text; -using Newtonsoft.Json; +using Newtonsoft.Json; +using System; namespace RH_Engine { @@ -27,14 +23,13 @@ namespace RH_Engine } return res; - } public static string GetSessionID(string msg, PC[] PCs) { dynamic jsonData = JsonConvert.DeserializeObject(msg); Newtonsoft.Json.Linq.JArray data = jsonData.data; - for (int i = data.Count-1; i >= 0; i--) + for (int i = data.Count - 1; i >= 0; i--) { dynamic d = data[i]; foreach (PC pc in PCs) @@ -50,6 +45,18 @@ namespace RH_Engine return null; } + public static string GetSerial(string json) + { + dynamic jsonData = JsonConvert.DeserializeObject(json); + return jsonData.data.data.serial; + } + + public static string GetID(string json) + { + dynamic d = JsonConvert.DeserializeObject(json); + return d.id; + } + public static string GetTunnelID(string json) { dynamic jsonData = JsonConvert.DeserializeObject(json); @@ -60,15 +67,30 @@ namespace RH_Engine return null; } - public static string GetRouteID(string json) + /// + /// method to get the uuid from requests for adding a node,route or road + /// + /// the json response froo the server + /// the uuid of the created object + public static string GetResponseUuid(string json) { dynamic jsonData = JsonConvert.DeserializeObject(json); - if (jsonData.data.status == "ok") + if (jsonData.data.data.status == "ok") { - return jsonData.data.uuid; + return jsonData.data.data.data.uuid; } return null; } + public static string getPanelID(string json) + { + dynamic jsonData = JsonConvert.DeserializeObject(json); + if (jsonData.data.data.data.name == "dashboard") + { + Console.WriteLine(jsonData.data.data.data.uuid); + return jsonData.data.data.data.uuid; + } + return null; + } } -} +} \ No newline at end of file diff --git a/RH-Engine/Program.cs b/RH-Engine/Program.cs index 5955866..63c86fb 100644 --- a/RH-Engine/Program.cs +++ b/RH-Engine/Program.cs @@ -1,35 +1,97 @@ -using LibNoise.Primitive; +using LibNoise.Primitive; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; -using System.Globalization; -using System.IO; +using System.Collections.Generic; using System.Net.Sockets; -using System.Runtime.Intrinsics.X86; -using System.Security.Cryptography.X509Certificates; using System.Text; -using System.Threading; namespace RH_Engine { + public delegate void HandleSerial(string message); - internal class Program + class Program { private static PC[] PCs = { //new PC("DESKTOP-M2CIH87", "Fabian"), - new PC("T470S", "Shinichi"), + //new PC("T470S", "Shinichi"), //new PC("DESKTOP-DHS478C", "semme"), + new PC("HP-ZBOOK-SEM", "Sem"), //new PC("DESKTOP-TV73FKO", "Wouter"), - //new PC("DESKTOP-SINMKT1", "Ralf"), + new PC("DESKTOP-SINMKT1", "Ralf van Aert"), //new PC("NA", "Bart") }; + + private static ServerResponseReader serverResponseReader; + private static string sessionId = string.Empty; + private static string tunnelId = string.Empty; + private static string routeId = string.Empty; + private static string panelId = string.Empty; + private static string bikeId = string.Empty; + + private static Dictionary serialResponses = new Dictionary(); + private static void Main(string[] args) { TcpClient client = new TcpClient("145.48.6.10", 6666); CreateConnection(client.GetStream()); + } + /// + /// initializes and starts the reading of the responses from the vr server + /// + /// the networkstream + private static void initReader(NetworkStream stream) + { + serverResponseReader = new ServerResponseReader(stream); + serverResponseReader.callback = HandleResponse; + serverResponseReader.StartRead(); + } + /// + /// callback method that handles responses from the server + /// + /// the response message from the server + public static void HandleResponse(string message) + { + string id = JSONParser.GetID(message); + + // because the first messages don't have a serial, we need to check on the id + if (id == "session/list") + { + sessionId = JSONParser.GetSessionID(message, PCs); + } + else if (id == "tunnel/create") + { + tunnelId = JSONParser.GetTunnelID(message); + if (tunnelId == null) + { + Console.WriteLine("could not find a valid tunnel id!"); + return; + } + } + + if (message.Contains("serial")) + { + //Console.WriteLine("GOT MESSAGE WITH SERIAL: " + message + "\n\n\n"); + string serial = JSONParser.GetSerial(message); + //Console.WriteLine("Got serial " + serial); + if (serialResponses.ContainsKey(serial)) serialResponses[serial].Invoke(message); + } + } + + /// + /// method that sends the speciefied message with the specified serial, and executes the given action upon receivind a reply from the server with this serial. + /// + /// the networkstream to use + /// the message to send + /// the serial to check for + /// the code to be executed upon reveiving a reply from the server with the specified serial + public static void SendMessageAndOnResponse(NetworkStream stream, string message, string serial, HandleSerial action) + { + serialResponses.Add(serial, action); + WriteTextMessage(stream, message); } /// @@ -47,65 +109,30 @@ namespace RH_Engine stream.Write(res); - //Console.WriteLine("sent message " + message); + Console.WriteLine("sent message " + message); } - /// - /// reads a response from the server - /// - /// the network stream to use - /// the returned message from the server - public static string ReadPrefMessage(NetworkStream stream) - { - byte[] lengthBytes = new byte[4]; - - stream.Read(lengthBytes, 0, 4); - Console.WriteLine("read message.."); - - int length = BitConverter.ToInt32(lengthBytes); - - //Console.WriteLine("length is: " + length); - - byte[] buffer = new byte[length]; - int totalRead = 0; - - //read bytes until stream indicates there are no more - do - { - int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); - totalRead += read; - //Console.WriteLine("ReadMessage: " + read); - } while (totalRead < length); - - return Encoding.UTF8.GetString(buffer, 0, totalRead); - } /// /// connects to the server and creates the tunnel /// /// the network stream to use private static void CreateConnection(NetworkStream stream) { - WriteTextMessage(stream, "{\r\n\"id\" : \"session/list\"\r\n}"); - string id = JSONParser.GetSessionID(ReadPrefMessage(stream), PCs); + initReader(stream); - string tunnelCreate = "{\"id\" : \"tunnel/create\", \"data\" : {\"session\" : \"" + id + "\"}}"; + WriteTextMessage(stream, "{\r\n\"id\" : \"session/list\",\r\n\"serial\" : \"list\"\r\n}"); + + // wait until we have got a sessionId + while (sessionId == string.Empty) { } + + string tunnelCreate = "{\"id\" : \"tunnel/create\", \"data\" : {\"session\" : \"" + sessionId + "\"}}"; WriteTextMessage(stream, tunnelCreate); - string tunnelResponse = ReadPrefMessage(stream); - - Console.WriteLine(tunnelResponse); - - string tunnelID = JSONParser.GetTunnelID(tunnelResponse); - if (tunnelID == null) - { - Console.WriteLine("could not find a valid tunnel id!"); - return; - } - - sendCommands(stream, tunnelID); - - + // wait until we have a tunnel id + while (tunnelId == string.Empty) { } + Console.WriteLine("got tunnel id! sending commands..."); + sendCommands(stream, tunnelId); } /// @@ -117,27 +144,40 @@ namespace RH_Engine { Command mainCommand = new Command(tunnelID); - WriteTextMessage(stream, mainCommand.ResetScene()); - ReadPrefMessage(stream); - string routeid = CreateRoute(stream, mainCommand); + SendMessageAndOnResponse(stream, mainCommand.RouteCommand("routeID"), "routeID", (message) => routeId = JSONParser.GetResponseUuid(message)); - WriteTextMessage(stream, mainCommand.TerrainCommand(new int[] { 256, 256 }, null)); - Console.WriteLine(ReadPrefMessage(stream)); - string command; + //WriteTextMessage(stream, mainCommand.TerrainCommand(new int[] { 256, 256 }, null)); + //string command; - command = mainCommand.AddBikeModel(); + SendMessageAndOnResponse(stream, mainCommand.AddBikeModel("bikeID"), "bikeID", (message) => bikeId = JSONParser.GetResponseUuid(message)); - WriteTextMessage(stream, command); + SendMessageAndOnResponse(stream, mainCommand.addPanel("panelID", bikeId), "panelID", + (message) => + { + panelId = JSONParser.GetResponseUuid(message); + while (bikeId == string.Empty) { } + WriteTextMessage(stream, mainCommand.RouteFollow(routeId, bikeId, 5, new float[] { 0, -(float)Math.PI / 2f, 0 }, new float[] { 0, 0, 0 })); + }); - Console.WriteLine(ReadPrefMessage(stream)); + Console.WriteLine("id of head " + GetId(Command.STANDARD_HEAD, stream, mainCommand)); - command = mainCommand.AddModel("car", "data\\customModels\\TeslaRoadster.fbx"); - - WriteTextMessage(stream, command); - - Console.WriteLine(ReadPrefMessage(stream)); + //command = mainCommand.AddModel("car", "data\\customModels\\TeslaRoadster.fbx"); + //WriteTextMessage(stream, command); + //command = mainCommand.addPanel(); + // WriteTextMessage(stream, command); + // string response = ReadPrefMessage(stream); + // Console.WriteLine("add Panel response: \n\r" + response); + // string uuidPanel = JSONParser.getPanelID(response); + // WriteTextMessage(stream, mainCommand.ClearPanel(uuidPanel)); + // Console.WriteLine(ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.bikeSpeed(uuidPanel, 2.42)); + // Console.WriteLine(ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.ColorPanel(uuidPanel)); + // Console.WriteLine("Color panel: " + ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.SwapPanel(uuidPanel)); + // Console.WriteLine("Swap panel: " + ReadPrefMessage(stream)); } /// @@ -160,19 +200,6 @@ namespace RH_Engine } Console.WriteLine("Could not find id of " + name); return null; - - } - - public static string CreateRoute(NetworkStream stream, Command createGraphics) - { - WriteTextMessage(stream, createGraphics.RouteCommand()); - dynamic response = JsonConvert.DeserializeObject(ReadPrefMessage(stream)); - if (response.data.data.id == "route/add") - { - return response.data.data.data.uuid; - } - return null; - } public static void CreateTerrain(NetworkStream stream, Command createGraphics) @@ -185,12 +212,9 @@ namespace RH_Engine height[i] = improvedPerlin.GetValue(x / 10, x / 10, x * 100) + 1; x += 0.001f; } - WriteTextMessage(stream, createGraphics.TerrainCommand(new int[] { 256, 256 }, height)); - Console.WriteLine(ReadPrefMessage(stream)); WriteTextMessage(stream, createGraphics.AddNodeCommand()); - Console.WriteLine(ReadPrefMessage(stream)); } /// @@ -201,9 +225,14 @@ namespace RH_Engine /// all the children objects in the current scene public static JArray GetChildren(NetworkStream stream, Command createGraphics) { - WriteTextMessage(stream, createGraphics.GetSceneInfoCommand()); - dynamic response = JsonConvert.DeserializeObject(ReadPrefMessage(stream)); - return response.data.data.data.children; + JArray res = null; + SendMessageAndOnResponse(stream, createGraphics.GetSceneInfoCommand("getChildren"), "getChildren", (message) => + { + dynamic response = JsonConvert.DeserializeObject(message); + res = response.data.data.data.children; + }); + while (res == null) { } + return res; } /// @@ -225,15 +254,7 @@ namespace RH_Engine } return res; - } - - public static string getUUIDFromResponse(string response) - { - dynamic JSON = JsonConvert.DeserializeObject(response); - return JSON.data.data.data.uuid; - } - } /// @@ -246,6 +267,7 @@ namespace RH_Engine this.host = host; this.user = user; } + public string host { get; } public string user { get; } diff --git a/RH-Engine/ServerResponseReader.cs b/RH-Engine/ServerResponseReader.cs new file mode 100644 index 0000000..85e7f00 --- /dev/null +++ b/RH-Engine/ServerResponseReader.cs @@ -0,0 +1,77 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace RH_Engine +{ + public delegate void OnResponse(string response); + + class ServerResponseReader + { + public OnResponse callback + { + get; set; + } + + public NetworkStream Stream { get; } + + public ServerResponseReader(NetworkStream stream) + { + this.Stream = stream; + } + + public void StartRead() + { + Thread t = new Thread(() => + { + if (this.callback == null) + { + throw new Exception("Callback not initialized!"); + } + else + { + Console.WriteLine("Starting loop for reading"); + while (true) + { + string res = ReadPrefMessage(Stream); + //Console.WriteLine("[SERVERRESPONSEREADER] got message from server: " + res); + this.callback(res); + } + } + }); + + t.Start(); + } + + /// + /// reads a response from the server + /// + /// the network stream to use + /// the returned message from the server + public static string ReadPrefMessage(NetworkStream stream) + { + byte[] lengthBytes = new byte[4]; + + int streamread = stream.Read(lengthBytes, 0, 4); + //Console.WriteLine("read message.. " + streamread); + + int length = BitConverter.ToInt32(lengthBytes); + + //Console.WriteLine("length is: " + length); + + byte[] buffer = new byte[length]; + int totalRead = 0; + + //read bytes until stream indicates there are no more + do + { + int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); + totalRead += read; + //Console.WriteLine("ReadMessage: " + read); + } while (totalRead < length); + + return Encoding.UTF8.GetString(buffer, 0, totalRead); + } + } +} \ No newline at end of file diff --git a/Server/Client.cs b/Server/Client.cs new file mode 100644 index 0000000..5e385be --- /dev/null +++ b/Server/Client.cs @@ -0,0 +1,153 @@ +using System; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using Client; +using Newtonsoft.Json; + +namespace Server +{ + class Client + { + private Communication communication; + private TcpClient tcpClient; + private NetworkStream stream; + private byte[] buffer = new byte[1024]; + private byte[] totalBuffer = new byte[1024]; + private int totalBufferReceived = 0; + private SaveData saveData; + private string username = null; + private DateTime sessionStart; + + + + public string Username { get; set; } + + public Client(Communication communication, TcpClient tcpClient) + { + this.sessionStart = DateTime.Now; + this.communication = communication; + this.tcpClient = tcpClient; + this.stream = this.tcpClient.GetStream(); + stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); + } + + private void OnRead(IAsyncResult ar) + { + int receivedBytes = this.stream.EndRead(ar); + + if (totalBufferReceived + receivedBytes > 1024) + { + throw new OutOfMemoryException("buffer too small"); + } + Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, receivedBytes); + totalBufferReceived += receivedBytes; + + int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + while (totalBufferReceived >= expectedMessageLength) + { + //volledig packet binnen + byte[] messageBytes = new byte[expectedMessageLength]; + Array.Copy(totalBuffer, 0, messageBytes, 0, expectedMessageLength); + HandleData(messageBytes); + + Array.Copy(totalBuffer, expectedMessageLength, totalBuffer, 0, (totalBufferReceived - expectedMessageLength)); //maybe unsafe idk + + totalBufferReceived -= expectedMessageLength; + expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + if (expectedMessageLength <= 5) + { + break; + } + } + + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + + } + + private void OnWrite(IAsyncResult ar) + { + this.stream.EndWrite(ar); + } + + + /// + /// TODO + /// + /// including message length and messageId (can be changed) + private void HandleData(byte[] message) + { + //Console.WriteLine("Data " + packet); + //JsonConvert.DeserializeObject(packet); + //0x01 Json + //0x01 Raw data + + byte[] payloadbytes = new byte[BitConverter.ToInt32(message, 0) - 5]; + + Array.Copy(message, 5, payloadbytes, 0, payloadbytes.Length); + + string identifier; + bool isJson = DataParser.getJsonIdentifier(message, out identifier); + if (isJson) + { + switch (identifier) + { + case DataParser.LOGIN: + string username; + string password; + bool worked = DataParser.GetUsernamePassword(payloadbytes, out username, out password); + if (worked) + { + if (verifyLogin(username, password)) + { + Console.WriteLine("Log in"); + this.username = username; + byte[] response = DataParser.getLoginResponse("OK"); + stream.BeginWrite(response, 0, response.Length, new AsyncCallback(OnWrite), null); + this.saveData = new SaveData(Directory.GetCurrentDirectory() + "/" + username, sessionStart.ToString("yyyy-MM-dd HH-mm-ss")); + } + else + { + byte[] response = DataParser.getLoginResponse("wrong username or password"); + stream.BeginWrite(response, 0, response.Length, new AsyncCallback(OnWrite), null); + } + } + else + { + byte[] response = DataParser.getLoginResponse("invalid json"); + stream.BeginWrite(response, 0, response.Length, new AsyncCallback(OnWrite), null); + } + break; + default: + Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}"); + break; + } + Array.Copy(message, 5, payloadbytes, 0, message.Length - 5); + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payloadbytes)); + saveData.WriteDataJSON(Encoding.ASCII.GetString(payloadbytes)); + + } + else if (DataParser.isRawData(message)) + { + Console.WriteLine(BitConverter.ToString(message)); + saveData.WriteDataRAW(ByteArrayToString(message)); + } + + + } + + private bool verifyLogin(string username, string password) + { + return username == password; + } + + public static string ByteArrayToString(byte[] ba) + { + StringBuilder hex = new StringBuilder(ba.Length * 2); + foreach (byte b in ba) + hex.AppendFormat("{0:x2}", b); + return hex.ToString(); + } + } +} diff --git a/Server/Communication.cs b/Server/Communication.cs new file mode 100644 index 0000000..0d354c4 --- /dev/null +++ b/Server/Communication.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO.Pipes; +using System.Net.Sockets; +using System.Text; + +namespace Server +{ + class Communication + { + private TcpListener listener; + private List clients; + + public Communication(TcpListener listener) + { + this.listener = listener; + this.clients = new List(); + } + + public void Start() + { + listener.Start(); + Console.WriteLine($"==========================================================================\n" + + $"\tstarted accepting clients at {DateTime.Now}\n" + + $"=========================================================================="); + listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null); + } + + private void OnConnect(IAsyncResult ar) + { + var tcpClient = listener.EndAcceptTcpClient(ar); + Console.WriteLine($"Client connected from {tcpClient.Client.RemoteEndPoint}"); + clients.Add(new Client(this, tcpClient)); + listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null); + } + + internal void Disconnect(Client client) + { + clients.Remove(client); + } + } +} diff --git a/Server/Program.cs b/Server/Program.cs new file mode 100644 index 0000000..cd980a4 --- /dev/null +++ b/Server/Program.cs @@ -0,0 +1,19 @@ +using System.Net; +using System.Net.Sockets; + +namespace Server +{ + class Program + { + static void Main(string[] args) + { + Communication communication = new Communication(new TcpListener(IPAddress.Any, 5555)); + communication.Start(); + + while (true) + { + + } + } + } +} diff --git a/Server/SaveData.cs b/Server/SaveData.cs new file mode 100644 index 0000000..0286bde --- /dev/null +++ b/Server/SaveData.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Server +{ + class SaveData + { + private string path; + private string filename; + public SaveData(string path, string filename) + { + this.path = path; + this.filename = filename; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + + /// + /// Every line is a new data entry + /// + + public void WriteDataJSON(string data) + { + using (StreamWriter sw = File.AppendText(this.path + "/json"+filename+".txt")) + { + sw.WriteLine(data); + } + } + + public void WriteDataRAW(string data) + { + using (StreamWriter sw = File.AppendText(this.path + "/raw" + filename + ".txt")) + { + sw.WriteLine(data); + } + } + } +} diff --git a/Server/Server.csproj b/Server/Server.csproj new file mode 100644 index 0000000..a91c176 --- /dev/null +++ b/Server/Server.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + +