mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-10 14:26:45 +00:00
login/register working and Websocket partially implemented
This commit is contained in:
parent
bd5f8573e8
commit
3492e133e1
@ -18,8 +18,6 @@
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
|
@ -17,8 +17,6 @@
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
|
@ -20,8 +20,6 @@
|
||||
<orderEntry type="library" name="Maven: junit:junit:4.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
|
@ -1,14 +1,8 @@
|
||||
package net.simon987.npcplugin.io;
|
||||
|
||||
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.io.DatabaseManager;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class StatsDatabaseManager extends DatabaseManager {
|
||||
|
||||
@ -18,32 +12,7 @@ public class StatsDatabaseManager extends DatabaseManager {
|
||||
|
||||
public void saveVaultCompletion(ControllableUnit unit, String dimension) {
|
||||
|
||||
Connection connection = getConnection();
|
||||
|
||||
try {
|
||||
|
||||
PreparedStatement p = connection.prepareStatement("INSERT INTO mar_vault_clear " +
|
||||
"(username, clear_time, vault_id) VALUES (?,?,?)");
|
||||
p.setString(1, unit.getParent().getUsername());
|
||||
p.setInt(2, 0);
|
||||
p.setString(3, dimension);
|
||||
|
||||
int result = p.executeUpdate();
|
||||
|
||||
LogManager.LOGGER.fine("Saved vault clear (" + result + " rows changed)");
|
||||
|
||||
} catch (MySQLIntegrityConstraintViolationException e) {
|
||||
LogManager.LOGGER.fine("This vault was already cleared by " + unit.getParent().getUsername());
|
||||
} catch (SQLException e) {
|
||||
LogManager.LOGGER.severe(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,6 @@
|
||||
<orderEntry type="library" name="Maven: junit:junit:4.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
|
@ -16,10 +16,8 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
|
@ -88,22 +88,12 @@
|
||||
<version>1.4a</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.3.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.42</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.json-simple</groupId>
|
||||
<artifactId>json-simple</artifactId>
|
||||
|
@ -14,7 +14,8 @@ import net.simon987.server.game.debug.*;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.PluginManager;
|
||||
import net.simon987.server.user.User;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
import net.simon987.server.user.UserManager;
|
||||
import net.simon987.server.websocket.SocketServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.UnknownHostException;
|
||||
@ -39,12 +40,16 @@ public class GameServer implements Runnable {
|
||||
|
||||
private MongoClient mongo = null;
|
||||
|
||||
private UserManager userManager;
|
||||
|
||||
public GameServer() {
|
||||
|
||||
this.config = new ServerConfiguration("config.properties");
|
||||
|
||||
try{
|
||||
mongo = new MongoClient("localhost", 27017);
|
||||
userManager = new UserManager(mongo);
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -127,7 +132,7 @@ public class GameServer implements Runnable {
|
||||
uTime = System.currentTimeMillis() - startTime;
|
||||
waitTime = config.getInt("tick_length") - uTime;
|
||||
|
||||
LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | " + (int) (((double) uTime / waitTime) * 100) + "% load");
|
||||
// LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | " + (int) (((double) uTime / waitTime) * 100) + "% load");
|
||||
|
||||
try {
|
||||
if (waitTime >= 0) {
|
||||
@ -184,14 +189,12 @@ public class GameServer implements Runnable {
|
||||
save();
|
||||
}
|
||||
|
||||
socketServer.tick();
|
||||
// socketServer.tick();
|
||||
|
||||
LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
|
||||
" updated)");
|
||||
// LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
|
||||
// " updated)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void load() {
|
||||
|
||||
LogManager.LOGGER.info("Loading all data from MongoDB");
|
||||
@ -248,14 +251,12 @@ public class GameServer implements Runnable {
|
||||
int insertedWorlds = 0;
|
||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||
for (World w : universe.getWorlds()) {
|
||||
// LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
||||
insertedWorlds++;
|
||||
worlds.save(w.mongoSerialise());
|
||||
|
||||
// If the world should unload, it is removed from the Universe after having been saved.
|
||||
//If the world should unload, it is removed from the Universe after having been saved.
|
||||
if (w.shouldUnload()){
|
||||
unloaded_worlds++;
|
||||
// LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
||||
universe.removeWorld(w);
|
||||
}
|
||||
}
|
||||
@ -265,17 +266,15 @@ public class GameServer implements Runnable {
|
||||
if (!u.isGuest()) {
|
||||
users.save(u.mongoSerialise());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BasicDBObject serverObj = new BasicDBObject();
|
||||
serverObj.put("_id","serverinfo"); // a constant id ensures only one entry is kept and updated, instead of a new entry created every save.
|
||||
serverObj.put("_id", "serverinfo"); //A constant id ensures only one entry is kept and updated, instead of a new entry created every save.
|
||||
serverObj.put("time", gameUniverse.getTime());
|
||||
serverObj.put("nextObjectId", gameUniverse.getNextObjectId());
|
||||
server.save(serverObj);
|
||||
|
||||
LogManager.LOGGER.info(""+insertedWorlds+" worlds saved, "+unloaded_worlds+" unloaded");
|
||||
LogManager.LOGGER.info("Done!");
|
||||
LogManager.LOGGER.info("" + insertedWorlds + " worlds saved, " + unloaded_worlds + " unloaded");
|
||||
} catch (Exception e) {
|
||||
LogManager.LOGGER.severe("Problem happened during save function");
|
||||
e.printStackTrace();
|
||||
@ -297,4 +296,8 @@ public class GameServer implements Runnable {
|
||||
public DayNightCycle getDayNightCycle() {
|
||||
return dayNightCycle;
|
||||
}
|
||||
|
||||
public UserManager getUserManager() {
|
||||
return userManager;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
package net.simon987.server;
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
import net.simon987.server.user.RegistrationException;
|
||||
import net.simon987.server.web.AlertMessage;
|
||||
import net.simon987.server.web.AlertType;
|
||||
import net.simon987.server.websocket.SocketServer;
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import spark.ModelAndView;
|
||||
import spark.Spark;
|
||||
import spark.template.velocity.VelocityTemplateEngine;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@ -22,12 +24,6 @@ public class Main {
|
||||
//Load
|
||||
GameServer.INSTANCE.load();
|
||||
|
||||
SocketServer socketServer = new SocketServer(new InetSocketAddress(config.getString("webSocket_host"),
|
||||
config.getInt("webSocket_port")), config);
|
||||
|
||||
GameServer.INSTANCE.setSocketServer(socketServer);
|
||||
|
||||
(new Thread(socketServer)).start();
|
||||
(new Thread(GameServer.INSTANCE)).start();
|
||||
|
||||
//TEST ---------------------------
|
||||
@ -36,29 +32,100 @@ public class Main {
|
||||
VelocityTemplateEngine templateEngine = new VelocityTemplateEngine(new VelocityEngine(properties));
|
||||
//--
|
||||
|
||||
//Websocket
|
||||
Spark.webSocket("/socket", SocketServer.class);
|
||||
|
||||
Spark.staticFiles.externalLocation("static");
|
||||
|
||||
Spark.get("/", (request, response) -> {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
System.out.println((String) request.session().attribute("user"));
|
||||
model.put("session", request.session());
|
||||
|
||||
return new ModelAndView(model, "home.vm");
|
||||
}, templateEngine);
|
||||
|
||||
Spark.get("/leaderboard", (request, response) -> {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("session", request.session());
|
||||
|
||||
return new ModelAndView(new HashMap<>(), "leaderboard.vm");
|
||||
}, templateEngine);
|
||||
|
||||
Spark.get("/play", (request, response) -> {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("session", request.session());
|
||||
|
||||
return new ModelAndView(model, "play.vm");
|
||||
}, templateEngine);
|
||||
|
||||
Spark.get("/account", (request, response) -> {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("session", request.session());
|
||||
|
||||
|
||||
if (request.session().attribute("username") != null) {
|
||||
model.put("user", GameServer.INSTANCE.getGameUniverse().getUser(request.session().attribute("username")));
|
||||
}
|
||||
|
||||
return new ModelAndView(model, "account.vm");
|
||||
}, templateEngine);
|
||||
|
||||
Spark.post("/register", (request, response) -> {
|
||||
String username = request.queryParams("username");
|
||||
String password = request.queryParams("password");
|
||||
|
||||
if (username != null && password != null) {
|
||||
try {
|
||||
GameServer.INSTANCE.getUserManager().registerUser(username, password);
|
||||
|
||||
AlertMessage[] messages = {new AlertMessage("Successfully registered", AlertType.SUCCESS)};
|
||||
request.session().attribute("messages", messages);
|
||||
request.session().attribute("username", username);
|
||||
|
||||
LogManager.LOGGER.fine("(Web) " + username + " registered " + request.ip());
|
||||
} catch (RegistrationException e) {
|
||||
AlertMessage[] messages = {new AlertMessage(e.getMessage(), AlertType.DANGER)};
|
||||
request.session().attribute("messages", messages);
|
||||
}
|
||||
}
|
||||
|
||||
response.redirect("/account");
|
||||
return null;
|
||||
});
|
||||
|
||||
Spark.post("/login", (request, response) -> {
|
||||
String username = request.queryParams("username");
|
||||
String password = request.queryParams("password");
|
||||
|
||||
if (username != null && password != null) {
|
||||
if (GameServer.INSTANCE.getUserManager().validateUser(username, password)) {
|
||||
AlertMessage[] messages = {new AlertMessage("Logged in as " + username, AlertType.INFO)};
|
||||
request.session().attribute("messages", messages);
|
||||
request.session().attribute("username", username);
|
||||
|
||||
LogManager.LOGGER.fine("(Web) " + username + " logged in");
|
||||
} else {
|
||||
AlertMessage[] messages = {new AlertMessage("Invalid username or password", AlertType.DANGER)};
|
||||
request.session().attribute("messages", messages);
|
||||
}
|
||||
}
|
||||
|
||||
response.redirect("/account");
|
||||
return null;
|
||||
});
|
||||
|
||||
Spark.get("logout", (request, response) -> {
|
||||
|
||||
AlertMessage[] messages = {new AlertMessage("Logged out", AlertType.INFO)};
|
||||
request.session().attribute("messages", messages);
|
||||
request.session().removeAttribute("username");
|
||||
|
||||
response.redirect("/account");
|
||||
return null;
|
||||
});
|
||||
|
||||
Spark.after((request, response) -> response.header("Content-Encoding", "gzip"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ public class CPU implements MongoSerialisable {
|
||||
}
|
||||
int elapsed = (int) (System.currentTimeMillis() - startTime);
|
||||
|
||||
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
||||
// LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
||||
|
||||
|
||||
//Write execution cost and instruction count to memory
|
||||
@ -173,7 +173,6 @@ public class CPU implements MongoSerialisable {
|
||||
|
||||
public void executeInstruction(Instruction instruction, int source, int destination) {
|
||||
|
||||
|
||||
//Execute the instruction
|
||||
if (source == 0) {
|
||||
//No operand (assuming that destination is also null)
|
||||
|
@ -1,8 +1,10 @@
|
||||
package net.simon987.server.event;
|
||||
|
||||
import net.simon987.server.webserver.OnlineUser;
|
||||
import net.simon987.server.websocket.OnlineUser;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DebugCommandEvent extends GameEvent {
|
||||
|
||||
private JSONObject command;
|
||||
@ -37,7 +39,11 @@ public class DebugCommandEvent extends GameEvent {
|
||||
response.put("t", "debug");
|
||||
response.put("message", message);
|
||||
|
||||
((OnlineUser) getSource()).getWebSocket().send(response.toJSONString());
|
||||
try {
|
||||
((OnlineUser) getSource()).getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package net.simon987.server.user;
|
||||
|
||||
public class RegistrationException extends Exception {
|
||||
|
||||
public RegistrationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,7 @@ public class User implements MongoSerialisable {
|
||||
private String username;
|
||||
|
||||
private String userCode;
|
||||
private String password;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
@ -49,6 +50,7 @@ public class User implements MongoSerialisable {
|
||||
dbObject.put("code", userCode);
|
||||
dbObject.put("controlledUnit", controlledUnit.getObjectId());
|
||||
dbObject.put("cpu", cpu.mongoSerialise());
|
||||
dbObject.put("password", password);
|
||||
|
||||
return dbObject;
|
||||
|
||||
@ -59,6 +61,7 @@ public class User implements MongoSerialisable {
|
||||
User user = new User((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("controlledUnit")));
|
||||
user.username = (String) obj.get("username");
|
||||
user.userCode = (String) obj.get("code");
|
||||
user.password = (String) obj.get("password");
|
||||
|
||||
user.getControlledUnit().setParent(user);
|
||||
|
||||
@ -107,4 +110,8 @@ public class User implements MongoSerialisable {
|
||||
public void setGuest(boolean guest) {
|
||||
this.guest = guest;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.simon987.server.user;
|
||||
|
||||
import com.mongodb.*;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import org.springframework.security.crypto.bcrypt.BCrypt;
|
||||
|
||||
@ -34,16 +35,37 @@ public class UserManager {
|
||||
return userList;
|
||||
}
|
||||
|
||||
public void registerUser(User user, String password) {
|
||||
public void registerUser(String username, String password) throws RegistrationException {
|
||||
|
||||
DBObject dbUser = user.mongoSerialise();
|
||||
if (username.length() < 5 || username.length() > 20) {
|
||||
throw new RegistrationException("Username must be 5-20 characters");
|
||||
}
|
||||
if (password.length() < 8 || password.length() > 96) {
|
||||
throw new RegistrationException("Password must be 8-96 characters");
|
||||
}
|
||||
|
||||
String salt = BCrypt.gensalt(12);
|
||||
String hashedPassword = BCrypt.hashpw(password, salt);
|
||||
//Check if exists
|
||||
DBObject where = new BasicDBObject();
|
||||
where.put("_id", username);
|
||||
|
||||
dbUser.put("password", hashedPassword);
|
||||
if (userCollection.findOne(where) != null) {
|
||||
throw new RegistrationException("Username is already in use");
|
||||
}
|
||||
|
||||
userCollection.save(dbUser);
|
||||
try {
|
||||
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(username, true);
|
||||
user.setUsername(username);
|
||||
|
||||
String salt = BCrypt.gensalt();
|
||||
String hashedPassword = BCrypt.hashpw(password, salt);
|
||||
user.setPassword(hashedPassword);
|
||||
|
||||
DBObject dbUser = user.mongoSerialise();
|
||||
|
||||
userCollection.save(dbUser);
|
||||
} catch (Exception e) {
|
||||
throw new RegistrationException("An exception occurred while trying to create user: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateUser(String username, String password) {
|
||||
@ -52,7 +74,6 @@ public class UserManager {
|
||||
where.put("_id", username);
|
||||
|
||||
DBObject user = userCollection.findOne(where);
|
||||
|
||||
return user != null && BCrypt.checkpw(password, (String) user.get("password"));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package net.simon987.server.web;
|
||||
|
||||
public class AlertMessage {
|
||||
|
||||
private String message;
|
||||
private AlertType type;
|
||||
|
||||
public AlertMessage(String message, AlertType type) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public AlertType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
23
Server/src/main/java/net/simon987/server/web/AlertType.java
Normal file
23
Server/src/main/java/net/simon987/server/web/AlertType.java
Normal file
@ -0,0 +1,23 @@
|
||||
package net.simon987.server.web;
|
||||
|
||||
public enum AlertType {
|
||||
|
||||
SUCCESS("alert-success"),
|
||||
INFO("alert-info"),
|
||||
WARNING("alert-info"),
|
||||
DANGER("alert-danger"),
|
||||
PRIMARY("alert-primary"),
|
||||
SECONDARY("alert-secondary"),
|
||||
DARK("alert-dark");
|
||||
|
||||
public String name;
|
||||
|
||||
AlertType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface MessageHandler {
|
||||
|
||||
void handle(OnlineUser user, JSONObject json) throws WebsocketNotConnectedException;
|
||||
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class SocketServer extends WebSocketServer {
|
||||
|
||||
private OnlineUserManager userManager = new OnlineUserManager();
|
||||
|
||||
private SocketServerDatabase database;
|
||||
|
||||
private MessageDispatcher messageDispatcher = new MessageDispatcher();
|
||||
|
||||
public SocketServer(InetSocketAddress address, ServerConfiguration config) {
|
||||
super(address);
|
||||
|
||||
if (config.getInt("use_secure_webSocket") != 0) {
|
||||
|
||||
SSLContext context = getContext(config.getString("cert_path"));
|
||||
if (context != null) {
|
||||
setWebSocketFactory(new DefaultSSLWebSocketServerFactory(context));
|
||||
|
||||
LogManager.LOGGER.info("(WS) Enabled secure webSocket");
|
||||
} else {
|
||||
LogManager.LOGGER.severe("(WS) Failed to create SSL context");
|
||||
}
|
||||
}
|
||||
|
||||
setConnectionLostTimeout(120);
|
||||
setReuseAddr(true); //To avoid BindException
|
||||
|
||||
database = new SocketServerDatabase(config);
|
||||
|
||||
messageDispatcher.addHandler(new UserInfoRequestHandler());
|
||||
messageDispatcher.addHandler(new TerrainRequestHandler());
|
||||
messageDispatcher.addHandler(new ObjectsRequestHandler());
|
||||
messageDispatcher.addHandler(new CodeUploadHandler());
|
||||
messageDispatcher.addHandler(new CodeRequestHandler());
|
||||
messageDispatcher.addHandler(new KeypressHandler());
|
||||
messageDispatcher.addHandler(new FloppyHandler());
|
||||
messageDispatcher.addHandler(new DebugCommandHandler());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||
LogManager.LOGGER.info("(WS) New Websocket connection " + conn.getRemoteSocketAddress());
|
||||
userManager.add(new OnlineUser(conn));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
|
||||
LogManager.LOGGER.info("(WS) Closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason);
|
||||
userManager.remove(userManager.getUser(conn));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, String message) {
|
||||
OnlineUser onlineUser = userManager.getUser(conn);
|
||||
|
||||
if (onlineUser != null) {
|
||||
|
||||
if (onlineUser.isAuthenticated()) {
|
||||
|
||||
messageDispatcher.dispatch(onlineUser, message);
|
||||
|
||||
} else {
|
||||
LogManager.LOGGER.info("(WS) Received message from unauthenticated user " + conn.getRemoteSocketAddress());
|
||||
|
||||
//We expect a 128 characters long token
|
||||
if (message.length() == 128) {
|
||||
|
||||
String username = database.validateAuthToken(message);
|
||||
|
||||
if (username != null) {
|
||||
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(username, true);
|
||||
|
||||
onlineUser.setModerator(database.isModerator(username));
|
||||
|
||||
LogManager.LOGGER.info("(WS) User was successfully authenticated: " + user.getUsername() +
|
||||
" moderator: " + onlineUser.isModerator());
|
||||
|
||||
onlineUser.setUser(user);
|
||||
onlineUser.setAuthenticated(true);
|
||||
|
||||
conn.send("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||
|
||||
} else {
|
||||
|
||||
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(GameServer.INSTANCE.getGameUniverse().getGuestUsername(), false);
|
||||
onlineUser.setUser(user);
|
||||
onlineUser.setAuthenticated(true);
|
||||
onlineUser.setGuest(true);
|
||||
|
||||
LogManager.LOGGER.info("(WS) Created guest user " +
|
||||
onlineUser.getUser().getUsername() + conn.getRemoteSocketAddress());
|
||||
|
||||
conn.send("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, ByteBuffer message) {
|
||||
//System.out.println("received ByteBuffer from " + conn.getRemoteSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket conn, Exception ex) {
|
||||
|
||||
if (ex instanceof BindException) {
|
||||
|
||||
LogManager.LOGGER.severe("Address already in use");
|
||||
System.exit(-1);
|
||||
|
||||
} else {
|
||||
LogManager.LOGGER.severe("an error occurred on connection " + conn + ": " + ex);
|
||||
userManager.remove(userManager.getUser(conn));
|
||||
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
LogManager.LOGGER.info("(WS) Server started successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every tick
|
||||
*/
|
||||
public void tick() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("t", "tick");
|
||||
|
||||
// LogManager.LOGGER.info("Notified " + userManager.getOnlineUsers().size() + " users");
|
||||
|
||||
ArrayList<OnlineUser> onlineUsers = new ArrayList<>(userManager.getOnlineUsers()); //Avoid ConcurrentModificationException
|
||||
for (OnlineUser user : onlineUsers) {
|
||||
|
||||
if (user.getWebSocket().isOpen()) {
|
||||
|
||||
if (user.isGuest()) {
|
||||
|
||||
json.remove("c");
|
||||
user.getWebSocket().send(json.toJSONString());
|
||||
|
||||
} else {
|
||||
try {
|
||||
ControllableUnit unit = user.getUser().getControlledUnit();
|
||||
|
||||
//Send keyboard updated buffer
|
||||
ArrayList<Integer> kbBuffer = unit.getKeyboardBuffer();
|
||||
JSONArray keys = new JSONArray();
|
||||
keys.addAll(kbBuffer);
|
||||
json.put("keys", keys);
|
||||
|
||||
//Send console buffer
|
||||
if (unit.getConsoleMessagesBuffer().size() > 0) {
|
||||
|
||||
JSONArray buff = new JSONArray();
|
||||
|
||||
for (char[] message : unit.getConsoleMessagesBuffer()) {
|
||||
buff.add(new String(message));
|
||||
}
|
||||
|
||||
json.put("c", buff);
|
||||
} else {
|
||||
json.remove("c");
|
||||
}
|
||||
|
||||
json.put("cm", unit.getConsoleMode());
|
||||
|
||||
|
||||
//Send tick message
|
||||
user.getWebSocket().send(json.toJSONString());
|
||||
} catch (NullPointerException e) {
|
||||
//User is online but not completely initialised
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public OnlineUserManager getUserManager() {
|
||||
return userManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/SSLServerLetsEncryptExample.java
|
||||
*/
|
||||
/*
|
||||
* * Copyright (c) 2010-2017 Nathan Rajlich
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
private static SSLContext getContext(String pathTo) {
|
||||
SSLContext context;
|
||||
String password = "MAR";
|
||||
try {
|
||||
context = SSLContext.getInstance("TLS");
|
||||
|
||||
byte[] certBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "cert.pem")),
|
||||
"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
|
||||
byte[] keyBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "privkey.pem")),
|
||||
"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
|
||||
|
||||
X509Certificate cert = generateCertificateFromDER(certBytes);
|
||||
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
|
||||
|
||||
KeyStore keystore = KeyStore.getInstance("JKS");
|
||||
keystore.load(null);
|
||||
keystore.setCertificateEntry("cert-alias", cert);
|
||||
keystore.setKeyEntry("key-alias", key, password.toCharArray(), new Certificate[]{cert});
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(keystore, password.toCharArray());
|
||||
|
||||
KeyManager[] km = kmf.getKeyManagers();
|
||||
|
||||
context.init(km, null, null);
|
||||
} catch (Exception e) {
|
||||
context = null;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
|
||||
String data = new String(pem);
|
||||
String[] tokens = data.split(beginDelimiter);
|
||||
tokens = tokens[1].split(endDelimiter);
|
||||
return DatatypeConverter.parseBase64Binary(tokens[0]);
|
||||
}
|
||||
|
||||
private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
|
||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
|
||||
return (RSAPrivateKey) factory.generatePrivate(spec);
|
||||
}
|
||||
|
||||
private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
|
||||
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||
}
|
||||
|
||||
private static byte[] getBytes(File file) {
|
||||
byte[] bytesArray = new byte[(int) file.length()];
|
||||
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
fis.read(bytesArray); //read file into bytes[]
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bytesArray;
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CodeRequestHandler implements MessageHandler {
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
public void handle(OnlineUser user, JSONObject json) throws IOException {
|
||||
|
||||
if (json.get("t").equals("codeRequest")) {
|
||||
|
||||
@ -18,7 +20,7 @@ public class CodeRequestHandler implements MessageHandler {
|
||||
response.put("t", "code");
|
||||
response.put("code", "; Create a free account to control your own Cubot with assembly language!"); //todo load from config
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
|
||||
} else {
|
||||
|
||||
@ -27,7 +29,7 @@ public class CodeRequestHandler implements MessageHandler {
|
||||
response.put("t", "code");
|
||||
response.put("code", user.getUser().getUserCode());
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.Assembler;
|
||||
@ -6,10 +6,12 @@ import net.simon987.server.assembly.AssemblyResult;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CodeUploadHandler implements MessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
public void handle(OnlineUser user, JSONObject json) throws IOException {
|
||||
if (json.get("t").equals("uploadCode")) {
|
||||
|
||||
LogManager.LOGGER.fine("(WS) Code upload from " + user.getUser().getUsername());
|
||||
@ -48,11 +50,9 @@ public class CodeUploadHandler implements MessageHandler {
|
||||
response.put("bytes", ar.bytes.length);
|
||||
response.put("exceptions", ar.exceptions.size());
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.event.DebugCommandEvent;
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class DebugCommandHandler implements MessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) throws WebsocketNotConnectedException {
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
|
||||
|
||||
if (json.get("t").equals("debug") && user.isModerator()) {
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
@ -21,7 +21,7 @@ public class FloppyHandler implements MessageHandler {
|
||||
|
||||
if (user.getUser().getControlledUnit().getFloppyData() != null) {
|
||||
byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes();
|
||||
user.getWebSocket().send(bytes);
|
||||
LogManager.LOGGER.severe("TODO FloppyHandler.handle()");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MessageDispatcher {
|
||||
@ -32,11 +32,8 @@ public class MessageDispatcher {
|
||||
for (MessageHandler handler : handlers) {
|
||||
try {
|
||||
handler.handle(user, json);
|
||||
} catch (WebsocketNotConnectedException e) {
|
||||
LogManager.LOGGER.fine("Catched WebsocketNotConnectedException");
|
||||
} catch (Exception e1) {
|
||||
LogManager.LOGGER.severe(e1.getMessage());
|
||||
e1.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
@ -0,0 +1,11 @@
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface MessageHandler {
|
||||
|
||||
void handle(OnlineUser user, JSONObject json) throws IOException;
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.GameObject;
|
||||
@ -7,11 +7,13 @@ import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ObjectsRequestHandler implements MessageHandler {
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
public void handle(OnlineUser user, JSONObject json) throws IOException {
|
||||
if (json.get("t").equals("object")) {
|
||||
// LogManager.LOGGER.fine("(WS) Objects request from " + user.getUser().getUsername());
|
||||
|
||||
@ -43,7 +45,7 @@ public class ObjectsRequestHandler implements MessageHandler {
|
||||
|
||||
|
||||
if (user.getWebSocket().isOpen()) {
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.user.User;
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
public class OnlineUser {
|
||||
|
||||
|
||||
private boolean authenticated = false;
|
||||
|
||||
private WebSocket webSocket;
|
||||
private Session webSocket;
|
||||
|
||||
private boolean guest;
|
||||
|
||||
@ -19,12 +19,12 @@ public class OnlineUser {
|
||||
*/
|
||||
private User user;
|
||||
|
||||
public OnlineUser(WebSocket webSocket) {
|
||||
public OnlineUser(Session webSocket) {
|
||||
this.webSocket = webSocket;
|
||||
|
||||
}
|
||||
|
||||
public WebSocket getWebSocket() {
|
||||
public Session getWebSocket() {
|
||||
return webSocket;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -12,7 +12,7 @@ public class OnlineUserManager {
|
||||
private ArrayList<OnlineUser> onlineUsers = new ArrayList<>(10);
|
||||
|
||||
|
||||
public OnlineUser getUser(WebSocket socket) {
|
||||
public OnlineUser getUser(Session socket) {
|
||||
|
||||
ArrayList<OnlineUser> _onlineUsers = new ArrayList<>(onlineUsers);
|
||||
|
@ -0,0 +1,129 @@
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@WebSocket
|
||||
public class SocketServer {
|
||||
|
||||
private OnlineUserManager onlineUserManager = new OnlineUserManager();
|
||||
|
||||
private MessageDispatcher messageDispatcher = new MessageDispatcher();
|
||||
|
||||
public SocketServer() {
|
||||
|
||||
messageDispatcher.addHandler(new UserInfoRequestHandler());
|
||||
messageDispatcher.addHandler(new TerrainRequestHandler());
|
||||
messageDispatcher.addHandler(new ObjectsRequestHandler());
|
||||
messageDispatcher.addHandler(new CodeUploadHandler());
|
||||
messageDispatcher.addHandler(new CodeRequestHandler());
|
||||
messageDispatcher.addHandler(new KeypressHandler());
|
||||
messageDispatcher.addHandler(new FloppyHandler());
|
||||
messageDispatcher.addHandler(new DebugCommandHandler());
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(Session session) {
|
||||
LogManager.LOGGER.info("(WS) New Websocket connection " + session.getRemoteAddress());
|
||||
onlineUserManager.add(new OnlineUser(session));
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(Session session, int code, String reason) {
|
||||
LogManager.LOGGER.info("(WS) Closed " + session.getRemoteAddress() + " with exit code " + code + " additional info: " + reason);
|
||||
onlineUserManager.remove(onlineUserManager.getUser(session));
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, String message) {
|
||||
OnlineUser onlineUser = onlineUserManager.getUser(session);
|
||||
|
||||
if (onlineUser != null) {
|
||||
|
||||
if (onlineUser.isAuthenticated()) {
|
||||
|
||||
messageDispatcher.dispatch(onlineUser, message);
|
||||
|
||||
} else {
|
||||
|
||||
LogManager.LOGGER.info("(WS) Received message from unauthenticated user " + session.getRemoteAddress());
|
||||
//todo
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every tick
|
||||
*/
|
||||
public void tick() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("t", "tick");
|
||||
|
||||
ArrayList<OnlineUser> onlineUsers = new ArrayList<>(onlineUserManager.getOnlineUsers()); //Avoid ConcurrentModificationException
|
||||
for (OnlineUser user : onlineUsers) {
|
||||
|
||||
if (user.getWebSocket().isOpen()) {
|
||||
|
||||
if (user.isGuest()) {
|
||||
|
||||
json.remove("c");
|
||||
try {
|
||||
user.getWebSocket().getRemote().sendString((json.toJSONString()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
ControllableUnit unit = user.getUser().getControlledUnit();
|
||||
|
||||
//Send keyboard updated buffer
|
||||
ArrayList<Integer> kbBuffer = unit.getKeyboardBuffer();
|
||||
JSONArray keys = new JSONArray();
|
||||
keys.addAll(kbBuffer);
|
||||
json.put("keys", keys);
|
||||
|
||||
//Send console buffer
|
||||
if (unit.getConsoleMessagesBuffer().size() > 0) {
|
||||
|
||||
JSONArray buff = new JSONArray();
|
||||
|
||||
for (char[] message : unit.getConsoleMessagesBuffer()) {
|
||||
buff.add(new String(message));
|
||||
}
|
||||
|
||||
json.put("c", buff);
|
||||
} else {
|
||||
json.remove("c");
|
||||
}
|
||||
|
||||
json.put("cm", unit.getConsoleMode());
|
||||
|
||||
//Send tick message
|
||||
user.getWebSocket().getRemote().sendString(json.toJSONString());
|
||||
} catch (NullPointerException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.io.DatabaseManager;
|
@ -1,4 +1,4 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.World;
|
||||
@ -6,10 +6,12 @@ import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TerrainRequestHandler implements MessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
public void handle(OnlineUser user, JSONObject json) throws IOException {
|
||||
if (json.get("t").equals("terrain") && json.containsKey("x") && json.containsKey("y") &&
|
||||
json.containsKey("dimension")) {
|
||||
|
||||
@ -44,14 +46,14 @@ public class TerrainRequestHandler implements MessageHandler {
|
||||
response.put("terrain", terrain);
|
||||
response.put("size", world.getWorldSize());
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString(response.toJSONString());
|
||||
} else {
|
||||
//Uncharted World
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("t", "terrain");
|
||||
response.put("ok", false);
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
user.getWebSocket().getRemote().sendString((response.toJSONString()));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
package net.simon987.server.webserver;
|
||||
package net.simon987.server.websocket;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UserInfoRequestHandler implements MessageHandler {
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject message) {
|
||||
public void handle(OnlineUser user, JSONObject message) throws IOException {
|
||||
|
||||
if (message.get("t").equals("userInfo")) {
|
||||
|
||||
@ -31,8 +33,7 @@ public class UserInfoRequestHandler implements MessageHandler {
|
||||
|
||||
json.put("t", "userInfo");
|
||||
json.put("maxWidth", GameServer.INSTANCE.getGameUniverse().getMaxWidth());
|
||||
user.getWebSocket().send(json.toJSONString());
|
||||
|
||||
user.getWebSocket().getRemote().sendString(json.toJSONString());
|
||||
|
||||
}
|
||||
}
|
@ -9,47 +9,103 @@
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<div class="card-header"><h5>Account - login & register</h5></div>
|
||||
<div class="card-header"><h5>Account</h5></div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Login</h5>
|
||||
<form>
|
||||
<div class="row">
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Username" placeholder="Username" name="username" class="form-control">
|
||||
#if($session.attribute("username"))
|
||||
## ALREADY LOGGED IN
|
||||
<p>Logged in as <strong>$session.attribute("username")</strong></p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title">Change password</h5>
|
||||
<form method="post" action="/change_password">
|
||||
<div class="row">
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Current password" type="password" placeholder="Current password"
|
||||
name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Password" type="password" placeholder="Password" name="password"
|
||||
class="form-control">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="form-group">
|
||||
<input title="New password" type="password" placeholder="New password"
|
||||
name="new_password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group">
|
||||
<input title="Repeat new password" type="password" placeholder="Repeat new password"
|
||||
name="new_password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-outline-primary text-mono">Register</button>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title">Debug information</h5>
|
||||
<div class="card card-block bg-light text-dark text-mono" style="padding: 1em">
|
||||
<h5>CPU</h5>
|
||||
<pre>$user.getCpu()</pre>
|
||||
|
||||
<h5>Code</h5>
|
||||
<pre>$user.getUserCode()</pre>
|
||||
|
||||
<h5>Controlled unit</h5>
|
||||
<p>id: $user.getControlledUnit().getObjectId()</p>
|
||||
<p>energy: $user.getControlledUnit().getEnergy()</p>
|
||||
<p>x: $user.getControlledUnit().getX()</p>
|
||||
<p>y: $user.getControlledUnit().getY()</p>
|
||||
<p>console mode: $user.getControlledUnit().getConsoleMode()</p>
|
||||
<p>kbBuffer size: $user.getControlledUnit().getKeyboardBuffer().size()</p>
|
||||
<h5>World</h5>
|
||||
<pre>$user.getControlledUnit().getWorld()</pre>
|
||||
</div>
|
||||
#else
|
||||
## NOT LOGGED IN
|
||||
<h5 class="card-title">Login</h5>
|
||||
<form method="post" action="/login">
|
||||
<div class="row">
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Username" placeholder="Username" name="username" class="form-control">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary text-mono">Login</button>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title">Register</h5>
|
||||
<form>
|
||||
<div class="row">
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Username" placeholder="Username" name="username" class="form-control">
|
||||
<div class="col form-group">
|
||||
<input title="Password" type="password" placeholder="Password" name="password"
|
||||
class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Password" type="password" placeholder="Password" name="password"
|
||||
class="form-control">
|
||||
|
||||
<button type="submit" class="btn btn-primary text-mono">Login</button>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title">Register</h5>
|
||||
<form method="post" action="/register">
|
||||
<div class="row">
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Username" placeholder="Username" name="username" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col form-group">
|
||||
<input title="Password" type="password" placeholder="Password" name="password"
|
||||
class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-outline-primary text-mono">Register</button>
|
||||
|
||||
</form>
|
||||
<button type="submit" class="btn btn-outline-primary text-mono">Register</button>
|
||||
</form>
|
||||
#end
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,3 +29,12 @@
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
#foreach($msg in $session.attribute("messages"))
|
||||
<div class="alert $msg.getType()"><a href="#" class="close" data-dismiss="alert"
|
||||
aria-label="close">×</a>$msg.getMessage()</div>
|
||||
#end
|
||||
$session.removeAttribute("messages")
|
||||
</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user