TotalFreedomMod Electrum

Version 5.0

This TotalFreedomMod release implements many changes. Most notably, the
internals have been completely revamped. TotalFreedomMod now relies on the
Aero library for core mechanics such as command handling and services.

Another important change is the UUID system. In TotalFreedomMod Electrum,
it has been completely removed. The core reason for this is that the
system as a whole was very bugged. Additionally, it did not solve the
primary reason for its conception: preserving player data when the player
changes their username. This is because TotalFreedomMod servers usually
run in offline-mode. This meaning that some of the players joining do not
have a registerd Mojang UUID whatsoever. All in all, the UUID system was
buggy, and it did not fix the reason it was implemented, so it has been
completely removed. The admin list and the ban list now use usernames and
IPs again.

Lastly, many smaller changes have been implemented. Due to the amount of
changes, they have not been named individualy. Please refer to the issues
below for more details.

Fixes #342
Fixes #350
Fixes #380
Fixes #684
Fixes #704
Fixes #716
Fixes #735
Fixes #745
Fixes #784
Fixes #765
Fixes #791
Fixes #805
Fixes #826
Fixes #883
Fixes #1524
Fixes #1534
Fixes #1536
Fixes #1538
Fixes #1545
Fixes #1546
Fixes #1568
Fixes #1627
Resolves #403
Resolves #435
Resolves #597
Resolves #603
Resolves #628
Resolves #690
Resolves #708
Resolves #747
Resolves #748
Resolves #749
Resolves #764
Resolves #767
Resolves #782
Resolves #809
Resolves #803
Resolves #811
Resolves #813
Resolves #830
Resolves #848
Resolves #856
Resolves #876
Resolves #908
Resolves #992
Resolves #1018
Resolves #1432
Resolves #1446
Resolves #1494
Resolves #1501
Resolves #1526
Resolves #1540
Resolves #1550
Resolves #1560
Resolves #1561
Resolves #1578
Resolves #1613
This commit is contained in:
Jerom van der Sar
2016-05-12 21:40:39 +02:00
parent 924f718d5a
commit aca3398d21
109 changed files with 2112 additions and 2036 deletions

View File

@ -10,7 +10,6 @@ public class HTMLGenerationTools
private HTMLGenerationTools()
{
throw new AssertionError();
}
public static String paragraph(String data)

View File

@ -3,7 +3,8 @@ package me.totalfreedom.totalfreedommod.httpd;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.totalfreedom.totalfreedommod.FreedomService;
@ -11,6 +12,8 @@ import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.HTTPSession;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
import me.totalfreedom.totalfreedommod.httpd.module.HTTPDModule;
import me.totalfreedom.totalfreedommod.httpd.module.Module_dump;
import me.totalfreedom.totalfreedommod.httpd.module.Module_file;
import me.totalfreedom.totalfreedommod.httpd.module.Module_help;
import me.totalfreedom.totalfreedommod.httpd.module.Module_list;
@ -21,18 +24,16 @@ import me.totalfreedom.totalfreedommod.httpd.module.Module_schematic;
import me.totalfreedom.totalfreedommod.util.FLog;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bukkit.Bukkit;
public class HTTPDaemon extends FreedomService
{
public static String MIME_DEFAULT_BINARY = "application/octet-stream";
//
private static final Pattern EXT_REGEX = Pattern.compile("\\.([^\\.\\s]+)$");
//
public static final int PORT = ConfigEntry.HTTPD_PORT.getInteger();
//
private static final TFM_HTTPD HTTPD = new TFM_HTTPD(PORT);
public int port;
private HTTPD httpd;
public Map<String, ModuleExecutable> modules = new HashMap<>();
public HTTPDaemon(TotalFreedomMod plugin)
{
@ -47,13 +48,27 @@ public class HTTPDaemon extends FreedomService
return;
}
port = ConfigEntry.HTTPD_PORT.getInteger();;
httpd = new HTTPD(port);
// Modules
modules.clear();
module("dump", Module_dump.class, true);
module("file", Module_file.class, true);
module("help", Module_help.class, false);
module("list", Module_list.class, false);
module("logs", Module_logs.class, true);
module("permbans", Module_permbans.class, true);
module("players", Module_players.class, false);
module("schematic", Module_schematic.class, true);
try
{
HTTPD.start();
httpd.start();
if (HTTPD.isAlive())
if (httpd.isAlive())
{
FLog.info("TFM HTTPd started. Listening on port: " + HTTPD.getListeningPort());
FLog.info("TFM HTTPd started. Listening on port: " + httpd.getListeningPort());
}
else
{
@ -74,160 +89,25 @@ public class HTTPDaemon extends FreedomService
return;
}
HTTPD.stop();
httpd.stop();
FLog.info("TFM HTTPd stopped.");
}
private static enum ModuleType
private void module(String name, Class<? extends HTTPDModule> clazz, boolean async)
{
DUMP(new ModuleExecutable(false, "dump")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Response(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "The DUMP module is disabled. It is intended for debugging use only.");
}
}),
HELP(new ModuleExecutable(true, "help")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_help(session).getResponse();
}
}),
LIST(new ModuleExecutable(true, "list")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_list(session).getResponse();
}
}),
FILE(new ModuleExecutable(false, "file")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_file(session).getResponse();
}
}),
SCHEMATIC(new ModuleExecutable(false, "schematic")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_schematic(session).getResponse();
}
}),
PERMBANS(new ModuleExecutable(false, "permbans")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_permbans(session).getResponse();
}
}),
PLAYERS(new ModuleExecutable(true, "players")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_players(session).getResponse();
}
}),
LOGS(new ModuleExecutable(false, "logs")
{
@Override
public Response getResponse(HTTPSession session)
{
return new Module_logs(session).getResponse();
}
});
//
private final ModuleExecutable moduleExecutable;
private ModuleType(ModuleExecutable moduleExecutable)
{
this.moduleExecutable = moduleExecutable;
}
private abstract static class ModuleExecutable
{
private final boolean runOnBukkitThread;
private final String name;
private ModuleExecutable(boolean runOnBukkitThread, String name)
{
this.runOnBukkitThread = runOnBukkitThread;
this.name = name;
}
public Response execute(final HTTPSession session)
{
try
{
if (this.runOnBukkitThread)
{
return Bukkit.getScheduler().callSyncMethod(TotalFreedomMod.plugin, new Callable<Response>()
{
@Override
public Response call() throws Exception
{
return getResponse(session);
}
}).get();
}
else
{
return getResponse(session);
}
}
catch (Exception ex)
{
FLog.severe(ex);
}
return null;
}
public abstract Response getResponse(HTTPSession session);
public String getName()
{
return name;
}
}
public ModuleExecutable getModuleExecutable()
{
return moduleExecutable;
}
private static ModuleType getByName(String needle)
{
for (ModuleType type : values())
{
if (type.getModuleExecutable().getName().equalsIgnoreCase(needle))
{
return type;
}
}
return FILE;
}
modules.put(name, ModuleExecutable.forClass(plugin, clazz, async));
}
private static class TFM_HTTPD extends NanoHTTPD
private class HTTPD extends NanoHTTPD
{
public TFM_HTTPD(int port)
private HTTPD(int port)
{
super(port);
}
public TFM_HTTPD(String hostname, int port)
private HTTPD(String hostname, int port)
{
super(hostname, port);
}
@ -235,25 +115,28 @@ public class HTTPDaemon extends FreedomService
@Override
public Response serve(HTTPSession session)
{
Response response;
final String[] args = StringUtils.split(session.getUri(), "/");
ModuleExecutable mex = modules.get("file");
if (args.length >= 1)
{
mex = modules.get(args[0].toLowerCase());
}
if (mex == null)
{
return new Response(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Error 404: Not Found - The requested resource was not found on this server.");
}
try
{
final String[] args = StringUtils.split(session.getUri(), "/");
final ModuleType moduleType = args.length >= 1 ? ModuleType.getByName(args[0]) : ModuleType.FILE;
response = moduleType.getModuleExecutable().execute(session);
return mex.execute(session);
}
catch (Exception ex)
{
response = new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "Error 500: Internal Server Error\r\n" + ex.getMessage() + "\r\n" + ExceptionUtils.getStackTrace(ex));
FLog.severe(ex);
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "Error 500: Internal Server Error\r\n" + ex.getMessage() + "\r\n" + ExceptionUtils.getStackTrace(ex));
}
if (response == null)
{
response = new Response(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Error 404: Not Found - The requested resource was not found on this server.");
}
return response;
}
}
@ -289,4 +172,5 @@ public class HTTPDaemon extends FreedomService
return response;
}
}

View File

@ -0,0 +1,85 @@
package me.totalfreedom.totalfreedommod.httpd;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import lombok.Getter;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.httpd.module.HTTPDModule;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.pravian.aero.component.PluginComponent;
import org.bukkit.Bukkit;
public abstract class ModuleExecutable
{
@Getter
private final boolean async;
public ModuleExecutable(boolean async)
{
this.async = async;
}
public NanoHTTPD.Response execute(final NanoHTTPD.HTTPSession session)
{
try
{
if (async)
{
return getResponse(session);
}
// Sync to server thread
return Bukkit.getScheduler().callSyncMethod(TotalFreedomMod.plugin(), new Callable<NanoHTTPD.Response>()
{
@Override
public NanoHTTPD.Response call() throws Exception
{
return getResponse(session);
}
}).get();
}
catch (Exception ex)
{
FLog.severe(ex);
}
return null;
}
public abstract NanoHTTPD.Response getResponse(NanoHTTPD.HTTPSession session);
public static ModuleExecutable forClass(final TotalFreedomMod plugin, Class<? extends HTTPDModule> clazz, boolean async)
{
final Constructor<? extends HTTPDModule> cons;
try
{
cons = clazz.getConstructor(TotalFreedomMod.class, NanoHTTPD.HTTPSession.class);
}
catch (Exception ex)
{
throw new IllegalArgumentException("Improperly defined module!");
}
return new ModuleExecutable(async)
{
@Override
public NanoHTTPD.Response getResponse(NanoHTTPD.HTTPSession session)
{
try
{
return cons.newInstance(plugin, session).getResponse();
}
catch (Exception ex)
{
FLog.severe(ex);
return null;
}
}
};
}
}

View File

@ -3,13 +3,16 @@ package me.totalfreedom.totalfreedommod.httpd.module;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.httpd.HTTPDPageBuilder;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.HTTPSession;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Method;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
import me.totalfreedom.totalfreedommod.util.FLog;
import net.pravian.aero.component.PluginComponent;
public abstract class HTTPDModule
public abstract class HTTPDModule extends PluginComponent<TotalFreedomMod>
{
protected final String uri;
@ -19,8 +22,9 @@ public abstract class HTTPDModule
protected final Socket socket;
protected final HTTPSession session;
public HTTPDModule(HTTPSession session)
public HTTPDModule(TotalFreedomMod plugin, HTTPSession session)
{
super(plugin);
this.uri = session.getUri();
this.method = session.getMethod();
this.headers = session.getHeaders();

View File

@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.list;
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.paragraph;
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
@ -18,9 +19,9 @@ public class Module_dump extends HTTPDModule
private File echoFile = null;
private final String body;
public Module_dump(NanoHTTPD.HTTPSession session)
public Module_dump(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
//Body needs to be computed before getResponse, so we know if a text response or a file echo is needed.
this.body = body();

View File

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
@ -57,9 +58,9 @@ public class Module_file extends HTTPDModule
MIME_TYPES.put("class", "application/octet-stream");
}
public Module_file(NanoHTTPD.HTTPSession session)
public Module_file(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
private File getRootDir()

View File

@ -13,7 +13,7 @@ import me.totalfreedom.totalfreedommod.command.FreedomCommand;
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.heading;
import static me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools.paragraph;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
import me.totalfreedom.totalfreedommod.rank.RankBase;
import me.totalfreedom.totalfreedommod.rank.Displayable;
import net.pravian.aero.command.CommandReflection;
import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
import org.apache.commons.lang3.StringUtils;
@ -25,9 +25,9 @@ import org.bukkit.command.SimpleCommandMap;
public class Module_help extends HTTPDModule
{
public Module_help(NanoHTTPD.HTTPSession session)
public Module_help(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override
@ -77,7 +77,7 @@ public class Module_help extends HTTPDModule
responseBody.append(heading(pluginName, 2)).append("<ul>\r\n");
RankBase lastTfmCommandLevel = null;
Displayable lastTfmCommandLevel = null;
for (Command command : commands)
{
if (!TotalFreedomMod.pluginName.equals(pluginName))
@ -86,7 +86,7 @@ public class Module_help extends HTTPDModule
continue;
}
RankBase tfmCommandLevel = FreedomCommand.getFrom(command).getPerms().level();
Displayable tfmCommandLevel = FreedomCommand.getFrom(command).getPerms().level();
if (lastTfmCommandLevel == null || lastTfmCommandLevel != tfmCommandLevel)
{
responseBody.append("</ul>\r\n").append(heading(tfmCommandLevel.getName(), 3)).append("<ul>\r\n");

View File

@ -9,9 +9,9 @@ import org.bukkit.entity.Player;
public class Module_list extends HTTPDModule
{
public Module_list(NanoHTTPD.HTTPSession session)
public Module_list(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override
@ -27,7 +27,7 @@ public class Module_list extends HTTPDModule
for (Player player : onlinePlayers)
{
String tag = TotalFreedomMod.plugin.rm.getDisplay(player).getTag();
String tag = plugin.rm.getDisplay(player).getTag();
body.append("<li>").append(tag).append(player.getName()).append("</li>\r\n");
}

View File

@ -1,15 +1,16 @@
package me.totalfreedom.totalfreedommod.httpd.module;
import java.io.File;
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
public class Module_logs extends Module_file
{
public Module_logs(NanoHTTPD.HTTPSession session)
public Module_logs(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override

View File

@ -9,18 +9,18 @@ import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
public class Module_permbans extends HTTPDModule
{
public Module_permbans(NanoHTTPD.HTTPSession session)
public Module_permbans(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override
public NanoHTTPD.Response getResponse()
{
File permbanFile = new File(TotalFreedomMod.plugin.getDataFolder(), PermbanList.CONFIG_FILENAME);
File permbanFile = new File(plugin.getDataFolder(), PermbanList.CONFIG_FILENAME);
if (permbanFile.exists())
{
return HTTPDaemon.serveFileBasic(new File(TotalFreedomMod.plugin.getDataFolder(), PermbanList.CONFIG_FILENAME));
return HTTPDaemon.serveFileBasic(new File(plugin.getDataFolder(), PermbanList.CONFIG_FILENAME));
}
else
{

View File

@ -12,9 +12,9 @@ import org.json.simple.JSONObject;
public class Module_players extends HTTPDModule
{
public Module_players(NanoHTTPD.HTTPSession session)
public Module_players(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override
@ -36,7 +36,7 @@ public class Module_players extends HTTPDModule
}
// Admins
for (Admin admin : TotalFreedomMod.plugin.al.getAllAdmins().values())
for (Admin admin : plugin.al.getAllAdmins().values())
{
final String username = admin.getName();
@ -49,7 +49,7 @@ public class Module_players extends HTTPDModule
telnetadmins.add(username);
break;
case SENIOR_ADMIN:
senioradmins.add(senioradmins);
senioradmins.add(username);
break;
}
}

View File

@ -39,9 +39,9 @@ public class Module_schematic extends HTTPDModule
+ "<button type=\"submit\">Submit</button>\n"
+ "</form>";
public Module_schematic(NanoHTTPD.HTTPSession session)
public Module_schematic(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
{
super(session);
super(plugin, session);
}
@Override
@ -235,7 +235,7 @@ public class Module_schematic extends HTTPDModule
private boolean isAuthorized(String remoteAddress)
{
Admin entry = TotalFreedomMod.plugin.al.getEntryByIp(remoteAddress);
Admin entry = plugin.al.getEntryByIp(remoteAddress);
return entry != null && entry.isActive();
}