package space;
import io.netty.util.internal.chmv8.ConcurrentHashMapV8;
import java.io.IOException;
import java.net.BindException;
import java.net.ConnectException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedDeque;
import space.celestials.StarSystem;
import space.events.CelestialRequest;
import space.events.Disconnect;
import space.events.EntityRequest;
import space.events.Keys;
import space.events.Login;
import space.events.Message;
import space.events.UseShip;
import space.models.Ship;
import space.models.User;
import space.physics.Entity;
import sql.MySQL;
import sql.SQL;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
public class Server {
private static Server _instance = new Server();
public static Server instance() { return _instance; }
private ArrayList<StarSystem> _system;
public final double acc = 1 * 0.0625;
public final double dec = 0.75 * 0.0625;
private ConcurrentLinkedDeque<User> _user = new ConcurrentLinkedDeque<>();
private ConcurrentHashMapV8<SocketIOClient, User> _userMap = new ConcurrentHashMapV8<>();
private SocketIOServer _server;
private SQL _sql;
private Server() { }
public void start() {
System.out.println("Initialising...");
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Shutting down...");
if(_server != null) {
System.out.println("Shutting down network threads...");
_server.stop();
}
if(_system != null) {
System.out.println("Unloading star systems...");
for(StarSystem system : _system) {
system.stop();
while(system.isAlive()) {
try {
system.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
if(_sql != null) {
System.out.println("Disconnecting from SQL server...");
_sql.close();
}
System.out.println("Goodbye.");
}
});
try {
_sql = SQL.create(MySQL.class);
_sql.connect("project1.monoxidedesign.com", "hairydata", "hairydata", "WaRcebYmnz4eSnGs");
} catch(InstantiationException | IllegalAccessException | ClassNotFoundException e) {
System.err.println("We couldn't load Connector/J. Make sure the library is there and the build path is configured properly.");
return;
} catch(SQLException e) {
if(e.getCause() instanceof ConnectException) {
System.err.println("We couldn't find the SQL server you specified. Sorry about that.");
return;
} else {
e.printStackTrace();
}
return;
}
try {
_system = StarSystem.load();
} catch(SQLException e) {
if(e instanceof MySQLSyntaxErrorException) {
System.err.println(e.getLocalizedMessage());
if(e.getMessage().contains("doesn't exist")) {
System.err.println("Make sure you're up to date on your migrations.");
}
} else {
e.printStackTrace();
}
return;
}
Configuration config = new Configuration();
config.setPort(9092);
_server = new SocketIOServer(config);
_server.addDisconnectListener(new Disconnect());
_server.addEventListener("lo", User.Login.class, new Login());
_server.addEventListener("ms", User.Message.class, new Message());
_server.addEventListener("us", Ship.Use.class, new UseShip());
_server.addEventListener("er", Entity.Request.class, new EntityRequest());
_server.addEventListener("cr", Entity.Request.class, new CelestialRequest());
_server.addEventListener("ke", Ship.Keys.class, new Keys());
System.out.println("Starting listening thread...");
try {
_server.start();
} catch(Exception e) {
if(e instanceof BindException && e.getMessage().contains("Address already in use")) {
System.err.println("Sorry, we can't open the server because there is already a server running on the selected port. " +
"You'll have to either close that program or change the port this server runs on.");
} else {
e.printStackTrace();
}
return;
}
System.out.println("Server running.");
try {
System.in.read();
} catch(IOException e) {
e.printStackTrace();
}
System.exit(0);
}
public void broadcastEvent(String name, Object packet) {
_server.getBroadcastOperations().sendEvent(name, packet);
}
public void broadcastMessage(String from, String message) {
broadcastEvent("ms", new User.Message(from, message));
}
public User userFromSocket(SocketIOClient socket) {
return _userMap.get(socket);
}
public Ship findShip(int systemID, int shipID) {
for(StarSystem system : _system) {
if(system.id == systemID) {
return system.findShip(shipID);
}
}
return null;
}
public void addUser(SocketIOClient socket, User.Login data) {
try {
User user = User.getUserIfAuthed(socket, data);
if(user != null) {
_user.add(user);
_userMap.put(socket, user);
System.out.println("New user added " + user.id);
user.serializeLoginResponse().send();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
public void removeUser(SocketIOClient socket) {
User user = _userMap.get(socket);
_userMap.remove(socket);
if(user != null) {
System.out.println("Disconnecting " + user.id);
user.leaveShip();
_user.remove(user);
}
}
}