package se.rhel;
import se.rhel.EndPoint;
import se.rhel.TcpConnection;
import se.rhel.UdpConnection;
import se.rhel.client.ClientPacketHandler;
import se.rhel.observer.ClientListener;
import se.rhel.observer.ClientObserver;
import se.rhel.packet.*;
import se.rhel.util.Log;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
public class Client implements EndPoint {
private static final int CLIENT_UPDATE_INTERVAL = 200;
private UdpConnection mUdpConnection;
private TcpConnection mTcpConnection;
private ClientObserver mClientObserver;
private int mId = -1;
private boolean mIsRunning;
private boolean mSendIdlePackage;
private static long startLatancy;
private static long endLatency;
private static ArrayList<Long> mAverageLatancey = new ArrayList<>();
private static long currLatency = -1L;
Client() {
Log.set(Log.LEVEL_DEBUG);
ClientPacketHandler mHandler = new ClientPacketHandler(this);
mClientObserver = new ClientObserver();
mHandler.setObserver(mClientObserver);
mTcpConnection = new TcpConnection(mHandler);
mUdpConnection = new UdpConnection(mHandler);
PacketRegisterInitializer.register();
}
@Override
public void run() {
Log.info("Client", "Client started");
while(mIsRunning) {
// Do client stuff..
long startTime = System.currentTimeMillis();
update();
long elapsedTime = System.currentTimeMillis() - startTime;
if(elapsedTime < CLIENT_UPDATE_INTERVAL) try {
Thread.sleep(CLIENT_UPDATE_INTERVAL - elapsedTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void update () {
// We want to send still-alive-packages to the server
if(mSendIdlePackage) {
// Also send latency packet
sendTcp(new LatencyPacket(mId));
startLatancy = System.currentTimeMillis();
sendUdp(new IdlePacket(mId));
}
}
public void sendIdlePackage(boolean value) {
mSendIdlePackage = value;
}
/**
* Should be called when a time has been measured between
* send and receive a packet
*/
public void setEndLatency() {
endLatency = System.currentTimeMillis();
if(endLatency != 0L && startLatancy != 0L) {
mAverageLatancey.add((endLatency-startLatancy));
}
if(mAverageLatancey.size() == 10) {
long sum = 0L;
for(long latency : mAverageLatancey) {
sum += latency;
}
sum /= mAverageLatancey.size();
currLatency = sum;
mAverageLatancey.clear();
}
}
/**
* Returns current average latency, or -1L if none
* @return long latency
*/
public static long getLatency() {
if(currLatency != -1L)
return currLatency;
if(mAverageLatancey.size() > 0)
return mAverageLatancey.get(0);
return -1L;
}
@Override
public void start() {
mIsRunning = true;
new Thread(this, "ClientThread").start();
}
@Override
public void stop() {
if(!mIsRunning)
return;
mIsRunning = false;
}
public UdpConnection getUDPConnection() {
return mUdpConnection;
}
public void connect(String host, int tcpPort, int udpPort) throws IOException {
try {
InetAddress address = InetAddress.getByName(host);
mUdpConnection.connect(address, udpPort);
mTcpConnection.connect(address, tcpPort);
} catch (IOException e) {
dispose();
throw e;
}
}
public void addListener(ClientListener toAdd) {
mClientObserver.addListener(toAdd);
}
/**
* If equals -1 it means that
* the client haven't got response
* from server yet
* @return clientId
*/
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
public void sendTcp(Packet packet) {
sendTcp(packet.getData());
}
public void sendTcp(byte[] data) {
Log.trace("Client", "Send TCP > " + Packet.class.getName());
mTcpConnection.sendTcp(data);
}
public void sendUdp(Packet packet) {
sendUdp(packet.getData());
}
public void sendUdp(byte[] data) {
Log.trace("Client", "Send UDP >" + Packet.class.getName());
mUdpConnection.sendUdpFromClient(data);
}
public void dispose() {
this.stop();
this.mUdpConnection.stop();
this.mTcpConnection.stop();
}
}