Skip to content

Instantly share code, notes, and snippets.

@sirolf2009
Last active November 6, 2015 15:03
Show Gist options
  • Save sirolf2009/242c35c162ae835aa4b7 to your computer and use it in GitHub Desktop.
Save sirolf2009/242c35c162ae835aa4b7 to your computer and use it in GitHub Desktop.
A rest api based socket server
import static spark.Spark.post;
import static spark.Spark.get;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import spark.Request;
import spark.servlet.SparkApplication;
public class Server implements SparkApplication {
private static final Logger log = LogManager.getLogger(Server.class);
private List<Listener> listeners;
private Map<Integer, Connection> connections;
private List<Integer> disconnectedConnections;
private Gson gson;
private Counter counter;
public Server() {
listeners = new ArrayList<Listener>();
connections = new HashMap<Integer, Connection>();
gson = new Gson();
counter = new Counter();
disconnectedConnections = new ArrayList<Integer>();
}
@Override
public void init() {
post("/push/:ID", (req, res) -> {
log.debug(req.params("ID")+" is pushing:\n"+req.body());
new Thread(() -> {
for(Listener listener : listeners) {
try {
listener.received(getConnection(Integer.parseInt(req.params("ID"))), parse(req));
} catch(Exception e) {
log.error("Failed to receive new data", e);
}
}
}).start();
return msg("ok");
});
get("/register", (req, res) -> {
int ID = counter.next();
Connection connection = new Connection(this, ID);
connections.put(ID, connection);
log.trace(ID+" registered");
for(Listener listener : listeners) {
try {
listener.connected(connection);
} catch(Exception e) {
log.error("Failed to deliver a new connection to a listener");
}
}
return ID;
});
get("/unregister/:ID", (req, res) -> {
if(req.params("ID") == null) {
log.debug(req.ip()+" unregister without registering");
return "/register for /unregister";
}
int ID = -1;
try {
ID = Integer.parseInt(req.params("ID"));
} catch(NumberFormatException e) {
log.error(req.params("ID")+" cannot be parsed as an integer");
return "That is not an ID";
}
getConnection(ID).close();
return "ok";
});
get("/fetch/:ID", (req, res) -> {
if(req.params("ID") == null) {
log.debug(req.ip()+" fetched without registering");
return "/register for /fetch";
}
int ID = -1;
try {
ID = Integer.parseInt(req.params("ID"));
} catch(NumberFormatException e) {
log.error(req.params("ID")+" cannot be parsed as an integer");
return "That is not an ID";
}
log.debug(ID+" is fetching updates");
if(disconnectedConnections.contains(ID)) {
log.debug(req.params("ID")+" is about to hear that he is disconnected");
disconnectedConnections.remove(new Integer(ID));
res.status(400);
}
if(getConnection(ID) == null) {
log.error(ID+" tried to fetch, but he does not exist");
return "You don't exist";
}
String body = getConnection(ID).getMessages(gson);
log.debug(ID+" is replied with \n"+body);
return body;
});
try {
new ServerProgram(this);
} catch (IOException e) {
log.error("Failed to start serverprogram", e);
}
}
//Implemented from kryo
public void sendToTCP(int hostConnection, Object object) {
if(hostConnection > 0) {
log.debug("send "+object+" to "+hostConnection);
connections.get(hostConnection).send(object);
}
}
public Connection[] getConnections() {
return connections.values().toArray(new Connection[connections.values().size()]);
}
public void addListener(Listener listener) {
log.debug("Adding listener: "+listener);
listeners.add(listener);
}
//No longer implemented from kryo
public String msg(String msg) {
return gson.toJson(new Message(msg));
}
public void close(Connection connection) {
for(Listener listener : listeners) {
try {
listener.disconnected(connection);
} catch(Exception e) {
log.error("Failed to deliver a disconnect to a listener", e);
}
}
connections.remove(connection.getID());
disconnectedConnections.add(connection.getID());
}
public Connection getConnection(int ID) {
return connections.get(ID);
}
public Object parse(Request req) {
String body = req.body();
try {
return gson.fromJson(body, PacketMessage.Multiplayer.class);
} catch(JsonSyntaxException e) {}
try {
return gson.fromJson(body, PacketMessage.Game.class);
} catch(JsonSyntaxException e) {}
try {
return gson.fromJson(body, PacketMessage.Finish.class);
} catch(JsonSyntaxException e) {}
try {
return gson.fromJson(body, PacketMessage.GameStart.class);
} catch(JsonSyntaxException e) {}
try {
return gson.fromJson(body, PacketMessage.HostSettings.class);
} catch(JsonSyntaxException e) {}
throw new RuntimeException("Json body is not a known object:\n"+body);
}
private class Counter {
private int i = 0;
public int next() {
i++;
return i;
}
}
private class Message {
private String message;
public Message(String message) {
this.message = message;
}
}
public interface Listener {
public void connected(Connection connection);
public void received(Connection connection, Object object);
public void disconnected(Connection connection);
}
public class Connection {
private int id;
private Server server;
private Queue<Object> messageQueue; //RabbitMQueue easier variant
public Connection(Server server, int id) {
setServer(server);
setID(id);
setMessageQueue(new LinkedList<Object>());
}
public Connection() {
}
public String getMessages(Gson gson) {
String messages = gson.toJson(messageQueue);
flush();
return messages;
}
public void send(Object object) {
messageQueue.add(object);
}
public void flush() {
messageQueue.clear();
}
public void close() {
server.close(this);
}
public int getID() {
return id;
}
public void setID(int id) {
this.id = id;
}
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
}
public Queue<Object> getMessageQueue() {
return messageQueue;
}
public void setMessageQueue(Queue<Object> messageQueue) {
this.messageQueue = messageQueue;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment