[#922] Refactored file accessing
- All plugin files moved to /assets/ inside the jar - InputStreams, lines and flat string now accessed through Resource interface obtained from PlanFiles - Removed FileUtil - Removed old methods from PlanFiles that returned something that is now accessed via Resource interface. - Implemented a PlanFiles class for Sponge that uses Sponge Asset API for fetching items in the jar.
@ -32,7 +32,6 @@ import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.ExportSettings;
|
||||
import com.djrapitops.plan.system.settings.theme.Theme;
|
||||
import com.djrapitops.plan.system.settings.theme.ThemeVal;
|
||||
import com.djrapitops.plan.utilities.file.FileUtil;
|
||||
import com.djrapitops.plan.utilities.html.pages.InspectPage;
|
||||
import com.djrapitops.plan.utilities.html.pages.PageFactory;
|
||||
import com.djrapitops.plugin.api.Check;
|
||||
@ -217,12 +216,13 @@ public class HtmlExport extends SpecificExport {
|
||||
copyFromJar(resources);
|
||||
|
||||
try {
|
||||
String demo = files.readFromResourceFlat("web/js/demo.js")
|
||||
String demo = files.getCustomizableResourceOrDefault("web/js/demo.js")
|
||||
.asString()
|
||||
.replace("${defaultTheme}", theme.getValue(ThemeVal.THEME_DEFAULT));
|
||||
List<String> lines = Arrays.asList(demo.split("\n"));
|
||||
File outputFolder = new File(getFolder(), "js");
|
||||
Verify.isTrue(outputFolder.exists() && outputFolder.isDirectory() || outputFolder.mkdirs(),
|
||||
() -> new FileNotFoundException("Output folder could not be created at" + outputFolder.getAbsolutePath()));
|
||||
() -> new FileNotFoundException("Output folder could not be created at " + outputFolder.getAbsolutePath()));
|
||||
export(new File(outputFolder, "demo.js"), lines);
|
||||
} catch (IOException e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
@ -258,19 +258,21 @@ public class HtmlExport extends SpecificExport {
|
||||
}
|
||||
|
||||
private void copyFromJar(String resource) throws IOException {
|
||||
String possibleFile = resource.replace("web/", "").replace("/", File.separator);
|
||||
List<String> lines = FileUtil.lines(plugin, new File(plugin.getDataFolder(), possibleFile), resource);
|
||||
String outputFile = possibleFile.replace("web/", "");
|
||||
File to = new File(getFolder(), outputFile);
|
||||
List<String> lines = files.getCustomizableResourceOrDefault(resource).asLines();
|
||||
|
||||
File to = new File(getFolder(), resource.replace("web/", "").replace("/", File.separator));
|
||||
File locationFolder = to.getParentFile();
|
||||
|
||||
Verify.isTrue(locationFolder.exists() && locationFolder.isDirectory() || locationFolder.mkdirs(),
|
||||
() -> new FileNotFoundException("Output folder could not be created at" + locationFolder.getAbsolutePath()));
|
||||
|
||||
if (to.exists()) {
|
||||
Files.delete(to.toPath());
|
||||
if (!to.createNewFile()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export(to, lines);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* {@link Resource} implementation for a {@link File}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class FileResource implements Resource {
|
||||
|
||||
private final String resourceName;
|
||||
private final File file;
|
||||
|
||||
public FileResource(String resourceName, File file) {
|
||||
this.resourceName = resourceName;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public static List<String> lines(File file) throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
if (file != null && file.exists()) {
|
||||
try (Stream<String> linesStream = Files.lines(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
lines = linesStream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream asInputStream() throws IOException {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> asLines() throws IOException {
|
||||
return lines(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() throws IOException {
|
||||
StringBuilder flat = new StringBuilder();
|
||||
try (Scanner scanner = new Scanner(file, "UTF-8")) {
|
||||
while (scanner.hasNextLine()) {
|
||||
flat.append(scanner.nextLine()).append("\r\n");
|
||||
}
|
||||
}
|
||||
return flat.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.file;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* {@link Resource} implementation for something that is read via InputStream.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class JarResource implements Resource {
|
||||
|
||||
private final String resourceName;
|
||||
private final StreamSupplier streamSupplier;
|
||||
|
||||
public JarResource(String resourceName, StreamSupplier streamSupplier) {
|
||||
this.resourceName = resourceName;
|
||||
this.streamSupplier = streamSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream asInputStream() throws IOException {
|
||||
InputStream stream = streamSupplier.get();
|
||||
if (stream == null) {
|
||||
throw new FileNotFoundException("a Resource was not found inside the jar (" + resourceName + "), " +
|
||||
"Plan does not support /reload or updates using " +
|
||||
"Plugin Managers, restart the server and see if the error persists.");
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> asLines() throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
try (
|
||||
InputStream inputStream = asInputStream();
|
||||
Scanner scanner = new Scanner(inputStream, "UTF-8")
|
||||
) {
|
||||
while (scanner.hasNextLine()) {
|
||||
lines.add(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() throws IOException {
|
||||
StringBuilder flat = new StringBuilder();
|
||||
try (
|
||||
InputStream inputStream = asInputStream();
|
||||
Scanner scanner = new Scanner(inputStream, "UTF-8")
|
||||
) {
|
||||
while (scanner.hasNextLine()) {
|
||||
flat.append(scanner.nextLine()).append("\r\n");
|
||||
}
|
||||
}
|
||||
return flat.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
interface StreamSupplier {
|
||||
InputStream get() throws IOException;
|
||||
}
|
||||
}
|
@ -19,15 +19,15 @@ package com.djrapitops.plan.system.file;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.system.SubSystem;
|
||||
import com.djrapitops.plan.utilities.file.FileUtil;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Abstracts File methods of Plugin classes so that they can be tested without Mocks.
|
||||
@ -37,7 +37,7 @@ import java.util.List;
|
||||
@Singleton
|
||||
public class PlanFiles implements SubSystem {
|
||||
|
||||
private final PlanPlugin plugin;
|
||||
protected final PlanPlugin plugin;
|
||||
|
||||
private final File dataFolder;
|
||||
private final File configFile;
|
||||
@ -68,7 +68,7 @@ public class PlanFiles implements SubSystem {
|
||||
}
|
||||
|
||||
public File getFileFromPluginFolder(String name) {
|
||||
return new File(dataFolder, name);
|
||||
return new File(dataFolder, name.replace("/", File.separator));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,53 +89,53 @@ public class PlanFiles implements SubSystem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file from jar as lines.
|
||||
* Get a file in the jar as a {@link Resource}.
|
||||
*
|
||||
* @param fileName Name of the file.
|
||||
* @return lines of the file
|
||||
* @throws IOException If the resource can not be read.
|
||||
* @param resourceName Path to the file inside jar/assets/ folder.
|
||||
* @return a {@link Resource} for accessing the resource.
|
||||
*/
|
||||
public List<String> readFromResource(String fileName) throws IOException {
|
||||
return FileUtil.lines(plugin, fileName);
|
||||
}
|
||||
|
||||
public InputStream readStreamFromResource(String fileName) throws IOException {
|
||||
return plugin.getResource(fileName);
|
||||
public Resource getResourceFromJar(String resourceName) {
|
||||
return new JarResource("assets/" + resourceName, () -> plugin.getResource("assets/" + resourceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file from jar as a flat String.
|
||||
* Get a file from plugin folder as a {@link Resource}.
|
||||
*
|
||||
* @param fileName Name of the file
|
||||
* @return Flattened lines with {@code \r\n} line separators.
|
||||
* @throws IOException If the resource can not be read.
|
||||
* @param resourceName Path to the file inside the plugin folder.
|
||||
* @return a {@link Resource} for accessing the resource.
|
||||
*/
|
||||
public String readFromResourceFlat(String fileName) throws IOException {
|
||||
return flatten(readFromResource(fileName));
|
||||
public Resource getResourceFromPluginFolder(String resourceName) {
|
||||
return new FileResource(resourceName, getFileFromPluginFolder(resourceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file from jar or /plugins/Plan/ folder.
|
||||
* Get a customizable resource from the plugin files or from the jar if one doesn't exist.
|
||||
*
|
||||
* @param fileName Name of the file
|
||||
* @return Flattened lines with {@code \r\n} line separators.
|
||||
* @throws IOException If the resource can not be read.
|
||||
* @param resourceName Path to the file inside the plugin folder.
|
||||
* @return a {@link Resource} for accessing the resource, either from the plugin folder or jar.
|
||||
*/
|
||||
public String readCustomizableResourceFlat(String fileName) throws IOException {
|
||||
return flatten(FileUtil.lines(
|
||||
plugin, new File(plugin.getDataFolder(), fileName.replace("/", File.separator)), fileName
|
||||
));
|
||||
public Resource getCustomizableResourceOrDefault(String resourceName) {
|
||||
return attemptToFind(resourceName).map(file -> (Resource) new FileResource(resourceName, file)).orElse(getResourceFromJar(resourceName));
|
||||
}
|
||||
|
||||
public InputStream readCustomizableResource(String fileName) {
|
||||
return FileUtil.stream(plugin, new File(plugin.getDataFolder(), fileName.replace("/", File.separator)), fileName);
|
||||
}
|
||||
private Optional<File> attemptToFind(String resourceName) {
|
||||
if (dataFolder.exists() && dataFolder.isDirectory()) {
|
||||
ArrayDeque<File> que = new ArrayDeque<>();
|
||||
que.add(dataFolder);
|
||||
|
||||
private String flatten(List<String> lines) {
|
||||
StringBuilder flat = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
flat.append(line).append("\r\n");
|
||||
while (!que.isEmpty()) {
|
||||
File file = que.pop();
|
||||
if (file.isFile() && resourceName.equals(file.getName())) {
|
||||
return Optional.of(file);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
que.addAll(Arrays.asList(files));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return flat.toString();
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.system.file;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface for accessing plugin resources in jar or plugin files.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Resource {
|
||||
|
||||
/**
|
||||
* Get the name of this Resource.
|
||||
*
|
||||
* @return Relative file path given to {@link PlanFiles}.
|
||||
*/
|
||||
String getResourceName();
|
||||
|
||||
/**
|
||||
* Get the resource as an InputStream.
|
||||
*
|
||||
* @return InputStream of the resource, not closed automatically.
|
||||
* @throws IOException If the resource is unavailable.
|
||||
*/
|
||||
InputStream asInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Get the resource as lines.
|
||||
*
|
||||
* @return Lines of the resource file.
|
||||
* @throws IOException If the resource is unavailable.
|
||||
*/
|
||||
List<String> asLines() throws IOException;
|
||||
|
||||
/**
|
||||
* Get the resource as a String with each line separated by CRLF newline characters {@code \r\n}.
|
||||
*
|
||||
* @return Flat string with each line separated by {@code \r\n}.
|
||||
* @throws IOException If the resource is unavailable.
|
||||
*/
|
||||
String asString() throws IOException;
|
||||
|
||||
}
|
@ -45,7 +45,7 @@ public class ServerInfoFile extends Config {
|
||||
}
|
||||
|
||||
public void prepare() throws IOException {
|
||||
try (ConfigReader reader = new ConfigReader(files.readStreamFromResource("DefaultServerInfoFile.yml"))) {
|
||||
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("DefaultServerInfoFile.yml").asInputStream())) {
|
||||
copyMissing(reader.read());
|
||||
}
|
||||
save();
|
||||
|
@ -16,7 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.system.locale;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.system.file.FileResource;
|
||||
import com.djrapitops.plan.system.file.PlanFiles;
|
||||
import com.djrapitops.plan.system.locale.lang.*;
|
||||
|
||||
import java.io.File;
|
||||
@ -36,16 +37,16 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class Locale extends HashMap<Lang, Message> {
|
||||
|
||||
public static Locale forLangCodeString(PlanPlugin plugin, String code) throws IOException {
|
||||
return forLangCode(LangCode.fromString(code), plugin);
|
||||
public static Locale forLangCodeString(PlanFiles files, String code) throws IOException {
|
||||
return forLangCode(LangCode.fromString(code), files);
|
||||
}
|
||||
|
||||
public static Locale forLangCode(LangCode code, PlanPlugin plugin) throws IOException {
|
||||
return new LocaleFileReader(plugin, code.getFileName()).load();
|
||||
public static Locale forLangCode(LangCode code, PlanFiles files) throws IOException {
|
||||
return new LocaleFileReader(files.getResourceFromJar("locale/" + code.getFileName())).load();
|
||||
}
|
||||
|
||||
public static Locale fromFile(File file) throws IOException {
|
||||
return new LocaleFileReader(file).load();
|
||||
return new LocaleFileReader(new FileResource(file.getName(), file)).load();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,11 +16,9 @@
|
||||
*/
|
||||
package com.djrapitops.plan.system.locale;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.system.file.Resource;
|
||||
import com.djrapitops.plan.system.locale.lang.Lang;
|
||||
import com.djrapitops.plan.utilities.file.FileUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -34,12 +32,8 @@ public class LocaleFileReader {
|
||||
|
||||
private List<String> lines;
|
||||
|
||||
public LocaleFileReader(File from) throws IOException {
|
||||
lines = FileUtil.lines(from);
|
||||
}
|
||||
|
||||
public LocaleFileReader(PlanPlugin planPlugin, String fileName) throws IOException {
|
||||
lines = FileUtil.lines(planPlugin, "locale/" + fileName);
|
||||
public LocaleFileReader(Resource resource) throws IOException {
|
||||
lines = resource.asLines();
|
||||
}
|
||||
|
||||
public Locale load() {
|
||||
|
@ -132,7 +132,7 @@ public class LocaleSystem implements SubSystem {
|
||||
try {
|
||||
String setting = config.get(PluginSettings.LOCALE);
|
||||
if (!"default".equalsIgnoreCase(setting)) {
|
||||
return Optional.of(Locale.forLangCodeString(plugin, setting));
|
||||
return Optional.of(Locale.forLangCodeString(files, setting));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to read locale from jar: " + config.get(PluginSettings.LOCALE) + ", " + e.toString());
|
||||
|
@ -76,7 +76,7 @@ public class BukkitConfigSystem extends ConfigSystem {
|
||||
@Override
|
||||
protected void copyDefaults() throws IOException {
|
||||
configUpdater.applyConfigUpdate(config);
|
||||
try (ConfigReader reader = new ConfigReader(files.readStreamFromResource("config.yml"))) {
|
||||
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("config.yml").asInputStream())) {
|
||||
config.copyMissing(reader.read());
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class ProxyConfigSystem extends ConfigSystem {
|
||||
@Override
|
||||
protected void copyDefaults() throws IOException {
|
||||
configUpdater.applyConfigUpdate(config);
|
||||
try (ConfigReader reader = new ConfigReader(files.readStreamFromResource("bungeeconfig.yml"))) {
|
||||
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("bungeeconfig.yml").asInputStream())) {
|
||||
config.copyMissing(reader.read());
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class ThemeConfig extends Config {
|
||||
String fileName = config.get(DisplaySettings.THEME);
|
||||
String fileLocation = getFileLocation(fileName);
|
||||
|
||||
try (ConfigReader reader = new ConfigReader(files.readStreamFromResource(fileLocation))) {
|
||||
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar(fileLocation).asInputStream())) {
|
||||
return reader.read();
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not find theme " + fileLocation + ". Attempting to use default.");
|
||||
|
@ -49,7 +49,7 @@ public class ByteResponse extends Response {
|
||||
exchange.sendResponseHeaders(getCode(), 0);
|
||||
|
||||
try (OutputStream out = exchange.getResponseBody();
|
||||
InputStream bis = files.readCustomizableResource(fileName)) {
|
||||
InputStream bis = files.getCustomizableResourceOrDefault(fileName).asInputStream()) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int count;
|
||||
while ((count = bis.read(buffer)) != -1) {
|
||||
|
@ -32,7 +32,7 @@ public class FileResponse extends Response {
|
||||
|
||||
public FileResponse(String fileName, PlanFiles files) throws IOException {
|
||||
super.setHeader("HTTP/1.1 200 OK");
|
||||
super.setContent(files.readCustomizableResourceFlat(fileName));
|
||||
super.setContent(files.getCustomizableResourceOrDefault(fileName).asString());
|
||||
}
|
||||
|
||||
public static String format(String fileName) {
|
||||
|
@ -40,7 +40,7 @@ public class ErrorResponse extends PageResponse {
|
||||
|
||||
public ErrorResponse(VersionCheckSystem versionCheckSystem, PlanFiles files) throws IOException {
|
||||
this.versionCheckSystem = versionCheckSystem;
|
||||
setContent(files.readCustomizableResourceFlat("web/error.html"));
|
||||
setContent(files.getCustomizableResourceOrDefault("web/error.html").asString());
|
||||
}
|
||||
|
||||
public ErrorResponse(String message) {
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.utilities.file;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.utilities.MiscUtils;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileUtil {
|
||||
|
||||
private FileUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static List<String> lines(PlanPlugin plugin, File savedFile, String defaults) throws IOException {
|
||||
if (savedFile.exists()) {
|
||||
return lines(savedFile);
|
||||
} else {
|
||||
String fileName = savedFile.getName();
|
||||
File found = attemptToFind(fileName, new File(plugin.getDataFolder(), "web"));
|
||||
if (found != null) {
|
||||
return lines(found);
|
||||
}
|
||||
}
|
||||
return lines(plugin, defaults);
|
||||
}
|
||||
|
||||
public static InputStream stream(PlanPlugin plugin, File savedFile, String defaults) {
|
||||
try {
|
||||
if (savedFile.exists()) {
|
||||
return stream(savedFile);
|
||||
} else {
|
||||
String fileName = savedFile.getName();
|
||||
File found = attemptToFind(fileName, new File(plugin.getDataFolder(), "web"));
|
||||
if (found != null) {
|
||||
return stream(found);
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException ignore) {
|
||||
// File was not found, use jar version
|
||||
}
|
||||
return stream(plugin, defaults);
|
||||
}
|
||||
|
||||
private static InputStream stream(PlanPlugin plugin, String resource) {
|
||||
return plugin.getResource(resource);
|
||||
}
|
||||
|
||||
private static InputStream stream(File savedFile) throws FileNotFoundException {
|
||||
return new FileInputStream(savedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Breadth-First search through the file tree to find the file.
|
||||
*
|
||||
* @param fileName Name of the searched file
|
||||
* @param dataFolder Folder to look from
|
||||
* @return File if found or null
|
||||
*/
|
||||
private static File attemptToFind(String fileName, File dataFolder) {
|
||||
if (dataFolder.exists() && dataFolder.isDirectory()) {
|
||||
ArrayDeque<File> que = new ArrayDeque<>();
|
||||
que.add(dataFolder);
|
||||
|
||||
while (!que.isEmpty()) {
|
||||
File file = que.pop();
|
||||
if (file.isFile() && fileName.equals(file.getName())) {
|
||||
return file;
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
que.addAll(Arrays.asList(files));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<String> lines(PlanPlugin plugin, String resource) throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
Scanner scanner = null;
|
||||
try (InputStream inputStream = plugin.getResource(resource)) {
|
||||
scanner = new Scanner(inputStream, "UTF-8");
|
||||
while (scanner.hasNextLine()) {
|
||||
lines.add(scanner.nextLine());
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
plugin.getPluginLogger().log(L.INFO_COLOR, "§ea Resource was not found inside the jar (" + resource + "), Plan does not support /reload or updates using " +
|
||||
"Plugin Managers, restart the server and see if the error persists.");
|
||||
throw new FileNotFoundException("File not found inside jar: " + resource);
|
||||
} finally {
|
||||
MiscUtils.close(scanner);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static List<String> lines(File file) throws IOException {
|
||||
return lines(file, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static List<String> lines(File file, Charset charset) throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
if (file != null && file.exists()) {
|
||||
try (Stream<String> linesStream = Files.lines(file.toPath(), charset)) {
|
||||
lines = linesStream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ public class AnalysisPage implements Page {
|
||||
performanceNumbers(placeholderReplacer);
|
||||
|
||||
try {
|
||||
return placeholderReplacer.apply(files.readCustomizableResourceFlat("web/server.html"));
|
||||
return placeholderReplacer.apply(files.getCustomizableResourceOrDefault("web/server.html").asString());
|
||||
} catch (IOException e) {
|
||||
throw new ParseException(e);
|
||||
} finally {
|
||||
|
@ -21,13 +21,13 @@ import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.data.store.objects.DateHolder;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.file.FileResource;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionLog;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
|
||||
import com.djrapitops.plan.utilities.file.FileUtil;
|
||||
import com.djrapitops.plan.utilities.formatting.Formatter;
|
||||
import com.djrapitops.plan.utilities.formatting.Formatters;
|
||||
import com.djrapitops.plan.utilities.html.Html;
|
||||
@ -282,7 +282,7 @@ public class DebugPage implements Page {
|
||||
.flatMap(FolderTimeStampFileLogger::getCurrentFile)
|
||||
.map(file -> {
|
||||
try {
|
||||
return FileUtil.lines(file);
|
||||
return FileResource.lines(file);
|
||||
} catch (IOException e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
return new ArrayList<String>();
|
||||
|
@ -271,7 +271,7 @@ public class InspectPage implements Page {
|
||||
InspectPagePluginsContent pluginsTab = (InspectPagePluginsContent) ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(playerUUID), InspectPagePluginsContent::new);
|
||||
pluginsTab.addTab(new InspectPagePluginsContent(pluginTabs.getNav(), pluginTabs.getTab()));
|
||||
|
||||
return replacer.apply(files.readCustomizableResourceFlat("web/player.html"));
|
||||
return replacer.apply(files.getCustomizableResourceOrDefault("web/player.html").asString());
|
||||
}
|
||||
|
||||
private void sessionsAndPlaytime(PlaceholderReplacer replacer, SessionsMutator sessionsMutator, SessionsMutator daySessionsMutator, SessionsMutator weekSessionsMutator, SessionsMutator monthSessionsMutator) {
|
||||
|
@ -92,7 +92,7 @@ public class NetworkPage implements Page {
|
||||
placeholderReplacer.put("navPluginsTabs", nav);
|
||||
placeholderReplacer.put("tabsPlugins", tabs);
|
||||
|
||||
return placeholderReplacer.apply(files.readCustomizableResourceFlat("web/network.html"));
|
||||
return placeholderReplacer.apply(files.getCustomizableResourceOrDefault("web/network.html").asString());
|
||||
} catch (Exception e) {
|
||||
throw new ParseException(e);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class PlayersPage implements Page {
|
||||
placeholderReplacer.put("playersTable", tables.playerTableForPlayersPage(playerContainers).parseHtml());
|
||||
timings.end("Pages", "Players page players table parsing");
|
||||
|
||||
return placeholderReplacer.apply(files.readCustomizableResourceFlat("web/players.html"));
|
||||
return placeholderReplacer.apply(files.getCustomizableResourceOrDefault("web/players.html").asString());
|
||||
} catch (Exception e) {
|
||||
throw new ParseException(e);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 557 B After Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
Before Width: | Height: | Size: 478 B After Width: | Height: | Size: 478 B |
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB |
@ -374,7 +374,7 @@
|
||||
svgHourText.addEventListener('click', this._onSelectHour.bind(this));
|
||||
}
|
||||
|
||||
svgClockElement.appendChild(svgHourCircle)
|
||||
svgClockElement.appendChild(svgHourCircle);
|
||||
svgClockElement.appendChild(svgHourText)
|
||||
}
|
||||
|
||||
@ -404,7 +404,7 @@
|
||||
svgHourText.addEventListener('click', this._onSelectHour.bind(this));
|
||||
}
|
||||
|
||||
svgClockElement.appendChild(svgHourCircle)
|
||||
svgClockElement.appendChild(svgHourCircle);
|
||||
svgClockElement.appendChild(svgHourText)
|
||||
}
|
||||
|
||||
@ -505,7 +505,7 @@
|
||||
var svgClockFace = this.createSVGElement("circle", {r: '192', fill: '#eee', stroke: '#bdbdbd', 'stroke-width': 2});
|
||||
var svgClockCenter = this.createSVGElement("circle", {r: '15', fill: '#757575'});
|
||||
|
||||
svgGElement.appendChild(svgClockFace)
|
||||
svgGElement.appendChild(svgClockFace);
|
||||
|
||||
if (isHour)
|
||||
{
|
||||
@ -523,9 +523,9 @@
|
||||
svgGElement.appendChild(svgMinuteHand);
|
||||
}
|
||||
|
||||
svgGElement.appendChild(svgClockCenter)
|
||||
svgGElement.appendChild(svgClockCenter);
|
||||
|
||||
svgElement.appendChild(svgGElement)
|
||||
svgElement.appendChild(svgGElement);
|
||||
|
||||
this.$dtpElement.find("#dtp-svg-clock").empty();
|
||||
this.$dtpElement.find("#dtp-svg-clock")[0].appendChild(svgElement);
|
@ -77,7 +77,7 @@
|
||||
this.animations = {
|
||||
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
|
||||
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof this.settings.offset == 'number') {
|
||||
this.settings.offset = {
|
||||
@ -87,9 +87,8 @@
|
||||
}
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
$.extend(Notify.prototype, {
|
||||
}
|
||||
$.extend(Notify.prototype, {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
@ -145,8 +144,8 @@
|
||||
break;
|
||||
default:
|
||||
this.$ele.find('[data-notify="' + command +'"]').html(commands[command]);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
|
||||
self.reposition(posX);
|
||||
},
|
||||
@ -264,7 +263,7 @@
|
||||
|
||||
this.$ele.find('[data-notify="dismiss"]').on('click', function() {
|
||||
self.close();
|
||||
})
|
||||
});
|
||||
|
||||
this.$ele.mouseover(function(e) {
|
||||
$(this).data('data-hover', "true");
|