package mountainrangepvp.net.lanping;
import mountainrangepvp.engine.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.util.*;
/**
* @author lachlan
*/
public class PingClient {
private final Log log;
private final Set<ServerData> servers;
private MulticastSocket socket;
private DatagramPacket packet;
private Thread listenThread;
public PingClient(Log log) {
this.log = log;
servers = new HashSet<>();
}
public void start() throws IOException {
socket = new MulticastSocket(PingConstants.MULTICAST_PORT);
socket.joinGroup(PingConstants.MULTICAST_ADDRESS);
packet = makePacket();
listenThread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
read();
process();
Thread.sleep(1000 / PingConstants.PING_RATE);
}
} catch (InterruptedException ex) {
log.fine("Ping Client shutting down");
}
}
}, "Ping Client");
listenThread.setDaemon(true);
listenThread.start();
}
public void stop() {
listenThread.interrupt();
socket.close();
}
private DatagramPacket makePacket() {
byte[] data = new byte[PingConstants.PING_DATA.length];
return new DatagramPacket(data, data.length);
}
private void read() {
try {
socket.receive(packet);
} catch (IOException ioe) {
if (!socket.isClosed())
log.warn("Could not read ping", ioe);
Thread.currentThread().interrupt();
}
}
private void process() {
byte[] data = packet.getData();
if (Arrays.equals(data, PingConstants.PING_DATA)) {
ServerData server = new ServerData(packet.getAddress().
getHostAddress());
servers.remove(server);
servers.add(server);
}
packet.setLength(data.length);
}
public List<ServerData> getServers() {
List<ServerData> tmp = new ArrayList<>(servers);
List<ServerData> list = new ArrayList<>();
for (ServerData server : tmp) {
if (server.getFreshness() < PingConstants.PING_SERVER_FRESHNESS) {
list.add(server);
}
}
return list;
}
public static class ServerData {
public final String ip;
public final long foundTime;
public ServerData(String ip) {
this.ip = ip;
this.foundTime = System.currentTimeMillis();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ServerData other = (ServerData) obj;
if (!Objects.equals(this.ip, other.ip)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return ip.hashCode();
}
public int getFreshness() {
return (int) (System.currentTimeMillis() - foundTime);
}
@Override
public String toString() {
return "Server[" + "ip=" + ip + ", freshness=" + getFreshness() + "ms]";
}
}
}