Skip to content

Commit 3eed5e3

Browse files
committed
v1.0.0
1 parent d4ff60e commit 3eed5e3

File tree

13 files changed

+314
-67
lines changed

13 files changed

+314
-67
lines changed

build.gradle

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@ dependencies {
3939

4040
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
4141

42-
implementation 'org.java-websocket:Java-WebSocket:1.5.3'
43-
44-
annotationProcessor modImplementation("io.wispforest:owo-lib:${project.owo_version}")
45-
46-
implementation 'org.json:json:20250107'
42+
implementation(include('org.java-websocket:Java-WebSocket:1.6.0'))
43+
implementation(include('org.json:json:20250107'))
44+
implementation(include("org.yaml:snakeyaml:2.2"))
4745
}
4846

4947
processResources {
@@ -54,8 +52,8 @@ processResources {
5452

5553
filesMatching("fabric.mod.json") {
5654
expand "version": project.version,
57-
"minecraft_version": project.minecraft_version,
58-
"loader_version": project.loader_version
55+
"minecraft_version": project.minecraft_version,
56+
"loader_version": project.loader_version
5957
}
6058
}
6159

gradle.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ archives_base_name=web_socket_console
1313
# check this on https://modmuss50.me/fabric.html
1414
fabric_version=0.119.2+1.21.4
1515
loom_version=1.9-SNAPSHOT
16-
owo_version=0.12.20+1.21.4

src/client/resources/websocket_console.client.mixins.json renamed to src/client/resources/web_socket_console.client.mixins.json

File renamed without changes.

src/main/java/dev/loat/web_socket_console/WebSocketConsole.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
package dev.loat.web_socket_console;
22

3-
import dev.loat.web_socket_console.config.ModConfig;
3+
import dev.loat.web_socket_console.config.files.WebSocketConsoleConfigFile;
4+
import dev.loat.web_socket_console.config.parser.YamlSerializer;
45
import dev.loat.web_socket_console.console.LogAppender;
56
import dev.loat.web_socket_console.logging.Logger;
67
import dev.loat.web_socket_console.web_socket.WebSocketConsoleServer;
78
import net.fabricmc.api.ModInitializer;
89
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
10+
import net.fabricmc.loader.api.FabricLoader;
911
import net.minecraft.server.MinecraftServer;
1012
import org.apache.logging.log4j.Level;
1113
import org.apache.logging.log4j.core.LoggerContext;
1214

1315
import org.apache.logging.log4j.LogManager;
1416

17+
import java.io.File;
18+
1519
public class WebSocketConsole implements ModInitializer {
1620
private static WebSocketConsoleServer webSocketConsoleServer;
1721
private static MinecraftServer serverInstance;
1822

23+
private static WebSocketConsoleConfigFile modConfig;
24+
1925
@Override
2026
public void onInitialize() {
2127
Logger.setLoggerClass(WebSocketConsole.class);
2228

2329
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
24-
int port = ModConfig.WEB_SOCKET_CONFIG.port();
25-
Level logLevel = Level.valueOf(ModConfig.WEB_SOCKET_CONFIG.logLevel());
30+
var path = FabricLoader.getInstance().getConfigDir().resolve("web_socket_console/config.yaml");
31+
var config = new YamlSerializer<>(
32+
path.toString(),
33+
WebSocketConsoleConfigFile.class
34+
);
35+
36+
try {
37+
if(!new File(path.toString()).exists()) {
38+
config.serialize(new WebSocketConsoleConfigFile());
39+
}
40+
} catch (Exception e) {
41+
throw new RuntimeException(e);
42+
}
43+
44+
try {
45+
WebSocketConsole.modConfig = config.parse();
46+
} catch (Exception e) {
47+
throw new RuntimeException(e);
48+
}
2649

2750
WebSocketConsole.serverInstance = server;
2851
WebSocketConsole.webSocketConsoleServer = new WebSocketConsoleServer(
2952
WebSocketConsole.serverInstance,
30-
port
53+
WebSocketConsole.modConfig.port,
54+
WebSocketConsole.modConfig.logLevel
3155
);
3256
Logger.info("Starting WebSocket server");
3357
WebSocketConsole.webSocketConsoleServer.start();
@@ -36,7 +60,11 @@ public void onInitialize() {
3660
var logger = ctx.getConfiguration().getLoggers().get("");
3761
var webSocketLogAppender = new LogAppender(WebSocketConsole.webSocketConsoleServer);
3862
webSocketLogAppender.start();
39-
logger.addAppender(webSocketLogAppender, logLevel, null);
63+
logger.addAppender(
64+
webSocketLogAppender,
65+
Level.valueOf(WebSocketConsole.modConfig.logLevel),
66+
null
67+
);
4068
ctx.updateLoggers();
4169
});
4270

src/main/java/dev/loat/web_socket_console/config/ModConfig.java

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
package dev.loat.web_socket_console.config.files;
22

3-
import blue.endless.jankson.Comment;
4-
import io.wispforest.owo.config.annotation.Config;
5-
import org.apache.logging.log4j.Level;
3+
import dev.loat.web_socket_console.config.parser.annotation.Comment;
4+
5+
class LogLevel {
6+
public static String DEBUG = "DEBUG";
7+
public static String INFO = "INFO";
8+
public static String WARN = "WARN";
9+
public static String ERROR = "ERROR";
10+
}
611

7-
@Config(
8-
wrapperName = "WebSocketConsoleConfig",
9-
name = "web_socket_console/config"
10-
)
1112
public class WebSocketConsoleConfigFile {
1213
@Comment("The Port to use for the WebSocket server.")
1314
public int port = 8080;
1415

15-
@Comment("""
16-
17-
The LogLevel to use for the WebSocket server.
18-
19-
- "DEBUG"
20-
- "INFO"
21-
- "WARN"
22-
- "ERROR"
16+
@Comment("""
17+
The LogLevel to use for the WebSocket server.
18+
19+
- "DEBUG"
20+
- "INFO"
21+
- "WARN"
22+
- "ERROR"
2323
""")
24-
public String logLevel = Level.DEBUG.name();
25-
}
24+
public String logLevel = LogLevel.DEBUG;
25+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package dev.loat.web_socket_console.config.parser;
2+
3+
import dev.loat.web_socket_console.config.parser.annotation.Comment;
4+
import org.yaml.snakeyaml.DumperOptions;
5+
import org.yaml.snakeyaml.LoaderOptions;
6+
import org.yaml.snakeyaml.Yaml;
7+
import org.yaml.snakeyaml.constructor.Constructor;
8+
import org.yaml.snakeyaml.nodes.Tag;
9+
import org.yaml.snakeyaml.representer.Representer;
10+
11+
import java.io.FileWriter;
12+
import java.io.InputStream;
13+
import java.lang.reflect.Field;
14+
import java.nio.file.Files;
15+
import java.nio.file.Paths;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
public class YamlSerializer<ConfigClass> {
21+
private final String filePath;
22+
private final Class<ConfigClass> configClass;
23+
24+
public YamlSerializer(String filePath, Class<ConfigClass> configClass) {
25+
this.filePath = filePath;
26+
this.configClass = configClass;
27+
}
28+
29+
/**
30+
* Serializes a configuration object to a YAML file with comments.
31+
*
32+
* @param config The configuration object to serialize.
33+
* @throws Exception If an error occurs while writing the file.
34+
*/
35+
public void serialize(ConfigClass config) throws Exception {
36+
DumperOptions options = new DumperOptions();
37+
options.setIndent(2);
38+
options.setPrettyFlow(true);
39+
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
40+
41+
Representer representer = new Representer(options);
42+
representer.addClassTag(configClass, Tag.MAP);
43+
44+
Yaml yaml = new Yaml(representer, options);
45+
46+
String tempFile = filePath + ".tmp";
47+
try (FileWriter writer = new FileWriter(tempFile)) {
48+
yaml.dump(config, writer);
49+
}
50+
51+
Map<String, Object> yamlData;
52+
try (InputStream inputStream = Files.newInputStream(Paths.get(tempFile))) {
53+
yamlData = new Yaml().load(inputStream);
54+
}
55+
56+
List<String> modifiedLines = new ArrayList<>();
57+
Field[] fields = configClass.getDeclaredFields();
58+
59+
for (Field field : fields) {
60+
Comment comment = field.getAnnotation(Comment.class);
61+
String fieldName = field.getName();
62+
63+
if (comment != null) {
64+
String[] commentLines = comment.value().split("\n");
65+
for (String commentLine : commentLines) {
66+
String trimmedLine = commentLine.trim();
67+
if (!trimmedLine.isEmpty()) {
68+
modifiedLines.add("# " + trimmedLine);
69+
} else {
70+
modifiedLines.add("#");
71+
}
72+
}
73+
}
74+
75+
if (yamlData != null && yamlData.containsKey(fieldName)) {
76+
Object value = yamlData.get(fieldName);
77+
String yamlValue = yaml.dump(value).trim();
78+
if (yamlValue.contains("\n")) {
79+
yamlValue = yamlValue.substring(0, yamlValue.indexOf('\n'));
80+
}
81+
modifiedLines.add(fieldName + ": " + yamlValue);
82+
} else {
83+
modifiedLines.add(fieldName + ": null");
84+
}
85+
}
86+
87+
Files.write(Paths.get(filePath), modifiedLines);
88+
Files.deleteIfExists(Paths.get(tempFile));
89+
}
90+
91+
/**
92+
* Parses a YAML file and returns a configuration object.
93+
*
94+
* @return The configuration object reflecting the YAML file structure.
95+
* @throws Exception If an error occurs while reading the file or casting.
96+
*/
97+
public ConfigClass parse() throws Exception {
98+
try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
99+
LoaderOptions loaderOptions = new LoaderOptions();
100+
loaderOptions.setAllowDuplicateKeys(false);
101+
Constructor constructor = new Constructor(configClass, loaderOptions);
102+
Yaml yaml = new Yaml(constructor);
103+
Object result = yaml.load(inputStream);
104+
if (result == null) {
105+
throw new IllegalStateException("No data found in YAML file: " + filePath);
106+
}
107+
return configClass.cast(result);
108+
}
109+
}
110+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dev.loat.web_socket_console.config.parser.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.FIELD)
10+
public @interface Comment {
11+
String value();
12+
}

src/main/java/dev/loat/web_socket_console/web_socket/WebSocketConsoleServer.java

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dev.loat.web_socket_console.web_socket;
22

33
import dev.loat.web_socket_console.logging.Logger;
4-
import dev.loat.web_socket_console.web_socket.receive.Parser;
4+
import dev.loat.web_socket_console.web_socket.client.WebSocketClientList;
55
import net.minecraft.server.MinecraftServer;
66
import org.java_websocket.WebSocket;
77
import org.java_websocket.handshake.ClientHandshake;
@@ -11,11 +11,15 @@
1111
import java.util.Collections;
1212
import java.util.HashSet;
1313
import java.util.Set;
14+
import java.util.concurrent.Executors;
15+
import java.util.concurrent.ScheduledExecutorService;
1416

1517
public class WebSocketConsoleServer extends WebSocketServer {
16-
private final Set<WebSocket> connections = Collections.synchronizedSet(new HashSet<>());
18+
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
19+
private final Set<WebSocket> clients = Collections.synchronizedSet(new HashSet<>());
1720
private final MinecraftServer serverInstance;
1821
private final int port;
22+
private final String logLevel;
1923

2024
/**
2125
* This class represents a WebSocket server for the minecraft server console.
@@ -25,22 +29,23 @@ public class WebSocketConsoleServer extends WebSocketServer {
2529
*/
2630
public WebSocketConsoleServer(
2731
MinecraftServer minecraftServerInstance,
28-
int port
32+
int port,
33+
String logLevel
2934
) {
3035
super(new InetSocketAddress(port));
3136
this.serverInstance = minecraftServerInstance;
3237
this.port = port;
38+
this.logLevel = logLevel;
3339
}
3440

3541
@Override
3642
public void onOpen(
3743
WebSocket connection,
3844
ClientHandshake clientHandshake
3945
) {
46+
this.clients.add(connection);
4047

41-
connections.add(connection);
42-
43-
Logger.info("New client connected: {}", connection.getRemoteSocketAddress());
48+
Logger.info("Client connected: {}", connection.getRemoteSocketAddress());
4449
}
4550

4651
@Override
@@ -50,10 +55,10 @@ public void onClose(
5055
String reason,
5156
boolean remote
5257
) {
53-
connections.remove(connection);
58+
clients.remove(connection);
5459

5560
Logger.info(
56-
"Existing client disconnected: {} with code {}",
61+
"Client disconnected: {} with code {}",
5762
connection.getRemoteSocketAddress(),
5863
code
5964
);
@@ -64,21 +69,14 @@ public void onMessage(
6469
WebSocket connection,
6570
String message
6671
) {
67-
Logger.info(message);
68-
69-
Parser.addListener("auth", (payload) -> {Logger.info(payload.toString());});
70-
Parser.addListener("execute", (payload) -> {Logger.info(payload.toString());});
71-
Parser.addListener("stats", (payload) -> {Logger.info(payload.toString());});
72-
73-
Parser.parse(message);
72+
// Logger.info(message);
7473

75-
76-
// if (this.serverInstance != null) {
77-
// serverInstance.execute(() -> serverInstance.getCommandManager().executeWithPrefix(
78-
// serverInstance.getCommandSource(),
79-
// message
80-
// ));
81-
// }
74+
if (this.serverInstance != null) {
75+
serverInstance.execute(() -> serverInstance.getCommandManager().executeWithPrefix(
76+
serverInstance.getCommandSource(),
77+
message
78+
));
79+
}
8280
}
8381

8482
@Override
@@ -91,12 +89,12 @@ public void onError(
9189

9290
@Override
9391
public void onStart() {
94-
Logger.info("Started WebSocket server on *:{}", this.port);
92+
Logger.info("Started WebSocket server on *:{} with log level {}", this.port, this.logLevel);
9593
}
9694

9795
public void broadcastToClients(LogMessage message) {
98-
synchronized (this.connections) {
99-
for (WebSocket connection : this.connections) {
96+
synchronized (this.clients) {
97+
for (WebSocket connection : this.clients) {
10098
connection.send(message.toFormattedString());
10199
}
102100
}

0 commit comments

Comments
 (0)