Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Etzelia | f2a6249af1 |
2
pom.xml
2
pom.xml
|
@ -3,7 +3,7 @@
|
||||||
<groupId>xyz.etztech</groupId>
|
<groupId>xyz.etztech</groupId>
|
||||||
<artifactId>ServerAPI</artifactId>
|
<artifactId>ServerAPI</artifactId>
|
||||||
<!-- Version is used in plugin.yml -->
|
<!-- Version is used in plugin.yml -->
|
||||||
<version>0.0.1</version>
|
<version>0.0.3</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<!-- Plugin Information -->
|
<!-- Plugin Information -->
|
||||||
|
|
|
@ -3,20 +3,20 @@ package xyz.etztech.serverapi;
|
||||||
|
|
||||||
import org.bukkit.BanEntry;
|
import org.bukkit.BanEntry;
|
||||||
import org.bukkit.BanList;
|
import org.bukkit.BanList;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import xyz.etztech.serverapi.commands.MainCommand;
|
import xyz.etztech.serverapi.commands.MainCommand;
|
||||||
|
import xyz.etztech.serverapi.listeners.AsyncPlayerChatListener;
|
||||||
|
import xyz.etztech.serverapi.token.TokenList;
|
||||||
import xyz.etztech.serverapi.tps.TPS;
|
import xyz.etztech.serverapi.tps.TPS;
|
||||||
import xyz.etztech.serverapi.web.IProvider;
|
import xyz.etztech.serverapi.web.IProvider;
|
||||||
import xyz.etztech.serverapi.web.Web;
|
import xyz.etztech.serverapi.web.Web;
|
||||||
import xyz.etztech.serverapi.web.api.*;
|
import xyz.etztech.serverapi.web.api.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class ServerAPI extends JavaPlugin implements IProvider {
|
public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
|
@ -26,6 +26,8 @@ public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
private Web web = new Web(this);
|
private Web web = new Web(this);
|
||||||
private final Logger log = Logger.getLogger( "Minecraft" );
|
private final Logger log = Logger.getLogger( "Minecraft" );
|
||||||
|
|
||||||
|
private static final List<ChatAPI> chat = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
|
@ -34,6 +36,7 @@ public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
|
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
|
new AsyncPlayerChatListener(this);
|
||||||
new MainCommand(this);
|
new MainCommand(this);
|
||||||
|
|
||||||
tps = new TPS();
|
tps = new TPS();
|
||||||
|
@ -52,7 +55,8 @@ public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
web.stop();
|
web.stop();
|
||||||
web.start(
|
web.start(
|
||||||
getConfig().getInt("port", 8080),
|
getConfig().getInt("port", 8080),
|
||||||
getConfig().getString("password", "")
|
new TokenList(getConfig().getConfigurationSection("auth")),
|
||||||
|
getConfig().getStringList("custom")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +72,10 @@ public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
return tps;
|
return tps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ChatAPI> getChat() {
|
||||||
|
return chat;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TPSAPI TPS() {
|
public TPSAPI TPS() {
|
||||||
return new TPSAPI(tps.getHistory());
|
return new TPSAPI(tps.getHistory());
|
||||||
|
@ -111,8 +119,64 @@ public class ServerAPI extends JavaPlugin implements IProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryAPI query() {
|
public List<ChatAPI> chat() {
|
||||||
return QueryAPI.fromMinecraft(getServer());
|
return chat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void kick(BanAPI kick) {
|
||||||
|
Player player = Bukkit.getPlayerExact(kick.getTarget());
|
||||||
|
if (player != null) {
|
||||||
|
getServer().getScheduler().runTask(this, () -> {
|
||||||
|
player.kickPlayer("You have been kicked: " + kick.getReason());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ban(BanAPI ban) {
|
||||||
|
Date expires = null;
|
||||||
|
if (ban.getExpiration() != 0) {
|
||||||
|
expires = new Date(ban.getExpiration());
|
||||||
|
}
|
||||||
|
Bukkit.getBanList(BanList.Type.NAME).addBan(ban.getTarget(), ban.getReason(), expires, "ServerAPI");
|
||||||
|
Player player = Bukkit.getPlayerExact(ban.getTarget());
|
||||||
|
if (player != null) {
|
||||||
|
getServer().getScheduler().runTask(this, () -> {
|
||||||
|
player.kickPlayer("You have been banned: " + ban.getReason());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unban(BanAPI ban) {
|
||||||
|
Bukkit.getBanList(BanList.Type.NAME).pardon(ban.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcast(BroadcastAPI broadcast) {
|
||||||
|
Bukkit.broadcastMessage(String.format("%s > %s", broadcast.getFrom(), broadcast.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void custom(CustomAPI custom) {
|
||||||
|
getServer().getScheduler().runTask(this, () -> {
|
||||||
|
getServer().dispatchCommand(getServer().getConsoleSender(), custom.build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PingAPI ping() {
|
||||||
|
return PingAPI.fromMinecraft(getServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PluginAPI> plugins() {
|
||||||
|
List<PluginAPI> plugins = new ArrayList<>();
|
||||||
|
for (Plugin plugin : getServer().getPluginManager().getPlugins()) {
|
||||||
|
plugins.add(PluginAPI.fromMinecraft(plugin));
|
||||||
|
}
|
||||||
|
return plugins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package xyz.etztech.serverapi.listeners;
|
||||||
|
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
|
import xyz.etztech.serverapi.ServerAPI;
|
||||||
|
import xyz.etztech.serverapi.web.api.ChatAPI;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class AsyncPlayerChatListener implements Listener {
|
||||||
|
private final ServerAPI plugin;
|
||||||
|
|
||||||
|
public AsyncPlayerChatListener(ServerAPI plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority= EventPriority.MONITOR, ignoreCancelled=true)
|
||||||
|
public void onChat(AsyncPlayerChatEvent event) {
|
||||||
|
int chatLimit = plugin.getConfig().getInt("chat", 100);
|
||||||
|
if (ServerAPI.getChat().size() >= chatLimit) {
|
||||||
|
ServerAPI.getChat().remove(0);
|
||||||
|
}
|
||||||
|
ServerAPI.getChat().add(new ChatAPI(
|
||||||
|
String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()),
|
||||||
|
new Date().getTime()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package xyz.etztech.serverapi.token;
|
||||||
|
|
||||||
|
public class Token {
|
||||||
|
private final String token;
|
||||||
|
private final TokenScope scope;
|
||||||
|
|
||||||
|
public Token(String token, TokenScope scope) {
|
||||||
|
this.token = token;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenScope getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canGET() {
|
||||||
|
return scope == TokenScope.GET || scope == TokenScope.ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canPOST() {
|
||||||
|
return scope == TokenScope.POST || scope == TokenScope.ALL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package xyz.etztech.serverapi.token;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TokenList {
|
||||||
|
private final boolean protectGET;
|
||||||
|
private final boolean protectPOST;
|
||||||
|
private final List<Token> tokens;
|
||||||
|
|
||||||
|
public TokenList(boolean protectGET, boolean protectPOST, List<Token> tokens) {
|
||||||
|
this.protectGET = protectGET;
|
||||||
|
this.protectPOST = protectPOST;
|
||||||
|
this.tokens = tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenList(ConfigurationSection auth) {
|
||||||
|
if (auth == null) {
|
||||||
|
this.protectGET = false;
|
||||||
|
this.protectPOST = false;
|
||||||
|
this.tokens = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.protectGET = auth.getBoolean("get", true);
|
||||||
|
this.protectPOST = auth.getBoolean("post", true);
|
||||||
|
this.tokens = new ArrayList<>();
|
||||||
|
ConfigurationSection tokenSection = auth.getConfigurationSection("tokens");
|
||||||
|
if (tokenSection == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String token : tokenSection.getKeys(false)) {
|
||||||
|
this.tokens.add(new Token(token, TokenScope.parseScope(tokenSection.getString(token, "none"))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtectGET() {
|
||||||
|
return protectGET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtectPOST() {
|
||||||
|
return protectPOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Token> getTokens() {
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package xyz.etztech.serverapi.token;
|
||||||
|
|
||||||
|
public enum TokenScope {
|
||||||
|
NONE,
|
||||||
|
GET,
|
||||||
|
POST,
|
||||||
|
ALL;
|
||||||
|
|
||||||
|
public static TokenScope parseScope(String scope) {
|
||||||
|
if (scope == null) {
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
switch (scope.toLowerCase()) {
|
||||||
|
case "get":
|
||||||
|
return GET;
|
||||||
|
case "post":
|
||||||
|
return POST;
|
||||||
|
case "all":
|
||||||
|
return ALL;
|
||||||
|
default:
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,9 +21,14 @@ public class GraphQL implements QueryGraphql {
|
||||||
return provider.players().toArray(new PlayerAPI[0]);
|
return provider.players().toArray(new PlayerAPI[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GraphQLName("query")
|
@GraphQLName("ping")
|
||||||
public QueryAPI getQuery() {
|
public PingAPI getPing() {
|
||||||
return provider.query();
|
return provider.ping();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("plugins")
|
||||||
|
public PluginAPI[] getPlugins() {
|
||||||
|
return provider.plugins().toArray(new PluginAPI[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GraphQLName("world")
|
@GraphQLName("world")
|
||||||
|
@ -40,4 +45,9 @@ public class GraphQL implements QueryGraphql {
|
||||||
public TPSAPI getTps() {
|
public TPSAPI getTps() {
|
||||||
return provider.TPS();
|
return provider.TPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GraphQLName("chat")
|
||||||
|
public ChatAPI[] getChat() {
|
||||||
|
return provider.chat().toArray(new ChatAPI[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,24 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface IProvider {
|
public interface IProvider {
|
||||||
|
|
||||||
|
// GET
|
||||||
Set<BanAPI> bans();
|
Set<BanAPI> bans();
|
||||||
Set<PlayerAPI> players();
|
Set<PlayerAPI> players();
|
||||||
QueryAPI query();
|
PingAPI ping();
|
||||||
TPSAPI TPS();
|
TPSAPI TPS();
|
||||||
List<WorldAPI> worlds();
|
List<WorldAPI> worlds();
|
||||||
WorldAPI world(String name);
|
WorldAPI world(String name);
|
||||||
|
List<PluginAPI> plugins();
|
||||||
|
List<ChatAPI> chat();
|
||||||
|
|
||||||
|
// POST
|
||||||
|
void kick(BanAPI kick);
|
||||||
|
void ban(BanAPI ban);
|
||||||
|
void unban(BanAPI ban);
|
||||||
|
void broadcast(BroadcastAPI broadcast);
|
||||||
|
void custom(CustomAPI custom);
|
||||||
|
|
||||||
|
// MISC
|
||||||
void log(String message);
|
void log(String message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Adding a new endpoint
|
||||||
|
|
||||||
|
1. Create a new `<endpoint>API` class in [api](api).
|
||||||
|
* Make sure to correctly add the appropriate JSON and GraphQL annotations.
|
||||||
|
Look at other classes for examples.
|
||||||
|
* **NOTE:** If anything returned could be null, make sure to instead provide an appropriate zero-value property,
|
||||||
|
otherwise GraphQL will choke.
|
||||||
|
See [PluginAPI::new](api/PluginAPI.java) for an example.
|
||||||
|
2. Add a method to return the needed data to [IProvider](IProvider.java).
|
||||||
|
3. Add a new REST endpoint to the [Web::start](Web.java) method.
|
||||||
|
4. Add a new GraphQL method to [GraphQL](GraphQL.java)
|
||||||
|
* Make sure to correctly add the appropriate GraphQL annotation.
|
||||||
|
5. Modify both [ServerAPI](../ServerAPI.java)
|
||||||
|
and [MockProvider](../../../../../../test/java/xyz/etztech/serverapi/MockProvider.java)
|
||||||
|
to fulfill the [IProvider](IProvider.java) interface.
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
[ServerRunner](../../../../../../test/java/xyz/etztech/serverapi/ServerRunner.java) should start up the API using
|
||||||
|
[MockProvider](../../../../../../test/java/xyz/etztech/serverapi/MockProvider.java).
|
||||||
|
|
||||||
|
If possible, a real test on a running Minecraft server would ideal!
|
|
@ -4,6 +4,7 @@ import io.javalin.Javalin;
|
||||||
import io.javalin.core.event.EventListener;
|
import io.javalin.core.event.EventListener;
|
||||||
import io.javalin.core.plugin.Plugin;
|
import io.javalin.core.plugin.Plugin;
|
||||||
import io.javalin.core.util.RouteOverviewPlugin;
|
import io.javalin.core.util.RouteOverviewPlugin;
|
||||||
|
import io.javalin.http.BadRequestResponse;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import io.javalin.http.UnauthorizedResponse;
|
import io.javalin.http.UnauthorizedResponse;
|
||||||
import io.javalin.plugin.graphql.GraphQLOptions;
|
import io.javalin.plugin.graphql.GraphQLOptions;
|
||||||
|
@ -12,18 +13,25 @@ import io.javalin.plugin.json.JavalinJson;
|
||||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||||
import org.slf4j.helpers.NOPLogger;
|
import org.slf4j.helpers.NOPLogger;
|
||||||
import xyz.etztech.serverapi.ServerAPI;
|
import xyz.etztech.serverapi.ServerAPI;
|
||||||
|
import xyz.etztech.serverapi.token.TokenList;
|
||||||
|
import xyz.etztech.serverapi.web.api.BanAPI;
|
||||||
|
import xyz.etztech.serverapi.web.api.BroadcastAPI;
|
||||||
|
import xyz.etztech.serverapi.web.api.CustomAPI;
|
||||||
import xyz.etztech.serverapi.web.api.ErrorAPI;
|
import xyz.etztech.serverapi.web.api.ErrorAPI;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Web {
|
public class Web {
|
||||||
private final IProvider provider;
|
private final IProvider provider;
|
||||||
private String password;
|
private TokenList tokens;
|
||||||
|
private List<String> custom;
|
||||||
private Javalin app;
|
private Javalin app;
|
||||||
|
|
||||||
public Web(IProvider provider) {
|
public Web(IProvider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(int port, String password) {
|
public void start(int port, TokenList tokens, List<String> custom) {
|
||||||
Javalin.log = NOPLogger.NOP_LOGGER;
|
Javalin.log = NOPLogger.NOP_LOGGER;
|
||||||
app = Javalin.create(config -> {
|
app = Javalin.create(config -> {
|
||||||
config.registerPlugin(graphql());
|
config.registerPlugin(graphql());
|
||||||
|
@ -31,17 +39,33 @@ public class Web {
|
||||||
config.enableCorsForAllOrigins();
|
config.enableCorsForAllOrigins();
|
||||||
}).events(this::events).exception(Exception.class, this::exception);
|
}).events(this::events).exception(Exception.class, this::exception);
|
||||||
|
|
||||||
this.password = password;
|
this.custom = custom;
|
||||||
if (!"".equals(password)) {
|
|
||||||
|
this.tokens = tokens;
|
||||||
|
if (tokens != null) {
|
||||||
|
provider.log(String.format("Loaded %d tokens", tokens.getTokens().size()));
|
||||||
|
if (!tokens.isProtectPOST()) {
|
||||||
|
provider.log("WARNING: You have disabled POST protection, which can enable users to arbitrarily run actions against your server.");
|
||||||
|
}
|
||||||
app.before(this::access);
|
app.before(this::access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// REST Endpoints
|
||||||
|
// For GraphQL endpoints, see GraphQL.java
|
||||||
app.get("/bans", this::bans);
|
app.get("/bans", this::bans);
|
||||||
app.get("/players", this::players);
|
app.get("/players", this::players);
|
||||||
app.get("/query", this::query);
|
app.get("/plugins", this::plugins);
|
||||||
|
app.get("/ping", this::ping);
|
||||||
app.get("/tps", this::tps);
|
app.get("/tps", this::tps);
|
||||||
app.get("/worlds", this::worlds);
|
app.get("/worlds", this::worlds);
|
||||||
app.get("/worlds/:name", this::world);
|
app.get("/worlds/:name", this::world);
|
||||||
|
app.get("/chat", this::chat);
|
||||||
|
|
||||||
|
app.post("/kick", this::kick);
|
||||||
|
app.post("/ban", this::ban);
|
||||||
|
app.post("/unban", this::unban);
|
||||||
|
app.post("/broadcast", this::broadcast);
|
||||||
|
app.post("/custom", this::custom);
|
||||||
|
|
||||||
// What in the actual fuck... https://github.com/tipsy/javalin/issues/358
|
// What in the actual fuck... https://github.com/tipsy/javalin/issues/358
|
||||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
@ -74,13 +98,22 @@ public class Web {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void access(Context ctx) {
|
public void access(Context ctx) {
|
||||||
String pw = ctx.header("X-ServerAPI-Password");
|
String token = ctx.header("X-ServerAPI-Token");
|
||||||
if (pw == null) {
|
if (token == null) {
|
||||||
pw = ctx.queryParam("password");
|
token = ctx.queryParam("token");
|
||||||
}
|
}
|
||||||
|
boolean isGET = "GET".equalsIgnoreCase(ctx.method());
|
||||||
|
boolean isPOST = "POST".equalsIgnoreCase(ctx.method());
|
||||||
|
|
||||||
if (!password.equals(pw)) {
|
if (isGET && !tokens.isProtectGET()) return;
|
||||||
throw new UnauthorizedResponse(JavalinJson.toJson(new ErrorAPI(401, "Unauthorized")));
|
if (isPOST && !tokens.isProtectPOST()) return;
|
||||||
|
|
||||||
|
String finalToken = token;
|
||||||
|
boolean pass = tokens.getTokens().stream().anyMatch(t -> t.getToken().equals(finalToken) &&
|
||||||
|
((isGET && t.canGET()) || (isPOST && t.canPOST())));
|
||||||
|
|
||||||
|
if (!pass) {
|
||||||
|
throw new UnauthorizedResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,15 +136,52 @@ public class Web {
|
||||||
ctx.json(provider.world(ctx.pathParam("name")));
|
ctx.json(provider.world(ctx.pathParam("name")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void chat(Context ctx) {
|
||||||
|
ctx.json(provider.chat());
|
||||||
|
}
|
||||||
|
|
||||||
public void players(Context ctx) {
|
public void players(Context ctx) {
|
||||||
ctx.json(provider.players());
|
ctx.json(provider.players());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void plugins(Context ctx) {
|
||||||
|
ctx.json(provider.plugins());
|
||||||
|
}
|
||||||
|
|
||||||
public void bans(Context ctx) {
|
public void bans(Context ctx) {
|
||||||
ctx.json(provider.bans());
|
ctx.json(provider.bans());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void query(Context ctx) {
|
public void ping(Context ctx) {
|
||||||
ctx.json(provider.query());
|
ctx.json(provider.ping());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kick(Context ctx) {
|
||||||
|
provider.kick(JavalinJson.fromJson(ctx.body(), BanAPI.class));
|
||||||
|
ctx.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ban(Context ctx) {
|
||||||
|
provider.ban(JavalinJson.fromJson(ctx.body(), BanAPI.class));
|
||||||
|
ctx.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unban(Context ctx) {
|
||||||
|
provider.unban(JavalinJson.fromJson(ctx.body(), BanAPI.class));
|
||||||
|
ctx.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcast(Context ctx) {
|
||||||
|
provider.broadcast(JavalinJson.fromJson(ctx.body(), BroadcastAPI.class));
|
||||||
|
ctx.status(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void custom(Context ctx) {
|
||||||
|
CustomAPI capi = JavalinJson.fromJson(ctx.body(), CustomAPI.class);
|
||||||
|
if (custom.stream().noneMatch(c -> c.equalsIgnoreCase(capi.getCommand()))) {
|
||||||
|
throw new BadRequestResponse();
|
||||||
|
}
|
||||||
|
provider.custom(capi);
|
||||||
|
ctx.status(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package xyz.etztech.serverapi.web.api;
|
package xyz.etztech.serverapi.web.api;
|
||||||
|
|
||||||
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
||||||
import com.expediagroup.graphql.annotations.GraphQLDirective;
|
|
||||||
import com.expediagroup.graphql.annotations.GraphQLName;
|
import com.expediagroup.graphql.annotations.GraphQLName;
|
||||||
import org.bukkit.BanEntry;
|
import org.bukkit.BanEntry;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@GraphQLName("Ban")
|
@GraphQLName("Ban")
|
||||||
@GraphQLDescription("Ban GraphQL")
|
@GraphQLDescription("Ban GraphQL")
|
||||||
public class BanAPI {
|
public class BanAPI {
|
||||||
|
@ -16,6 +13,14 @@ public class BanAPI {
|
||||||
private final long created;
|
private final long created;
|
||||||
private final long expiration;
|
private final long expiration;
|
||||||
|
|
||||||
|
public BanAPI() {
|
||||||
|
this.target = "";
|
||||||
|
this.source = "";
|
||||||
|
this.reason = "";
|
||||||
|
this.created = 0;
|
||||||
|
this.expiration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public BanAPI(String target, String source, String reason, long created, long expiration) {
|
public BanAPI(String target, String source, String reason, long created, long expiration) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package xyz.etztech.serverapi.web.api;
|
||||||
|
|
||||||
|
public class BroadcastAPI {
|
||||||
|
private final String from;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public BroadcastAPI() {
|
||||||
|
this.from = "";
|
||||||
|
this.message = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public BroadcastAPI(String from, String message) {
|
||||||
|
this.from = from;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package xyz.etztech.serverapi.web.api;
|
||||||
|
|
||||||
|
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
||||||
|
import com.expediagroup.graphql.annotations.GraphQLName;
|
||||||
|
|
||||||
|
@GraphQLName("Chat")
|
||||||
|
@GraphQLDescription("Chat GraphQL")
|
||||||
|
public class ChatAPI {
|
||||||
|
private final String message;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
public ChatAPI(String message, long timestamp) {
|
||||||
|
this.message = message;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("message")
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("timestamp")
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package xyz.etztech.serverapi.web.api;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class CustomAPI {
|
||||||
|
private final String command;
|
||||||
|
private final List<String> args;
|
||||||
|
|
||||||
|
public CustomAPI() {
|
||||||
|
this.command = "";
|
||||||
|
this.args = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomAPI(String command, List<String> args) {
|
||||||
|
this.command = command;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getArgs() {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String build() {
|
||||||
|
return command + " " + String.join(" ", args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@ import com.expediagroup.graphql.annotations.GraphQLName;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
|
||||||
@GraphQLName("MCQuery")
|
@GraphQLName("Ping")
|
||||||
@GraphQLDescription("MCQuery GraphQL")
|
@GraphQLDescription("Ping GraphQL")
|
||||||
public class QueryAPI {
|
public class PingAPI {
|
||||||
private final String type;
|
private final String type;
|
||||||
private final String version;
|
private final String version;
|
||||||
private final String motd;
|
private final String motd;
|
||||||
|
@ -16,7 +16,7 @@ public class QueryAPI {
|
||||||
@JsonProperty("max_players")
|
@JsonProperty("max_players")
|
||||||
private final int maxPlayers;
|
private final int maxPlayers;
|
||||||
|
|
||||||
public QueryAPI(String type, String version, String motd, int currentPlayers, int maxPlayers) {
|
public PingAPI(String type, String version, String motd, int currentPlayers, int maxPlayers) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.motd = motd;
|
this.motd = motd;
|
||||||
|
@ -49,8 +49,8 @@ public class QueryAPI {
|
||||||
return maxPlayers;
|
return maxPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static QueryAPI fromMinecraft(Server server) {
|
public static PingAPI fromMinecraft(Server server) {
|
||||||
return new QueryAPI(
|
return new PingAPI(
|
||||||
server.getName(),
|
server.getName(),
|
||||||
server.getBukkitVersion().split("-")[0], // 1.x.x-R0.1-SNAPSHOT
|
server.getBukkitVersion().split("-")[0], // 1.x.x-R0.1-SNAPSHOT
|
||||||
server.getMotd(),
|
server.getMotd(),
|
|
@ -0,0 +1,54 @@
|
||||||
|
package xyz.etztech.serverapi.web.api;
|
||||||
|
|
||||||
|
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
||||||
|
import com.expediagroup.graphql.annotations.GraphQLName;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@GraphQLName("Plugin")
|
||||||
|
@GraphQLDescription("Plugin GraphQL")
|
||||||
|
public class PluginAPI {
|
||||||
|
private final String name;
|
||||||
|
private final String version;
|
||||||
|
private final List<String> authors;
|
||||||
|
private final String website;
|
||||||
|
|
||||||
|
|
||||||
|
public PluginAPI(String name, String version, List<String> authors, String website) {
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
this.authors = authors != null ? authors : new ArrayList<>();
|
||||||
|
this.website = website != null ? website : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("name")
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("version")
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("authors")
|
||||||
|
public List<String> getAuthors() {
|
||||||
|
return authors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GraphQLName("website")
|
||||||
|
public String getWebsite() {
|
||||||
|
return website;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PluginAPI fromMinecraft(Plugin plugin) {
|
||||||
|
return new PluginAPI(
|
||||||
|
plugin.getName(),
|
||||||
|
plugin.getDescription().getVersion(),
|
||||||
|
plugin.getDescription().getAuthors(),
|
||||||
|
plugin.getDescription().getWebsite()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package xyz.etztech.serverapi.web.api;
|
||||||
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
import com.expediagroup.graphql.annotations.GraphQLDescription;
|
||||||
import com.expediagroup.graphql.annotations.GraphQLName;
|
import com.expediagroup.graphql.annotations.GraphQLName;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
@GraphQLName("World")
|
@GraphQLName("World")
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
# The port to run on
|
# The port to run on
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
# (Optional) password
|
# Number of chat logs to retain
|
||||||
password: ''
|
chat: 100
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
auth:
|
||||||
|
# Protect GET routes. If false, GET routes are public.
|
||||||
|
get: true
|
||||||
|
# Protect POST routes. If false, POST routes are public.
|
||||||
|
post: true
|
||||||
|
tokens:
|
||||||
|
token: access
|
||||||
|
|
||||||
|
# Custom commands (POST)
|
||||||
|
custom:
|
||||||
|
- say
|
|
@ -46,6 +46,21 @@ public class MockProvider implements IProvider {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void kick(BanAPI kick) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ban(BanAPI ban) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unban(BanAPI ban) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcast(BroadcastAPI broadcast) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void custom(CustomAPI custom) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<PlayerAPI> players() {
|
public Set<PlayerAPI> players() {
|
||||||
return new HashSet<>(Arrays.asList(
|
return new HashSet<>(Arrays.asList(
|
||||||
|
@ -56,8 +71,27 @@ public class MockProvider implements IProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryAPI query() {
|
public PingAPI ping() {
|
||||||
return new QueryAPI("Mock", "0.0.1", "Hello, world!", 0, 100);
|
return new PingAPI("Mock", "0.0.1", "Hello, world!", 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PluginAPI> plugins() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new PluginAPI("ServerAPI", "0.0.1", Collections.singletonList("Etzelia"), "https://git.etztech.xyz"),
|
||||||
|
new PluginAPI("dynmap", "0.1.0", null, "https://www.spigotmc.org/resources/dynmap.274/"),
|
||||||
|
new PluginAPI("CoreProtect", "1.0.0", Collections.singletonList("Intelli"), null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ChatAPI> chat() {
|
||||||
|
long now = new Date().getTime();
|
||||||
|
return Arrays.asList(
|
||||||
|
new ChatAPI("message 1", now-2),
|
||||||
|
new ChatAPI("message 2", now-1),
|
||||||
|
new ChatAPI("message 3", now)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,12 +1,29 @@
|
||||||
package xyz.etztech.serverapi;
|
package xyz.etztech.serverapi;
|
||||||
|
|
||||||
|
import xyz.etztech.serverapi.token.Token;
|
||||||
|
import xyz.etztech.serverapi.token.TokenList;
|
||||||
|
import xyz.etztech.serverapi.token.TokenScope;
|
||||||
import xyz.etztech.serverapi.web.Web;
|
import xyz.etztech.serverapi.web.Web;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ServerRunner {
|
public class ServerRunner {
|
||||||
|
|
||||||
|
static TokenList tokens = new TokenList(true, true, Arrays.asList(
|
||||||
|
new Token("testGET", TokenScope.GET),
|
||||||
|
new Token("testPOST", TokenScope.POST),
|
||||||
|
new Token("testAll", TokenScope.ALL),
|
||||||
|
new Token("testNone", TokenScope.NONE)
|
||||||
|
));
|
||||||
|
|
||||||
|
static List<String> custom = Arrays.asList(
|
||||||
|
"test",
|
||||||
|
"say"
|
||||||
|
);
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Web web = new Web(new MockProvider());
|
Web web = new Web(new MockProvider());
|
||||||
|
web.start(8080, tokens, custom);
|
||||||
web.start(8080, "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue