Skip to content

Commit 6179f2b

Browse files
committed
Initial work, still more to do.
1 parent 494259f commit 6179f2b

6 files changed

Lines changed: 281 additions & 1 deletion

File tree

pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
<id>sonatype</id>
6464
<url>https://oss.sonatype.org/content/groups/public/</url>
6565
</repository>
66+
<repository>
67+
<id>placeholderapi</id>
68+
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
69+
</repository>
6670
</repositories>
6771

6872
<dependencies>
@@ -72,5 +76,11 @@
7276
<version>1.16.5-R0.1-SNAPSHOT</version>
7377
<scope>provided</scope>
7478
</dependency>
79+
<dependency>
80+
<groupId>me.clip</groupId>
81+
<artifactId>placeholderapi</artifactId>
82+
<version>2.10.9</version>
83+
<scope>provided</scope>
84+
</dependency>
7585
</dependencies>
7686
</project>

src/main/java/pw/chew/jsonrestapi/JSONRestAPI.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
package pw.chew.jsonrestapi;
22

3+
import org.bukkit.configuration.file.FileConfiguration;
34
import org.bukkit.plugin.java.JavaPlugin;
5+
import pw.chew.jsonrestapi.commands.ReloadCommand;
46

57
public final class JSONRestAPI extends JavaPlugin {
8+
// Files
9+
private static FileConfiguration config;
610

711
@Override
812
public void onEnable() {
13+
// Get and save config
14+
config = this.getConfig();
15+
config.addDefault("port", 6548);
16+
config.addDefault("authkey", "CHANGE_ME_PLEASE");
17+
config.options().copyDefaults(true);
18+
saveDefaultConfig();
19+
920
// Plugin startup logic
21+
RestServer server = new RestServer(config, this.getLogger());
22+
server.setDaemon(true);
23+
server.start();
24+
25+
this.getCommand("jrareload").setExecutor(new ReloadCommand(config, this));
1026

27+
this.getLogger().info("Listening on port " + config.getInt("port"));
1128
}
1229

1330
@Override
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package pw.chew.jsonrestapi;
2+
3+
import me.clip.placeholderapi.PlaceholderAPI;
4+
import org.bukkit.Bukkit;
5+
import org.bukkit.configuration.file.FileConfiguration;
6+
7+
import java.io.BufferedReader;
8+
import java.io.IOException;
9+
import java.io.InputStreamReader;
10+
import java.io.OutputStreamWriter;
11+
import java.io.PrintWriter;
12+
import java.net.ServerSocket;
13+
import java.net.Socket;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import java.util.Locale;
17+
import java.util.UUID;
18+
import java.util.logging.Logger;
19+
20+
public class RestServer extends Thread {
21+
22+
private static FileConfiguration config;
23+
private static Logger logger;
24+
25+
public RestServer(FileConfiguration config, Logger logger) {
26+
RestServer.config = config;
27+
RestServer.logger = logger;
28+
}
29+
30+
private int getPort() {
31+
return config.getInt("port");
32+
}
33+
34+
public static void updateConfig(FileConfiguration newConfig) {
35+
config = newConfig;
36+
}
37+
38+
@SuppressWarnings("InfiniteLoopStatement")
39+
@Override
40+
public void run() {
41+
try {
42+
ServerSocket socket = new ServerSocket(getPort());
43+
while (true) {
44+
ServerResponder responder = new ServerResponder(socket.accept());
45+
responder.setDaemon(true);
46+
responder.start();
47+
}
48+
} catch (IOException ex) {
49+
logger.severe("Failed to initialize server socket.");
50+
ex.printStackTrace();
51+
}
52+
}
53+
54+
private static class ServerResponder extends Thread {
55+
private final Socket inSocket;
56+
private final List<String> acceptedMethods = Arrays.asList("GET", "POST");
57+
58+
private ServerResponder(Socket inSocket) {
59+
this.inSocket = inSocket;
60+
}
61+
62+
@Override
63+
public void run() {
64+
try (
65+
InputStreamReader inputStreamReader = new InputStreamReader(inSocket.getInputStream());
66+
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
67+
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(inSocket.getOutputStream());
68+
PrintWriter printWriter = new PrintWriter(outputStreamWriter)
69+
) {
70+
String request = bufferedReader.readLine();
71+
if (request == null) {
72+
return;
73+
}
74+
75+
while (true) {
76+
String ignore = bufferedReader.readLine();
77+
if (ignore == null || ignore.length() == 0) {
78+
break;
79+
}
80+
}
81+
82+
int initialSplit = request.indexOf(' ');
83+
if (initialSplit == -1) {
84+
respondBadRequest(printWriter);
85+
return;
86+
}
87+
88+
String method = request.substring(0, initialSplit);
89+
90+
if (method.isEmpty()) {
91+
respondBadRequest(printWriter);
92+
return;
93+
}
94+
95+
if (!acceptedMethods.contains(method.toUpperCase(Locale.ROOT))) {
96+
respondNotAllowed(printWriter);
97+
return;
98+
}
99+
100+
int routeSplit = request.indexOf(' ', initialSplit + 1);
101+
if (routeSplit == -1) {
102+
respondBadRequest(printWriter);
103+
return;
104+
}
105+
106+
String route = request.substring(initialSplit + 1, routeSplit);
107+
int routeQuerySplit = route.indexOf('?');
108+
if (routeQuerySplit != -1) {
109+
route = route.substring(0, routeQuerySplit);
110+
}
111+
112+
// Remove initial slash
113+
route = route.replaceFirst("/", "");
114+
115+
logger.info("Received request with route: " + route);
116+
117+
// Check if route exists
118+
if (config.contains("routes." + route)) {
119+
String key = "routes." + route + ".";
120+
String configMethod = config.getString(key + "method");
121+
122+
if (!method.equals(configMethod)) {
123+
respondNotAllowed(printWriter);
124+
return;
125+
}
126+
127+
String response = PlaceholderAPI.setPlaceholders(Bukkit.getOfflinePlayer(UUID.randomUUID()), config.getString(key + "placeholder"));
128+
129+
respondOk(printWriter, response);
130+
} else {
131+
respondNotFound(printWriter);
132+
}
133+
} catch (IOException e) {
134+
e.printStackTrace();
135+
}
136+
}
137+
138+
/**
139+
* Responds to the HTTP request with a not allowed header.
140+
*
141+
* @param writer The {@link PrintWriter} to print the response to.
142+
*/
143+
private void respondNotAllowed(PrintWriter writer) {
144+
writer.printf("HTTP/1.2 405 Not Allowed%n%n");
145+
}
146+
147+
/**
148+
* Responds to the HTTP request with a bad request header.
149+
*
150+
* @param writer The {@link PrintWriter} to print the response to.
151+
*/
152+
private void respondBadRequest(PrintWriter writer) {
153+
writer.printf("HTTP/1.2 400 Bad Request%n%n");
154+
}
155+
156+
/**
157+
* Responds to the HTTP request with a not found header.
158+
*
159+
* @param writer The {@link PrintWriter} to print the response to.
160+
*/
161+
private void respondNotFound(PrintWriter writer) {
162+
writer.printf("HTTP/1.2 404 Not Found%n%n");
163+
}
164+
165+
/**
166+
* Responds to the HTTP request with an OK header.
167+
*
168+
* @param writer The {@link PrintWriter} to print the response to.
169+
*/
170+
private void respondOk(PrintWriter writer, String response) {
171+
writer.printf("HTTP/1.2 200 OK%n%n" + response);
172+
}
173+
}
174+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package pw.chew.jsonrestapi.commands;
2+
3+
import org.bukkit.command.Command;
4+
import org.bukkit.command.CommandExecutor;
5+
import org.bukkit.command.CommandSender;
6+
import org.bukkit.configuration.file.FileConfiguration;
7+
import org.jetbrains.annotations.NotNull;
8+
import pw.chew.jsonrestapi.JSONRestAPI;
9+
import pw.chew.jsonrestapi.RestServer;
10+
11+
public class ReloadCommand implements CommandExecutor {
12+
public static FileConfiguration config;
13+
public final JSONRestAPI plugin;
14+
15+
public ReloadCommand(FileConfiguration baseConfig, JSONRestAPI plugin) {
16+
config = baseConfig;
17+
this.plugin = plugin;
18+
}
19+
20+
@Override
21+
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
22+
sender.sendMessage("Reloading the config.");
23+
plugin.reloadConfig();
24+
config = plugin.getConfig();
25+
// Tell the server about the new config.
26+
RestServer.updateConfig(config);
27+
sender.sendMessage("Configuration reloaded!");
28+
return true;
29+
}
30+
}

src/main/resources/config.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
### JSONRestAPI Configuration ###
2+
# Thank you for downloading this plugin!
3+
# I hope this isn't overly complicated, but if you run into issues, feel free to request support below:
4+
# Discord: https://discord.gg/0kYlxgkh65QhZAjm
5+
# GitHub Discussions: https://github.com/ChewMC/JSONRestAPI/discussions
6+
7+
# Made changes? Run /jrareload
8+
# Requires jsonrestapi.reload or OP.
9+
10+
# The port to listen on.
11+
## Some shared hosts don't handle this very well, so you may need to change this value.
12+
## Only change this if you receive a "port in use" warning in your console on startup.
13+
## Confused? Feel free to contact me above.
14+
port: 6548
15+
16+
# An auth-key for private requests.
17+
## Only takes effect if authkey: true in the routes below, plus the root route.
18+
authkey: CHANGE_ME_PLEASE
19+
20+
# Route setup
21+
## By default, the root route accept a raw POST value for any info not provided here.
22+
## You can set up specific routes below.
23+
## A GET request must not be player-specific, and can for example be to query the players online.
24+
## A POST request must have a "username" or "uuid" parameter specified. Auth key is enabled by default for these.
25+
26+
routes:
27+
# The path to listen to. This must be lowercase.
28+
# Slashes are accepted, for example, ping/the_server
29+
# Do not include an initial slash, it is implied.
30+
# This one is /ping, for example.
31+
ping:
32+
# The placeholder to parse.
33+
# This runs the parse function on this string, so anything not in placeholders will render raw.
34+
placeholder: Pong!
35+
# The method type, described above.
36+
method: GET
37+
# Whether or not to use an auth key, default false for GET.
38+
authkey: false

src/main/resources/plugin.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ name: JSONRestAPI
22
version: ${project.version}
33
main: pw.chew.jsonrestapi.JSONRestAPI
44
api-version: 1.16
5-
depend: [ placeholderapi ]
5+
depend: [PlaceholderAPI]
66
authors: [ Chew ]
77
description: A simple web server for receiving and parsing requests.
88
website: https://chew.pw/mc
9+
10+
commands:
11+
jrareload:
12+
description: Reloads the configuration.
13+
usage: "Usage: /jrareload"
14+
permission: jsonrestapi.reload
15+
permission-message: Only people with permission can reload, sorry!
16+
17+
permissions:
18+
jsonrestapi.reload:
19+
default: op

0 commit comments

Comments
 (0)