feat: switch over to jetty

This commit is contained in:
TheClashFruit 2023-09-30 15:36:31 +02:00
parent 6ed3dc5ce4
commit a7f3038261
Signed by: TheClashFruit
GPG key ID: CF4A319B9A73290C
10 changed files with 266 additions and 94 deletions

View file

@ -16,7 +16,14 @@ dependencies {
implementation files('/home/tcf/MinecraftDev/craftbukkit-1.1-R5-SNAPSHOT.jar')
implementation 'org.java-websocket:Java-WebSocket:1.5.4'
implementation 'org.eclipse.jetty:jetty-server:9.4.52.v20230823'
implementation 'org.eclipse.jetty:jetty-servlet:9.4.52.v20230823'
implementation 'org.eclipse.jetty.websocket:websocket-server:9.4.52.v20230823'
implementation 'org.eclipse.jetty.websocket:websocket-servlet:9.4.52.v20230823'
implementation 'javax.servlet:javax.servlet-api:4.0.1'
implementation 'javax.websocket:javax.websocket-api:1.1'
implementation 'com.google.code.gson:gson:2.10.1'
}

View file

@ -1,37 +1,48 @@
package me.theclashfruit.crss;
import com.google.gson.Gson;
import me.theclashfruit.crss.api.ChatServlet;
import me.theclashfruit.crss.api.ChatSocket;
import me.theclashfruit.crss.listener.ChatListener;
import me.theclashfruit.crss.listener.FunListener;
import me.theclashfruit.crss.models.SystemData;
import me.theclashfruit.crss.models.SystemMessage;
import me.theclashfruit.crss.models.SocketData;
import me.theclashfruit.crss.models.SocketMessage;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.net.UnknownHostException;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletHandler;
public class Plugin extends JavaPlugin {
ChatSocket chatSocket;
Server server = new Server(25580);
Connector connector = new ServerConnector(server);
ServletHandler handler = new ServletHandler();
@Override
public void onEnable() {
getLogger().info("Plugin enabled!");
PluginManager pluginManager = getServer().getPluginManager();
// create chat socket
try {
chatSocket = new ChatSocket(25580);
// create api server
// ContextHandler context = new ContextHandler(new ApiHandler(), "/v1");
chatSocket.start();
} catch (UnknownHostException e) {
handler.addServletWithMapping(ChatServlet.class, "/v1/chat");
server.addConnector(connector);
server.setHandler(handler);
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
// register events
pluginManager.registerEvents(new FunListener(), this);
pluginManager.registerEvents(new ChatListener(chatSocket), this);
pluginManager.registerEvents(new ChatListener(), this);
}
@Override
@ -40,20 +51,17 @@ public class Plugin extends JavaPlugin {
// stop chat socket
try {
Gson gson = new Gson();
String chatMessage = gson.toJson(new SystemMessage(
ChatSocket.broadcast(new SocketMessage(
"serverStop",
new SystemData(
new SocketData(
null,
"Server stopped.",
0xFF5555
false
)
));
chatSocket.broadcast(chatMessage);
chatSocket.stop();
} catch (InterruptedException e) {
server.stop();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

View file

@ -0,0 +1,15 @@
package me.theclashfruit.crss.api;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "Chat WebSocket API")
public class ChatServlet extends WebSocketServlet {
@Override
public void configure(WebSocketServletFactory factory) {
factory.register(ChatSocket.class);
}
}

View file

@ -1,42 +1,75 @@
package me.theclashfruit.crss.api;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import com.google.gson.Gson;
import me.theclashfruit.crss.models.SocketData;
import me.theclashfruit.crss.models.SocketMessage;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.*;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import javax.websocket.EncodeException;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import static org.bukkit.Bukkit.getLogger;
import static org.bukkit.Bukkit.getPlayer;
public class ChatSocket extends WebSocketServer {
public ChatSocket(int port) throws UnknownHostException {
super(new InetSocketAddress(port));
@WebSocket
public class ChatSocket {
private static Set<ChatSocket> chatConnections = new CopyOnWriteArraySet<>();
private Session session;
@OnWebSocketConnect
public void onConnect(Session session) throws IOException {
this.session = session;
SocketMessage greeting = new SocketMessage(
"connectionGreet",
new SocketData(
null,
"Greetings!",
true
)
);
Gson gson = new Gson();
session.getRemote().sendString(
gson.toJson(greeting)
);
chatConnections.add(this);
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
@OnWebSocketMessage
public void onMessage(String message) throws IOException, EncodeException {
getLogger().info(message);
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
@OnWebSocketClose
public void onClose(int statusCode, String reason) throws IOException {
chatConnections.remove(this);
}
@Override
public void onMessage(WebSocket conn, String message) {
@OnWebSocketError
public void onError(Throwable throwable) {
getLogger().throwing(ChatSocket.class.getName(), "WebSocket", throwable);
}
@Override
public void onError(WebSocket conn, Exception ex) {
public static void broadcast(SocketMessage message) {
chatConnections.forEach(endpoint -> {
try {
Gson gson = new Gson();
endpoint
.session
.getRemote()
.sendString(
gson.toJson(message)
);
} catch (IOException e) {
getLogger().throwing(ChatSocket.class.getName(), "WebSocket", e);
}
@Override
public void onStart() {
getLogger().info("WebSocket server started on port " + getAddress().getPort() + "!");
});
}
}

View file

@ -1,12 +1,9 @@
package me.theclashfruit.crss.listener;
import com.google.gson.Gson;
import me.theclashfruit.crss.Plugin;
import me.theclashfruit.crss.api.ChatSocket;
import me.theclashfruit.crss.models.ChatData;
import me.theclashfruit.crss.models.ChatMessage;
import me.theclashfruit.crss.models.SystemData;
import me.theclashfruit.crss.models.SystemMessage;
import me.theclashfruit.crss.models.*;
import me.theclashfruit.crss.util.StringUtil;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -17,88 +14,67 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.ServerCommandEvent;
public class ChatListener implements Listener {
private final ChatSocket chatSocket;
public ChatListener(ChatSocket chatSocket) {
this.chatSocket = chatSocket;
}
@EventHandler
public void onChat(PlayerChatEvent event) {
Gson gson = new Gson();
String chatMessage = gson.toJson(new ChatMessage(
ChatSocket.broadcast(new SocketMessage(
"chatMessage",
new ChatData(
event.getMessage(),
new SocketData(
event.getPlayer().getName(),
0xFFFFFF
event.getMessage(),
false
)
));
chatSocket.broadcast(chatMessage);
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Gson gson = new Gson();
String chatMessage = gson.toJson(new SystemMessage(
ChatSocket.broadcast(new SocketMessage(
"playerJoin",
new SystemData(
new SocketData(
null,
event.getPlayer().getName() + " joined the game.",
0xFFFF55
false
)
));
chatSocket.broadcast(chatMessage);
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
Gson gson = new Gson();
String chatMessage = gson.toJson(new SystemMessage(
ChatSocket.broadcast(new SocketMessage(
"playerQuit",
new SystemData(
new SocketData(
null,
event.getPlayer().getName() + " left the game.",
0xFFFF55
false
)
));
chatSocket.broadcast(chatMessage);
}
@EventHandler
public void onDeath(PlayerDeathEvent event) {
Gson gson = new Gson();
String chatMessage = gson.toJson(new SystemMessage(
ChatSocket.broadcast(new SocketMessage(
"playerDeath",
new SystemData(
new SocketData(
null,
event.getDeathMessage(),
0xFFFFFF
false
)
));
chatSocket.broadcast(chatMessage);
}
@EventHandler
public void onServerCommand(ServerCommandEvent event) {
switch (event.getCommand().substring(0, 3)) {
switch (StringUtil.getFirstPartBeforeSpace(event.getCommand())) {
case "say":
Gson gson = new Gson();
String chatMessage = gson.toJson(new SystemMessage(
ChatSocket.broadcast(new SocketMessage(
"serverSay",
new SystemData(
new SocketData(
null,
ChatColor.stripColor(event.getCommand().substring(4)),
0xAA00AA
false
)
));
chatSocket.broadcast(chatMessage);
break;
default:
break;

View file

@ -0,0 +1,37 @@
package me.theclashfruit.crss.models;
public class SocketData {
private String username;
private String message;
private Boolean isSystemMessage;
public SocketData(String username, String message, Boolean isSystemMessage) {
this.username = username;
this.message = message;
this.isSystemMessage = isSystemMessage;
}
public String getUsername() {
return username;
}
public String getMessage() {
return message;
}
public Boolean getIsSystemMessage() {
return isSystemMessage;
}
public void setUsername(String username) {
this.username = username;
}
public void setMessage(String message) {
this.message = message;
}
public void setIsSystemMessage(Boolean isSystemMessage) {
this.isSystemMessage = isSystemMessage;
}
}

View file

@ -0,0 +1,27 @@
package me.theclashfruit.crss.models;
public class SocketMessage {
private String event;
private SocketData data;
public SocketMessage(String event, SocketData data) {
this.event = event;
this.data = data;
}
public String getEvent() {
return event;
}
public SocketData getData() {
return data;
}
public void setEvent(String event) {
this.event = event;
}
public void setData(SocketData data) {
this.data = data;
}
}

View file

@ -0,0 +1,33 @@
package me.theclashfruit.crss.util;
import com.google.gson.Gson;
import me.theclashfruit.crss.models.SocketMessage;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
public class MessageDecoder implements Decoder.Text<SocketMessage> {
private static final Gson gson = new Gson();
@Override
public SocketMessage decode(String s) throws DecodeException {
return gson.fromJson(s, SocketMessage.class);
}
@Override
public boolean willDecode(String s) {
return (s != null);
}
@Override
public void init(EndpointConfig endpointConfig) {
// Custom initialization logic
}
@Override
public void destroy() {
// Close resources
}
}

View file

@ -0,0 +1,28 @@
package me.theclashfruit.crss.util;
import com.google.gson.Gson;
import me.theclashfruit.crss.models.SocketMessage;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
public class MessageEncoder implements Encoder.Text<SocketMessage> {
private static final Gson gson = new Gson();
@Override
public String encode(SocketMessage message) throws EncodeException {
return gson.toJson(message);
}
@Override
public void init(EndpointConfig endpointConfig) {
// Custom initialization logic
}
@Override
public void destroy() {
// Close resources
}
}

View file

@ -0,0 +1,8 @@
package me.theclashfruit.crss.util;
public interface StringUtil {
static String getFirstPartBeforeSpace(String input) {
int index = input.contains(" ") ? input.indexOf(" ") : 0;
return input.substring(0, index);
}
}