commit 8d5a6524329a8a3a06a9460275336423ab38e4e2
Author: jeffcheasey88 <66554203+jeffcheasey88@users.noreply.github.com>
Date: Sat Mar 25 19:47:30 2023 +0100
first commit
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..da9ddb9
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..30263e5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+bin/
+.settings/
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 0000000..710842b
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ Endg-2048-Backend
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/json-simple-1.1.1.jar b/json-simple-1.1.1.jar
new file mode 100644
index 0000000..dfd5856
Binary files /dev/null and b/json-simple-1.1.1.jar differ
diff --git a/src/be/jeffcheasey88/Main.java b/src/be/jeffcheasey88/Main.java
new file mode 100644
index 0000000..082773a
--- /dev/null
+++ b/src/be/jeffcheasey88/Main.java
@@ -0,0 +1,70 @@
+package be.jeffcheasey88;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.regex.Matcher;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+import be.jeffcheasey88.webserver.Client;
+import be.jeffcheasey88.webserver.HttpReader;
+import be.jeffcheasey88.webserver.HttpUtil;
+import be.jeffcheasey88.webserver.HttpWriter;
+import be.jeffcheasey88.webserver.Response;
+import be.jeffcheasey88.webserver.Router;
+
+public class Main {
+
+ public static void main(String[] args) throws Exception {
+ Router router = new Router();
+
+ router.setDefault(new Response(){
+ @Override
+ public void exec(Matcher matcher, HttpReader reader, HttpWriter writer) throws Exception {
+ HttpUtil.switchToWebSocket(reader, writer);
+
+ JSONObject welcome = new JSONObject();
+ welcome.put("action", "state");
+ welcome.put("game", "game1");
+ HttpUtil.sendWebSocket(writer, welcome.toJSONString());
+
+ Player player = new Player(writer);
+ Party party = Party.pick();
+ party.join(player);
+ while(!party.ready()) Thread.sleep(10);
+ Player opposite = party.getOpposite(player);
+ sendState(writer, opposite.getState());
+
+ while(!reader.isClosed()){
+ JSONObject json = (JSONObject) new JSONParser().parse(HttpUtil.readWebSocket(reader));
+ String action = (String)json.get("action");
+ if(action.equals("restart")){
+ player.setState(null);
+ sendState(writer, null);
+ }else if(action.equals("state")){
+ player.setState((String)json.get("value"));
+ }
+
+ sendState(opposite.getWriter(), player.getState());
+ }
+ }
+
+ private void sendState(HttpWriter writer, String state) throws Exception{
+ JSONObject set = new JSONObject();
+ set.put("action", "state");
+ set.put("game", "game2");
+ if(state != null) set.put("value", state);
+ HttpUtil.sendWebSocket(writer, set.toJSONString());
+ }
+ });
+
+ ServerSocket server = new ServerSocket(80);
+ while(!server.isClosed()){
+ Socket socket = server.accept();
+ Client client = new Client(socket, router);
+ client.start();
+ }
+ }
+
+}
diff --git a/src/be/jeffcheasey88/Party.java b/src/be/jeffcheasey88/Party.java
new file mode 100644
index 0000000..cc60f7f
--- /dev/null
+++ b/src/be/jeffcheasey88/Party.java
@@ -0,0 +1,39 @@
+package be.jeffcheasey88;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Party {
+
+ private static Set parties = new HashSet<>();
+
+ public static Party pick(){
+ for(Party party : parties){
+ if(!party.ready()) return party;
+ }
+ Party party = new Party();
+ parties.add(party);
+ return party;
+ }
+
+ private Player one;
+ private Player second;
+
+ private Party() {}
+
+ public void join(Player player){
+ if(this.one == null){
+ this.one = player;
+ }else{
+ this.second = player;
+ }
+ }
+
+ public boolean ready(){
+ return one != null && second != null;
+ }
+
+ public Player getOpposite(Player current){
+ return current.equals(one) ? second : one;
+ }
+}
diff --git a/src/be/jeffcheasey88/Player.java b/src/be/jeffcheasey88/Player.java
new file mode 100644
index 0000000..e7a5adc
--- /dev/null
+++ b/src/be/jeffcheasey88/Player.java
@@ -0,0 +1,26 @@
+package be.jeffcheasey88;
+
+import be.jeffcheasey88.webserver.HttpWriter;
+
+public class Player {
+
+ private String state;
+ private final HttpWriter writer;
+
+ public Player(HttpWriter writer){
+ this.writer = writer;
+ }
+
+ public void setState(String state){
+ this.state = state;
+ }
+
+ public String getState(){
+ return this.state;
+ }
+
+ public HttpWriter getWriter(){
+ return this.writer;
+ }
+
+}
diff --git a/src/be/jeffcheasey88/webserver/Client.java b/src/be/jeffcheasey88/webserver/Client.java
new file mode 100644
index 0000000..fd4f825
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/Client.java
@@ -0,0 +1,29 @@
+package be.jeffcheasey88.webserver;
+
+import java.net.Socket;
+import java.util.Arrays;
+
+public class Client extends Thread{
+
+ private HttpReader reader;
+ private HttpWriter writer;
+ private Router router;
+
+ public Client(Socket socket, Router router) throws Exception{
+ this.reader = new HttpReader(socket);
+ this.writer = new HttpWriter(socket);
+ this.router = router;
+ }
+
+ @Override
+ public void run(){
+ try {
+ String[] headers = reader.readLine().split("\\s");
+ System.out.println(Arrays.toString(headers));
+
+ router.exec(headers[0], headers[1], reader, writer);
+ writer.flush();
+ writer.close();
+ } catch (Exception e){}
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/HttpReader.java b/src/be/jeffcheasey88/webserver/HttpReader.java
new file mode 100644
index 0000000..7438e83
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/HttpReader.java
@@ -0,0 +1,40 @@
+package be.jeffcheasey88.webserver;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.Socket;
+
+public class HttpReader {
+
+ private Socket socket;
+ private InputStream in;
+ private BufferedReader reader;
+
+ public HttpReader(Socket socket) throws Exception{
+ this.socket = socket;
+ this.in = socket.getInputStream();
+ this.reader = new BufferedReader(new InputStreamReader(in));
+ }
+
+ public boolean isClosed(){
+ return this.socket.isClosed();
+ }
+
+ public int read(byte[] buffer) throws IOException{
+ return this.in.read(buffer);
+ }
+
+ public int read(char[] buffer) throws IOException {
+ return this.reader.read(buffer);
+ }
+
+ public String readLine() throws IOException{
+ return this.reader.readLine();
+ }
+
+ public boolean ready() throws IOException{
+ return this.reader.ready();
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/HttpUtil.java b/src/be/jeffcheasey88/webserver/HttpUtil.java
new file mode 100644
index 0000000..c7175a4
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/HttpUtil.java
@@ -0,0 +1,334 @@
+package be.jeffcheasey88.webserver;
+
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.simple.parser.JSONParser;
+
+public class HttpUtil {
+
+ private HttpUtil(){}
+
+ public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception{
+ writer.write("HTTP/1.1 "+code+" "+codeMessage(code)+"\n");
+ for(String header : headers) writer.write(header+"\n");
+ writer.write("\n");
+ writer.flush();
+ }
+
+ public static void skipHeaders(HttpReader reader) throws Exception{
+ String line;
+ while(((line = reader.readLine()) != null) && (line.length() > 0));
+ }
+
+ public static List readMultiPartData(HttpReader reader) throws Exception{
+ List list = new ArrayList<>();
+
+ reader.readLine();
+
+ while(reader.ready()){
+ String line;
+ while(((line = reader.readLine()) != null) && (line.length() > 0)){
+
+ }
+ String buffer = "";
+ while(((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))){
+ buffer+=line;
+ }
+ list.add(buffer);
+ }
+
+ return list;
+ }
+
+ public static void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{
+ String key = readWebSocketKey(reader);
+ if(key == null) throw new IllegalArgumentException();
+
+ writer.write("HTTP/1.1 101 Switching Protocols\n");
+ writer.write("Connection: Upgrade\n");
+ writer.write("Upgrade: websocket\n");
+ writer.write("Sec-WebSocket-Accept: "+
+ printBase64Binary(
+ MessageDigest.getInstance("SHA-1").
+ digest((key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8")))+"\n");
+ writer.write("\n");
+ writer.flush();
+ }
+
+ private static Pattern WEBSOCKET_KEY = Pattern.compile("Sec-WebSocket-Key: (.*)");
+
+ public static String readWebSocketKey(HttpReader reader) throws Exception {
+ String line;
+ String key = null;
+ while(((line = reader.readLine()) != null) && (line.length() > 0)){
+ if(key != null){
+ continue;
+ }
+ Matcher matcher = WEBSOCKET_KEY.matcher(line);
+ if(matcher.matches()) key = matcher.group(1);
+ }
+ return key;
+ }
+
+ private static Pattern AUTORIZATION = Pattern.compile("Authorization: Bearer (.*)");
+
+ public static String readAuthorization(HttpReader reader) throws Exception {
+ String line;
+ String key = null;
+ while(((line = reader.readLine()) != null) && (line.length() > 0)){
+ Matcher matcher = AUTORIZATION.matcher(line);
+ if(matcher.matches()){
+ key = matcher.group(1);
+ break;
+ }
+ }
+ return key;
+ }
+
+ public static Object readJson(HttpReader reader) throws Exception{
+ String line = "";
+ while(reader.ready()){
+ char[] c = new char[1];
+ reader.read(c);
+ line+=c[0];
+ if(c[0] == '}'){
+ Object parse;
+ try {
+ parse = new JSONParser().parse(line);
+ if(parse != null) return parse;
+ }catch(Exception e){}
+ }
+ }
+ return null;
+ }
+
+ //I found this code on StackOverFlow !!!!! (and the write too)
+ public static String readWebSocket(HttpReader reader) throws Exception{
+ int buffLenth = 1024;
+ int len = 0;
+ byte[] b = new byte[buffLenth];
+ //rawIn is a Socket.getInputStream();
+ while(true){
+ len = reader.read(b);
+ if(len!=-1){
+ byte rLength = 0;
+ int rMaskIndex = 2;
+ int rDataStart = 0;
+ //b[0] is always text in my case so no need to check;
+ byte data = b[1];
+ byte op = (byte) 127;
+ rLength = (byte) (data & op);
+
+ if(rLength==(byte)126) rMaskIndex=4;
+ if(rLength==(byte)127) rMaskIndex=10;
+
+ byte[] masks = new byte[4];
+
+ int j=0;
+ int i=0;
+ for(i=rMaskIndex;i<(rMaskIndex+4);i++){
+ masks[j] = b[i];
+ j++;
+ }
+
+ rDataStart = rMaskIndex + 4;
+
+ int messLen = len - rDataStart;
+
+ byte[] message = new byte[messLen];
+
+ for(i=rDataStart, j=0; i= 126 && rawData.length <= 65535){
+ frame[1] = (byte) 126;
+ int len = rawData.length;
+ frame[2] = (byte)((len >> 8 ) & (byte)255);
+ frame[3] = (byte)(len & (byte)255);
+ frameCount = 4;
+ }else{
+ frame[1] = (byte) 127;
+ int len = rawData.length;
+ frame[2] = (byte)((len >> 56 ) & (byte)255);
+ frame[3] = (byte)((len >> 48 ) & (byte)255);
+ frame[4] = (byte)((len >> 40 ) & (byte)255);
+ frame[5] = (byte)((len >> 32 ) & (byte)255);
+ frame[6] = (byte)((len >> 24 ) & (byte)255);
+ frame[7] = (byte)((len >> 16 ) & (byte)255);
+ frame[8] = (byte)((len >> 8 ) & (byte)255);
+ frame[9] = (byte)(len & (byte)255);
+ frameCount = 10;
+ }
+
+ int bLength = frameCount + rawData.length;
+
+ byte[] reply = new byte[bLength];
+
+ int bLim = 0;
+ for(int i=0; i= 3; j += 3) {
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3);
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F);
+ i -= 3;
+ }
+ if (i == 1) {
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4);
+ paramArrayOfchar[paramInt3++] = '=';
+ paramArrayOfchar[paramInt3++] = '=';
+ }
+ if (i == 2) {
+ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
+ paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2);
+ paramArrayOfchar[paramInt3++] = '=';
+ }
+ return paramInt3;
+ }
+
+ private static char encode(int paramInt) {
+ return encodeMap[paramInt & 0x3F];
+ }
+ private static final char[] encodeMap = initEncodeMap();
+
+ private static char[] initEncodeMap() {
+ char[] arrayOfChar = new char[64];
+ byte b;
+ for (b = 0; b < 26; b++)
+ arrayOfChar[b] = (char)(65 + b);
+ for (b = 26; b < 52; b++)
+ arrayOfChar[b] = (char)(97 + b - 26);
+ for (b = 52; b < 62; b++)
+ arrayOfChar[b] = (char)(48 + b - 52);
+ arrayOfChar[62] = '+';
+ arrayOfChar[63] = '/';
+ return arrayOfChar;
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/HttpWriter.java b/src/be/jeffcheasey88/webserver/HttpWriter.java
new file mode 100644
index 0000000..7fc8389
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/HttpWriter.java
@@ -0,0 +1,36 @@
+package be.jeffcheasey88.webserver;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+
+public class HttpWriter{
+
+ private OutputStream out;
+ private BufferedWriter writer;
+
+ public HttpWriter(Socket socket) throws Exception{
+ this.out = socket.getOutputStream();
+ this.writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
+ }
+
+ public void write(byte[] buffer) throws IOException{
+ this.out.write(buffer);
+ this.out.flush();
+ }
+
+ public void write(String message) throws IOException{
+ this.writer.write(message);
+ }
+
+ public void flush() throws IOException{
+ this.writer.flush();
+ }
+
+ public void close() throws IOException{
+ this.writer.close();
+ }
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/Response.java b/src/be/jeffcheasey88/webserver/Response.java
new file mode 100644
index 0000000..9c543ae
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/Response.java
@@ -0,0 +1,9 @@
+package be.jeffcheasey88.webserver;
+
+import java.util.regex.Matcher;
+
+public interface Response{
+
+ void exec(Matcher matcher, HttpReader reader, HttpWriter writer) throws Exception ;
+
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/Route.java b/src/be/jeffcheasey88/webserver/Route.java
new file mode 100644
index 0000000..26f5ebe
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/Route.java
@@ -0,0 +1,15 @@
+package be.jeffcheasey88.webserver;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Route {
+
+ String path() default "^.*$";
+ String type() default "GET";
+
+}
\ No newline at end of file
diff --git a/src/be/jeffcheasey88/webserver/Router.java b/src/be/jeffcheasey88/webserver/Router.java
new file mode 100644
index 0000000..f62c8bf
--- /dev/null
+++ b/src/be/jeffcheasey88/webserver/Router.java
@@ -0,0 +1,49 @@
+package be.jeffcheasey88.webserver;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Router{
+
+ private Map responses;
+ private Map patterns;
+ private Response noFileFound;
+
+ public Router() throws Exception{
+ this.responses = new HashMap<>();
+ this.patterns = new HashMap<>();
+ }
+
+ public void register(Response response){
+ try {
+ Method method = response.getClass().getDeclaredMethod("exec", Response.class.getDeclaredMethods()[0].getParameterTypes());
+ Route route = method.getAnnotation(Route.class);
+
+ this.responses.put(response, route);
+ this.patterns.put(response, Pattern.compile(route.path()));
+ } catch (Exception e){
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public void setDefault(Response response){
+ this.noFileFound = response;
+ }
+
+ public void exec(String type, String path,HttpReader reader, HttpWriter writer) throws Exception {
+ for(Entry routes : this.responses.entrySet()){
+ if(routes.getValue().type().equals(type)){
+ Matcher matcher = this.patterns.get(routes.getKey()).matcher(path);
+ if(matcher.matches()){
+ routes.getKey().exec(matcher, reader, writer);
+ return;
+ }
+ }
+ }
+ if(noFileFound != null) noFileFound.exec(null, reader, writer);
+ }
+}
\ No newline at end of file