46: Support human-readable time units for PERSISTENT alarm grace periods
This commit is contained in:
+59
-26
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class AlarmConfigurationParser {
|
||||
|
||||
@@ -91,41 +93,24 @@ public final class AlarmConfigurationParser {
|
||||
String normalized = triggerText.toUpperCase(Locale.ROOT);
|
||||
|
||||
if (normalized.equals("ONETIME")) {
|
||||
return new TriggerConfiguration(AlarmTrigger.ONETIME, 0);
|
||||
return new TriggerConfiguration(AlarmTrigger.ONETIME, 0L);
|
||||
}
|
||||
|
||||
if (normalized.equals("CROSSING")) {
|
||||
return new TriggerConfiguration(AlarmTrigger.CROSSING, 0);
|
||||
return new TriggerConfiguration(AlarmTrigger.CROSSING, 0L);
|
||||
}
|
||||
|
||||
if (normalized.equals("PERSISTENT")) {
|
||||
return new TriggerConfiguration(AlarmTrigger.PERSISTENT, 0);
|
||||
return new TriggerConfiguration(AlarmTrigger.PERSISTENT, 0L);
|
||||
}
|
||||
|
||||
if (normalized.startsWith("PERSISTENT:")) {
|
||||
String graceText = normalized.substring("PERSISTENT:".length());
|
||||
String graceText = triggerText.substring("PERSISTENT:".length());
|
||||
|
||||
if (graceText.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing persistent grace period: " + triggerText);
|
||||
}
|
||||
|
||||
ΩsecondsΩ gracePeriodSeconds;
|
||||
try {
|
||||
gracePeriodSeconds = Integer.parseInt(graceText);
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid persistent grace period: " + triggerText,
|
||||
exception
|
||||
);
|
||||
}
|
||||
|
||||
if (gracePeriodSeconds < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Persistent grace period cannot be negative: " + triggerText
|
||||
);
|
||||
}
|
||||
|
||||
return new TriggerConfiguration(AlarmTrigger.PERSISTENT, gracePeriodSeconds);
|
||||
return new TriggerConfiguration(
|
||||
AlarmTrigger.PERSISTENT,
|
||||
parsePersistentGracePeriod(graceText)
|
||||
);
|
||||
}
|
||||
|
||||
if (normalized.startsWith("ONETIME:")) {
|
||||
@@ -139,6 +124,51 @@ public final class AlarmConfigurationParser {
|
||||
throw new IllegalArgumentException("Unknown trigger: " + triggerText);
|
||||
}
|
||||
|
||||
private static ΩmilliSecondsΩ parsePersistentGracePeriod(String graceText) {
|
||||
Matcher matcher = PERSISTENT_GRACE_PERIOD_PATTERN.matcher(graceText);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
throw invalidPersistentGracePeriod(graceText);
|
||||
}
|
||||
|
||||
try {
|
||||
long value = Long.parseLong(matcher.group(1));
|
||||
long millisecondsPerUnit = switch (matcher.group(2)) {
|
||||
case "ms" -> 1L;
|
||||
case "s" -> 1_000L;
|
||||
case "m" -> 60_000L;
|
||||
case "h" -> 3_600_000L;
|
||||
case "d" -> 86_400_000L;
|
||||
case "w" -> 604_800_000L;
|
||||
case "M" -> 2_592_000_000L;
|
||||
case "y" -> 31_536_000_000L;
|
||||
default -> throw new AssertionError("Unsupported grace period suffix");
|
||||
};
|
||||
|
||||
return Math.multiplyExact(value, millisecondsPerUnit);
|
||||
} catch (NumberFormatException | ArithmeticException exception) {
|
||||
throw invalidPersistentGracePeriod(graceText, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static IllegalArgumentException invalidPersistentGracePeriod(
|
||||
String graceText
|
||||
) {
|
||||
return invalidPersistentGracePeriod(graceText, null);
|
||||
}
|
||||
|
||||
private static IllegalArgumentException invalidPersistentGracePeriod(
|
||||
String graceText,
|
||||
Exception cause
|
||||
) {
|
||||
return new IllegalArgumentException(
|
||||
"Invalid persistent grace period '" + graceText
|
||||
+ "'. Expected a non-negative whole number followed by one of: "
|
||||
+ "ms, s, m, h, d, w, M, y",
|
||||
cause
|
||||
);
|
||||
}
|
||||
|
||||
private static final class Cursor {
|
||||
private Cursor(String line) {
|
||||
this.line = line;
|
||||
@@ -245,10 +275,13 @@ public final class AlarmConfigurationParser {
|
||||
|
||||
private record TriggerConfiguration(
|
||||
AlarmTrigger trigger,
|
||||
ΩsecondsΩ gracePeriod
|
||||
ΩmilliSecondsΩ gracePeriod
|
||||
) {
|
||||
}
|
||||
|
||||
private static final Pattern PERSISTENT_GRACE_PERIOD_PATTERN =
|
||||
Pattern.compile("(\\d+)(ms|s|m|h|d|w|M|y)");
|
||||
|
||||
private AlarmConfigurationParser() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +91,14 @@ public final class PriceAlarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
ΩsecondsΩ gracePeriod = definition.triggerGracePeriod();
|
||||
ΩmilliSecondsΩ gracePeriod = definition.triggerGracePeriod();
|
||||
|
||||
if (gracePeriod == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !Instant.now().isBefore(
|
||||
lastTriggeredAt.plusSeconds(gracePeriod)
|
||||
lastTriggeredAt.plusMillis(gracePeriod)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ public record PriceAlarmDefinition(
|
||||
JupiterPerpsAsset asset,
|
||||
String conditionExpression,
|
||||
AlarmTrigger trigger,
|
||||
ΩsecondsΩ triggerGracePeriod
|
||||
ΩmilliSecondsΩ triggerGracePeriod
|
||||
) {
|
||||
public PriceAlarmDefinition {
|
||||
Objects.requireNonNull(asset, "asset");
|
||||
|
||||
@@ -5,6 +5,6 @@ public record ResolvedPriceAlarm(
|
||||
JupiterPerpsAsset asset,
|
||||
PriceCondition condition,
|
||||
AlarmTrigger trigger,
|
||||
ΩsecondsΩ triggerGracePeriod
|
||||
ΩmilliSecondsΩ triggerGracePeriod
|
||||
) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user