Skip to content

Commit

Permalink
fixed server and confirming
Browse files Browse the repository at this point in the history
  • Loading branch information
Hadron67 committed May 15, 2020
1 parent f4c1beb commit 3a8c3b6
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 73 deletions.
7 changes: 5 additions & 2 deletions src/main/java/com/hadroncfy/sreplay/SReplayMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.google.gson.JsonParseException;
Expand Down Expand Up @@ -47,10 +48,12 @@ public static Server getServer(){
}

public static List<File> listRecordings() {
return Arrays.asList(config.savePath.listFiles(f -> !f.isDirectory()));
List<File> files = Arrays.asList(config.savePath.listFiles(f -> !f.isDirectory()));
Collections.sort(files);
return files;
}

public static void loadConfig() throws IOException {
public static void loadConfig() throws IOException, JsonParseException {
File file = new File("config", "sreplay.json");
if (file.exists()){
try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,60 @@

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import com.hadroncfy.sreplay.SReplayMod;
import com.hadroncfy.sreplay.config.TextRenderer;

import net.minecraft.server.command.ServerCommandSource;

public class ConfirmationManager {
private static final Random random = new Random();
private final Map<String, ConfirmationEntry> confirms = new HashMap<>();
private final long timeout;
public ConfirmationManager(long timeout){
private final int codeBound;
public ConfirmationManager(long timeout, int codeBound){
this.timeout = timeout;
this.codeBound = codeBound;
}

public void submit(String label, String code, ConfirmationHandler h){
synchronized(this){
confirms.put(label, new ConfirmationEntry(label, code, h));
public synchronized void submit(String label, ServerCommandSource src, Runnable h){
ConfirmationEntry e = confirms.get(label);
if (e != null){
e.t.cancel();
}
final int code = random.nextInt(codeBound);
src.sendFeedback(TextRenderer.render(SReplayMod.getFormats().confirmingHint, Integer.toString(code)), false);
confirms.put(label, new ConfirmationEntry(src, label, code, h));
}

public boolean confirm(String label, String code){
synchronized(this){
ConfirmationEntry h = confirms.get(label);
if (h != null){
public synchronized boolean confirm(String label, int code){
ConfirmationEntry h = confirms.get(label);
if (h != null){
if (code == h.code){
h.t.cancel();
h.handler.onConfirm(code.equals(h.code), false);
if (code.equals(h.code)){
confirms.remove(label);
}
return true;
h.handler.run();
confirms.remove(label);
}
else {
h.src.sendError(SReplayMod.getFormats().incorrectConfirmationCode);
}
return false;
return true;
}
return false;
}

public boolean cancel(String label){
synchronized(this){
ConfirmationEntry h = confirms.get(label);
if (h != null){
h.t.cancel();
h.handler.onConfirm(false, true);
confirms.remove(label);
return true;
}
return false;
public synchronized boolean cancel(String label){
ConfirmationEntry h = confirms.get(label);
if (h != null){
h.t.cancel();
confirms.remove(label);
h.src.sendFeedback(SReplayMod.getFormats().operationCancelled, true);
return true;
}
return false;
}

@FunctionalInterface
Expand All @@ -53,10 +65,12 @@ public interface ConfirmationHandler {

private class ConfirmationEntry extends TimerTask {
final String label;
final ConfirmationHandler handler;
final ServerCommandSource src;
final Runnable handler;
final Timer t;
final String code;
public ConfirmationEntry(String label, String code, ConfirmationHandler h){
final int code;
public ConfirmationEntry(ServerCommandSource src, String label, int code, Runnable h){
this.src = src;
this.label = label;
this.handler = h;
t = new Timer();
Expand All @@ -68,7 +82,7 @@ public ConfirmationEntry(String label, String code, ConfirmationHandler h){
public void run() {
synchronized(ConfirmationManager.this){
confirms.remove(label);
handler.onConfirm(false, true);
src.sendFeedback(SReplayMod.getFormats().operationCancelled, true);
}
}
}
Expand Down
27 changes: 9 additions & 18 deletions src/main/java/com/hadroncfy/sreplay/command/SReplayCommand.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hadroncfy.sreplay.command;

import com.google.gson.JsonParseException;
import com.hadroncfy.sreplay.SReplayMod;
import com.hadroncfy.sreplay.config.TextRenderer;
import com.hadroncfy.sreplay.recording.Photographer;
Expand Down Expand Up @@ -42,7 +43,7 @@ public class SReplayCommand {
private static final Logger LOGGER = LogManager.getLogger();
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");

private final ConfirmationManager cm = new ConfirmationManager(20000);
private final ConfirmationManager cm = new ConfirmationManager(20000, 999);
private final Random rand = new Random();

public SReplayCommand(){
Expand All @@ -69,7 +70,7 @@ public void register(CommandDispatcher<ServerCommandSource> d) {
.suggests(this::suggestRecordingFile)
.executes(this::deleteRecording)))
.then(literal("confirm")
.then(argument("code", StringArgumentType.word()).executes(this::confirm)))
.then(argument("code", IntegerArgumentType.integer(0)).executes(this::confirm)))
.then(literal("cancel").executes(this::cancel))
.then(literal("reload").executes(this::reload))
.then(literal("server")
Expand Down Expand Up @@ -308,15 +309,15 @@ public int reload(CommandContext<ServerCommandSource> ctx){
SReplayMod.loadConfig();
ctx.getSource().sendFeedback(render(SReplayMod.getFormats().reloadedConfig), false);
return 1;
} catch (IOException e) {
} catch (IOException | JsonParseException e) {
e.printStackTrace();
ctx.getSource().sendFeedback(render(SReplayMod.getFormats().failedToReloadConfig, e.toString()), false);
return 0;
}
}

public int confirm(CommandContext<ServerCommandSource> ctx) {
final String code = StringArgumentType.getString(ctx, "code");
final int code = IntegerArgumentType.getInteger(ctx, "code");
if (!cm.confirm(ctx.getSource().getName(), code)) {
ctx.getSource().sendFeedback(SReplayMod.getFormats().nothingToConfirm, false);
}
Expand Down Expand Up @@ -347,21 +348,11 @@ public int deleteRecording(CommandContext<ServerCommandSource> ctx) {
final File rec = new File(SReplayMod.getConfig().savePath, StringArgumentType.getString(ctx, "recording"));
final MinecraftServer server = src.getMinecraftServer();
if (rec.exists()) {
String code = Integer.toString(rand.nextInt(100));
src.sendFeedback(render(SReplayMod.getFormats().aboutToDeleteRecording, rec.getName()), true);
src.sendFeedback(render(SReplayMod.getFormats().confirmingHint, code), false);
cm.submit(src.getName(), code, (match, cancelled) -> {
if (!cancelled) {
if (match) {
rec.delete();
server.getPlayerManager()
.sendToAll(render(SReplayMod.getFormats().deletedRecordingFile, src.getName(), rec.getName()));
} else {
src.sendFeedback(SReplayMod.getFormats().incorrectConfirmationCode, false);
}
} else {
src.sendFeedback(SReplayMod.getFormats().operationCancelled, false);
}
cm.submit(src.getName(), src, () -> {
rec.delete();
server.getPlayerManager()
.sendToAll(render(SReplayMod.getFormats().deletedRecordingFile, src.getName(), rec.getName()));
});
} else {
src.sendFeedback(render(SReplayMod.getFormats().fileNotFound, rec.getName()), true);
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/com/hadroncfy/sreplay/config/Formats.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@ private static Text red(String s){
recordingFileItem = new LiteralText("- $1($2M) ").setStyle(new Style().setColor(Formatting.GREEN))
.append(new LiteralText("[下载]").setStyle(new Style().setColor(Formatting.BLUE).setClickEvent(
new ClickEvent(Action.RUN_COMMAND, "/sreplay get $1")
)))
).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new LiteralText("点击以生成下载链接").setStyle(new Style().setItalic(true).setColor(Formatting.GRAY))
))))
.append(new LiteralText("[删除]").setStyle(new Style().setColor(Formatting.RED).setClickEvent(
new ClickEvent(Action.RUN_COMMAND, "/sreplay delete $1")
))),
).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new LiteralText("点击以删除").setStyle(new Style().setItalic(true).setColor(Formatting.GRAY))
)))),
savingRecordingFile = new LiteralText("[SReplay] 正在保存")
.append(new LiteralText("$1").setStyle(new Style().setColor(Formatting.GREEN)))
.append(new LiteralText("的录像文件")),
Expand Down
29 changes: 28 additions & 1 deletion src/main/java/com/hadroncfy/sreplay/server/FileEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,46 @@

import java.io.File;
import java.util.Date;
import java.util.Random;

public class FileEntry {
private static final Random random = new Random();
private final File file;
private final Date expiresOn;
private final String path;
private Date expiresOn;

private static String randomString(int len){
final StringBuilder sb = new StringBuilder();
while (len --> 0){
int i = random.nextInt(16);
if (i >= 10){
sb.append((char)(i - 10 + 'a'));
}
else {
sb.append((char)('0' + i));
}
}
return sb.toString();
}

public FileEntry(File file, long last){
this.file = file;
path = "/" + randomString(32) + "/" + file.getName();
expiresOn = new Date(new Date().getTime() + last);
}

public boolean isExpired(){
return new Date().after(expiresOn);
}

public String getPath(){
return path;
}

public void touch(long last){
expiresOn = new Date(new Date().getTime() + last);
}

public File getFile(){
return file;
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/hadroncfy/sreplay/server/HttpHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ public HttpHandler(Server server){
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
final String path = msg.uri();
LOGGER.info("Got request");
LOGGER.info("Got request " + path + " from " + ctx.channel().remoteAddress().toString());
server.removeExpiredFiles();
final FileEntry fileEntry = server.urls.get(path);
final FileEntry fileEntry = server.getFile(path);
if (fileEntry == null || !fileEntry.getFile().exists()){
// No no no, no 404
ctx.close();
return;
}
final File file = fileEntry.getFile();
server.urls.remove(path);
server.removeFile(fileEntry);
final HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(200));
response.headers().set("Content-Type", "application/zip");
HttpUtil.setContentLength(response, file.length());
Expand Down
41 changes: 22 additions & 19 deletions src/main/java/com/hadroncfy/sreplay/server/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.File;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;

Expand Down Expand Up @@ -30,7 +31,6 @@

public class Server {
private static final Logger LOGGER = LogManager.getLogger();
private static final Random random = new Random();
// Stolen from ServerNetworkIo
public static final Lazy<NioEventLoopGroup> DEFAULT_CHANNEL = new Lazy<>(() -> {
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
Expand All @@ -39,7 +39,8 @@ public class Server {
return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build());
});

final Map<String, FileEntry> urls = new HashMap<>();
private final Map<String, FileEntry> urls = new HashMap<>();
private final Map<File, FileEntry> filesByFile = new HashMap<>();
private ChannelFuture channel;

public synchronized ChannelFuture bind(InetAddress address, int port){
Expand Down Expand Up @@ -88,32 +89,34 @@ public synchronized ChannelFuture stop(){
}

void removeExpiredFiles(){
for (String path: urls.keySet()){
for (String path: new HashSet<>(urls.keySet())){
final FileEntry f = urls.get(path);
if (f.isExpired()){
urls.remove(path);
removeFile(f);
}
}
}

private static String randomString(int len){
final StringBuilder sb = new StringBuilder();
while (len --> 0){
int i = random.nextInt(16);
if (i >= 10){
sb.append((char)(i - 10 + 'a'));
}
else {
sb.append((char)('0' + i));
}
}
return sb.toString();
FileEntry getFile(String path){
return urls.get(path);
}

void removeFile(FileEntry f){
urls.remove(f.getPath());
filesByFile.remove(f.getFile());
}

public String addFile(File file, long last){
final String path = '/' + randomString(32) + '/' + file.getName();
removeExpiredFiles();
urls.put(path, new FileEntry(file, last));
return path;
FileEntry fe = filesByFile.get(file);
if (fe == null){
fe = new FileEntry(file, last);
urls.put(fe.getPath(), fe);
filesByFile.put(file, fe);
}
else {
fe.touch(last);
}
return fe.getPath();
}
}

0 comments on commit 3a8c3b6

Please sign in to comment.