mirror of
https://github.com/JonasunderscoreJones/McWebserver.git
synced 2025-10-23 03:19:19 +02:00
some fixes I assume
This commit is contained in:
parent
385879c305
commit
8d9deef4a6
7 changed files with 149 additions and 118 deletions
|
@ -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.
|
// 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}"
|
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||||
|
|
||||||
|
implementation files('libs/java-curl-1.2.2.jar')
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
|
BIN
libs/java-curl-1.2.2.jar
Normal file
BIN
libs/java-curl-1.2.2.jar
Normal file
Binary file not shown.
|
@ -1,12 +1,15 @@
|
||||||
package me.jonasjones.mcwebserver;
|
package me.jonasjones.mcwebserver;
|
||||||
|
|
||||||
|
import com.roxstudio.utils.CUrl;
|
||||||
import me.jonasjones.mcwebserver.config.ModConfigs;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
import me.jonasjones.mcwebserver.web.HTTPServer;
|
import me.jonasjones.mcwebserver.web.ServerHandler;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 {
|
public class McWebserver implements ModInitializer {
|
||||||
// This logger is used to write text to the console and the log file.
|
// 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 String MOD_ID = "mcwebserver";
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER");
|
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
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
@ -24,15 +30,30 @@ public class McWebserver implements ModInitializer {
|
||||||
|
|
||||||
LOGGER.info("McWebserver initialized!");
|
LOGGER.info("McWebserver initialized!");
|
||||||
|
|
||||||
if (ModConfigs.IS_ENABLED) {
|
|
||||||
LOGGER.info("Starting Webserver...");
|
|
||||||
|
|
||||||
new Thread(() -> {
|
webserverthread.start();
|
||||||
new HTTPServer(new Socket());
|
new Thread(() -> {
|
||||||
HTTPServer.main();
|
while (true) {
|
||||||
}).start();
|
if (!mcserveractive) {
|
||||||
} else {
|
LOGGER.info("LMFAFMAKONJDGOADJINGOADNGHOADNHGOADNHOADHON");
|
||||||
LOGGER.info("Webserver disabled in the config file.");
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package me.jonasjones.mcwebserver.mixin;
|
package me.jonasjones.mcwebserver.mixin;
|
||||||
|
|
||||||
import me.jonasjones.mcwebserver.McWebserver;
|
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.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(TitleScreen.class)
|
@Mixin(MinecraftServer.class)
|
||||||
public class InitializeMixin {
|
public class WebserverStopMixin {
|
||||||
@Inject(at = @At("HEAD"), method = "init()V")
|
@Inject(at = @At("HEAD"), method = "shutdown")
|
||||||
private void init(CallbackInfo info) {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,8 @@ import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.McWebserver.mcserveractive;
|
||||||
|
|
||||||
public class HTTPServer implements Runnable {
|
public class HTTPServer implements Runnable {
|
||||||
static Path WEB_ROOT;
|
static Path WEB_ROOT;
|
||||||
static final String DEFAULT_FILE = ModConfigs.WEB_FILE_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);
|
McWebserver.LOGGER.info("Listening for connections on port : " + PORT);
|
||||||
|
|
||||||
// we listen until user halts server execution
|
// we listen until user halts server execution
|
||||||
while (true) {
|
while (mcserveractive) {
|
||||||
HTTPServer myServer = new HTTPServer(serverConnect.accept());
|
HTTPServer myServer = new HTTPServer(serverConnect.accept());
|
||||||
|
|
||||||
VerboseLogger.info("Connection opened. (" + Instant.now() + ")");
|
VerboseLogger.info("Connection opened. (" + Instant.now() + ")");
|
||||||
|
@ -70,6 +72,7 @@ public class HTTPServer implements Runnable {
|
||||||
// create dedicated thread to manage the client connection
|
// create dedicated thread to manage the client connection
|
||||||
Thread thread = new Thread(myServer);
|
Thread thread = new Thread(myServer);
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,105 +83,108 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// we manage our particular client connection
|
if (mcserveractive) {
|
||||||
BufferedReader in = null; PrintWriter out = null; BufferedOutputStream dataOut = null;
|
// we manage our particular client connection
|
||||||
String fileRequested = null;
|
BufferedReader in = null;
|
||||||
|
PrintWriter out = null;
|
||||||
|
BufferedOutputStream dataOut = null;
|
||||||
|
String fileRequested = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// we read characters from the client via input stream on the socket
|
// we read characters from the client via input stream on the socket
|
||||||
in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
|
in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
|
||||||
// we get character output stream to client (for headers)
|
// we get character output stream to client (for headers)
|
||||||
out = new PrintWriter(connect.getOutputStream());
|
out = new PrintWriter(connect.getOutputStream());
|
||||||
// get binary output stream to client (for requested data)
|
// get binary output stream to client (for requested data)
|
||||||
dataOut = new BufferedOutputStream(connect.getOutputStream());
|
dataOut = new BufferedOutputStream(connect.getOutputStream());
|
||||||
|
|
||||||
// get first line of the request from the client
|
// get first line of the request from the client
|
||||||
String input = in.readLine();
|
String input = in.readLine();
|
||||||
// we parse the request with a string tokenizer
|
// we parse the request with a string tokenizer
|
||||||
StringTokenizer parse = new StringTokenizer(input);
|
StringTokenizer parse = new StringTokenizer(input);
|
||||||
String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client
|
String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client
|
||||||
// we get file requested
|
// we get file requested
|
||||||
fileRequested = parse.nextToken().toLowerCase();
|
fileRequested = parse.nextToken().toLowerCase();
|
||||||
|
|
||||||
// we support only GET and HEAD methods, we check
|
// we support only GET and HEAD methods, we check
|
||||||
if (!method.equals("GET") && !method.equals("HEAD")) {
|
if (!method.equals("GET") && !method.equals("HEAD")) {
|
||||||
VerboseLogger.info("501 Not Implemented : " + method + " method.");
|
VerboseLogger.info("501 Not Implemented : " + method + " method.");
|
||||||
|
|
||||||
// we return the not supported file to the client
|
// we return the not supported file to the client
|
||||||
Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED);
|
Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED);
|
||||||
long fileLength = Files.size(file);
|
long fileLength = Files.size(file);
|
||||||
String contentMimeType = "text/html";
|
String contentMimeType = "text/html";
|
||||||
//read content to return to client
|
//read content to return to client
|
||||||
byte[] fileData = readFileData(file);
|
byte[] fileData = readFileData(file);
|
||||||
|
|
||||||
// we send HTTP Headers with data to client
|
// we send HTTP Headers with data to client
|
||||||
dataOut.write(NOT_IMPLEMENTED);
|
dataOut.write(NOT_IMPLEMENTED);
|
||||||
dataOut.write(HEADERS); //hopefully enough credits
|
dataOut.write(HEADERS); //hopefully enough credits
|
||||||
dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8));
|
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-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("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8));
|
||||||
dataOut.write(CRLF); // blank line between headers and content, very important !
|
dataOut.write(CRLF); // blank line between headers and content, very important !
|
||||||
// file
|
// file
|
||||||
dataOut.write(fileData, 0, fileData.length);
|
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();
|
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) {
|
} 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 {
|
private byte[] readFileData(Path file) throws IOException {
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
package me.jonasjones.mcwebserver.web;
|
package me.jonasjones.mcwebserver.web;
|
||||||
|
|
||||||
|
|
||||||
import me.jonasjones.mcwebserver.McWebserver;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
|
|
||||||
public class ServerHandler extends Thread {
|
import java.net.Socket;
|
||||||
static ServerHandler thread = new ServerHandler();
|
|
||||||
public static void startServer() {
|
|
||||||
McWebserver.LOGGER.info("Starting Webserver...");
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void stopServer() throws InterruptedException {
|
import static me.jonasjones.mcwebserver.McWebserver.LOGGER;
|
||||||
McWebserver.LOGGER.info("Stopping Webserver...");
|
|
||||||
thread.interrupt();
|
public class ServerHandler implements Runnable {
|
||||||
McWebserver.LOGGER.info("Webserver stopped!");
|
public static Socket socket = new Socket();
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"minVersion": "0.8",
|
"minVersion": "0.8",
|
||||||
"package": "net.fabricmc.example.mixin",
|
"package": "me.jonasjones.mcwebserver.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
|
"WebserverStopMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue