add HTTPAPI
This commit is contained in:
1 parent
dddabe30cc
commit
ee1c92e36f
4 files changed
+113
-4
No files matched your search
+2
-1
@@ -30,7 +30,8 @@ dependencies {
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
shadow('com.maxmind.geoip2:geoip2:4.2.0')
|
||||
implementation("io.javalin:javalin:6.4.0")
|
||||
implementation "io.javalin:javalin:6.4.0"
|
||||
implementation 'com.github.houbb:pinyin:0.4.0'
|
||||
shadow('com.google.inject:guice:7.0.0') {
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
exclude group: 'com.google.guava', module: 'listenablefuture'
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package io.ib67.sfcraft.module.supervisor;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.ib67.sfcraft.ServerModule;
|
||||
import io.ib67.sfcraft.config.SFConfig;
|
||||
import io.ib67.sfcraft.module.SignatureService;
|
||||
import io.ib67.sfcraft.util.Helper;
|
||||
import io.ib67.sfcraft.util.LitematicConverter;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.UploadedFile;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.NbtSizeTracker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Log4j2
|
||||
public class WebModule extends ServerModule {
|
||||
private static final int PERMISSION_UPLOAD_SCHEMATICS = 2;
|
||||
private static final Path SCHEMATIC_DIR = Path.of("config/worldedit/schematics/");
|
||||
@Inject
|
||||
SFConfig config;
|
||||
@Inject
|
||||
SignatureService signatureService;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void onInitialize() {
|
||||
Files.createDirectories(SCHEMATIC_DIR);
|
||||
Thread.ofVirtual().name("SFCraft API Web").start(() -> {
|
||||
Javalin.create(cfg -> cfg.useVirtualThreads = true)
|
||||
.post("/api/schematics", this::uploadSchematic)
|
||||
.start(config.httpPort);
|
||||
});
|
||||
}
|
||||
|
||||
private void uploadSchematic(@NotNull Context context) {
|
||||
if (context.contentLength() > config.maxSchematicSize) {
|
||||
context.result("Content is too large!");
|
||||
return;
|
||||
}
|
||||
var signRaw = Base64.getUrlDecoder().decode(context.pathParam("sign"));
|
||||
var verifiedSign = signatureService.readSignature(Unpooled.wrappedBuffer(signRaw));
|
||||
if ((verifiedSign.permission() & PERMISSION_UPLOAD_SCHEMATICS) == 0) {
|
||||
context.result("Permission denied!");
|
||||
return;
|
||||
}
|
||||
var files = context.uploadedFileMap();
|
||||
files.forEach((k, v) -> handleUploadSchematic(context, k, v));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void handleUploadSchematic(@NotNull Context context, String fileName, List<UploadedFile> v) {
|
||||
if (v.size() != 1) {
|
||||
return;
|
||||
}
|
||||
var file = v.getFirst();
|
||||
if (file.size() > config.maxSchematicSize) {
|
||||
context.result("Content is too large!");
|
||||
return;
|
||||
}
|
||||
fileName = Helper.cleanFileName(fileName);
|
||||
if (fileName.endsWith(".schematic")) {
|
||||
Files.write(SCHEMATIC_DIR.resolve(fileName), file.content().readAllBytes());
|
||||
file.content().close();
|
||||
log.info("Saved "+fileName+" as a schematic.");
|
||||
context.result("Success!");
|
||||
} else if (fileName.endsWith(".litematic")) {
|
||||
log.error("Handling new {}", fileName);
|
||||
var baseFileName = fileName.substring(0, fileName.length() - 10);
|
||||
new LitematicConverter(
|
||||
file.content(),
|
||||
new NbtSizeTracker(config.maxSchematicSize, 16)
|
||||
).read((name, nbt) -> {
|
||||
name = Helper.cleanFileName(baseFileName + "-" + name + ".schematic");
|
||||
try {
|
||||
NbtIo.writeCompressed(nbt, SCHEMATIC_DIR.resolve(name));
|
||||
log.info("Schematic" + name+" has been saved!");
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred when serializing .schematic from .litematic.", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ib67.sfcraft.util;
|
||||
|
||||
import com.github.houbb.pinyin.api.impl.Pinyin;
|
||||
import com.github.houbb.pinyin.constant.enums.PinyinStyleEnum;
|
||||
import com.github.houbb.pinyin.util.PinyinHelper;
|
||||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import io.ib67.sfcraft.SFCraft;
|
||||
import io.ib67.sfcraft.config.SFConfig;
|
||||
@@ -29,8 +32,10 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Helper {
|
||||
private static final Pattern ILLEGAL_CHARACTERS = Pattern.compile("[./\\\\#%!@&*]");
|
||||
public static final char COLOR = '§';
|
||||
|
||||
public static boolean canBack(ServerPlayerEntity player) {
|
||||
@@ -43,6 +48,15 @@ public class Helper {
|
||||
return nearby != null;
|
||||
}
|
||||
|
||||
public static String cleanFileName(String filename) {
|
||||
var name = PinyinHelper.toPinyin(filename, PinyinStyleEnum.NORMAL,"_");
|
||||
name = ILLEGAL_CHARACTERS.matcher(name).replaceAll("");
|
||||
if(name.length() > 32){
|
||||
name = name.substring(0,32);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static boolean teleportSafely(ServerPlayerEntity player, ServerWorld world, int x, int y, int z, float yaw, float pitch) {
|
||||
var pos = new BlockPos(x, y, z);
|
||||
var stand = world.getBlockState(pos);
|
||||
|
||||
@@ -20,7 +20,6 @@ public class LitematicConverter implements AutoCloseable {
|
||||
public static final String NBT_LITEMATICA_ROOT = "";
|
||||
private final InputStream input;
|
||||
private final NbtSizeTracker sizeTracker;
|
||||
private NbtCompound root;
|
||||
|
||||
public LitematicConverter(InputStream input, NbtSizeTracker sizeTracker) {
|
||||
this.input = input;
|
||||
@@ -31,8 +30,7 @@ public class LitematicConverter implements AutoCloseable {
|
||||
public void read(
|
||||
BiConsumer<String, NbtCompound> schematicOutput
|
||||
) {
|
||||
if (root != null) throw new IllegalStateException("Litematica file is already read");
|
||||
root = NbtIo.readCompressed(input, sizeTracker).getCompound(NBT_LITEMATICA_ROOT);
|
||||
var root = NbtIo.readCompressed(input, sizeTracker).getCompound(NBT_LITEMATICA_ROOT);
|
||||
var dataVersion = root.getInt("MinecraftDataVersion");
|
||||
var regionsNbt = root.getCompound("Regions");
|
||||
var i = 0;
|
||||
|
||||
Reference in new issue
Block a user