mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-09-11 11:45:27 +02:00
refactoring of the SimpleLogFile-parser
This commit is contained in:
@@ -3,6 +3,7 @@ package kst4contest.controller;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.SQLException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
@@ -2016,6 +2017,115 @@ private ObservableList<String>
|
||||
return matchingMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the global Worked state from the Simplelogfile to every active
|
||||
* callsign variant with the same base callsign. UI-backed state is changed only
|
||||
* on the JavaFX Application Thread.
|
||||
*
|
||||
* @param workedBaseCalls normalized callsigns detected in the selected file
|
||||
*/
|
||||
public void applySimpleLogWorkedBaseCalls(Set<String> workedBaseCalls) {
|
||||
Set<String> normalizedWorkedBaseCalls = normalizeWorkedBaseCalls(workedBaseCalls);
|
||||
if (normalizedWorkedBaseCalls.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
runOnFxThread(() -> {
|
||||
int changedMembers = markSimpleLogWorkedMembers(
|
||||
activeChatMembersByCallAndCategory.values(), normalizedWorkedBaseCalls);
|
||||
int changedClusterMessages = markSimpleLogWorkedClusterMessages(
|
||||
lst_clusterMemberList, normalizedWorkedBaseCalls);
|
||||
|
||||
if (changedMembers > 0) {
|
||||
fireUserListUpdate("Simplelogfile Worked status updated");
|
||||
}
|
||||
|
||||
LOGGER.log(Level.FINE,
|
||||
"Simplelogfile marked {0} active members and {1} cluster messages as worked.",
|
||||
new Object[] { changedMembers, changedClusterMessages });
|
||||
});
|
||||
}
|
||||
|
||||
static int markSimpleLogWorkedMembers(
|
||||
Collection<ChatMember> members,
|
||||
Set<String> workedBaseCalls
|
||||
) {
|
||||
if (members == null || workedBaseCalls == null || workedBaseCalls.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int changed = 0;
|
||||
for (ChatMember member : members) {
|
||||
if (member == null || member.isWorked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String memberCall = member.getCallSignRaw() != null
|
||||
? member.getCallSignRaw() : member.getCallSign();
|
||||
String baseCall = ChatMember.normalizeCallSignToBaseCallSign(memberCall);
|
||||
if (baseCall != null && workedBaseCalls.contains(baseCall.toUpperCase(Locale.ROOT))) {
|
||||
member.setWorked(true);
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int markSimpleLogWorkedClusterMessages(
|
||||
Collection<ClusterMessage> clusterMessages,
|
||||
Set<String> workedBaseCalls
|
||||
) {
|
||||
if (clusterMessages == null || workedBaseCalls == null || workedBaseCalls.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int changed = 0;
|
||||
for (ClusterMessage clusterMessage : clusterMessages) {
|
||||
if (clusterMessage == null || clusterMessage.isReceiverWkd()
|
||||
|| clusterMessage.getReceiver() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChatMember receiver = clusterMessage.getReceiver();
|
||||
String receiverCall = receiver.getCallSignRaw() != null
|
||||
? receiver.getCallSignRaw() : receiver.getCallSign();
|
||||
String baseCall = ChatMember.normalizeCallSignToBaseCallSign(receiverCall);
|
||||
if (baseCall != null && workedBaseCalls.contains(baseCall.toUpperCase(Locale.ROOT))) {
|
||||
clusterMessage.setReceiverWkd(true);
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static Set<String> normalizeWorkedBaseCalls(Set<String> workedBaseCalls) {
|
||||
if (workedBaseCalls == null || workedBaseCalls.isEmpty()) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
Set<String> normalizedCalls = new HashSet<>();
|
||||
for (String callSign : workedBaseCalls) {
|
||||
String baseCall = ChatMember.normalizeCallSignToBaseCallSign(callSign);
|
||||
if (baseCall != null && !baseCall.isBlank()) {
|
||||
normalizedCalls.add(baseCall.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
return Set.copyOf(normalizedCalls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the UI after a missing Simplelogfile was created successfully.
|
||||
*
|
||||
* @param filePath absolute path of the new file
|
||||
*/
|
||||
public void notifySimpleLogFileCreated(Path filePath) {
|
||||
if (filePath == null || statusListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
runOnFxThread(() -> statusListener.onSimpleLogFileCreated(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the band-specific NOT-QRV state to every active category variant of the
|
||||
* same base callsign. The database already uses callSignRaw as its key; applying
|
||||
@@ -4098,4 +4208,4 @@ private ObservableList<String>
|
||||
|
||||
return "Sniffed: (" + senderCall + " > " + receiverCall + ") " + msgText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import kst4contest.model.ThreadStateMessage;
|
||||
|
||||
public interface StatusUpdateListener {
|
||||
@@ -33,4 +35,13 @@ public interface StatusUpdateListener {
|
||||
// Optional for non-UI listeners.
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Called after KST4Contest successfully creates a missing Simplelogfile.
|
||||
*
|
||||
* @param filePath absolute path of the newly created file
|
||||
*/
|
||||
default void onSimpleLogFileCreated(Path filePath) {
|
||||
// Optional for non-UI listeners.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -14,73 +15,50 @@ import kst4contest.model.ChatMember;
|
||||
|
||||
public class UCXLogFileToHashsetParser {
|
||||
|
||||
public BufferedReader fileReader;
|
||||
// private final String PTRN_CallSign = "(([a-zA-Z]{1,2}[\\d{1}]?\\/)?(\\d{1}[a-zA-Z][\\d{1}][a-zA-Z]{1,3})((\\/p)|(\\/\\d))?)|(([a-zA-Z0-9]{1,2}[\\d{1}]?\\/)?(([a-zA-Z]{1,2}(\\d{1}[a-zA-Z]{1,4})))((\\/p)|(\\/\\d))?)"; //OLD, S51AR for example will not work
|
||||
private final String PTRN_CallSign = "(([a-zA-Z]{1,2}[\\d]{1}?\\/)?(\\d{1}[a-zA-Z][\\d]{1}[a-zA-Z]{1,3})((\\/p)|(\\/\\d))?)|(([a-zA-Z0-9]{1,2}[\\d]{1}?\\/)?(([a-zA-Z]{1,2}(\\d{1}[a-zA-Z]{1,4})))((\\/p)|(\\/\\d))?)|([A-Z]\\d{2}[A-Z]{1,3})";
|
||||
|
||||
private static final Pattern CALL_SIGN_PATTERN = Pattern.compile(
|
||||
"(([a-zA-Z]{1,2}[\\d]{1}?\\/)?(\\d{1}[a-zA-Z][\\d]{1}[a-zA-Z]{1,3})((\\/p)|(\\/\\d))?)"
|
||||
+ "|(([a-zA-Z0-9]{1,2}[\\d]{1}?\\/)?(([a-zA-Z]{1,2}(\\d{1}[a-zA-Z]{1,4})))((\\/p)|(\\/\\d))?)"
|
||||
+ "|([A-Z]\\d{2}[A-Z]{1,3})");
|
||||
|
||||
private final Path logFile;
|
||||
|
||||
public UCXLogFileToHashsetParser(String filePathAndName) {
|
||||
|
||||
try {
|
||||
fileReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filePathAndName))));
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
this.logFile = Path.of(filePathAndName);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a line of the ucxlog-Logfile inhibits a Callsign<br/>
|
||||
* <b>returns ChatMember = null, if no frequency found</b>
|
||||
*
|
||||
* @param chatMessage
|
||||
*/
|
||||
private ChatMember checkIfLineInhibitsCallSign(String line) {
|
||||
|
||||
Pattern pattern = Pattern.compile(PTRN_CallSign);
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
String matchedString = "";
|
||||
private String findLastCallSign(String line) {
|
||||
Matcher matcher = CALL_SIGN_PATTERN.matcher(line);
|
||||
String matchedCallSign = "";
|
||||
|
||||
while (matcher.find()) {
|
||||
|
||||
matchedString = matcher.group();
|
||||
// System.out.println("[UCXLogFile:] Processed worked Callsign from file: " + matchedString);
|
||||
|
||||
matchedCallSign = matcher.group();
|
||||
}
|
||||
|
||||
ChatMember newChatMember = new ChatMember();
|
||||
|
||||
newChatMember.setCallSign(matchedString.toUpperCase());
|
||||
|
||||
return newChatMember;
|
||||
|
||||
return matchedCallSign.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ucxlog-live-file (full qualified path given by constructor
|
||||
* argument), looks by regex for callsigns and builds a hashmap with only one
|
||||
* entry by callsign
|
||||
* Parses the selected log file and returns every detected station as a
|
||||
* normalized base callsign. The reader is closed after each pass so the logging
|
||||
* application can continue replacing or rotating the file.
|
||||
*
|
||||
* @return unique normalized base callsigns found in the file
|
||||
* @throws IOException if the file cannot be read
|
||||
*/
|
||||
public HashMap<String, String> parse() throws IOException {
|
||||
public Set<String> parse() throws IOException {
|
||||
Set<String> workedBaseCalls = new HashSet<>();
|
||||
|
||||
HashMap<String, String> chatMemberMap = new HashMap();
|
||||
|
||||
String line;
|
||||
while ((line = fileReader.readLine()) != null) {
|
||||
// System.out.println("raw: " + line);
|
||||
ChatMember temp = checkIfLineInhibitsCallSign(line);
|
||||
|
||||
if (temp.getCallSign() != "") {
|
||||
chatMemberMap.put(temp.getCallSign(), temp.getCallSign());
|
||||
try (BufferedReader fileReader = Files.newBufferedReader(logFile, Charset.defaultCharset())) {
|
||||
String line;
|
||||
while ((line = fileReader.readLine()) != null) {
|
||||
String matchedCallSign = findLastCallSign(line);
|
||||
String baseCallSign = ChatMember.normalizeCallSignToBaseCallSign(matchedCallSign);
|
||||
if (baseCallSign != null && !baseCallSign.isBlank()) {
|
||||
workedBaseCalls.add(baseCallSign.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println(chatMemberMap.size());
|
||||
return chatMemberMap;
|
||||
|
||||
return workedBaseCalls;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,325 +1,100 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import kst4contest.model.ChatMember;
|
||||
import kst4contest.model.ClusterMessage;
|
||||
import kst4contest.view.GuiUtils;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class UserActualizationTask extends TimerTask {
|
||||
|
||||
private ChatController client;
|
||||
private static final Logger LOGGER = Logger.getLogger(UserActualizationTask.class.getName());
|
||||
|
||||
private final ChatController client;
|
||||
|
||||
public UserActualizationTask(ChatController client) {
|
||||
|
||||
this.client = client;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Thread.currentThread().setName("UserActualizationTask");
|
||||
|
||||
/*
|
||||
* File-based log synchronization is optional. Do not create, open or parse the
|
||||
* configured file while the feature is disabled.
|
||||
*/
|
||||
try {
|
||||
updateWorkedCallSignsFromFile();
|
||||
} catch (RuntimeException exception) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unexpected failure while updating Worked callsigns from the Simplelogfile; "
|
||||
+ "the periodic task will continue.",
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWorkedCallSignsFromFile() {
|
||||
if (!client.getChatPreferences().isLogsynch_fileBasedWkdCallInterpreterEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// System.out.println("[Useract: ] Thread runned now");
|
||||
|
||||
// System.out.println("***********************Useract started");
|
||||
|
||||
/**
|
||||
* ******************************************since here: old mechanic for
|
||||
* marking worked stations by .ucx-file
|
||||
*/
|
||||
|
||||
HashMap<String, String> fetchedWorkedSet = new HashMap<>();
|
||||
// HashMap<String, String> fetchedWorkedSetUdpBckup = new HashMap<>();
|
||||
|
||||
File f = new File(this.client.getChatPreferences().getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly());
|
||||
if (!f.exists() && !f.isDirectory()) {
|
||||
try {
|
||||
f.createNewFile();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
String configuredFileName = client.getChatPreferences()
|
||||
.getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly();
|
||||
if (configuredFileName == null || configuredFileName.isBlank()) {
|
||||
LOGGER.warning("Cannot read the Simplelogfile because no file is selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
UCXLogFileToHashsetParser getWorkedCallsignsOfUCXLogFile = new UCXLogFileToHashsetParser(
|
||||
this.client.getChatPreferences().getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly());
|
||||
final Path logFile;
|
||||
try {
|
||||
logFile = Path.of(configuredFileName).toAbsolutePath().normalize();
|
||||
} catch (InvalidPathException exception) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Cannot use the configured Simplelogfile path: " + configuredFileName,
|
||||
exception);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean created = createMissingLogFile(logFile);
|
||||
if (!Files.isRegularFile(logFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fetchedWorkedSet = getWorkedCallsignsOfUCXLogFile.parse();
|
||||
|
||||
System.out.println("USERACT: fetchedWorkedSet size: " + fetchedWorkedSet.size());
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Set<String> workedBaseCalls = new UCXLogFileToHashsetParser(logFile.toString()).parse();
|
||||
client.applySimpleLogWorkedBaseCalls(workedBaseCalls);
|
||||
LOGGER.log(Level.FINE,
|
||||
"Read {0} unique base callsigns from Simplelogfile {1}.",
|
||||
new Object[] { workedBaseCalls.size(), logFile });
|
||||
} catch (IOException exception) {
|
||||
LOGGER.log(Level.WARNING, "Cannot read Simplelogfile " + logFile, exception);
|
||||
}
|
||||
|
||||
ObservableList<ChatMember> praktiKSTActiveUserList = this.client.getLst_chatMemberList();
|
||||
|
||||
for (Iterator iterator = praktiKSTActiveUserList.iterator(); iterator.hasNext();) {
|
||||
ChatMember chatMember = (ChatMember) iterator.next();
|
||||
|
||||
// System.out.println(chatMember.getCallSign());
|
||||
// System.out.println("USERACT active user list entries " + praktiKSTActiveUserList.size());
|
||||
|
||||
if (fetchedWorkedSet.containsKey(chatMember.getCallSign())) {
|
||||
chatMember.setWorked(true);
|
||||
System.out.println("[USERACT, info:] marking Chatuser " + chatMember.getCallSign()
|
||||
+ " as worked, based on READONLY-Logfile.");
|
||||
}
|
||||
|
||||
// if (fetchedWorkedSetUdpBckup.containsKey(chatMember.getCallSign())) {
|
||||
// chatMember.setWorked(true);
|
||||
// System.out.println("[USERACT, info:] marking Chatuser " + chatMember.getCallSign() + " as worked, based on UDPLsnBackup-Logfile.");
|
||||
// }
|
||||
// GuiUtils.triggerGUIFilteredChatMemberListChange(this.client); //todo: quick and dirty gui fix
|
||||
if (created) {
|
||||
client.notifySimpleLogFileCreated(logFile);
|
||||
}
|
||||
|
||||
ObservableList<ClusterMessage> praktiKSTClusterList = this.client.getLst_clusterMemberList();
|
||||
|
||||
for (Iterator iterator = praktiKSTClusterList.iterator(); iterator.hasNext();) {
|
||||
ClusterMessage clusterMessage = (ClusterMessage) iterator.next();
|
||||
|
||||
if (fetchedWorkedSet.containsKey(clusterMessage.getReceiver().getCallSign())) {
|
||||
clusterMessage.setReceiverWkd(true);
|
||||
System.out.println("[USERACT, info:] marking Clusterspotted "
|
||||
+ clusterMessage.getReceiver().getCallSign() + " as worked.");
|
||||
}
|
||||
|
||||
// if (fetchedWorkedSetUdpBckup.containsKey(clusterMessage.getReceiver().getCallSign())) {
|
||||
// clusterMessage.setReceiverWkd(true);
|
||||
// System.out.println("[USERACT, info:] marking Clusterspotted "
|
||||
// + clusterMessage.getReceiver().getCallSign() + " as worked.");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ******************************************end here: old mechanic for marking
|
||||
* worked stations by .ucx-file
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ******************************************since here: new mechanic for
|
||||
* marking worked stations by udp/adif based information
|
||||
*/
|
||||
// HashMap<String, String> fetchedWorkedMap = new HashMap<>();
|
||||
//
|
||||
// fetchedWorkedMap = this.client.getMap_ucxLogInfoWorkedCalls();
|
||||
|
||||
// ObservableList<ChatMember> praktiKSTActiveUserList1 = this.client.getLst_chatMemberList();
|
||||
//
|
||||
// for (Iterator iterator = praktiKSTActiveUserList.iterator(); iterator.hasNext();) {
|
||||
// ChatMember chatMember = (ChatMember) iterator.next();
|
||||
//
|
||||
// if (fetchedWorkedMap.containsKey(chatMember.getCallSign())) {
|
||||
// chatMember.setWorked(true);
|
||||
// System.out.println("[USERACT, info:] marking Chatuser " + chatMember.getCallSign() + " as worked based on UDP Log Info Collector.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// ObservableList<ClusterMessage> praktiKSTClusterList1 = this.client.getLst_clusterMemberList();
|
||||
//
|
||||
// for (Iterator iterator = praktiKSTClusterList.iterator(); iterator.hasNext();) {
|
||||
// ClusterMessage clusterMessage = (ClusterMessage) iterator.next();
|
||||
//
|
||||
// if (fetchedWorkedMap.containsKey(clusterMessage.getReceiver().getCallSign())) {
|
||||
// clusterMessage.setReceiverWkd(true);
|
||||
// System.out.println("[USERACT, info:] marking Clusterspotted "
|
||||
// + clusterMessage.getReceiver().getCallSign() + " as worked based on UDP Log Info Collector.");
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
//
|
||||
// UCXLogFileToHashsetParser getWorkedCallsignsOfUCXLogFile = new UCXLogFileToHashsetParser(
|
||||
// "C:\\UcxLog\\Logs\\DO5AMF\\DVU322_I.UCX");
|
||||
// try {
|
||||
// fetchedWorkedSet = getWorkedCallsignsOfUCXLogFile.parse();
|
||||
// } catch (IOException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// ObservableList<ChatMember> praktiKSTActiveUserList = this.client.getLst_chatMemberList();
|
||||
//
|
||||
// for (Iterator iterator = praktiKSTActiveUserList.iterator(); iterator.hasNext();) {
|
||||
// ChatMember chatMember = (ChatMember) iterator.next();
|
||||
//
|
||||
// if (fetchedWorkedSet.containsKey(chatMember.getCallSign())) {
|
||||
// chatMember.setWorked(true);
|
||||
// System.out.println("[USERACT, info:] marking Chatuser " + chatMember.getCallSign() + " as worked.");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// ObservableList<ClusterMessage> praktiKSTClusterList = this.client.getLst_clusterMemberList();
|
||||
//
|
||||
// for (Iterator iterator = praktiKSTClusterList.iterator(); iterator.hasNext();) {
|
||||
// ClusterMessage clusterMessage = (ClusterMessage) iterator.next();
|
||||
//
|
||||
// if (fetchedWorkedSet.containsKey(clusterMessage.getReceiver().getCallSign())) {
|
||||
// clusterMessage.setReceiverWkd(true);
|
||||
// System.out.println("[USERACT, info:] marking Clusterspotted "
|
||||
// + clusterMessage.getReceiver().getCallSign() + " as worked.");
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* ******************************************end here: new mechanic for marking
|
||||
* worked stations by udp/adif based information
|
||||
*
|
||||
*/
|
||||
|
||||
// System.out.println("[UserActualizationtask:] Userlist actualization will be performed now. "
|
||||
// + LocalDateTime.ofInstant(Instant.ofEpochMilli(scheduledExecutionTime()),
|
||||
// ZoneId.systemDefault()));
|
||||
|
||||
// ChatMessage actualizeUserMsg = new ChatMessage();
|
||||
// actualizeUserMsg.setDirectedToServer(true);
|
||||
// actualizeUserMsg.setMessage("/show users");
|
||||
|
||||
// client.getMessageTXBus().add(actualizeUserMsg);
|
||||
|
||||
// Enumeration<String> e = this.client.getChatMemberTable().keys();
|
||||
//
|
||||
// while (e.hasMoreElements()) {
|
||||
// String key = e.nextElement();
|
||||
//
|
||||
// System.out.println(this.client.getChatMemberTable().get(key).getCallSign() + ", "
|
||||
// + this.client.getChatMemberTable().get(key).getQra() + ": "
|
||||
// + this.client.getChatMemberTable().get(key).getFrequency());
|
||||
//
|
||||
// }
|
||||
|
||||
// System.out.println("[UserAct]: Show the Cluster with known frequencies now: ");
|
||||
//
|
||||
// Enumeration<String> e2 = this.client.getdXClusterMemberTable().keys();
|
||||
//
|
||||
// while (e2.hasMoreElements()) {
|
||||
// String key = e2.nextElement();
|
||||
//
|
||||
// System.out.println(this.client.getdXClusterMemberTable().get(key).getCallSign() + ", "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getQra() + ": "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getFrequency());
|
||||
//
|
||||
// }
|
||||
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
//
|
||||
// System.out.print("\n");
|
||||
// }
|
||||
|
||||
/**
|
||||
* keeepalive start
|
||||
*/
|
||||
// ChatMessage keepAliveMSG = new ChatMessage();
|
||||
// keepAliveMSG.setMessageText("\r");
|
||||
// keepAliveMSG.setMessageDirectedToServer(true);
|
||||
//
|
||||
// System.out.println(new Utils4KST().time_generateCurrentMMDDhhmmTimeString() + " [UserAct]: Sending keepalive: "
|
||||
// + keepAliveMSG.getMessageText());
|
||||
// /**
|
||||
// * Sending keepalive
|
||||
// */
|
||||
// this.client.getMessageTXBus().add(keepAliveMSG);
|
||||
|
||||
/**
|
||||
* keeepalive end
|
||||
*/
|
||||
|
||||
// System.out.println("[UserAct]: Show the Userlist with known frequencies sorted now: ");
|
||||
|
||||
// ObservableList<ChatMember> userlist = this.client.getLst_chatMemberList();
|
||||
|
||||
// for (Iterator iterator = userlist.iterator(); iterator.hasNext();) {
|
||||
// ChatMember chatMember = (ChatMember) iterator.next();
|
||||
// System.out.println("[Useract] Entry " + this.client.getLst_chatMemberList().indexOf(chatMember) + ": " + chatMember.getCallSign());
|
||||
// }
|
||||
|
||||
//
|
||||
// String chatMembers ="";
|
||||
|
||||
// SortedSet<String> keys = new TreeSet<>(this.client.getChatMemberTable().keySet());
|
||||
// for (String key : keys) {
|
||||
//
|
||||
// chatMembers += this.client.getChatMemberTable().get(key).getCallSign() + ", "
|
||||
// + this.client.getChatMemberTable().get(key).getName() + " in "
|
||||
// + this.client.getChatMemberTable().get(key).getQra() + " @ QRG: "
|
||||
// + this.client.getChatMemberTable().get(key).getFrequency() + "\n";
|
||||
//
|
||||
// System.out.println(this.client.getChatMemberTable().get(key).getCallSign() + ", "
|
||||
// + this.client.getChatMemberTable().get(key).getName() + " in "
|
||||
// + this.client.getChatMemberTable().get(key).getQra() + " @ QRG: "
|
||||
// + this.client.getChatMemberTable().get(key).getFrequency());
|
||||
// }
|
||||
|
||||
// System.out.println("\n[UserAct]: Show the Clusterlist with known frequencies sorted now: ");
|
||||
|
||||
// String dxcMembers ="";
|
||||
|
||||
// SortedSet<String> keys2 = new TreeSet<>(this.client.getdXClusterMemberTable().keySet());
|
||||
// for (String key : keys2) {
|
||||
// System.out.println(this.client.getdXClusterMemberTable().get(key).getCallSign() + " in "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getQra() + " @ QRG: "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getFrequency());
|
||||
//
|
||||
// dxcMembers += this.client.getdXClusterMemberTable().get(key).getCallSign() + " in "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getQra() + " @ QRG: "
|
||||
// + this.client.getdXClusterMemberTable().get(key).getFrequency();
|
||||
//
|
||||
// }
|
||||
|
||||
// File userListLogger = new File(new Utils4KST().time_generateCurrentMMddString() + "_praktiKST_userlist.txt");
|
||||
//
|
||||
// FileWriter fileWriterRAWChatMSGOut = null;
|
||||
//
|
||||
// try {
|
||||
// fileWriterRAWChatMSGOut = new FileWriter(userListLogger, true);
|
||||
// } catch (IOException e1) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// BufferedWriter bufwrtrRawMSGOut;
|
||||
//
|
||||
// bufwrtrRawMSGOut = new BufferedWriter(fileWriterRAWChatMSGOut);
|
||||
|
||||
// System.out.println("#######################################" + chatMembers);
|
||||
// try {
|
||||
// bufwrtrRawMSGOut.write(new Utils4KST().time_generateCurrentMMDDhhmmTimeString() + " " +this.client.getChatMemberTable().size() + " Chatmembers:\n" + chatMembers+ "\n");
|
||||
// bufwrtrRawMSGOut.write(new Utils4KST().time_generateCurrentMMDDhhmmTimeString() + " " + this.client.getdXClusterMemberTable().size() + " Clusterentries:\n" + dxcMembers + "\n");
|
||||
|
||||
// bufwrtrRawMSGOut.flush();
|
||||
|
||||
// } catch (IOException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
// try {
|
||||
// bufwrtrRawMSGOut.close();
|
||||
// } catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
}
|
||||
|
||||
private boolean createMissingLogFile(Path logFile) {
|
||||
if (Files.exists(logFile)) {
|
||||
if (!Files.isRegularFile(logFile)) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"The selected Simplelogfile path is not a regular file: {0}",
|
||||
logFile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.createFile(logFile);
|
||||
LOGGER.log(Level.INFO, "Created missing Simplelogfile {0}.", logFile);
|
||||
return true;
|
||||
} catch (FileAlreadyExistsException exception) {
|
||||
return false;
|
||||
} catch (IOException | SecurityException exception) {
|
||||
LOGGER.log(Level.WARNING, "Cannot create Simplelogfile " + logFile, exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(
|
||||
Kst4ContestApplication.class.getName());
|
||||
private static final String SIMPLE_LOG_MANUAL_URL =
|
||||
"https://kst4contest.hamradioonline.de/manual/en/log-sync/"
|
||||
+ "#method-1-universal-file-based-callsign-interpreter-simplelogfile";
|
||||
|
||||
private boolean gridSquareHighlightEnabled = false;
|
||||
|
||||
@@ -12129,6 +12132,28 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSimpleLogFileCreated(Path filePath) {
|
||||
Alert alert = new Alert(AlertType.INFORMATION);
|
||||
alert.setTitle("Simplelogfile created");
|
||||
alert.setHeaderText("The selected Simplelogfile did not exist and has been created");
|
||||
|
||||
Label explanation = new Label(
|
||||
"File: " + filePath + "\n\n"
|
||||
+ "Configure your logging application to write its live log to this file. "
|
||||
+ "Then log a test QSO and verify that the callsign is marked as worked "
|
||||
+ "in KST4Contest within one minute.");
|
||||
explanation.setWrapText(true);
|
||||
|
||||
Hyperlink manualLink = new Hyperlink("Open the Simplelogfile manual");
|
||||
manualLink.setOnAction(event -> getHostServices().showDocument(SIMPLE_LOG_MANUAL_URL));
|
||||
|
||||
VBox content = new VBox(10, explanation, manualLink);
|
||||
content.setPrefWidth(560);
|
||||
alert.getDialogPane().setContent(content);
|
||||
alert.show();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forces the station FilteredList to evaluate all active predicates again.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import kst4contest.model.ChatMember;
|
||||
import kst4contest.model.ClusterMessage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ChatControllerSimpleLogTest {
|
||||
|
||||
@Test
|
||||
void marksEveryActiveVariantOfWorkedBaseCallsign() {
|
||||
ChatMember categoryTwoVariant = member("9A0BB-2");
|
||||
ChatMember categoryThreeVariant = member("9A0BB-70");
|
||||
ChatMember unrelated = member("DL1ABC");
|
||||
|
||||
int changed = ChatController.markSimpleLogWorkedMembers(
|
||||
List.of(categoryTwoVariant, categoryThreeVariant, unrelated),
|
||||
Set.of("9A0BB"));
|
||||
|
||||
assertEquals(2, changed);
|
||||
assertTrue(categoryTwoVariant.isWorked());
|
||||
assertTrue(categoryThreeVariant.isWorked());
|
||||
assertFalse(unrelated.isWorked());
|
||||
}
|
||||
|
||||
@Test
|
||||
void marksClusterReceiverByBaseCallsignAndHandlesIncompleteMessages() {
|
||||
ClusterMessage matching = new ClusterMessage();
|
||||
matching.setReceiver(member("9A0BB-70"));
|
||||
ClusterMessage incomplete = new ClusterMessage();
|
||||
|
||||
int changed = ChatController.markSimpleLogWorkedClusterMessages(
|
||||
List.of(matching, incomplete), Set.of("9A0BB"));
|
||||
|
||||
assertEquals(1, changed);
|
||||
assertTrue(matching.isReceiverWkd());
|
||||
assertFalse(incomplete.isReceiverWkd());
|
||||
}
|
||||
|
||||
private static ChatMember member(String callSign) {
|
||||
ChatMember member = new ChatMember();
|
||||
member.setCallSign(callSign);
|
||||
return member;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anySet;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import kst4contest.model.ChatPreferences;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class UserActualizationTaskTest {
|
||||
|
||||
@TempDir
|
||||
Path temporaryDirectory;
|
||||
|
||||
@Mock
|
||||
ChatController controller;
|
||||
|
||||
@Mock
|
||||
ChatPreferences preferences;
|
||||
|
||||
@BeforeEach
|
||||
void configureControllerPreferences() {
|
||||
when(controller.getChatPreferences()).thenReturn(preferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
void disabledInterpreterDoesNotCreateOrReadFile() {
|
||||
when(preferences.isLogsynch_fileBasedWkdCallInterpreterEnabled()).thenReturn(false);
|
||||
|
||||
new UserActualizationTask(controller).run();
|
||||
|
||||
verify(controller, never()).applySimpleLogWorkedBaseCalls(anySet());
|
||||
verify(controller, never()).notifySimpleLogFileCreated(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsMissingFileAndNotifiesOnlyOnce() {
|
||||
Path logFile = temporaryDirectory.resolve("created.log").toAbsolutePath().normalize();
|
||||
when(preferences.isLogsynch_fileBasedWkdCallInterpreterEnabled()).thenReturn(true);
|
||||
when(preferences.getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly())
|
||||
.thenReturn(logFile.toString());
|
||||
UserActualizationTask task = new UserActualizationTask(controller);
|
||||
|
||||
task.run();
|
||||
task.run();
|
||||
|
||||
assertTrue(Files.isRegularFile(logFile));
|
||||
verify(controller, times(2)).applySimpleLogWorkedBaseCalls(anySet());
|
||||
verify(controller, times(1)).notifySimpleLogFileCreated(logFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void readFailureIsContainedAndDoesNotUpdateUiState() {
|
||||
when(preferences.isLogsynch_fileBasedWkdCallInterpreterEnabled()).thenReturn(true);
|
||||
when(preferences.getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly())
|
||||
.thenReturn(temporaryDirectory.toString());
|
||||
|
||||
assertDoesNotThrow(() -> new UserActualizationTask(controller).run());
|
||||
|
||||
verify(controller, never()).applySimpleLogWorkedBaseCalls(anySet());
|
||||
verify(controller, never()).notifySimpleLogFileCreated(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,48 @@
|
||||
package kst4contest.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
import kst4contest.controller.UCXLogFileToHashsetParser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
public class TestUCXLogFileToHashsetParser {
|
||||
class TestUCXLogFileToHashsetParser {
|
||||
|
||||
@TempDir
|
||||
Path temporaryDirectory;
|
||||
|
||||
@Test
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
void parsesUniqueWorkedBaseCallsignsWithFixedPattern() throws IOException {
|
||||
Path logFile = temporaryDirectory.resolve("contest.log");
|
||||
Files.writeString(logFile, String.join(System.lineSeparator(),
|
||||
"QSO 001 S53CC 144 MHz",
|
||||
"QSO 002 9A0BB-70 432 MHz",
|
||||
"QSO 003 s53cc repeated",
|
||||
"no station here"));
|
||||
|
||||
UCXLogFileToHashsetParser testTheParser = new UCXLogFileToHashsetParser("C:\\UcxLog\\Logs\\DO5AMF\\DVU322_I.UCX");
|
||||
try {
|
||||
testTheParser.parse();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Set<String> result = new UCXLogFileToHashsetParser(logFile.toString()).parse();
|
||||
|
||||
assertEquals(Set.of("S53CC", "9A0BB"), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void closesFileAfterEveryParsePass() throws IOException {
|
||||
Path logFile = temporaryDirectory.resolve("replaceable.log");
|
||||
Files.writeString(logFile, "QSO DL1ABC");
|
||||
|
||||
UCXLogFileToHashsetParser parser = new UCXLogFileToHashsetParser(logFile.toString());
|
||||
assertEquals(Set.of("DL1ABC"), parser.parse());
|
||||
|
||||
Path replacement = temporaryDirectory.resolve("replacement.log");
|
||||
Files.move(logFile, replacement);
|
||||
assertFalse(Files.exists(logFile));
|
||||
assertTrue(Files.exists(replacement));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user