Changed Autoanswer implementation (cooldown timer, message routing) and its documentation
This commit is contained in:
@@ -43,7 +43,7 @@ public class ApplicationConstants {
|
||||
|
||||
public static final String DISCONNECT_RDR_POISONPILL = "UNKNOWN: KST4C KILL POISONPILL_KILLTHREAD=: " + sessionRuntimeUniqueId; //whereever a (blocking) udp or tcp reader in an infinite loop gets this message, it will break this loop
|
||||
|
||||
public static final String AUTOANSWER_PREFIX = "[KST4C Automsg] "; // hard-coded marker (user can't remove it)
|
||||
public static final String AUTOANSWER_PREFIX = "[KST4C Automsg]"; // hard-coded marker (user cannot remove it)
|
||||
|
||||
/**
|
||||
* UI message retention limits.
|
||||
|
||||
@@ -47,13 +47,12 @@ public class MessageBusManagementThread extends Thread {
|
||||
private final String PTRN_QRG_CAT3 = "(([0-9]{3,5}[\\.|,| ]?[0-9]{3})([\\.|,][\\d]{1,2})?)|(([a-zA-Z][0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)|((\\b[0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)";
|
||||
|
||||
|
||||
// ==== Autoanswer Flood/Pingpong Protection ====
|
||||
private static final String AUTOANSWER_PREFIX = ApplicationConstants.AUTOANSWER_PREFIX; // hard-coded marker (user can't remove it)
|
||||
private static final long AUTOANSWER_COOLDOWN_MS = 45_000L; // 45_000L = 45s
|
||||
// ==== Auto-answer flood/ping-pong protection ====
|
||||
private static final String AUTOANSWER_PREFIX = ApplicationConstants.AUTOANSWER_PREFIX;
|
||||
private static final long AUTOANSWER_COOLDOWN_MS = 120_000L; // two minutes
|
||||
|
||||
// Cooldown per opponent station (and ChatCategory) – only setted if this client sends
|
||||
// Cooldown per remote station and chat category; updated only after this client sends.
|
||||
private final Hashtable<String, Long> lastLocalAutoAnswerPerRemoteMs = new Hashtable<>();
|
||||
|
||||
// BufferedWriter bufwrtrDBGMSGOut;
|
||||
|
||||
// private String text;
|
||||
@@ -829,7 +828,11 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
versionInfo.setSender(itsMe);
|
||||
versionInfo.setReceiver(newMessageArrived.getSender());
|
||||
versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + " " + ApplicationConstants.AUTOANSWER_PREFIX + " " + "KST4Contest " + " v" + ApplicationConstants.APPLICATION_CURRENT_VERSION + " by DO5AMF");
|
||||
versionInfo.setChatCategory(newMessageArrived.getChatCategory());
|
||||
versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign()
|
||||
+ " " + AUTOANSWER_PREFIX
|
||||
+ " KST4Contest v" + ApplicationConstants.APPLICATION_CURRENT_VERSION
|
||||
+ " by DO5AMF");
|
||||
|
||||
this.client.getMessageTXBus().add(versionInfo);
|
||||
}
|
||||
@@ -876,11 +879,11 @@ public class MessageBusManagementThread extends Thread {
|
||||
// }
|
||||
// }
|
||||
|
||||
// ==== Unified Autoanswer (Generic + QRG) with Pingpong-Guard + per-Remote Cooldown ====
|
||||
// ==== Unified auto-answer (generic + QRG) with ping-pong guard and per-remote cooldown ====
|
||||
final String incomingText = newMessageArrived.getMessageText();
|
||||
final String incomingLower = (incomingText == null) ? "" : incomingText.toLowerCase(Locale.ROOT);
|
||||
|
||||
// 1) Pingpong-security: never ever react to auto generated messages
|
||||
// Never answer another automatically generated message.
|
||||
if (!isAutoMessage(newMessageArrived)) {
|
||||
|
||||
boolean qrgRequested = false;
|
||||
@@ -896,24 +899,17 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
boolean genericEnabled = this.client.getChatPreferences().isMsgHandling_autoAnswerEnabled();
|
||||
|
||||
// 2) Entscheide, ob überhaupt geantwortet wird (QRG hat Vorrang vor Generic)
|
||||
// A QRG reply takes precedence over the generic reply.
|
||||
String payload = null;
|
||||
|
||||
if (qrgRequested) {
|
||||
|
||||
if (this.client.getChatPreferences().isLoginToSecondChatEnabled()) {
|
||||
payload = "QRGs: " + this.client.getChatPreferences().getMYQRGFirstCat().getValue()
|
||||
+ " / " + this.client.getChatPreferences().getMYQRGSecondCat().getValue();
|
||||
} else {
|
||||
payload = "QRG is: " + this.client.getChatPreferences().getMYQRGFirstCat().getValue();
|
||||
}
|
||||
|
||||
payload = "QRG is: " + getAutoAnswerQrgForCategory(newMessageArrived.getChatCategory());
|
||||
} else if (genericEnabled) {
|
||||
|
||||
payload = this.client.getChatPreferences().getMessageHandling_autoAnswerTextMainCat();
|
||||
}
|
||||
|
||||
// 3) Cooldown pro Gegenstation: nur wenn DIESER Client jetzt wirklich sendet
|
||||
// Apply the cooldown only when this client is about to send a reply.
|
||||
if (payload != null && isAutoAnswerAllowedNow(newMessageArrived)) {
|
||||
|
||||
ChatMessage automaticAnswer = new ChatMessage();
|
||||
@@ -922,15 +918,15 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
automaticAnswer.setSender(itsMe);
|
||||
automaticAnswer.setReceiver(newMessageArrived.getSender());
|
||||
automaticAnswer.setChatCategory(newMessageArrived.getChatCategory());
|
||||
|
||||
// Prefix fest + nicht entfernbar, damit Auto↔Auto nicht pingpongt
|
||||
// The fixed prefix prevents automatic clients from answering each other.
|
||||
automaticAnswer.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign()
|
||||
+ " " + AUTOANSWER_PREFIX + " " + payload);
|
||||
|
||||
this.client.getMessageTXBus().add(automaticAnswer);
|
||||
|
||||
// Cooldown wird NUR hier gesetzt (nicht bei 'message sent by me' Echo),
|
||||
// damit nur lokale Auto-Sends zählen.
|
||||
// Record only locally generated replies, not the later server echo.
|
||||
markLocalAutoAnswerSent(newMessageArrived);
|
||||
}
|
||||
}
|
||||
@@ -1544,9 +1540,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
|
||||
/**
|
||||
* check if message had been auto generated
|
||||
* @param msg
|
||||
* @return
|
||||
* Returns whether a message carries the fixed marker used for automatic replies.
|
||||
*/
|
||||
private boolean isAutoMessage(ChatMessage msg) {
|
||||
return msg != null
|
||||
@@ -1554,6 +1548,22 @@ public class MessageBusManagementThread extends Thread {
|
||||
&& msg.getMessageText().contains(AUTOANSWER_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured QRG for the category in which the request was received.
|
||||
* If the category cannot be resolved, the main category remains the safe fallback.
|
||||
*/
|
||||
private String getAutoAnswerQrgForCategory(ChatCategory incomingCategory) {
|
||||
ChatCategory secondCategory = this.client.getChatCategorySecondChat();
|
||||
|
||||
if (incomingCategory != null
|
||||
&& secondCategory != null
|
||||
&& incomingCategory.getCategoryNumber() == secondCategory.getCategoryNumber()) {
|
||||
return this.client.getChatPreferences().getMYQRGSecondCat().getValue();
|
||||
}
|
||||
|
||||
return this.client.getChatPreferences().getMYQRGFirstCat().getValue();
|
||||
}
|
||||
|
||||
private String autoAnswerCooldownKey(ChatMessage incoming) {
|
||||
|
||||
String remoteCall = "UNKNOWN";
|
||||
@@ -1561,13 +1571,16 @@ public class MessageBusManagementThread extends Thread {
|
||||
remoteCall = incoming.getSender().getCallSign().toUpperCase();
|
||||
}
|
||||
|
||||
int cat = 0; // fallback
|
||||
if (incoming != null && incoming.getSender() != null && incoming.getSender().getChatCategory() != null) {
|
||||
cat = incoming.getSender().getChatCategory().getCategoryNumber();
|
||||
int categoryNumber = 0;
|
||||
if (incoming != null && incoming.getChatCategory() != null) {
|
||||
categoryNumber = incoming.getChatCategory().getCategoryNumber();
|
||||
} else if (incoming != null
|
||||
&& incoming.getSender() != null
|
||||
&& incoming.getSender().getChatCategory() != null) {
|
||||
categoryNumber = incoming.getSender().getChatCategory().getCategoryNumber();
|
||||
}
|
||||
|
||||
// pro Gegenstation + pro Chat-Kategorie (falls derselbe Call in Cat2/Cat3 PMs macht)
|
||||
return remoteCall + "|" + cat;
|
||||
return remoteCall + "|" + categoryNumber;
|
||||
}
|
||||
|
||||
private boolean isAutoAnswerAllowedNow(ChatMessage incoming) {
|
||||
|
||||
@@ -2692,6 +2692,14 @@ public class ChatPreferences {
|
||||
messageHandling_autoAnswerEnabledSecondCat,
|
||||
"messageHandling_autoAnswerEnabledSecondCat",
|
||||
"autoAnswerEnabledSecondCat");
|
||||
|
||||
/*
|
||||
* The user interface intentionally exposes one shared generic auto-answer
|
||||
* setting for both chat categories. Keep the legacy second-category XML
|
||||
* fields synchronized so existing configuration files remain compatible.
|
||||
*/
|
||||
messageHandling_autoAnswerTextSecondCat = messageHandling_autoAnswerTextMainCat;
|
||||
messageHandling_autoAnswerEnabledSecondCat = messageHandling_autoAnswerEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10472,38 +10472,37 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
// CheckBox chkBxEnableTRXMsgbyUCX = new CheckBox();
|
||||
|
||||
grdPnlMessageHandlingBeacon.add(generateLabeledSeparator(100,
|
||||
"Set the unworked penetrator Beacons (intervalled PM to unworked stations)"), 0, 0, 2, 1);
|
||||
|
||||
grdPnlMessageHandlingBeacon.add(generateLabeledSeparator(100,
|
||||
"Automatic answering options)"), 0, 1, 2, 1);
|
||||
"Automatic answering options"), 0, 0, 2, 1);
|
||||
|
||||
// Label lbl_unwkd_autoAnswerDescriptor = new Label("Auto-answer Text:");
|
||||
// grdPnlMessageHandlingBeacon.add(lbl_unwkd_autoAnswerDescriptor,0,3);
|
||||
|
||||
CheckBox chkbx_msgHandlingAutoAnswerEnabled = new CheckBox("Auto-reply (to all queries): ");
|
||||
chkbx_msgHandlingAutoAnswerEnabled.setTooltip(new Tooltip("KST4Contest will answer for you with your pre-definied text to all PMs"));
|
||||
CheckBox chkbx_msgHandlingAutoAnswerEnabled = new CheckBox("Enable automatic reply to all private messages");
|
||||
chkbx_msgHandlingAutoAnswerEnabled.setTooltip(new Tooltip(
|
||||
"KST4Contest replies with the configured text in the chat category from which the private message was received.\n"
|
||||
+ "The same station can receive one automatic reply per chat category every two minutes."));
|
||||
chkbx_msgHandlingAutoAnswerEnabled.setSelected(this.chatcontroller.getChatPreferences().isMsgHandling_autoAnswerEnabled());
|
||||
chkbx_msgHandlingAutoAnswerEnabled.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
|
||||
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerEnabled(chkbx_msgHandlingAutoAnswerEnabled.isSelected());
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerEnabledSecondCat(chkbx_msgHandlingAutoAnswerEnabled.isSelected());
|
||||
System.out.println("[Main.java, Info]: Autoreply turned on: " + newValue);
|
||||
}
|
||||
});
|
||||
|
||||
CheckBox chkbx_messageHandlingAutoQRGInfoEnabled = new CheckBox("Enable auto-reply with my QRG on QRG-request");
|
||||
|
||||
String changeMeToPreferences = "";
|
||||
changeMeToPreferences += ("ur qrg?\n");
|
||||
changeMeToPreferences += ("your qrg?\n");
|
||||
changeMeToPreferences += ("qrg?\n");
|
||||
changeMeToPreferences += ("freq?\n");
|
||||
changeMeToPreferences += ("pse QRG\n");
|
||||
|
||||
chkbx_messageHandlingAutoQRGInfoEnabled.setTooltip(new Tooltip("KST4Contest can answer with your QRG automatically. Following Strings causing reaction: \n " + changeMeToPreferences));
|
||||
CheckBox chkbx_messageHandlingAutoQRGInfoEnabled = new CheckBox("Enable automatic QRG replies");
|
||||
|
||||
String qrgRequestExamples = "ur qrg?\n"
|
||||
+ "your qrg?\n"
|
||||
+ "qrg?\n"
|
||||
+ "freq?\n"
|
||||
+ "pse qrg";
|
||||
|
||||
chkbx_messageHandlingAutoQRGInfoEnabled.setTooltip(new Tooltip(
|
||||
"KST4Contest replies with the QRG configured for the chat category in which the request was received.\n"
|
||||
+ "Recognized text:\n" + qrgRequestExamples));
|
||||
chkbx_messageHandlingAutoQRGInfoEnabled.setSelected(this.chatcontroller.getChatPreferences().isMessageHandling_autoAnswerToQRGRequestEnabled());
|
||||
chkbx_messageHandlingAutoQRGInfoEnabled.selectedProperty().addListener(new ChangeListener<Boolean>() {
|
||||
@Override
|
||||
@@ -10515,22 +10514,22 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
});
|
||||
|
||||
TextField txtFld_messageHandlingAutoAnswer = new TextField();
|
||||
txtFld_messageHandlingAutoAnswer.setPrefWidth(400);
|
||||
txtFld_messageHandlingAutoAnswer.setText(this.chatcontroller.getChatPreferences().getMessageHandling_autoAnswerTextMainCat());
|
||||
txtFld_messageHandlingAutoAnswer.textProperty().addListener(new ChangeListener<String>() {
|
||||
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observed, String oldString, String newString) {
|
||||
System.out.println("[Main.java, Info]: Setted the autoanswer: " + txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextMainCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextSecondCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
|
||||
System.out.println("[Main.java, Info]: Set the auto-answer text: " + newString);
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextMainCat(newString);
|
||||
chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextSecondCat(newString);
|
||||
}
|
||||
});
|
||||
|
||||
grdPnlMessageHandlingBeacon.add(chkbx_msgHandlingAutoAnswerEnabled, 0, 1);
|
||||
grdPnlMessageHandlingBeacon.add(txtFld_messageHandlingAutoAnswer, 1, 1);
|
||||
|
||||
grdPnlMessageHandlingBeacon.add(txtFld_messageHandlingAutoAnswer,1,2);
|
||||
grdPnlMessageHandlingBeacon.add(chkbx_msgHandlingAutoAnswerEnabled,0,2);
|
||||
|
||||
grdPnlMessageHandlingBeacon.add(chkbx_messageHandlingAutoQRGInfoEnabled,0,4, 2,1);
|
||||
grdPnlMessageHandlingBeacon.add(chkbx_messageHandlingAutoQRGInfoEnabled, 0, 2, 2, 1);
|
||||
|
||||
VBox vbxMsgHandlBeacon = new VBox();
|
||||
vbxMsgHandlBeacon.setPadding(new Insets(10, 10, 10, 10));
|
||||
|
||||
Reference in New Issue
Block a user