diff --git a/build.gradle b/build.gradle index 7a3be5d..f49b7c8 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,8 @@ dependencies { // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + + implementation files('libs/java-curl-1.2.2.jar') } processResources { diff --git a/libs/java-curl-1.2.2.jar b/libs/java-curl-1.2.2.jar new file mode 100644 index 0000000..3c20c7d Binary files /dev/null and b/libs/java-curl-1.2.2.jar differ diff --git a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java index 66b8327..9d5f394 100644 --- a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java +++ b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java @@ -1,12 +1,15 @@ package me.jonasjones.mcwebserver; +import com.roxstudio.utils.CUrl; import me.jonasjones.mcwebserver.config.ModConfigs; -import me.jonasjones.mcwebserver.web.HTTPServer; +import me.jonasjones.mcwebserver.web.ServerHandler; import net.fabricmc.api.ModInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT; public class McWebserver implements ModInitializer { // This logger is used to write text to the console and the log file. @@ -15,6 +18,9 @@ public class McWebserver implements ModInitializer { public static String MOD_ID = "mcwebserver"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER"); + private static ServerHandler webserver = new ServerHandler(); + public static Thread webserverthread = new Thread(webserver); + public static boolean mcserveractive = true; @Override public void onInitialize() { @@ -24,15 +30,30 @@ public class McWebserver implements ModInitializer { LOGGER.info("McWebserver initialized!"); - if (ModConfigs.IS_ENABLED) { - LOGGER.info("Starting Webserver..."); - new Thread(() -> { - new HTTPServer(new Socket()); - HTTPServer.main(); - }).start(); - } else { - LOGGER.info("Webserver disabled in the config file."); - } + webserverthread.start(); + new Thread(() -> { + while (true) { + if (!mcserveractive) { + LOGGER.info("LMFAFMAKONJDGOADJINGOADNGHOADNHGOADNHOADHON"); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.print("curl 127.0.0.1:" + WEB_PORT); + CUrl curl = new CUrl("curl http://localhost:" + WEB_PORT + "/index.html"); + curl.exec(); + break; + } else { + System.out.print(mcserveractive); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + }).start(); } } diff --git a/src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java similarity index 58% rename from src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java rename to src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java index 9212892..baeceaa 100644 --- a/src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java +++ b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java @@ -1,16 +1,17 @@ package me.jonasjones.mcwebserver.mixin; import me.jonasjones.mcwebserver.McWebserver; -import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.server.MinecraftServer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(TitleScreen.class) -public class InitializeMixin { - @Inject(at = @At("HEAD"), method = "init()V") +@Mixin(MinecraftServer.class) +public class WebserverStopMixin { + @Inject(at = @At("HEAD"), method = "shutdown") private void init(CallbackInfo info) { - McWebserver.LOGGER.info("This line is printed by an example mod mixin!"); + McWebserver.LOGGER.info("Stopping Webserver..."); + McWebserver.mcserveractive = false; } } diff --git a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java b/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java index 0e2fc25..772576f 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java @@ -20,6 +20,8 @@ import java.nio.file.Path; import java.time.Instant; import java.util.StringTokenizer; +import static me.jonasjones.mcwebserver.McWebserver.mcserveractive; + public class HTTPServer implements Runnable { static Path WEB_ROOT; static final String DEFAULT_FILE = ModConfigs.WEB_FILE_ROOT; @@ -62,7 +64,7 @@ public class HTTPServer implements Runnable { McWebserver.LOGGER.info("Listening for connections on port : " + PORT); // we listen until user halts server execution - while (true) { + while (mcserveractive) { HTTPServer myServer = new HTTPServer(serverConnect.accept()); VerboseLogger.info("Connection opened. (" + Instant.now() + ")"); @@ -70,6 +72,7 @@ public class HTTPServer implements Runnable { // create dedicated thread to manage the client connection Thread thread = new Thread(myServer); thread.start(); + } } @@ -80,105 +83,108 @@ public class HTTPServer implements Runnable { @Override public void run() { - // we manage our particular client connection - BufferedReader in = null; PrintWriter out = null; BufferedOutputStream dataOut = null; - String fileRequested = null; + if (mcserveractive) { + // we manage our particular client connection + BufferedReader in = null; + PrintWriter out = null; + BufferedOutputStream dataOut = null; + String fileRequested = null; - try { - // we read characters from the client via input stream on the socket - in = new BufferedReader(new InputStreamReader(connect.getInputStream())); - // we get character output stream to client (for headers) - out = new PrintWriter(connect.getOutputStream()); - // get binary output stream to client (for requested data) - dataOut = new BufferedOutputStream(connect.getOutputStream()); + try { + // we read characters from the client via input stream on the socket + in = new BufferedReader(new InputStreamReader(connect.getInputStream())); + // we get character output stream to client (for headers) + out = new PrintWriter(connect.getOutputStream()); + // get binary output stream to client (for requested data) + dataOut = new BufferedOutputStream(connect.getOutputStream()); - // get first line of the request from the client - String input = in.readLine(); - // we parse the request with a string tokenizer - StringTokenizer parse = new StringTokenizer(input); - String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client - // we get file requested - fileRequested = parse.nextToken().toLowerCase(); + // get first line of the request from the client + String input = in.readLine(); + // we parse the request with a string tokenizer + StringTokenizer parse = new StringTokenizer(input); + String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client + // we get file requested + fileRequested = parse.nextToken().toLowerCase(); - // we support only GET and HEAD methods, we check - if (!method.equals("GET") && !method.equals("HEAD")) { - VerboseLogger.info("501 Not Implemented : " + method + " method."); + // we support only GET and HEAD methods, we check + if (!method.equals("GET") && !method.equals("HEAD")) { + VerboseLogger.info("501 Not Implemented : " + method + " method."); - // we return the not supported file to the client - Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED); - long fileLength = Files.size(file); - String contentMimeType = "text/html"; - //read content to return to client - byte[] fileData = readFileData(file); + // we return the not supported file to the client + Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED); + long fileLength = Files.size(file); + String contentMimeType = "text/html"; + //read content to return to client + byte[] fileData = readFileData(file); - // we send HTTP Headers with data to client - dataOut.write(NOT_IMPLEMENTED); - dataOut.write(HEADERS); //hopefully enough credits - dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Type: %s\r\n".formatted(contentMimeType).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); - dataOut.write(CRLF); // blank line between headers and content, very important ! - // file - dataOut.write(fileData, 0, fileData.length); - dataOut.flush(); - - } else { - // GET or HEAD method - if (fileRequested.endsWith("/")) { - fileRequested += DEFAULT_FILE; - } - if (fileRequested.startsWith("/")) { - fileRequested = fileRequested.substring(1); - } - - Path file = WEB_ROOT.resolve(fileRequested).toRealPath(LinkOption.NOFOLLOW_LINKS); - if (!file.startsWith(WEB_ROOT)) { - VerboseLogger.warn("Access to file outside root: " + file); - throw new NoSuchFileException(fileRequested); - } - int fileLength = (int)Files.size(file); - String contentType = getContentType(fileRequested); - byte[] fileData = readFileData(file); - - // send HTTP Headers - dataOut.write(OK); - dataOut.write(HEADERS); - dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Type: %s\r\n".formatted(contentType).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); - dataOut.write(CRLF); // blank line between headers and content, very important ! - if (method.equals("GET")) { // GET method so we return content - dataOut.write(fileData, 0, fileLength); + // we send HTTP Headers with data to client + dataOut.write(NOT_IMPLEMENTED); + dataOut.write(HEADERS); //hopefully enough credits + dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Type: %s\r\n".formatted(contentMimeType).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); + dataOut.write(CRLF); // blank line between headers and content, very important ! + // file + dataOut.write(fileData, 0, fileData.length); dataOut.flush(); + + } else { + // GET or HEAD method + if (fileRequested.endsWith("/")) { + fileRequested += DEFAULT_FILE; + } + if (fileRequested.startsWith("/")) { + fileRequested = fileRequested.substring(1); + } + + Path file = WEB_ROOT.resolve(fileRequested).toRealPath(LinkOption.NOFOLLOW_LINKS); + if (!file.startsWith(WEB_ROOT)) { + VerboseLogger.warn("Access to file outside root: " + file); + throw new NoSuchFileException(fileRequested); + } + int fileLength = (int) Files.size(file); + String contentType = getContentType(fileRequested); + byte[] fileData = readFileData(file); + + // send HTTP Headers + dataOut.write(OK); + dataOut.write(HEADERS); + dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Type: %s\r\n".formatted(contentType).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); + dataOut.write(CRLF); // blank line between headers and content, very important ! + if (method.equals("GET")) { // GET method so we return content + dataOut.write(fileData, 0, fileLength); + dataOut.flush(); + } + + VerboseLogger.info("File " + fileRequested + " of type " + contentType + " returned"); + } - VerboseLogger.info("File " + fileRequested + " of type " + contentType + " returned"); + } catch (NoSuchFileException e) { + try { + fileNotFound(out, dataOut, fileRequested); + } catch (IOException ioe) { + VerboseLogger.error("Error with file not found exception : " + ioe.getMessage()); + } - } - - } catch (NoSuchFileException e) { - try { - fileNotFound(out, dataOut, fileRequested); } catch (IOException ioe) { - VerboseLogger.error("Error with file not found exception : " + ioe.getMessage()); + VerboseLogger.error("Server error : " + ioe); + } finally { + try { + in.close(); + out.close(); + dataOut.close(); + connect.close(); // we close socket connection + } catch (Exception e) { + VerboseLogger.error("Error closing stream : " + e.getMessage()); + } + + VerboseLogger.info("Connection closed."); } - } catch (IOException ioe) { - VerboseLogger.error("Server error : " + ioe); - } finally { - try { - in.close(); - out.close(); - dataOut.close(); - connect.close(); // we close socket connection - } catch (Exception e) { - VerboseLogger.error("Error closing stream : " + e.getMessage()); - } - - VerboseLogger.info("Connection closed."); } - - } private byte[] readFileData(Path file) throws IOException { diff --git a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java index 3d9cf22..4adae22 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java @@ -1,23 +1,23 @@ package me.jonasjones.mcwebserver.web; -import me.jonasjones.mcwebserver.McWebserver; -import net.minecraft.server.MinecraftServer; +import me.jonasjones.mcwebserver.config.ModConfigs; -public class ServerHandler extends Thread { - static ServerHandler thread = new ServerHandler(); - public static void startServer() { - McWebserver.LOGGER.info("Starting Webserver..."); - thread.start(); - } +import java.net.Socket; - public static void stopServer() throws InterruptedException { - McWebserver.LOGGER.info("Stopping Webserver..."); - thread.interrupt(); - McWebserver.LOGGER.info("Webserver stopped!"); - } +import static me.jonasjones.mcwebserver.McWebserver.LOGGER; + +public class ServerHandler implements Runnable { + public static Socket socket = new Socket(); public void run() { - HTTPServer.main(); + if (ModConfigs.IS_ENABLED) { + LOGGER.info("Starting Webserver..."); + + new HTTPServer(socket); + HTTPServer.main(); + } else { + LOGGER.info("Webserver disabled in the config file."); + } } } diff --git a/src/main/resources/mcwebserver.mixins.json b/src/main/resources/mcwebserver.mixins.json index aa57238..b6d7a65 100644 --- a/src/main/resources/mcwebserver.mixins.json +++ b/src/main/resources/mcwebserver.mixins.json @@ -1,9 +1,10 @@ { "required": true, "minVersion": "0.8", - "package": "net.fabricmc.example.mixin", + "package": "me.jonasjones.mcwebserver.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "WebserverStopMixin" ], "injectors": { "defaultRequire": 1