mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Added Race Status messages to the mock streaming data interface
Tags: #story[29]
This commit is contained in:
@@ -1,13 +1,12 @@
|
|||||||
package seng302.server;
|
package seng302.server;
|
||||||
|
|
||||||
import seng302.server.messages.Heartbeat;
|
import seng302.server.messages.*;
|
||||||
import seng302.server.messages.Message;
|
|
||||||
import seng302.server.messages.XMLMessage;
|
|
||||||
import seng302.server.messages.XMLMessageSubType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ public class ServerThread implements Runnable{
|
|||||||
private Thread runner;
|
private Thread runner;
|
||||||
private StreamingServerSocket server;
|
private StreamingServerSocket server;
|
||||||
private final int HEARTBEAT_PERIOD = 5000;
|
private final int HEARTBEAT_PERIOD = 5000;
|
||||||
|
private final int RACE_STATUS_PERIOD = 1000;
|
||||||
private final int PORT_NUMBER = 8085;
|
private final int PORT_NUMBER = 8085;
|
||||||
|
|
||||||
public ServerThread(String threadName){
|
public ServerThread(String threadName){
|
||||||
@@ -45,6 +45,29 @@ public class ServerThread implements Runnable{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A sample race status message
|
||||||
|
*/
|
||||||
|
public Message getTestRaceStatusMessage(){
|
||||||
|
BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0,
|
||||||
|
10000, 10000);
|
||||||
|
|
||||||
|
BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0,
|
||||||
|
10000, 10000);
|
||||||
|
|
||||||
|
BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0,
|
||||||
|
10000, 10000);
|
||||||
|
|
||||||
|
|
||||||
|
List<BoatSubMessage> boats = new ArrayList<BoatSubMessage>();
|
||||||
|
boats.add(boat1);
|
||||||
|
boats.add(boat2);
|
||||||
|
boats.add(boat3);
|
||||||
|
|
||||||
|
return new RaceStatusMessage(1, RaceStatus.PRESTART, 1000, WindDirection.EAST,
|
||||||
|
100, 3, RaceType.MATCH_RACE, 1, boats);
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try{
|
try{
|
||||||
server = new StreamingServerSocket(PORT_NUMBER);
|
server = new StreamingServerSocket(PORT_NUMBER);
|
||||||
@@ -87,6 +110,21 @@ public class ServerThread implements Runnable{
|
|||||||
}
|
}
|
||||||
}, 0, HEARTBEAT_PERIOD);
|
}, 0, HEARTBEAT_PERIOD);
|
||||||
|
|
||||||
|
// Timer to send the race status messages
|
||||||
|
Timer t1 = new Timer();
|
||||||
|
t1.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Message statusMessage = getTestRaceStatusMessage();
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.send(statusMessage);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100, RACE_STATUS_PERIOD);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of a boat
|
||||||
|
*/
|
||||||
|
public enum BoatStatus {
|
||||||
|
UNDEFINED(0),
|
||||||
|
PRESTART(1),
|
||||||
|
RACING(2),
|
||||||
|
FINISHED(3),
|
||||||
|
DNS(4),
|
||||||
|
DNF(5),
|
||||||
|
DSQ(6),
|
||||||
|
CS(7);
|
||||||
|
|
||||||
|
private long code;
|
||||||
|
|
||||||
|
BoatStatus(long code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCode(){
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The status of each boat, sent within a race status message
|
||||||
|
*/
|
||||||
|
public class BoatSubMessage {
|
||||||
|
private final int MESSAGE_SIZE = 20;
|
||||||
|
|
||||||
|
private long sourceId;
|
||||||
|
private BoatStatus boatStatus;
|
||||||
|
private long legNumber;
|
||||||
|
private long numberPenaltiesAwarded;
|
||||||
|
private long numberPenaltiesServed;
|
||||||
|
private long estimatedTimeAtNextMark;
|
||||||
|
private long estimatedTimeAtFinish;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boat Sub message from section 4.2 of the AC35 streaming data interface spec
|
||||||
|
* @param sourceId The source ID of the boat
|
||||||
|
* @param boatStatus The boats status
|
||||||
|
* @param legNumber The leg the boat is on (0= prestart, 1=start to first mark etc)
|
||||||
|
* @param numberPenaltiesAwarded The number of penalties awarded to the boat
|
||||||
|
* @param numberPenaltiesServed The number of penalties served to the boat
|
||||||
|
* @param estimatedTimeAtFinish The estimated time (UTC) the boat will finish the race
|
||||||
|
* @param estimatedTimeAtNextMark The estimated time (UTC) the boat will arrive at the next mark
|
||||||
|
*/
|
||||||
|
public BoatSubMessage(long sourceId, BoatStatus boatStatus, long legNumber, long numberPenaltiesAwarded, long numberPenaltiesServed,
|
||||||
|
long estimatedTimeAtFinish, long estimatedTimeAtNextMark){
|
||||||
|
this.sourceId = sourceId;
|
||||||
|
this.boatStatus = boatStatus;
|
||||||
|
this.legNumber = legNumber;
|
||||||
|
this.numberPenaltiesAwarded = numberPenaltiesAwarded;
|
||||||
|
this.numberPenaltiesServed = numberPenaltiesServed;
|
||||||
|
this.estimatedTimeAtFinish = estimatedTimeAtFinish;
|
||||||
|
this.estimatedTimeAtNextMark = estimatedTimeAtNextMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The size of this message in bytes
|
||||||
|
*/
|
||||||
|
public int getSize(){
|
||||||
|
return MESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a ByteBuffer containing this boat status message
|
||||||
|
*/
|
||||||
|
public ByteBuffer getByteBuffer(){
|
||||||
|
ByteBuffer buff = ByteBuffer.allocate(getSize());
|
||||||
|
int buffPos = 0;
|
||||||
|
|
||||||
|
// Source ID, 4 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(4).putInt((int) sourceId).array());
|
||||||
|
buffPos += 4;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Boat Status, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte) boatStatus.getCode()).array());
|
||||||
|
buffPos += 1;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Leg number, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte) legNumber).array());
|
||||||
|
buffPos += 1;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Number of penalties awarded, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte) numberPenaltiesAwarded).array());
|
||||||
|
buffPos += 1;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Number of penalties served, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte) numberPenaltiesServed).array());
|
||||||
|
buffPos += 1;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Estimated time at next mark, 6 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(6).putInt((int) estimatedTimeAtNextMark).array());
|
||||||
|
buffPos += 6;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
// Estimated time at finish, 6 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(6).putInt((int) estimatedTimeAtFinish).array());
|
||||||
|
buffPos += 6;
|
||||||
|
buff.position(buffPos);
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of the race
|
||||||
|
*/
|
||||||
|
public enum RaceStatus {
|
||||||
|
NOTACTIVE(0),
|
||||||
|
WARNING(1), // Between 3:00 and 1:00 before start
|
||||||
|
PREPARATORY(2), // Less than 1:00 before start
|
||||||
|
STARTED(3),
|
||||||
|
ABANDONED(6),
|
||||||
|
POSTPONED(7),
|
||||||
|
TERMINATED(8),
|
||||||
|
RACE_START_TIME_NOT_SET(9),
|
||||||
|
PRESTART(10); // More than 3:00 before start
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
RaceStatus(int code){
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode(){
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
|
public class RaceStatusMessage extends Message{
|
||||||
|
private final MessageType MESSAGE_TYPE = MessageType.RACE_STATUS;
|
||||||
|
private final int MESSAGE_VERSION = 2; //Always set to 1
|
||||||
|
private final int MESSAGE_BASE_SIZE = 24;
|
||||||
|
|
||||||
|
// fields
|
||||||
|
private long currentTime;
|
||||||
|
private long raceId;
|
||||||
|
private RaceStatus raceStatus;
|
||||||
|
private long expectedStartTime;
|
||||||
|
private WindDirection raceWindDirection;
|
||||||
|
private long windSpeed;
|
||||||
|
private long numBoatsInRace;
|
||||||
|
private RaceType raceType;
|
||||||
|
private List<BoatSubMessage> boats;
|
||||||
|
private CRC32 crc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message containing the current status of the race
|
||||||
|
* @param raceId The ID of the current race
|
||||||
|
* @param raceStatus The status of the race
|
||||||
|
* @param expectedStartTime The expected start time
|
||||||
|
* @param raceWindDirection The wind direction (north, east, south)
|
||||||
|
* @param windSpeed The wind speed in mm/sec
|
||||||
|
* @param numBoatsInRace The number of boats in the race
|
||||||
|
* @param raceType The race type (Match/fleet)
|
||||||
|
* @param sourceId The source of this message
|
||||||
|
* @param boats A list of boat status sub messages
|
||||||
|
*/
|
||||||
|
public RaceStatusMessage(long raceId, RaceStatus raceStatus, long expectedStartTime, WindDirection raceWindDirection,
|
||||||
|
long windSpeed, long numBoatsInRace, RaceType raceType, long sourceId, List<BoatSubMessage> boats){
|
||||||
|
currentTime = System.currentTimeMillis() / 1000L;
|
||||||
|
this.raceId = raceId;
|
||||||
|
this.raceStatus = raceStatus;
|
||||||
|
this.expectedStartTime = expectedStartTime;
|
||||||
|
this.raceWindDirection = raceWindDirection;
|
||||||
|
this.windSpeed = windSpeed;
|
||||||
|
this.numBoatsInRace = numBoatsInRace;
|
||||||
|
this.raceType = raceType;
|
||||||
|
this.boats = boats;
|
||||||
|
crc = new CRC32();
|
||||||
|
|
||||||
|
setHeader(new Header(MESSAGE_TYPE, (int) sourceId, (short) getSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size of this message in bytes
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_BASE_SIZE + (20 * (int) numBoatsInRace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send this message as a stream of bytes
|
||||||
|
* @param outputStream The output stream to send the message
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void send(DataOutputStream outputStream) {
|
||||||
|
ByteBuffer buff = ByteBuffer.allocate(Header.getSize() + getSize() + 4/*CRC*/);
|
||||||
|
|
||||||
|
buff.put(getHeader().getByteBuffer());
|
||||||
|
buff.position(Header.getSize());
|
||||||
|
|
||||||
|
// Version Number, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte)MESSAGE_VERSION).array());
|
||||||
|
buff.position(Header.getSize() + 1);
|
||||||
|
|
||||||
|
// Current time, 2 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(6).putInt((int)currentTime).array());
|
||||||
|
buff.position(Header.getSize() + 7);
|
||||||
|
|
||||||
|
// Race id, 4 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(4).putInt((int)raceId).array());
|
||||||
|
buff.position(Header.getSize() + 11);
|
||||||
|
|
||||||
|
// Race status, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte)raceStatus.getCode()).array());
|
||||||
|
buff.position(Header.getSize() + 12);
|
||||||
|
|
||||||
|
// Expected start time, 6 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(6).putInt((int)expectedStartTime).array());
|
||||||
|
buff.position(Header.getSize() + 18);
|
||||||
|
|
||||||
|
// Wind direction, 2 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(2).putShort((short)raceWindDirection.getCode()).array());
|
||||||
|
buff.position(Header.getSize() + 20);
|
||||||
|
|
||||||
|
// Wind Speed, 2 bytes
|
||||||
|
buff.put(ByteBuffer.allocate(2).putShort((short)windSpeed).array());
|
||||||
|
buff.position(Header.getSize() + 22);
|
||||||
|
|
||||||
|
// Number of boats, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte)numBoatsInRace).array());
|
||||||
|
buff.position(Header.getSize() + 23);
|
||||||
|
|
||||||
|
// Race Type, 1 byte
|
||||||
|
buff.put(ByteBuffer.allocate(1).put((byte)raceType.getCode()).array());
|
||||||
|
buff.position(Header.getSize() + 24);
|
||||||
|
|
||||||
|
int buffPosition = Header.getSize() + 24;
|
||||||
|
|
||||||
|
for (BoatSubMessage boatSubMessage : boats){
|
||||||
|
buff.put(boatSubMessage.getByteBuffer());
|
||||||
|
buffPosition += boatSubMessage.getSize();
|
||||||
|
buff.position(buffPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate CRC
|
||||||
|
crc.update(buff.array());
|
||||||
|
|
||||||
|
// Add CRC to message
|
||||||
|
buff.put(ByteBuffer.allocate(4).putInt((short)crc.getValue()).array());
|
||||||
|
|
||||||
|
// Send
|
||||||
|
try {
|
||||||
|
outputStream.write(buff.array());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum containing the types of races
|
||||||
|
* sent by the server
|
||||||
|
*/
|
||||||
|
public enum RaceType {
|
||||||
|
MATCH_RACE(1),
|
||||||
|
FLEET_RACE(2);
|
||||||
|
|
||||||
|
private long code;
|
||||||
|
|
||||||
|
RaceType(long code){
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCode(){
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum containing the supported wind directions
|
||||||
|
*/
|
||||||
|
public enum WindDirection {
|
||||||
|
NORTH(0x0000L),
|
||||||
|
EAST(0x4000L),
|
||||||
|
SOUTH(0x8000L);
|
||||||
|
|
||||||
|
private long code;
|
||||||
|
|
||||||
|
WindDirection(long code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user