1 parent
335fe303b5
commit
eebbc4d532
6 files changed
+219
-25
No files matched your search
@@ -5,6 +5,9 @@ This file contains update logs for this project. The top may contain a `Unreleas
|
||||
### Changed
|
||||
* Added Chinese language file (thanks to Spigot user yeban)
|
||||
|
||||
### Fixed
|
||||
* Fixed config parsing with multi line strings
|
||||
|
||||
## 3.0.4 - March 17th 2020
|
||||
### Changed
|
||||
* Bungee/Velocity: Added config option `waiting-server` to send players to a waiting server when global maintenance is enabled (instead of kicking them)
|
||||
|
||||
+2
-2
@@ -1,5 +1,4 @@
|
||||
.metadata
|
||||
dependencies/
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
@@ -92,4 +91,5 @@ $RECYCLE.BIN/
|
||||
*.msm
|
||||
*.msp
|
||||
*.lnk
|
||||
!MaintenanceAPI.jar
|
||||
!MaintenanceAPI.jar
|
||||
**/src/test/resources/
|
||||
@@ -93,10 +93,16 @@ public final class Config extends ConfigSection {
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
final byte[] bytes = this.saveConfigToString().getBytes(StandardCharsets.UTF_8);
|
||||
this.file.getParentFile().mkdirs();
|
||||
this.file.createNewFile();
|
||||
Files.write(this.file.toPath(), bytes);
|
||||
saveTo(file);
|
||||
}
|
||||
|
||||
public void saveTo(final File file) throws IOException {
|
||||
final byte[] bytes = toString().getBytes(StandardCharsets.UTF_8);
|
||||
if (file.getParentFile() != null) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
Files.write(file.toPath(), bytes);
|
||||
}
|
||||
|
||||
public boolean addMissingFields(final Map<String, Object> fields, final Map<String, String[]> comments) {
|
||||
@@ -150,10 +156,6 @@ public final class Config extends ConfigSection {
|
||||
return new Yaml(options);
|
||||
}
|
||||
|
||||
public String saveConfigToString() {
|
||||
return ConfigSerializer.serialize(this.header, this.values, this.comments, this.yaml);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.values.clear();
|
||||
this.comments.clear();
|
||||
@@ -176,4 +178,9 @@ public final class Config extends ConfigSection {
|
||||
public void resetAwesomeHeader() {
|
||||
this.header = AWESOME_HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ConfigSerializer.serialize(this.header, this.values, this.comments, this.yaml);
|
||||
}
|
||||
}
|
||||
+51
-15
@@ -40,7 +40,9 @@ public final class ConfigSerializer {
|
||||
private static final int INDENT_UNIT = 2;
|
||||
|
||||
public static String serialize(final String header, final Map<String, Object> data, final Map<String, String[]> comments, final Yaml yaml) {
|
||||
if (data.isEmpty()) return yaml.dump(null);
|
||||
if (data.isEmpty()) {
|
||||
return yaml.dump(null);
|
||||
}
|
||||
|
||||
final String rawYaml = yaml.dump(data);
|
||||
final StringBuilder fileData = new StringBuilder();
|
||||
@@ -61,46 +63,59 @@ public final class ConfigSerializer {
|
||||
key = join(array, array.length - backspace);
|
||||
keyLine = true;
|
||||
} else {
|
||||
keyLine = line.contains(":");
|
||||
keyLine = line.indexOf(':') != -1;
|
||||
}
|
||||
|
||||
if (keyLine) {
|
||||
final String newKey = substring.split(Pattern.quote(":"))[0]; // Not sure about the quote thing, so I'll just keep it :aaa:
|
||||
if (!key.isEmpty())
|
||||
key += PATH_SEPARATOR_STRING;
|
||||
key += newKey;
|
||||
if (!keyLine) {
|
||||
// Nothing to do, go to next line
|
||||
fileData.append(line).append('\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
final String newKey = substring.split(Pattern.quote(":"))[0]; // Not sure about the quote thing, so I'll just keep it :aaa:
|
||||
if (!key.isEmpty()) {
|
||||
key += PATH_SEPARATOR_STRING;
|
||||
}
|
||||
key += newKey;
|
||||
|
||||
// Add comments if present
|
||||
if (comments != null) {
|
||||
final String[] strings = comments.get(key);
|
||||
if (strings != null) {
|
||||
final String indentText = indent > 0 ? line.substring(0, indent) : "";
|
||||
for (final String comment : strings) {
|
||||
if (comment.isEmpty())
|
||||
if (comment.isEmpty()) {
|
||||
fileData.append('\n');
|
||||
else
|
||||
} else {
|
||||
fileData.append(indentText).append(comment).append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentKeyIndents = indents;
|
||||
}
|
||||
|
||||
currentKeyIndents = indents;
|
||||
fileData.append(line).append('\n');
|
||||
}
|
||||
return header != null && !header.isEmpty() ? header + fileData : fileData.toString();
|
||||
}
|
||||
|
||||
public static Map<String, String[]> deserializeComments(final String data) {
|
||||
//TODO go through known yaml keys and figure out comments from there instead of from line to line?
|
||||
final Map<String, String[]> comments = new HashMap<>();
|
||||
final List<String> currentComments = new ArrayList<>();
|
||||
boolean header = true;
|
||||
boolean multiLineValue = false;
|
||||
int currentIndents = 0;
|
||||
String key = "";
|
||||
for (final String line : data.split("\n")) {
|
||||
final String s = line.trim();
|
||||
// It's a comment!
|
||||
if (s.startsWith("#")) {
|
||||
currentComments.add(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Header is over - save it!
|
||||
if (header) {
|
||||
if (!currentComments.isEmpty()) {
|
||||
currentComments.add("");
|
||||
@@ -109,21 +124,39 @@ public final class ConfigSerializer {
|
||||
}
|
||||
header = false;
|
||||
}
|
||||
|
||||
// Save empty lines as well
|
||||
if (s.isEmpty()) {
|
||||
currentComments.add(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Multi line values?
|
||||
if (s.startsWith("- |")) {
|
||||
multiLineValue = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
final int indent = getIndents(line);
|
||||
final int indents = indent / INDENT_UNIT;
|
||||
// Check if the multi line value is over
|
||||
if (multiLineValue) {
|
||||
if (indents > currentIndents) continue;
|
||||
|
||||
multiLineValue = false;
|
||||
}
|
||||
|
||||
// Check if this is a level lower
|
||||
if (indents <= currentIndents) {
|
||||
final String[] array = key.split(PATH_SEPARATOR_QUOTED);
|
||||
final int backspace = currentIndents - indents + 1;
|
||||
key = join(array, array.length - backspace);
|
||||
final int delta = array.length - backspace;
|
||||
key = delta >= 0 ? join(array, delta) : key;
|
||||
}
|
||||
|
||||
// Finish current key
|
||||
final String separator = key.isEmpty() ? "" : PATH_SEPARATOR_STRING;
|
||||
final String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
|
||||
final String lineKey = line.indexOf(':') != -1 ? line.split(Pattern.quote(":"))[0] : line;
|
||||
key += separator + lineKey.substring(indent);
|
||||
currentIndents = indents;
|
||||
|
||||
@@ -138,8 +171,11 @@ public final class ConfigSerializer {
|
||||
private static int getIndents(final String line) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
if (line.charAt(i) == ' ') count++;
|
||||
else break;
|
||||
if (line.charAt(i) != ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,91 @@
|
||||
package eu.kennytv.maintenance.core.config;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
// I'm sorry in advance
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class ConfigTest {
|
||||
|
||||
@BeforeAll
|
||||
void initAll() {
|
||||
delete("config.yml");
|
||||
delete("config-saved.yml");
|
||||
delete("dirty-config-saved.yml");
|
||||
delete("dirty-config-upgraded.yml");
|
||||
copyOriginalToTest("config.yml", "config.yml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveConsistency() throws IOException {
|
||||
final Config config = new Config(getTestFile("config.yml"));
|
||||
config.load();
|
||||
|
||||
final File saveTo = getTestFile("config-saved.yml");
|
||||
config.saveTo(saveTo);
|
||||
|
||||
final Config newlyLoaded = new Config(saveTo);
|
||||
newlyLoaded.load();
|
||||
|
||||
assert newlyLoaded.toString().equals(config.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParsing() throws IOException {
|
||||
final Config config = new Config(getTestFile("dirty-config.yml"));
|
||||
config.load();
|
||||
final File saveTo = getTestFile("dirty-config-saved.yml");
|
||||
config.saveTo(saveTo);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpgrading() throws IOException {
|
||||
final Config config = new Config(getTestFile("dirty-config.yml"));
|
||||
config.load();
|
||||
|
||||
final Config newestConfig = new Config(getTestFile("config.yml"));
|
||||
newestConfig.load();
|
||||
|
||||
config.addMissingFields(newestConfig.getValues(), newestConfig.getComments());
|
||||
config.set("config-version", 4);
|
||||
final File saveTo = getTestFile("dirty-config-upgraded.yml");
|
||||
config.resetAwesomeHeader();
|
||||
config.saveTo(saveTo);
|
||||
|
||||
final Config newlyLoaded = new Config(saveTo);
|
||||
newlyLoaded.load();
|
||||
|
||||
assert newlyLoaded.contains("waiting-server");
|
||||
assert newlyLoaded.getComments().get("maintenance-enabled") != null;
|
||||
assert newlyLoaded.getComments().get("mysql.use-ssl") != null;
|
||||
assert newlyLoaded.getComments().get("update-checks") != null;
|
||||
assert newlyLoaded.getHeader().equals(newestConfig.getHeader());
|
||||
assert newlyLoaded.getSection("mysql").getString("username").equals("useer");
|
||||
assert newlyLoaded.getInt("config-version") == 4;
|
||||
}
|
||||
|
||||
private File getTestFile(final String path) {
|
||||
return new File("src/test/resources/" + path);
|
||||
}
|
||||
|
||||
private void copyOriginalToTest(final String from, final String to) {
|
||||
final File file = new File("src/main/resources/" + from);
|
||||
try {
|
||||
Files.copy(file, getTestFile(to));
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void delete(final String path) {
|
||||
final File file = getTestFile(path);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
# Enables maintenance mode.
|
||||
maintenance-enabled: true
|
||||
|
||||
# Enables maintenance on certain servers managed by your Bungee instance(s).
|
||||
proxied-maintenance-servers:
|
||||
- SpigotServer1
|
||||
# - AnotherServer
|
||||
|
||||
# If maintenance is enabled on a proxied server with players on it,
|
||||
# they will be sent to the fallback server instead of being kicked off the network.
|
||||
# If the fallback server is not reachable/not set, they will just be kicked off the network.
|
||||
fallback: ''
|
||||
|
||||
# The message shown in the multiplayer server list motd when maintenance is enabled.
|
||||
# If you put in multiple entries, one of them will be chosen randomly on every ping.
|
||||
# If running an endtimer, the time left can be displayed by including '%TIMER%' in a pingmessage (also works in playercount(-hover) message).
|
||||
pingmessages:
|
||||
- |2-
|
||||
&2&lX's &b&lServer &f- &7&l(1.12.2-1.15.2)
|
||||
&4&n&lMANUTENZIONE!
|
||||
enable-timerspecific-messages: true
|
||||
timerspecific-pingmessages:
|
||||
- |2-
|
||||
&2&lX's &b&lServer &f- &7&l(1.12.2-1.15.2)
|
||||
&4&n&lMANUTENZIONE! Torneremo tra %TIMER%
|
||||
enable-playercountmessage: true
|
||||
playercountmessage: '&41.12.2-1.15.2'
|
||||
playercounthovermessage: '&n&lStato server: In manutenzione'
|
||||
custom-maintenance-icon: false
|
||||
send-join-notification: false
|
||||
kick-online-players: true
|
||||
language: de
|
||||
mysql:
|
||||
use-mysql: false
|
||||
host: host
|
||||
port: 3306
|
||||
database: database
|
||||
username: useer
|
||||
password: password
|
||||
update-interval: 15
|
||||
use-ssl: true
|
||||
continue-endtimer-after-restart:
|
||||
enabled: false
|
||||
end: 0
|
||||
timer-broadcast-for-seconds:
|
||||
- 1200
|
||||
- 900
|
||||
- 600
|
||||
- 300
|
||||
- 120
|
||||
- 60
|
||||
- 30
|
||||
- 20
|
||||
- 10
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
update-checks: true
|
||||
config-version: 3
|
||||
Reference in new issue
Block a user