Merge branch 'NetworkedVisualiser' into splitIntoTwoModules
# Conflicts: # visualiser/src/main/java/seng302/VisualiserInput.java
This commit is contained in:
@@ -45,11 +45,6 @@
|
||||
<version>6.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>seng302</groupId>
|
||||
<artifactId>visualiser</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public class BinaryMessageDecoder {
|
||||
// System.out.println("XML Message!");
|
||||
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(this.message);
|
||||
xmdecoder.decode();
|
||||
data = new XMLMessage(xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMsgLength(), xmdecoder.getXmlMessageInputSource());
|
||||
data = new XMLMessage(xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMsgLength(), xmdecoder.getXmlMessageInputStream());
|
||||
break;
|
||||
case RACESTARTSTATUS:
|
||||
// System.out.println("Race Start Status Message");
|
||||
|
||||
@@ -2,9 +2,12 @@ package seng302.Networking.MessageDecoders;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static seng302.Networking.Utils.ByteConverter.bytesToLong;
|
||||
@@ -74,8 +77,9 @@ public class XMLMessageDecoder {
|
||||
* this will be used latter for the vis
|
||||
* @return xml string as inputsource
|
||||
*/
|
||||
public InputSource getXmlMessageInputSource() {
|
||||
InputSource is = new InputSource(new StringReader(xmlMessage.trim()));
|
||||
public InputStream getXmlMessageInputStream() {
|
||||
InputStream is = new ByteArrayInputStream(xmlMessage.trim().getBytes(StandardCharsets.UTF_8));
|
||||
// InputSource is = new InputSource(new StringReader(xmlMessage.trim()));
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
@@ -469,8 +469,8 @@ public class BoatLocationMessage extends AC35Data
|
||||
this.rudderAngle = rudderAngle;
|
||||
}
|
||||
|
||||
public seng302.GPSCoordinate getGPSLocation(){
|
||||
seng302.GPSCoordinate coord = new seng302.GPSCoordinate(AC35UnitConverter.convertGPS(latitude), AC35UnitConverter.convertGPS(longitude));
|
||||
public GPSCoordinate getGPSLocation(){
|
||||
GPSCoordinate coord = new GPSCoordinate(AC35UnitConverter.convertGPS(latitude), AC35UnitConverter.convertGPS(longitude));
|
||||
return coord;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package seng302.Networking.Utils;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Created by fwy13 on 25/04/17.
|
||||
*/
|
||||
@@ -12,13 +14,13 @@ public class XMLMessage extends AC35Data{
|
||||
private int xmlMsgSubType;
|
||||
private int sequenceNumber;
|
||||
private int xmlMsgLength;
|
||||
private InputSource xmlMessage;
|
||||
private InputStream xmlMessage;
|
||||
|
||||
public static int XMLTypeRegatta = 5;
|
||||
public static int XMLTypeRace = 6;
|
||||
public static int XMLTypeBoat = 7;
|
||||
|
||||
public XMLMessage(int ackNumber, long timeStamp, int xmlMsgSubType, int sequenceNumber, int xmlMsgLength, InputSource xmlMessage){
|
||||
public XMLMessage(int ackNumber, long timeStamp, int xmlMsgSubType, int sequenceNumber, int xmlMsgLength, InputStream xmlMessage){
|
||||
super(MessageType.XMLMESSAGE);
|
||||
this.ackNumber = ackNumber;
|
||||
this.timeStamp = timeStamp;
|
||||
@@ -28,7 +30,7 @@ public class XMLMessage extends AC35Data{
|
||||
this.xmlMessage = xmlMessage;
|
||||
}
|
||||
|
||||
public InputSource getXmlMessage() {
|
||||
public InputStream getXmlMessage() {
|
||||
return xmlMessage;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
package seng302.Networking;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.Mock.*;
|
||||
import seng302.Networking.Utils.*;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static seng302.Networking.Utils.ByteConverter.bytesToShort;
|
||||
|
||||
/**
|
||||
* TCP server to act as the mock AC35 streaming interface
|
||||
*/
|
||||
public class VisualiserInput implements Runnable
|
||||
{
|
||||
//time since last heartbeat
|
||||
private long lastHeartbeatTime;
|
||||
|
||||
//socket port 4945 as 4940 is ac35 live port and 4941 is ac35 test port
|
||||
private Socket connectionSocket;
|
||||
|
||||
long heartbeatSeqNum;
|
||||
|
||||
private StreamedCourse course = null;
|
||||
|
||||
private Map<Integer, BoatLocationMessage> boatLocation;
|
||||
|
||||
public VisualiserInput(Socket connectionSocket) throws IOException{
|
||||
|
||||
this.connectionSocket = connectionSocket;
|
||||
|
||||
this.course = new StreamedCourse();
|
||||
this.boatLocation = new HashMap<>();
|
||||
this.connectionSocket = connectionSocket;
|
||||
|
||||
|
||||
//start Time
|
||||
this.lastHeartbeatTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides StreamedCourse container for fixed course data
|
||||
* @return course for current VisualiserInput instance
|
||||
* @see seng302.Mock.StreamedCourse
|
||||
*/
|
||||
public StreamedCourse getCourse() {
|
||||
return course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last boat location message associated with the given boat source ID.
|
||||
* @param sourceID unique global identifier for boat
|
||||
* @return most recent location message
|
||||
*/
|
||||
public BoatLocationMessage getBoatLocationMessage(int sourceID) {
|
||||
return boatLocation.get(sourceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the time since last heartbeat
|
||||
* @return time since last heartbeat
|
||||
*/
|
||||
private double timeSinceHeartbeat() {
|
||||
long now = System.currentTimeMillis();
|
||||
return (now - lastHeartbeatTime) / 1000.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an inputStream and reads the first 15 bytes (the header) and gets the message length
|
||||
* for the whole message then reads that and returns the byte array
|
||||
* @param inStream inputStream from socket
|
||||
* @return encoded binary messsage bytes
|
||||
* @throws IOException
|
||||
*/
|
||||
private static byte[] getBytes(InputStream inStream) throws IOException {
|
||||
byte[] headerBytes = new byte[15];
|
||||
inStream.read(headerBytes);
|
||||
byte[] messageLenBytes = Arrays.copyOfRange(headerBytes, 13, 15);
|
||||
short messageLen = bytesToShort(messageLenBytes);
|
||||
byte[] messageBytesWithCRC = new byte[messageLen+4];
|
||||
while (inStream.available() < messageLen + 4){
|
||||
//WE NEED THIS!!!!
|
||||
}
|
||||
inStream.read(messageBytesWithCRC, 0, messageLen + 4);
|
||||
ByteBuffer binaryMessageBytes = ByteBuffer.allocate(headerBytes.length+messageBytesWithCRC.length);
|
||||
binaryMessageBytes.put(headerBytes);
|
||||
binaryMessageBytes.put(messageBytesWithCRC);
|
||||
return binaryMessageBytes.array();
|
||||
}
|
||||
|
||||
public void run(){
|
||||
try{
|
||||
System.out.println("running");
|
||||
//receiver loop that gets the input
|
||||
boolean receiverLoop = true;
|
||||
while(receiverLoop) {
|
||||
//gets the input from the socket
|
||||
InputStream inFromClient = connectionSocket.getInputStream();
|
||||
|
||||
//converts the input into a byte array that can be read by the decoder
|
||||
byte[] binaryMessage = getBytes(inFromClient);
|
||||
|
||||
//decode the binary message into readable date
|
||||
BinaryMessageDecoder testDecoder = new BinaryMessageDecoder(binaryMessage);
|
||||
AC35Data data = testDecoder.decode();
|
||||
if (data == null){
|
||||
continue;
|
||||
}
|
||||
|
||||
//checks which message is being received and does what is needed for that message
|
||||
MessageType mType = data.getType();
|
||||
switch (mType) {
|
||||
case HEARTBEAT:
|
||||
lastHeartbeatTime = System.currentTimeMillis();
|
||||
//note: if the program runs for over 340 years, this will crash.
|
||||
heartbeatSeqNum = ByteConverter.bytesToLong(testDecoder.getMessage());
|
||||
System.out.println("HeartBeat Message! " + heartbeatSeqNum);
|
||||
break;
|
||||
case RACESTATUS:
|
||||
System.out.println("Race Status Message");
|
||||
break;
|
||||
case DISPLAYTEXTMESSAGE:
|
||||
// System.out.println("Display Text Message");
|
||||
//no decoder for this.
|
||||
break;
|
||||
case XMLMESSAGE:
|
||||
System.out.println("XML Message!");
|
||||
XMLMessage xml = (XMLMessage) data;
|
||||
try {
|
||||
if (xml.getXmlMsgSubType() == xml.XMLTypeRegatta){
|
||||
System.out.println("Setting Regatta");
|
||||
course.setRegattaXMLReader(new RegattaXMLReader(xml.getXmlMessage()));
|
||||
} else if (xml.getXmlMsgSubType() == xml.XMLTypeRace){
|
||||
System.out.println("Setting Course");
|
||||
course.setStreamedCourseXMLReader(new StreamedCourseXMLReader(xml.getXmlMessage()));
|
||||
} else if (xml.getXmlMsgSubType() == xml.XMLTypeBoat){
|
||||
System.out.println("Setting Boats");
|
||||
course.setBoatXMLReader(new BoatXMLReader(xml.getXmlMessage()));
|
||||
}
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
case RACESTARTSTATUS:
|
||||
System.out.println("Race Start Status Message");
|
||||
break;
|
||||
case YACHTEVENTCODE:
|
||||
// System.out.println("Yacht Action Code!");
|
||||
//no decoder
|
||||
break;
|
||||
case YACHTACTIONCODE:
|
||||
// System.out.println("Yacht Action Code!");
|
||||
//no decoder
|
||||
break;
|
||||
case CHATTERTEXT:
|
||||
// System.out.println("Chatter Text Message!");
|
||||
//no decoder
|
||||
break;
|
||||
case BOATLOCATION:
|
||||
BoatLocationMessage msg = (BoatLocationMessage) data;
|
||||
if (boatLocation.containsKey(msg.getSourceID())){
|
||||
if (msg.getTime() > boatLocation.get(msg.getSourceID()).getTime()){
|
||||
boatLocation.put(msg.getSourceID(), msg);
|
||||
}
|
||||
}else{
|
||||
boatLocation.put(msg.getSourceID(), msg);
|
||||
}
|
||||
System.out.println("Boat Location Message!");
|
||||
break;
|
||||
case MARKROUNDING:
|
||||
// System.out.println("Mark Rounding Message!");
|
||||
break;
|
||||
case COURSEWIND:
|
||||
// System.out.println("Course Wind Message!");
|
||||
break;
|
||||
case AVGWIND:
|
||||
// System.out.println("Average Wind Message!");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Broken Message!");
|
||||
break;
|
||||
}
|
||||
|
||||
//if no heartbeat has been received in more than 6 seconds
|
||||
//the connection will need to be restarted
|
||||
if (timeSinceHeartbeat() > 6){
|
||||
System.out.println("Connection has stopped, trying to reconnect");
|
||||
receiverLoop = false;
|
||||
}
|
||||
}
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String argv[]) throws Exception
|
||||
{
|
||||
//this is the test data that streams form the AC35 website
|
||||
|
||||
Socket socket = new Socket(InetAddress.getLocalHost(), 4942);
|
||||
// Socket socket = new Socket("livedata.americascup.com",4941);
|
||||
VisualiserInput receiver = new VisualiserInput(socket);
|
||||
receiver.run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,13 +53,13 @@ public class BinaryMessageDecoderTest {
|
||||
Assert.assertEquals((short)1, decoderXML.getSequenceNumber());
|
||||
Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength());
|
||||
|
||||
Reader reader = decoderXML.getXmlMessageInputSource().getCharacterStream();
|
||||
int c;
|
||||
String contents = "";
|
||||
while((c = reader.read()) != -1) {
|
||||
contents += (char)c;
|
||||
}
|
||||
Assert.assertEquals(xmlString.toString(), contents);
|
||||
// Reader reader = decoderXML.getXmlMessageInputStream().getCharacterStream();
|
||||
// int c;
|
||||
// String contents = "";
|
||||
// while((c = reader.read()) != -1) {
|
||||
// contents += (char)c;
|
||||
// }
|
||||
// Assert.assertEquals(xmlString.toString(), contents);
|
||||
|
||||
}catch (IOException e){
|
||||
System.out.println(e);
|
||||
|
||||
@@ -40,14 +40,6 @@ public class XMLMessageDecoderTest {
|
||||
Assert.assertEquals((short)1, decoderXML.getSequenceNumber());
|
||||
Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength());
|
||||
|
||||
Reader reader = decoderXML.getXmlMessageInputSource().getCharacterStream();
|
||||
int c;
|
||||
String contents = "";
|
||||
while((c = reader.read()) != -1) {
|
||||
contents += (char)c;
|
||||
}
|
||||
Assert.assertEquals(xmlString.toString(), contents);
|
||||
|
||||
}catch (IOException e){
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user