config manager: manually parse config keys

The regex used took too long to complete with large inputs that can
appear when the user has a corrupted config.
This commit is contained in:
Adam
2020-12-02 19:19:28 -05:00
parent ed591b123b
commit 16149cdcae
2 changed files with 68 additions and 42 deletions

View File

@@ -112,11 +112,9 @@ public class ConfigManager
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
@VisibleForTesting private static final int KEY_SPLITTER_GROUP = 0;
static final Pattern KEY_SPLITTER = Pattern.compile("([^.]+)\\.(?:(" + RSPROFILE_GROUP + "\\.[^.]+)\\.)?(.*)"); private static final int KEY_SPLITTER_PROFILE = 1;
private static final int KEY_SPLITTER_GROUP = 1; private static final int KEY_SPLITTER_KEY = 2;
private static final int KEY_SPLITTER_PROFILE = 2;
private static final int KEY_SPLITTER_KEY = 3;
private final File settingsFileInput; private final File settingsFileInput;
private final EventBus eventBus; private final EventBus eventBus;
@@ -229,15 +227,15 @@ public class ConfigManager
{ {
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue()); log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
Matcher matcher = KEY_SPLITTER.matcher(entry.getKey()); String[] split = splitKey(entry.getKey());
if (!matcher.find()) if (split == null)
{ {
continue; continue;
} }
final String groupName = matcher.group(KEY_SPLITTER_GROUP); final String groupName = split[KEY_SPLITTER_GROUP];
final String profile = matcher.group(KEY_SPLITTER_PROFILE); final String profile = split[KEY_SPLITTER_PROFILE];
final String key = matcher.group(KEY_SPLITTER_KEY); final String key = split[KEY_SPLITTER_KEY];
final String value = entry.getValue(); final String value = entry.getValue();
final String oldValue = (String) properties.setProperty(entry.getKey(), value); final String oldValue = (String) properties.setProperty(entry.getKey(), value);
@@ -282,30 +280,30 @@ public class ConfigManager
{ {
if (!properties.containsKey(wholeKey)) if (!properties.containsKey(wholeKey))
{ {
Matcher matcher = KEY_SPLITTER.matcher(wholeKey); String[] split = splitKey(wholeKey);
if (!matcher.find()) if (split == null)
{ {
return; return;
} }
String groupName = matcher.group(KEY_SPLITTER_GROUP); String groupName = split[KEY_SPLITTER_GROUP];
String profile = matcher.group(KEY_SPLITTER_PROFILE); String profile = split[KEY_SPLITTER_PROFILE];
String key = matcher.group(KEY_SPLITTER_KEY); String key = split[KEY_SPLITTER_KEY];
unsetConfiguration(groupName, profile, key); unsetConfiguration(groupName, profile, key);
} }
}); });
properties.forEach((wholeKey, objValue) -> properties.forEach((wholeKey, objValue) ->
{ {
Matcher matcher = KEY_SPLITTER.matcher((String) wholeKey); String[] split = splitKey((String) wholeKey);
if (!matcher.find()) if (split == null)
{ {
return; return;
} }
String groupName = matcher.group(KEY_SPLITTER_GROUP); String groupName = split[KEY_SPLITTER_GROUP];
String profile = matcher.group(KEY_SPLITTER_PROFILE); String profile = split[KEY_SPLITTER_PROFILE];
String key = matcher.group(KEY_SPLITTER_KEY); String key = split[KEY_SPLITTER_KEY];
String value = String.valueOf(objValue); String value = String.valueOf(objValue);
setConfiguration(groupName, profile, key, value); setConfiguration(groupName, profile, key, value);
}); });
@@ -361,17 +359,17 @@ public class ConfigManager
Map<String, String> copy = (Map) ImmutableMap.copyOf(properties); Map<String, String> copy = (Map) ImmutableMap.copyOf(properties);
copy.forEach((wholeKey, value) -> copy.forEach((wholeKey, value) ->
{ {
Matcher matcher = KEY_SPLITTER.matcher(wholeKey); String[] split = splitKey(wholeKey);
if (!matcher.find()) if (split == null)
{ {
log.debug("Properties key malformed!: {}", wholeKey); log.debug("Properties key malformed!: {}", wholeKey);
properties.remove(wholeKey); properties.remove(wholeKey);
return; return;
} }
String groupName = matcher.group(KEY_SPLITTER_GROUP); String groupName = split[KEY_SPLITTER_GROUP];
String profile = matcher.group(KEY_SPLITTER_PROFILE); String profile = split[KEY_SPLITTER_PROFILE];
String key = matcher.group(KEY_SPLITTER_KEY); String key = split[KEY_SPLITTER_KEY];
ConfigChanged configChanged = new ConfigChanged(); ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName); configChanged.setGroup(groupName);
@@ -937,13 +935,13 @@ public class ConfigManager
continue; continue;
} }
Matcher m = KEY_SPLITTER.matcher(key); String[] split = splitKey(key);
if (!m.find()) if (split == null)
{ {
continue; continue;
} }
profileKeys.add(m.group(KEY_SPLITTER_PROFILE)); profileKeys.add(split[KEY_SPLITTER_PROFILE]);
} }
return profileKeys.stream() return profileKeys.stream()
@@ -1061,6 +1059,34 @@ public class ConfigManager
} }
} }
/**
* Split a config key into (group, profile, key)
* @param key in form group.(rsprofile.profile.)?key
* @return an array of {group, profile, key}
*/
@VisibleForTesting
@Nullable
static String[] splitKey(String key)
{
int i = key.indexOf('.');
if (i == -1)
{
// all keys must have a group and key
return null;
}
String group = key.substring(0, i);
String profile = null;
key = key.substring(i + 1);
if (key.startsWith(RSPROFILE_GROUP + "."))
{
i = key.indexOf('.', RSPROFILE_GROUP.length() + 2); // skip . after RSPROFILE_GROUP
profile = key.substring(0, i);
key = key.substring(i + 1);
}
return new String[]{group, profile, key};
}
private synchronized void migrateConfig() private synchronized void migrateConfig()
{ {
String migrationKey = "profileMigrationDone"; String migrationKey = "profileMigrationDone";
@@ -1108,20 +1134,20 @@ public class ConfigManager
String profKey = profiles.computeIfAbsent(username, u -> String profKey = profiles.computeIfAbsent(username, u ->
findRSProfile(getRSProfiles(), u, RuneScapeProfileType.STANDARD, u, true).getKey()); findRSProfile(getRSProfiles(), u, RuneScapeProfileType.STANDARD, u, true).getKey());
Matcher oldKeyM = KEY_SPLITTER.matcher(oldkey); String[] oldKeySplit = splitKey(oldkey);
if (!oldKeyM.find()) if (oldKeySplit == null)
{ {
log.warn("skipping migration of invalid key \"{}\"", oldkey); log.warn("skipping migration of invalid key \"{}\"", oldkey);
return false; return false;
} }
if (oldKeyM.group(KEY_SPLITTER_PROFILE) != null) if (oldKeySplit[KEY_SPLITTER_PROFILE] != null)
{ {
log.debug("skipping migrated key \"{}\"", oldkey); log.debug("skipping migrated key \"{}\"", oldkey);
return false; return false;
} }
Matcher newKeyM = KEY_SPLITTER.matcher(newKey); String[] newKeySplit = splitKey(newKey);
if (!newKeyM.find() || newKeyM.group(KEY_SPLITTER_PROFILE) != null) if (newKeySplit == null || newKeySplit[KEY_SPLITTER_PROFILE] != null)
{ {
log.warn("migration produced a bad key: \"{}\" -> \"{}\"", oldkey, newKey); log.warn("migration produced a bad key: \"{}\" -> \"{}\"", oldkey, newKey);
return false; return false;
@@ -1142,10 +1168,10 @@ public class ConfigManager
} }
} }
String oldGroup = oldKeyM.group(KEY_SPLITTER_GROUP); String oldGroup = oldKeySplit[KEY_SPLITTER_GROUP];
String oldKeyPart = oldKeyM.group(KEY_SPLITTER_KEY); String oldKeyPart = oldKeySplit[KEY_SPLITTER_KEY];
String value = getConfiguration(oldGroup, oldKeyPart); String value = getConfiguration(oldGroup, oldKeyPart);
setConfiguration(newKeyM.group(KEY_SPLITTER_GROUP), profKey, newKeyM.group(KEY_SPLITTER_KEY), value); setConfiguration(newKeySplit[KEY_SPLITTER_GROUP], profKey, newKeySplit[KEY_SPLITTER_KEY], value);
unsetConfiguration(oldGroup, oldKeyPart); unsetConfiguration(oldGroup, oldKeyPart);
return true; return true;
}); });

View File

@@ -32,7 +32,6 @@ import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import net.runelite.api.Client; import net.runelite.api.Client;
@@ -40,6 +39,7 @@ import net.runelite.client.RuneLite;
import net.runelite.client.account.AccountSession; import net.runelite.client.account.AccountSession;
import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.EventBus;
import org.junit.Assert; import org.junit.Assert;
import static org.junit.Assert.assertNotNull;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -153,11 +153,11 @@ public class ConfigManagerTest
}) })
{ {
String whole = ConfigManager.getWholeKey(test[0], test[1], test[2]); String whole = ConfigManager.getWholeKey(test[0], test[1], test[2]);
Matcher m = ConfigManager.KEY_SPLITTER.matcher(whole); String[] split = ConfigManager.splitKey(whole);
Assert.assertTrue(m.find()); assertNotNull(split);
Assert.assertEquals(m.group(1), test[0]); Assert.assertEquals(split[0], test[0]);
Assert.assertEquals(m.group(2), test[1]); Assert.assertEquals(split[1], test[1]);
Assert.assertEquals(m.group(3), test[2]); Assert.assertEquals(split[2], test[2]);
} }
} }
} }