4: Implement severity in JupiterPerpsAlarm

This commit is contained in:
2026-06-19 11:53:57 +02:00
parent f8003cbeae
commit ec86e6c021
7 changed files with 47 additions and 15 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
# Asset Direction Target TRIGGER SEVERITY NOTE # Asset Direction Target TRIGGER SEVERITY NOTE
############################################################# #############################################################
SOL BELOW 70.0 ONETIME 2 "ALARM: Risiko for Perps Solana long LIKVIDERING!" SOL BELOW 170.0 ONETIME INFO "EMERGENCY: Risiko for Perps Solana long LIKVIDERING!"
SOL BELOW 71.4 ONETIME 2 "ALARM: Risiko for Solana Raydium LÅN LIKVIDERING!" #SOL BELOW 71.4 ONETIME CRITICAL "CRITICAL: Risiko for Solana Raydium LÅN LIKVIDERING!"
@@ -0,0 +1,10 @@
package com.r35157.jupiterperpsalarm;
public enum AlarmSeverity {
EMERGENCY, // Repeated wake-up alarm - sound always
CRITICAL, // One-shot wake-up alarm - sound always
WARN, // Audible warning - respecting quiet hours though
INFO, // Normal notification with visual and audible feedback
SILENT, // Low-priority notification - visual feedback without sound/vibration
GHOST // No visual/audible notification - only visible inside the Pushover app
}
@@ -1,5 +1,7 @@
package com.r35157.jupiterperpsalarm.impl.ref; package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.jupiterperpsalarm.AlarmSeverity;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.file.Files; import java.nio.file.Files;
@@ -44,15 +46,21 @@ public final class AlarmConfigurationParser {
JupiterPerpsAsset asset = JupiterPerpsAsset.valueOf( JupiterPerpsAsset asset = JupiterPerpsAsset.valueOf(
cursor.nextToken("asset").toUpperCase(Locale.ROOT) cursor.nextToken("asset").toUpperCase(Locale.ROOT)
); );
PriceDirection direction = PriceDirection.valueOf( PriceDirection direction = PriceDirection.valueOf(
cursor.nextToken("direction").toUpperCase(Locale.ROOT) cursor.nextToken("direction").toUpperCase(Locale.ROOT)
); );
BigDecimal target = new BigDecimal(cursor.nextToken("target")); BigDecimal target = new BigDecimal(cursor.nextToken("target"));
AlarmTrigger trigger = AlarmTrigger.valueOf( AlarmTrigger trigger = AlarmTrigger.valueOf(
cursor.nextToken("trigger").toUpperCase(Locale.ROOT) cursor.nextToken("trigger").toUpperCase(Locale.ROOT)
); );
int severity = Integer.parseInt(cursor.nextToken("severity"));
AlarmSeverity severity = AlarmSeverity.valueOf(
cursor.nextToken("severity").toUpperCase()
);
String note = cursor.nextQuotedString("note"); String note = cursor.nextQuotedString("note");
cursor.skipWhitespace(); cursor.skipWhitespace();
@@ -89,7 +89,7 @@ public final class JupiterPerpsAlarmImpl {
asset.oracleAccount() asset.oracleAccount()
); );
assetDefinitions.forEach(definition -> System.out.printf( assetDefinitions.forEach(definition -> System.out.printf(
" %s %s USD, %s, severity=%d%n", " %s %s USD, %s, severity=%s%n",
definition.direction(), definition.direction(),
definition.target().toPlainString(), definition.target().toPlainString(),
definition.trigger(), definition.trigger(),
@@ -1,5 +1,7 @@
package com.r35157.jupiterperpsalarm.impl.ref; package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.jupiterperpsalarm.AlarmSeverity;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Objects; import java.util.Objects;
@@ -8,7 +10,7 @@ public record PriceAlarmDefinition(
PriceDirection direction, PriceDirection direction,
BigDecimal target, BigDecimal target,
AlarmTrigger trigger, AlarmTrigger trigger,
int severity, AlarmSeverity severity,
String note String note
) { ) {
public PriceAlarmDefinition { public PriceAlarmDefinition {
@@ -21,8 +23,5 @@ public record PriceAlarmDefinition(
if (target.signum() <= 0) { if (target.signum() <= 0) {
throw new IllegalArgumentException("Target price must be positive"); throw new IllegalArgumentException("Target price must be positive");
} }
if (severity < 0) {
throw new IllegalArgumentException("Severity must be zero or positive");
}
} }
} }
@@ -1,5 +1,7 @@
package com.r35157.jupiterperpsalarm.impl.ref; package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.jupiterperpsalarm.AlarmSeverity;
import java.net.URI; import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.net.http.HttpClient; import java.net.http.HttpClient;
@@ -28,13 +30,13 @@ public final class PushoverAlarmAction implements AlarmAction {
price.slot() price.slot()
); );
// Severity and note are intentionally parsed and retained in the model, // TODO: Note is intentionally parsed and retained in the model, but are not used by Pushover yet.
// but are not used by Pushover yet. // https://git.r35157.com/r35157/com_r35157_nenjim-hubd-impl_ref/issues/7
String body = form("token", applicationToken) + "&" + String body = form("token", applicationToken) + "&" +
form("user", userKey) + "&" + form("user", userKey) + "&" +
form("title", title) + "&" + form("title", title) + "&" +
form("message", message) + "&" + form("message", message) + "&" +
"priority=2&retry=30&expire=10800&sound=persistent"; createPushoverSeverityParameters(alarm.severity());;
HttpRequest request = HttpRequest.newBuilder(PUSHOVER_URI) HttpRequest request = HttpRequest.newBuilder(PUSHOVER_URI)
.timeout(Duration.ofSeconds(15)) .timeout(Duration.ofSeconds(15))
@@ -56,7 +58,7 @@ public final class PushoverAlarmAction implements AlarmAction {
response.body() response.body()
); );
} else { } else {
System.out.println("Pushover emergency alarm sent."); System.out.println("Pushover alarm sent: " + alarm.severity());
} }
}); });
} }
@@ -66,6 +68,17 @@ public final class PushoverAlarmAction implements AlarmAction {
URLEncoder.encode(value, StandardCharsets.UTF_8); URLEncoder.encode(value, StandardCharsets.UTF_8);
} }
private static String createPushoverSeverityParameters(AlarmSeverity severity) {
return switch (severity) {
case EMERGENCY -> "priority=2&retry=30&expire=10800&sound=persistent";
case CRITICAL -> "priority=1&sound=spacealarm";
case WARN -> "priority=0&sound=siren";
case INFO -> "priority=0";
case SILENT -> "priority=-1";
case GHOST -> "priority=-2";
};
}
private final HttpClient httpClient = HttpClient.newHttpClient(); private final HttpClient httpClient = HttpClient.newHttpClient();
private final String applicationToken; private final String applicationToken;
private final String userKey; private final String userKey;
@@ -1,5 +1,7 @@
package com.r35157.jupiterperpsalarm.impl.ref; package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.jupiterperpsalarm.AlarmSeverity;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
@@ -17,14 +19,14 @@ public final class SelfTest {
private static void configurationParserTest() { private static void configurationParserTest() {
PriceAlarmDefinition alarm = AlarmConfigurationParser.parseLine( PriceAlarmDefinition alarm = AlarmConfigurationParser.parseLine(
"SOL ABOVE 75.7 ONETIME 2 \"ALARM: Risiko for likvidering!\"" "SOL ABOVE 75.7 ONETIME CRITICAL \"ALARM: Risiko for likvidering!\""
); );
require(alarm.asset() == JupiterPerpsAsset.SOL, "Asset parsing failed"); require(alarm.asset() == JupiterPerpsAsset.SOL, "Asset parsing failed");
require(alarm.direction() == PriceDirection.ABOVE, "Direction parsing failed"); require(alarm.direction() == PriceDirection.ABOVE, "Direction parsing failed");
require(alarm.target().compareTo(new BigDecimal("75.7")) == 0, "Target parsing failed"); require(alarm.target().compareTo(new BigDecimal("75.7")) == 0, "Target parsing failed");
require(alarm.trigger() == AlarmTrigger.ONETIME, "Trigger parsing failed"); require(alarm.trigger() == AlarmTrigger.ONETIME, "Trigger parsing failed");
require(alarm.severity() == 2, "Severity parsing failed"); require(alarm.severity() == AlarmSeverity.CRITICAL, "Severity parsing failed");
require(alarm.note().equals("ALARM: Risiko for likvidering!"), "Note parsing failed"); require(alarm.note().equals("ALARM: Risiko for likvidering!"), "Note parsing failed");
} }
@@ -89,7 +91,7 @@ public final class SelfTest {
direction, direction,
new BigDecimal(target), new BigDecimal(target),
trigger, trigger,
2, AlarmSeverity.CRITICAL,
"ignored for now" "ignored for now"
); );
} }