mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-07-14 08:36:41 +02:00
bugfix for #51. ManagebusManagementThread now never accesses or changes the JAVAFX view-backing ObservableList but using a concurrenthasmap which drives the Tableview backing list with snapshots
This commit is contained in:
@@ -24,6 +24,7 @@ import kst4contest.logic.PriorityCalculator;
|
||||
import kst4contest.model.*;
|
||||
import kst4contest.test.MockKstServer;
|
||||
import kst4contest.utils.PlayAudioUtils;
|
||||
import kst4contest.locatorUtils.Location;
|
||||
import kst4contest.view.Kst4ContestApplication;
|
||||
|
||||
import java.io.*;
|
||||
@@ -34,6 +35,7 @@ import java.util.function.Predicate;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Central Chat kst4contest.controller. Instantiate only one time per category of kst Chat.
|
||||
@@ -318,10 +320,8 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
|
||||
EnumSet<Band> offered = EnumSet.noneOf(Band.class);
|
||||
|
||||
synchronized (getLst_chatMemberList()) {
|
||||
for (ChatMember cm : getLst_chatMemberList()) {
|
||||
for (ChatMember cm : findActiveChatMembersByRawCall(callRaw)) {
|
||||
if (cm == null || cm.getCallSignRaw() == null) continue;
|
||||
if (!normalizeCallRaw(cm.getCallSignRaw()).equals(callRaw)) continue;
|
||||
|
||||
Map<Band, ChatMember.ActiveFrequencyInfo> map = cm.getKnownActiveBands();
|
||||
if (map == null || map.isEmpty()) continue;
|
||||
@@ -340,11 +340,9 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
+ " freq=" + e.getValue().frequency
|
||||
+ " ageMs=" + age);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return offered;
|
||||
}
|
||||
|
||||
@@ -356,10 +354,8 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
|
||||
EnumSet<Band> worked = EnumSet.noneOf(Band.class);
|
||||
|
||||
synchronized (getLst_chatMemberList()) {
|
||||
for (ChatMember cm : getLst_chatMemberList()) {
|
||||
for (ChatMember cm : findActiveChatMembersByRawCall(callRaw)) {
|
||||
if (cm == null || cm.getCallSignRaw() == null) continue;
|
||||
if (!normalizeCallRaw(cm.getCallSignRaw()).equals(callRaw)) continue;
|
||||
|
||||
if (cm.isWorked144()) worked.add(Band.B_144);
|
||||
if (cm.isWorked432()) worked.add(Band.B_432);
|
||||
@@ -368,9 +364,9 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
if (cm.isWorked3400()) worked.add(Band.B_3400);
|
||||
if (cm.isWorked5600()) worked.add(Band.B_5760);
|
||||
if (cm.isWorked10G()) worked.add(Band.B_10G);
|
||||
if (cm.isWorked24G()) worked.add(Band.B_24G); // optional, only if your Band enum supports it
|
||||
}
|
||||
if (cm.isWorked24G()) worked.add(Band.B_24G);
|
||||
}
|
||||
|
||||
return worked;
|
||||
}
|
||||
|
||||
@@ -645,7 +641,8 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
|
||||
// rotatorClient.
|
||||
|
||||
this.lst_chatMemberList.clear();;
|
||||
// this.lst_chatMemberList.clear();;
|
||||
this.clearActiveChatMembers();
|
||||
this.lst_clusterMemberList.clear();
|
||||
|
||||
this.setDisconnected(true);
|
||||
@@ -713,7 +710,7 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
}
|
||||
} else if (action.equals(ApplicationConstants.DISCSTRING_DISCONNECTONLY)){
|
||||
|
||||
this.lst_chatMemberList.clear();;
|
||||
this.clearActiveChatMembers();
|
||||
this.lst_clusterMemberList.clear();
|
||||
|
||||
|
||||
@@ -959,16 +956,9 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
if (targetCallsignRaw == null || targetCallsignRaw.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
String normalizedTargetCall = normalizeCallRaw(targetCallsignRaw);
|
||||
synchronized (getLst_chatMemberList()) {
|
||||
for (ChatMember member : getLst_chatMemberList()) {
|
||||
if (member == null || member.getCallSignRaw() == null) continue;
|
||||
if (normalizeCallRaw(member.getCallSignRaw()).equals(normalizedTargetCall)) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
List<ChatMember> matchingMembers = findActiveChatMembersByRawCall(targetCallsignRaw);
|
||||
return matchingMembers.isEmpty() ? null : matchingMembers.get(0);
|
||||
}
|
||||
|
||||
private String resolveSkedTargetLocator(String targetCallsignRaw) {
|
||||
@@ -976,22 +966,43 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
return null;
|
||||
}
|
||||
|
||||
String normalizedTargetCall = normalizeCallRaw(targetCallsignRaw);
|
||||
synchronized (getLst_chatMemberList()) {
|
||||
for (ChatMember member : getLst_chatMemberList()) {
|
||||
if (member == null || member.getCallSignRaw() == null) continue;
|
||||
if (!normalizeCallRaw(member.getCallSignRaw()).equals(normalizedTargetCall)) continue;
|
||||
|
||||
for (ChatMember member : findActiveChatMembersByRawCall(targetCallsignRaw)) {
|
||||
String locator = member.getQra();
|
||||
if (locator != null && !locator.isBlank()) {
|
||||
return locator.trim().toUpperCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// private ChatMember resolveSkedTargetMember(String targetCallsignRaw) {
|
||||
// if (targetCallsignRaw == null || targetCallsignRaw.isBlank()) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// List<ChatMember> matchingMembers = findActiveChatMembersByRawCall(targetCallsignRaw);
|
||||
// return matchingMembers.isEmpty() ? null : matchingMembers.get(0);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private String resolveSkedTargetLocator(String targetCallsignRaw) {
|
||||
// if (targetCallsignRaw == null || targetCallsignRaw.isBlank()) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// String normalizedTargetCall = normalizeCallRaw(targetCallsignRaw);
|
||||
//
|
||||
// for (ChatMember member : findActiveChatMembersByRawCall(targetCallsignRaw)) {
|
||||
// String locator = member.getQra();
|
||||
// if (locator != null && !locator.isBlank()) {
|
||||
// return locator.trim().toUpperCase(Locale.ROOT);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
public StationMetricsService getStationMetricsService() {
|
||||
return stationMetricsService;
|
||||
}
|
||||
@@ -1014,10 +1025,14 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
return new HashMap<>(lastInboundCategoryByCallSignRaw);
|
||||
}
|
||||
|
||||
// public List<ChatMember> snapshotChatMembers() {
|
||||
// synchronized (getLst_chatMemberList()) {
|
||||
// return new ArrayList<>(getLst_chatMemberList());
|
||||
// }
|
||||
// }
|
||||
|
||||
public List<ChatMember> snapshotChatMembers() {
|
||||
synchronized (getLst_chatMemberList()) {
|
||||
return new ArrayList<>(getLst_chatMemberList());
|
||||
}
|
||||
return new ArrayList<>(activeChatMembersByCallAndCategory.values());
|
||||
}
|
||||
|
||||
public List<ContestSked> snapshotActiveSkeds() {
|
||||
@@ -1126,13 +1141,27 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
private ObservableList<ChatMember> chatMemberList = FXCollections.observableArrayList(); // List of active stations
|
||||
|
||||
|
||||
private ObservableList<ChatMember> lst_chatMemberList = FXCollections.synchronizedObservableList(chatMemberList); // List
|
||||
// of active stn in chat
|
||||
private FilteredList<ChatMember> lst_chatMemberListFiltered = new FilteredList<ChatMember>(chatMemberList);
|
||||
private SortedList<ChatMember> lst_chatMemberSortedFilteredList = new SortedList<ChatMember>(lst_chatMemberListFiltered);
|
||||
|
||||
private ObservableList<ChatMember> lst_chatMemberList = FXCollections.synchronizedObservableList(chatMemberList); // List
|
||||
private ObservableList<Predicate<ChatMember>> lst_chatMemberListFilterPredicates = FXCollections.observableArrayList();
|
||||
private ObservableList<ClusterMessage> lst_clusterMemberList = FXCollections.observableArrayList();
|
||||
|
||||
/*
|
||||
* Thread-safe active-member model.
|
||||
*
|
||||
* MessageBusManagementThread must not use the JavaFX TableView backing list as
|
||||
* its primary data model. Otherwise every add/remove fires FilteredList,
|
||||
* SortedList and TableView selection listeners on the MessageBus thread and JavaFX
|
||||
* can throw "Not on FX application thread" or internal listener NPEs.
|
||||
*
|
||||
* This map is the worker-thread safe source of truth. The ObservableList below
|
||||
* remains a UI mirror and is mutated only on the JavaFX application thread.
|
||||
*/
|
||||
private final java.util.concurrent.ConcurrentMap<String, ChatMember> activeChatMembersByCallAndCategory =
|
||||
new java.util.concurrent.ConcurrentHashMap<>();
|
||||
|
||||
/*
|
||||
* Message table update buffers.
|
||||
@@ -1161,6 +1190,239 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
// ******************************************************************************************************************************************
|
||||
|
||||
|
||||
/**
|
||||
* Executes UI-bound work on the JavaFX application thread.
|
||||
*
|
||||
* Worker threads may call this safely. If the caller is already on the FX
|
||||
* thread, the action is executed immediately to preserve ordering.
|
||||
*/
|
||||
private void runOnFxThread(Runnable action) {
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
action.run();
|
||||
} else {
|
||||
Platform.runLater(action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the active-member key. The raw/base callsign alone is not enough
|
||||
* because the same station can be logged into multiple ON4KST categories at
|
||||
* the same time. Therefore the category number is part of the key.
|
||||
*/
|
||||
private String buildActiveChatMemberKey(String callSign, ChatCategory category) {
|
||||
String normalizedCallsign = ChatMember.normalizeCallSignToBaseCallSign(callSign);
|
||||
if (normalizedCallsign == null || normalizedCallsign.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int categoryNumber = category == null ? -1 : category.getCategoryNumber();
|
||||
return normalizedCallsign.trim().toUpperCase(Locale.ROOT) + "|" + categoryNumber;
|
||||
}
|
||||
|
||||
private String buildActiveChatMemberKey(ChatMember member) {
|
||||
if (member == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String callSign = member.getCallSignRaw() != null ? member.getCallSignRaw() : member.getCallSign();
|
||||
return buildActiveChatMemberKey(callSign, member.getChatCategory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or replaces an active chat member in the worker-thread model and mirrors
|
||||
* that change to the JavaFX list. This is the only supported path for ON4KST
|
||||
* user-enter events.
|
||||
*/
|
||||
public void addOrUpdateActiveChatMember(ChatMember member) {
|
||||
String key = buildActiveChatMemberKey(member);
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeChatMembersByCallAndCategory.put(key, member);
|
||||
|
||||
runOnFxThread(() -> {
|
||||
int existingIndex = findChatMemberIndexInUiListByKey(key);
|
||||
if (existingIndex >= 0) {
|
||||
lst_chatMemberList.set(existingIndex, member);
|
||||
} else {
|
||||
lst_chatMemberList.add(member);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an active chat member from the worker-thread model and from the UI
|
||||
* mirror. Removal from the ObservableList is always performed on the FX thread
|
||||
* because the list is bound to FilteredList/SortedList/TableView.
|
||||
*/
|
||||
public boolean removeActiveChatMember(ChatMember member) {
|
||||
String key = buildActiveChatMemberKey(member);
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChatMember removedMember = activeChatMembersByCallAndCategory.remove(key);
|
||||
runOnFxThread(() -> lst_chatMemberList.removeIf(currentMember -> key.equals(buildActiveChatMemberKey(currentMember))));
|
||||
return removedMember != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the active-member model and the JavaFX UI mirror. Use this instead of
|
||||
* getLst_chatMemberList().clear() from timers or worker threads.
|
||||
*/
|
||||
public void clearActiveChatMembers() {
|
||||
activeChatMembersByCallAndCategory.clear();
|
||||
runOnFxThread(() -> lst_chatMemberList.clear());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a member from the thread-safe active model. This avoids reading the
|
||||
* TableView backing list from MessageBusManagementThread.
|
||||
*/
|
||||
public ChatMember findActiveChatMember(ChatMember lookForThis) {
|
||||
String key = buildActiveChatMemberKey(lookForThis);
|
||||
return key == null ? null : activeChatMembersByCallAndCategory.get(key);
|
||||
}
|
||||
|
||||
public ChatMember findActiveChatMember(String callSign, ChatCategory category) {
|
||||
String key = buildActiveChatMemberKey(callSign, category);
|
||||
return key == null ? null : activeChatMembersByCallAndCategory.get(key);
|
||||
}
|
||||
|
||||
public int getActiveChatMemberCount() {
|
||||
return activeChatMembersByCallAndCategory.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all active category variants of a callsign. This is used when a QRG or
|
||||
* band hint should be propagated from one category instance to the same station
|
||||
* in another category.
|
||||
*/
|
||||
public List<ChatMember> findActiveChatMembersByRawCall(String callSignRaw) {
|
||||
String normalizedCallsign = ChatMember.normalizeCallSignToBaseCallSign(callSignRaw);
|
||||
if (normalizedCallsign == null || normalizedCallsign.isBlank()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String normalizedKeyPart = normalizedCallsign.trim().toUpperCase(Locale.ROOT);
|
||||
List<ChatMember> matchingMembers = new ArrayList<>();
|
||||
|
||||
for (ChatMember member : activeChatMembersByCallAndCategory.values()) {
|
||||
if (member == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String memberCall = member.getCallSignRaw() != null ? member.getCallSignRaw() : member.getCallSign();
|
||||
String normalizedMemberCall = ChatMember.normalizeCallSignToBaseCallSign(memberCall);
|
||||
if (normalizedMemberCall != null && normalizedMemberCall.equalsIgnoreCase(normalizedKeyPart)) {
|
||||
matchingMembers.add(member);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates locator and derived direction values in the active model. The UI list
|
||||
* contains the same member object, but the user-list refresh is still triggered
|
||||
* on the JavaFX thread so TableView/map derived displays can repaint safely.
|
||||
*/
|
||||
public boolean updateActiveChatMemberLocator(ChatMember lookupMember, String newLocator) {
|
||||
ChatMember activeMember = findActiveChatMember(lookupMember);
|
||||
if (activeMember == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activeMember.setQra(newLocator);
|
||||
activeMember.setQrb(new Location().getDistanceKmByTwoLocatorStrings(chatPreferences.getStn_loginLocatorMainCat(), newLocator));
|
||||
activeMember.setQTFdirection(new Location(chatPreferences.getStn_loginLocatorMainCat()).getBearing(new Location(newLocator)));
|
||||
fireUserListUpdate("Locator changed");
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean updateActiveChatMemberState(ChatMember lookupMember, int newState) {
|
||||
ChatMember activeMember = findActiveChatMember(lookupMember);
|
||||
if (activeMember == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activeMember.setState(newState);
|
||||
fireUserListUpdate("User state changed");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a UM3-style user-info update to an already known member. If ON4KST
|
||||
* sends the update before the matching enter message, the member is added so
|
||||
* later CH messages can resolve sender/receiver immediately.
|
||||
*/
|
||||
public void updateOrAddActiveChatMemberInfo(ChatMember updatedMember) {
|
||||
String key = buildActiveChatMemberKey(updatedMember);
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChatMember activeMember = activeChatMembersByCallAndCategory.get(key);
|
||||
if (activeMember == null) {
|
||||
addOrUpdateActiveChatMember(updatedMember);
|
||||
return;
|
||||
}
|
||||
|
||||
activeMember.setName(updatedMember.getName());
|
||||
activeMember.setQra(updatedMember.getQra());
|
||||
activeMember.setState(updatedMember.getState());
|
||||
activeMember.setLastActivity(updatedMember.getLastActivity());
|
||||
activeMember.setActivityTimeLastInEpoch(updatedMember.getActivityTimeLastInEpoch());
|
||||
activeMember.setQrb(updatedMember.getQrb());
|
||||
activeMember.setQTFdirection(updatedMember.getQTFdirection());
|
||||
fireUserListUpdate("User info updated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a newly detected QRG/band on all active category variants of a station.
|
||||
* The old StringProperty is still set for compatibility with existing TableView
|
||||
* columns and DXCluster code.
|
||||
*/
|
||||
public void applyDetectedFrequencyToActiveMembers(ChatMember sender, Band detectedBand, double detectedFrequencyMhz) {
|
||||
if (sender == null || detectedBand == null || detectedFrequencyMhz <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String displayFrequency = String.valueOf(detectedFrequencyMhz);
|
||||
String rawCall = sender.getCallSignRaw() != null ? sender.getCallSignRaw() : sender.getCallSign();
|
||||
|
||||
for (ChatMember member : findActiveChatMembersByRawCall(rawCall)) {
|
||||
if (member == null) {
|
||||
continue;
|
||||
}
|
||||
member.addKnownFrequency(detectedBand, detectedFrequencyMhz);
|
||||
member.setFrequency(new SimpleStringProperty(displayFrequency));
|
||||
}
|
||||
|
||||
// Also cover dummy senders that are not in the active model, e.g. [n/a] senders.
|
||||
sender.addKnownFrequency(detectedBand, detectedFrequencyMhz);
|
||||
sender.setFrequency(new SimpleStringProperty(displayFrequency));
|
||||
fireUserListUpdate("Frequency detected");
|
||||
}
|
||||
|
||||
private int findChatMemberIndexInUiListByKey(String key) {
|
||||
if (key == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lst_chatMemberList.size(); i++) {
|
||||
if (key.equals(buildActiveChatMemberKey(lst_chatMemberList.get(i)))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2011,7 +2273,7 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
socket.close();
|
||||
|
||||
chatController.setConnectedAndLoggedIn(false);
|
||||
chatController.getLst_chatMemberList().clear();
|
||||
chatController.clearActiveChatMembers();
|
||||
|
||||
System.out.println("[Chatcontroller, Warning: ] Socket closed or disconnected");
|
||||
|
||||
|
||||
@@ -324,31 +324,12 @@ public class MessageBusManagementThread extends Thread {
|
||||
// --- STEP 3: Process Result ---
|
||||
if (finalDetectedBand != null && finalDetectedFrequency > 0) {
|
||||
|
||||
// 1. Store in the new Map (for future context/history)
|
||||
|
||||
sender.addKnownFrequency(finalDetectedBand, finalDetectedFrequency);
|
||||
// No automatic full terrain analysis here.
|
||||
// The frequency is stored for later map/manual reachability requests.
|
||||
|
||||
//propagate known frequency to all instances of the same callsign (callRaw may exist multiple times)
|
||||
try {
|
||||
ArrayList<Integer> sameCallIdx = client.checkListForChatMemberIndexesByCallSign(sender);
|
||||
for (int idx : sameCallIdx) {
|
||||
ChatMember cm = client.getLst_chatMemberList().get(idx);
|
||||
if (cm != null && cm != sender) {
|
||||
cm.addKnownFrequency(finalDetectedBand, finalDetectedFrequency);
|
||||
// No automatic full terrain analysis here.
|
||||
// Avoids exhausting the online terrain API when many stations mention QRGs.
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("[SmartParser, warning]: failed to propagate known frequency across duplicates: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// 2. Set the old String-Property for GUI compatibility
|
||||
// We assume standard display format (MHz)
|
||||
sender.setFrequency(new javafx.beans.property.SimpleStringProperty(String.valueOf(finalDetectedFrequency)));
|
||||
/*
|
||||
* Store the detected QRG in the thread-safe active-member model.
|
||||
* The UI table is only a JavaFX mirror, so the MessageBus must not scan
|
||||
* or mutate getLst_chatMemberList() here.
|
||||
*/
|
||||
client.applyDetectedFrequencyToActiveMembers(sender, finalDetectedBand, finalDetectedFrequency);
|
||||
|
||||
System.out.println("[SmartParser] Detected for " + sender.getCallSign() + ": " +
|
||||
finalDetectedFrequency + " MHz (" + finalDetectedBand + ") " +
|
||||
@@ -491,6 +472,92 @@ public class MessageBusManagementThread extends Thread {
|
||||
return -1; // if it´s not found, the method will always end here and return -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a minimal receiver object for ON4KST broadcast messages.
|
||||
* Keeping this as an object, not null, protects all downstream chat filters
|
||||
* and debug logging from null receiver paths.
|
||||
*/
|
||||
private ChatMember createAllReceiver() {
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setCallSign("ALL");
|
||||
dummy.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
return dummy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a message sender from the thread-safe active-member model. If a
|
||||
* CH/CR message arrives before the matching user-enter message, a marked
|
||||
* fallback sender is used. The returned sender is never null.
|
||||
*/
|
||||
private ChatMember resolveInboundSender(String senderCallSign, ChatCategory category, ChatMessage message) {
|
||||
ChatMember lookup = new ChatMember();
|
||||
lookup.setCallSign(senderCallSign);
|
||||
lookup.setChatCategory(category);
|
||||
|
||||
ChatMember senderObj = this.client.findActiveChatMember(lookup);
|
||||
if (senderObj != null) {
|
||||
senderObj.setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
|
||||
// Remember the last active category so later outgoing replies can be routed correctly.
|
||||
this.client.rememberLastInboundCategory(senderObj.getCallSignRaw(), senderObj.getChatCategory());
|
||||
|
||||
// Metrics influence priority scoring; process them after message text is known.
|
||||
this.client.getStationMetricsService().onInboundMessage(
|
||||
senderObj.getCallSignRaw(),
|
||||
System.currentTimeMillis(),
|
||||
message == null ? null : message.getMessageText(),
|
||||
this.client.getChatPreferences(),
|
||||
this.client.getChatPreferences().getStn_loginCallSign()
|
||||
);
|
||||
|
||||
this.client.getScoreService().requestRecompute("rx-chat-message");
|
||||
return senderObj;
|
||||
}
|
||||
|
||||
ChatMember fallbackSender = new ChatMember();
|
||||
String myCall = this.client.getChatPreferences().getStn_loginCallSign();
|
||||
if (senderCallSign != null && senderCallSign.equalsIgnoreCase(myCall)) {
|
||||
fallbackSender.setCallSign(myCall);
|
||||
} else {
|
||||
fallbackSender.setCallSign("[n/a]" + senderCallSign);
|
||||
}
|
||||
fallbackSender.setChatCategory(category);
|
||||
fallbackSender.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
return fallbackSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a message receiver from the active-member model. Unknown receivers
|
||||
* are represented as explicit fallback objects instead of null. This keeps PM
|
||||
* echo display and historic messages stable even if the target station already
|
||||
* left the chat.
|
||||
*/
|
||||
private ChatMember resolveInboundReceiver(String receiverCallSign, ChatCategory category) {
|
||||
if (receiverCallSign == null || receiverCallSign.equals("0")) {
|
||||
return createAllReceiver();
|
||||
}
|
||||
|
||||
ChatMember lookup = new ChatMember();
|
||||
lookup.setCallSign(receiverCallSign);
|
||||
lookup.setChatCategory(category);
|
||||
|
||||
ChatMember receiverObj = this.client.findActiveChatMember(lookup);
|
||||
if (receiverObj != null) {
|
||||
return receiverObj;
|
||||
}
|
||||
|
||||
ChatMember fallbackReceiver = new ChatMember();
|
||||
String myCall = this.client.getChatPreferences().getStn_loginCallSign();
|
||||
if (receiverCallSign.equalsIgnoreCase(myCall)) {
|
||||
fallbackReceiver.setCallSign(myCall);
|
||||
} else {
|
||||
fallbackReceiver.setCallSign(receiverCallSign + "(left)");
|
||||
}
|
||||
fallbackReceiver.setChatCategory(category);
|
||||
fallbackReceiver.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
return fallbackReceiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes received messages via port 23001 (improved telnet Interface)
|
||||
*
|
||||
@@ -590,7 +657,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
|
||||
if (!client.getChatPreferences().getStn_loginCallSign().equals(newMember.getCallSign())) {
|
||||
this.client.getLst_chatMemberList().add(newMember); //the own call will not be in the list
|
||||
this.client.addOrUpdateActiveChatMember(newMember); // the own call will not be in the list
|
||||
// this.client.getReachabilityService().ensureAutoTropoMarginCalculated(newMember);
|
||||
// Reachability is calculated on demand only: map click, selected station, or manual request.
|
||||
}
|
||||
@@ -637,7 +704,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
newMember = this.client.getDbHandler().fetchChatMemberWkdDataForOnlyOneCallsignFromDB(newMember);
|
||||
|
||||
this.client.getLst_chatMemberList().add(newMember);
|
||||
this.client.addOrUpdateActiveChatMember(newMember);
|
||||
// this.client.getReachabilityService().ensureAutoTropoMarginCalculated(newMember);
|
||||
|
||||
this.client.getDbHandler().storeChatMember(newMember);
|
||||
@@ -665,17 +732,11 @@ public class MessageBusManagementThread extends Thread {
|
||||
newMember.setCallSign(splittedMessageLine[2]);
|
||||
|
||||
System.out.println("[MSGBUSMGT, Info:] User left Chat and will be removed from list ["
|
||||
+ this.client.getLst_chatMemberList().size() + "] :" + newMember.getCallSign());
|
||||
try {
|
||||
this.client.getLst_chatMemberList().remove(
|
||||
checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), newMember));
|
||||
+ this.client.getActiveChatMemberCount() + "] :" + newMember.getCallSign());
|
||||
|
||||
//since 1.26 new method design to detect chatcategory, too!
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("[MSGBUSMGT, EXC!, Error:] User sent left chat but had not been there ... ["
|
||||
+ this.client.getLst_chatMemberList().size() + "] :" + newMember.getCallSign() + "\n"
|
||||
+ e.getStackTrace());
|
||||
if (!this.client.removeActiveChatMember(newMember)) {
|
||||
System.out.println("[MSGBUSMGT, Info:] User sent left chat but was not active: "
|
||||
+ newMember.getCallSign() + " / " + newMember.getChatCategory());
|
||||
}
|
||||
|
||||
} else
|
||||
@@ -695,9 +756,12 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
chategoryForMessageAndMessageSender = newMessageArrived.getChatCategory();
|
||||
newMessageArrived.setMessageGeneratedTime(splittedMessageLine[2]);
|
||||
newMessageArrived.setMessageSenderName(splittedMessageLine[4]);
|
||||
newMessageArrived.setMessageText(splittedMessageLine[6]);
|
||||
|
||||
if (splittedMessageLine[3].equals("SERVER")) {
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
dummy.setCallSign("SERVER");
|
||||
dummy.setName("Sysop");
|
||||
newMessageArrived.setSender(dummy);
|
||||
@@ -707,77 +771,16 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
} else {
|
||||
|
||||
ChatMember sender = new ChatMember();
|
||||
sender.setCallSign(splittedMessageLine[3]);
|
||||
sender.setChatCategory(chategoryForMessageAndMessageSender);
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), sender);
|
||||
|
||||
|
||||
if (index != -1) {
|
||||
//user not found in the chatmember list
|
||||
try {
|
||||
// newMessageArrived.setSender(this.client.getLst_chatMemberList().get(index)); // set sender to member of
|
||||
// this.client.getLst_chatMemberList().get(index).setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
|
||||
ChatMember senderObj = this.client.getLst_chatMemberList().get(index);
|
||||
newMessageArrived.setSender(senderObj);
|
||||
senderObj.setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
|
||||
// Remember last inbound category per callsignRaw (required for correct send-routing later)
|
||||
this.client.rememberLastInboundCategory(senderObj.getCallSignRaw(), senderObj.getChatCategory());
|
||||
|
||||
// Metrics for scoring: momentum, response-time, no-reply, positive signals
|
||||
this.client.getStationMetricsService().onInboundMessage(
|
||||
senderObj.getCallSignRaw(),
|
||||
System.currentTimeMillis(),
|
||||
newMessageArrived.getMessageText(),
|
||||
this.client.getChatPreferences(),
|
||||
this.client.getChatPreferences().getStn_loginCallSign()
|
||||
);
|
||||
|
||||
// Activity/category changes influence priority => request recompute
|
||||
this.client.getScoreService().requestRecompute("rx-chat-message");
|
||||
|
||||
} catch (Exception exc) {
|
||||
ChatMember aSenderDummy = new ChatMember();
|
||||
aSenderDummy.setCallSign(splittedMessageLine[3] + "[n/a]");
|
||||
aSenderDummy.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
newMessageArrived.setSender(aSenderDummy);
|
||||
System.out.println("MsgBusmgtT: Catched Error! " + exc.getMessage() + " // " + splittedMessageLine[3] + " is not in the list! Faking sender!");
|
||||
exc.printStackTrace();
|
||||
}
|
||||
// b4 init list
|
||||
} else {
|
||||
//user not found in chatmember list, mark it, sender can not be set
|
||||
if (!sender.getCallSign().equals(this.client.getChatPreferences().getStn_loginCallSign().toUpperCase())) {
|
||||
sender.setCallSign("[n/a]" + sender.getCallSign());
|
||||
// if someone sent a message without being in the userlist (cause
|
||||
// on4kst missed implementing....), callsign will be marked
|
||||
} else {
|
||||
//that means, message was by own station, broadcasted to all other
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
|
||||
AirPlaneReflectionInfo preventNullpointerExc = new AirPlaneReflectionInfo();
|
||||
preventNullpointerExc.setAirPlanesReachableCntr(0);
|
||||
sender.setAirPlaneReflectInfo(preventNullpointerExc);
|
||||
newMessageArrived.setSender(sender); //my own call is the sender
|
||||
}
|
||||
newMessageArrived.setSender(resolveInboundSender(
|
||||
splittedMessageLine[3],
|
||||
chategoryForMessageAndMessageSender,
|
||||
newMessageArrived));
|
||||
}
|
||||
|
||||
// newMessageArrived.setSender(this.client.getChatMemberTable().get(splittedMessageLine[3]));
|
||||
}
|
||||
|
||||
newMessageArrived.setMessageSenderName(splittedMessageLine[4]);
|
||||
newMessageArrived.setMessageText(splittedMessageLine[6]);
|
||||
|
||||
if (splittedMessageLine[7].equals("0")) {
|
||||
// message is not directed to anyone, move it to the cq messages!
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
// message is not directed to anyone, move it to the cq messages.
|
||||
newMessageArrived.setReceiver(createAllReceiver());
|
||||
|
||||
this.client.publishChatMessage(newMessageArrived); // sdtout to all message-List (new from v1.7)
|
||||
|
||||
@@ -786,36 +789,9 @@ public class MessageBusManagementThread extends Thread {
|
||||
} else {
|
||||
//message is directed to another chatmember, process as such!
|
||||
|
||||
ChatMember receiver = new ChatMember();
|
||||
|
||||
receiver.setChatCategory(chategoryForMessageAndMessageSender); //got out of message itself
|
||||
|
||||
receiver.setCallSign(splittedMessageLine[7]);
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), receiver);
|
||||
|
||||
if (index != -1) {
|
||||
newMessageArrived.setReceiver(this.client.getLst_chatMemberList().get(index));// -1: Member left Chat
|
||||
// before...
|
||||
} else { //found in active member list
|
||||
|
||||
|
||||
if (receiver.getCallSign().equals(client.getChatPreferences().getStn_loginCallSign())) {
|
||||
/**
|
||||
* If mycallsign sent a message to the server, server will publish that message and
|
||||
* send it to all chatmember including me.
|
||||
* As mycall is not in the userlist, the message would not been displayed if I handle
|
||||
* it in the next case (marking left user, just for information). But I want an echo.
|
||||
*/
|
||||
|
||||
receiver.setCallSign(client.getChatPreferences().getStn_loginCallSign());
|
||||
newMessageArrived.setReceiver(receiver);
|
||||
} else {
|
||||
//this are user which left chat but had been adressed by this message
|
||||
receiver.setCallSign(receiver.getCallSign() + "(left)");
|
||||
newMessageArrived.setReceiver(receiver);
|
||||
}
|
||||
}
|
||||
newMessageArrived.setReceiver(resolveInboundReceiver(
|
||||
splittedMessageLine[7],
|
||||
chategoryForMessageAndMessageSender));
|
||||
|
||||
// System.out.println("message directed to: " + newMessageArrived.getReceiver().getCallSign() + ". EQ?: " + this.client.getownChatMemberObject().getCallSign() + " sent by: " + newMessageArrived.getSender().getCallSign().toUpperCase() + " -> EQ?: "+ this.client.getChatPreferences().getLoginCallSign().toUpperCase());
|
||||
|
||||
@@ -979,7 +955,21 @@ public class MessageBusManagementThread extends Thread {
|
||||
// the "to me message list" with modified messagetext, added rxers callsign
|
||||
|
||||
} else {
|
||||
//message sent to other user
|
||||
/*
|
||||
* Message sent from one other station to another other station.
|
||||
*
|
||||
* The old code reached this point only with members from the visible user list.
|
||||
* With explicit fallback sender/receiver objects, this path may also see
|
||||
* stations that already left the chat or arrived before their user-list entry.
|
||||
* In that case locators may be missing, so angle/range analysis and DX spotting
|
||||
* must be skipped while the chat message itself is still published.
|
||||
*/
|
||||
boolean senderHasLocator = newMessageArrived.getSender().getQra() != null
|
||||
&& !newMessageArrived.getSender().getQra().isBlank();
|
||||
boolean receiverHasLocator = newMessageArrived.getReceiver().getQra() != null
|
||||
&& !newMessageArrived.getReceiver().getQra().isBlank();
|
||||
|
||||
if (senderHasLocator && receiverHasLocator) {
|
||||
if (DirectionUtils.isInAngleAndRange(client.getChatPreferences().getStn_loginLocatorMainCat(),
|
||||
newMessageArrived.getSender().getQra(),
|
||||
newMessageArrived.getReceiver().getQra(),
|
||||
@@ -998,7 +988,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
if (client.getChatPreferences().isNotify_dxClusterServerEnabled()) {
|
||||
try {
|
||||
if (newMessageArrived.getSender().getFrequency() != null) {
|
||||
//TODO: testing for next version 3.33: addinitional information will be displayed in cluster if there is such an information
|
||||
//TODO: testing for next version 3.33: additional information will be displayed in cluster if there is such information
|
||||
ChatMember onlyForSpottingObject = new ChatMember();
|
||||
onlyForSpottingObject.setCallSign(newMessageArrived.getSender().getCallSign());
|
||||
onlyForSpottingObject.setFrequency(newMessageArrived.getSender().getFrequency());
|
||||
@@ -1014,11 +1004,10 @@ public class MessageBusManagementThread extends Thread {
|
||||
newMessageArrived.getSender().getAirPlaneReflectInfo().getRisingAirplanes().get(1).getPotential() + "%");
|
||||
}
|
||||
} else {
|
||||
|
||||
onlyForSpottingObject.setQra(newMessageArrived.getSender().getQra());
|
||||
}
|
||||
|
||||
this.client.getDxClusterServer().broadcastSingleDXClusterEntryToLoggers(onlyForSpottingObject); //tells the DXCluster server to send a DXC message for this member to the logbook software
|
||||
this.client.getDxClusterServer().broadcastSingleDXClusterEntryToLoggers(onlyForSpottingObject);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
System.out.println("[MSGBUSMGT, ERROR:] DXCluster messageserver error while processing spot for 0: " + newMessageArrived.getSender().getCallSign() + " // " + exception.getMessage());
|
||||
@@ -1036,14 +1025,21 @@ public class MessageBusManagementThread extends Thread {
|
||||
" ; sender bearing to me: " + new Location(newMessageArrived.getSender().getQra()).getBearing(new Location(client.getChatPreferences().getStn_loginLocatorMainCat())));
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
}
|
||||
} else {
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
System.out.println("[MSGBUSMGT, Info:] Skipping angle/range analysis for message with missing locator: "
|
||||
+ newMessageArrived.getSender().getCallSign() + " -> "
|
||||
+ newMessageArrived.getReceiver().getCallSign());
|
||||
}
|
||||
|
||||
// this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.publishChatMessage(newMessageArrived); // sdtout to all message-List (new from v1.7)
|
||||
// System.out.println("MSGBS bgfx: tx call = " + newMessageArrived.getSender().getCallSign() + " / rx call = " + newMessageArrived.getReceiver().getCallSign());
|
||||
}
|
||||
} catch (NullPointerException referenceDeletedByUserLeftChatDuringMessageprocessing) {
|
||||
System.out.println("MSGBS bgfx, <<<catched error>>>: referenced user left the chat during messageprocessing or message got before user entered chat message: " + referenceDeletedByUserLeftChatDuringMessageprocessing.getStackTrace());
|
||||
// referenceDeletedByUserLeftChatDuringMessageprocessing.printStackTrace();
|
||||
System.out.println("MSGBS bgfx, <<<catched error>>>: referenced user left the chat during messageprocessing or message got before user entered chat message: "
|
||||
+ referenceDeletedByUserLeftChatDuringMessageprocessing.getMessage());
|
||||
referenceDeletedByUserLeftChatDuringMessageprocessing.printStackTrace();
|
||||
}
|
||||
|
||||
// sdtout to me message-List
|
||||
@@ -1062,7 +1058,8 @@ public class MessageBusManagementThread extends Thread {
|
||||
+ " " + newMessageArrived.getSender().getCallSign() + ", " + newMessageArrived.getMessageSenderName() + " -> "
|
||||
+ newMessageArrived.getReceiver().getCallSign() + ": " + newMessageArrived.getMessageText());
|
||||
} catch (Exception exceptionOccured) {
|
||||
System.out.println("[MSGMgtBus: ERROR CHATCHED ON MAYBE NULL ISSUE]: " + exceptionOccured.getMessage() + "\n" + exceptionOccured.getStackTrace());
|
||||
System.out.println("[MSGMgtBus: ERROR CHATCHED ON MAYBE NULL ISSUE]: " + exceptionOccured.getMessage());
|
||||
exceptionOccured.printStackTrace();
|
||||
}
|
||||
|
||||
// --- Band/QRG recognition (fills ChatMember.knownActiveBands) ---
|
||||
@@ -1085,24 +1082,21 @@ public class MessageBusManagementThread extends Thread {
|
||||
temp4.setQra(splittedMessageLine[3]);
|
||||
temp4.setLastActivity(new Utils4KST().time_generateActualTimeInDateFormat());
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), temp4);
|
||||
|
||||
if (index != -1) {
|
||||
ChatMember foundThisInChatMemberList = this.client.findActiveChatMember(temp4);
|
||||
if (foundThisInChatMemberList == null && this.client.getChatCategorySecondChat() != null) {
|
||||
/*
|
||||
* LOC messages do not carry the category. The old implementation checked
|
||||
* only the main category. Try the second active category as a fallback so
|
||||
* dual-channel operation can still update locator changes.
|
||||
*/
|
||||
temp4.setChatCategory(this.client.getChatCategorySecondChat());
|
||||
foundThisInChatMemberList = this.client.findActiveChatMember(temp4);
|
||||
}
|
||||
|
||||
if (foundThisInChatMemberList != null) {
|
||||
System.out.println("[MSGBUSMGT:] Locator Change of [" + (splittedMessageLine[2] + "], old was: "
|
||||
+ this.client.getLst_chatMemberList().get(index).getQra() + " new is: "
|
||||
+ splittedMessageLine[3]));
|
||||
|
||||
ChatMember foundThisInChatMemberList = this.client.getLst_chatMemberList().get(index); //make less list accesses
|
||||
|
||||
// this.client.getLst_chatMemberList().get(index).setQra(splittedMessageLine[3]);
|
||||
// this.client.getLst_chatMemberList().get(index).setQrb(new Location().getDistanceKmByTwoLocatorStrings(client.getChatPreferences().getLoginLocator(), splittedMessageLine[3]));
|
||||
// this.client.getLst_chatMemberList().get(index).setQTFdirection(new Location(client.getChatPreferences().getLoginLocator()).getBearing(new Location(splittedMessageLine[3])));
|
||||
|
||||
foundThisInChatMemberList.setQra(splittedMessageLine[3]);
|
||||
foundThisInChatMemberList.setQrb(new Location().getDistanceKmByTwoLocatorStrings(client.getChatPreferences().getStn_loginLocatorMainCat(), splittedMessageLine[3]));
|
||||
foundThisInChatMemberList.setQTFdirection(new Location(client.getChatPreferences().getStn_loginLocatorMainCat()).getBearing(new Location(splittedMessageLine[3])));
|
||||
|
||||
+ foundThisInChatMemberList.getQra() + " new is: " + splittedMessageLine[3]));
|
||||
this.client.updateActiveChatMemberLocator(temp4, splittedMessageLine[3]);
|
||||
} else {
|
||||
System.out.println("[MSGBUSMGT:] ERROR! Locator Change of ["
|
||||
+ (splittedMessageLine[2] + "] is not possible, user is not in the Table!"));
|
||||
@@ -1232,11 +1226,9 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
stateChangeMember.setChatCategory(util_getChatCategoryByCategoryNrString(splittedMessageLine[1]));
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(),
|
||||
stateChangeMember);
|
||||
|
||||
if (index != -1 && index != 0) {
|
||||
this.client.getLst_chatMemberList().get(index).setState(stateChangeMember.getState());
|
||||
if (!this.client.updateActiveChatMemberState(stateChangeMember, stateChangeMember.getState())) {
|
||||
System.out.println("[MSGBUSMGT, Info:] State change for inactive user: "
|
||||
+ stateChangeMember.getCallSign() + " / " + stateChangeMember.getChatCategory());
|
||||
}
|
||||
|
||||
// this.client.getChatMemberTable().get(stateChangeMember.getCallSign())
|
||||
@@ -1266,14 +1258,9 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
// System.out.println("[MSGBUSMGT:] DXCluster Message detected ");
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(),
|
||||
stateChangeMember);
|
||||
|
||||
//-1 could be the case if mycall is processed
|
||||
if (index != -1) {
|
||||
this.client.getLst_chatMemberList().get(index).setName(stateChangeMember.getName());
|
||||
this.client.getLst_chatMemberList().get(index).setQra(stateChangeMember.getQra());
|
||||
this.client.getLst_chatMemberList().get(index).setState(stateChangeMember.getState());
|
||||
// -1 could be the case if mycall is processed; own call is not displayed in the active-member list.
|
||||
if (!client.getChatPreferences().getStn_loginCallSign().equalsIgnoreCase(stateChangeMember.getCallSign())) {
|
||||
this.client.updateOrAddActiveChatMemberInfo(stateChangeMember);
|
||||
}
|
||||
|
||||
} else
|
||||
@@ -1297,6 +1284,8 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
chategoryForMessageAndMessageSender = newMessageArrived.getChatCategory();
|
||||
newMessageArrived.setMessageGeneratedTime(splittedMessageLine[2]);
|
||||
newMessageArrived.setMessageSenderName(splittedMessageLine[4]);
|
||||
newMessageArrived.setMessageText(splittedMessageLine[6]);
|
||||
|
||||
if (splittedMessageLine[3].equals("SERVER")) {
|
||||
ChatMember dummy = new ChatMember();
|
||||
@@ -1309,76 +1298,16 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
} else {
|
||||
|
||||
ChatMember sender = new ChatMember();
|
||||
sender.setCallSign(splittedMessageLine[3]);
|
||||
sender.setChatCategory(chategoryForMessageAndMessageSender);
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), sender);
|
||||
|
||||
if (index != -1) {
|
||||
//user not found in the chatmember list
|
||||
try {
|
||||
// newMessageArrived.setSender(this.client.getLst_chatMemberList().get(index)); // set sender to member of
|
||||
// this.client.getLst_chatMemberList().get(index).setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
|
||||
ChatMember senderObj = this.client.getLst_chatMemberList().get(index);
|
||||
newMessageArrived.setSender(senderObj);
|
||||
senderObj.setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
|
||||
// Remember last inbound category per callsignRaw (required for correct send-routing later)
|
||||
this.client.rememberLastInboundCategory(senderObj.getCallSignRaw(), senderObj.getChatCategory());
|
||||
|
||||
// Metrics for scoring: momentum, response-time, no-reply, positive signals
|
||||
this.client.getStationMetricsService().onInboundMessage(
|
||||
senderObj.getCallSignRaw(),
|
||||
System.currentTimeMillis(),
|
||||
newMessageArrived.getMessageText(),
|
||||
this.client.getChatPreferences(),
|
||||
this.client.getChatPreferences().getStn_loginCallSign()
|
||||
);
|
||||
|
||||
// Activity/category changes influence priority => request recompute
|
||||
this.client.getScoreService().requestRecompute("rx-chat-message");
|
||||
|
||||
} catch (Exception exc) {
|
||||
ChatMember aSenderDummy = new ChatMember();
|
||||
aSenderDummy.setCallSign(splittedMessageLine[3] + "[n/a]");
|
||||
aSenderDummy.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
newMessageArrived.setSender(aSenderDummy);
|
||||
System.out.println("MsgBusmgtT: Catched Error! " + exc.getMessage() + " // " + splittedMessageLine[3] + " is not in the list! Faking sender!");
|
||||
exc.printStackTrace();
|
||||
}
|
||||
// b4 init list
|
||||
} else {
|
||||
//user not found in chatmember list, mark it, sender can not be set
|
||||
if (!sender.getCallSign().equals(this.client.getChatPreferences().getStn_loginCallSign().toUpperCase())) {
|
||||
sender.setCallSign("[n/a]" + sender.getCallSign());
|
||||
// if someone sent a message without being in the userlist (cause
|
||||
// on4kst missed implementing....), callsign will be marked
|
||||
} else {
|
||||
//that means, message was by own station, broadcasted to all other
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
|
||||
AirPlaneReflectionInfo preventNullpointerExc = new AirPlaneReflectionInfo();
|
||||
preventNullpointerExc.setAirPlanesReachableCntr(0);
|
||||
sender.setAirPlaneReflectInfo(preventNullpointerExc);
|
||||
newMessageArrived.setSender(sender); //my own call is the sender
|
||||
}
|
||||
newMessageArrived.setSender(resolveInboundSender(
|
||||
splittedMessageLine[3],
|
||||
chategoryForMessageAndMessageSender,
|
||||
newMessageArrived));
|
||||
}
|
||||
|
||||
// newMessageArrived.setSender(this.client.getChatMemberTable().get(splittedMessageLine[3]));
|
||||
}
|
||||
|
||||
newMessageArrived.setMessageSenderName(splittedMessageLine[4]);
|
||||
newMessageArrived.setMessageText(splittedMessageLine[6]);
|
||||
|
||||
if (splittedMessageLine[7].equals("0")) {
|
||||
// message is not directed to anyone, move it to the cq messages!
|
||||
ChatMember dummy = new ChatMember();
|
||||
dummy.setCallSign("ALL");
|
||||
newMessageArrived.setReceiver(dummy);
|
||||
// message is not directed to anyone, move it to the cq messages.
|
||||
newMessageArrived.setReceiver(createAllReceiver());
|
||||
|
||||
// this.client.getLst_globalChatMessageList().add(0, newMessageArrived); // sdtout to all message-List
|
||||
this.client.publishChatMessage(newMessageArrived); // sdtout to all message-List (new from v1.7)
|
||||
@@ -1386,35 +1315,9 @@ public class MessageBusManagementThread extends Thread {
|
||||
} else {
|
||||
//message is directed to another chatmember, process as such!
|
||||
|
||||
ChatMember receiver = new ChatMember();
|
||||
|
||||
receiver.setChatCategory(chategoryForMessageAndMessageSender); //got out of message itself
|
||||
|
||||
receiver.setCallSign(splittedMessageLine[7]);
|
||||
|
||||
int index = checkListForChatMemberIndexByCallSign(this.client.getLst_chatMemberList(), receiver);
|
||||
|
||||
if (index != -1) {
|
||||
newMessageArrived.setReceiver(this.client.getLst_chatMemberList().get(index));// -1: Member left Chat
|
||||
// before...
|
||||
} else { //found in active member list
|
||||
|
||||
if (receiver.getCallSign().equals(client.getChatPreferences().getStn_loginCallSign())) {
|
||||
/**
|
||||
* If mycallsign sent a message to the server, server will publish that message and
|
||||
* send it to all chatmember including me.
|
||||
* As mycall is not in the userlist, the message would not been displayed if I handle
|
||||
* it in the next case (marking left user, just for information). But I want an echo.
|
||||
*/
|
||||
|
||||
receiver.setCallSign(client.getChatPreferences().getStn_loginCallSign());
|
||||
newMessageArrived.setReceiver(receiver);
|
||||
} else {
|
||||
//this are user which left chat but had been adressed by this message
|
||||
receiver.setCallSign(receiver.getCallSign() + "(left)");
|
||||
newMessageArrived.setReceiver(receiver);
|
||||
}
|
||||
}
|
||||
newMessageArrived.setReceiver(resolveInboundReceiver(
|
||||
splittedMessageLine[7],
|
||||
chategoryForMessageAndMessageSender));
|
||||
|
||||
// System.out.println("message directed to: " + newMessageArrived.getReceiver().getCallSign() + ". EQ?: " + this.client.getownChatMemberObject().getCallSign() + " sent by: " + newMessageArrived.getSender().getCallSign().toUpperCase() + " -> EQ?: "+ this.client.getChatPreferences().getLoginCallSign().toUpperCase());
|
||||
|
||||
@@ -1447,7 +1350,16 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
} else {
|
||||
//message sent to other user
|
||||
if (DirectionUtils.isInAngleAndRange(client.getChatPreferences().getStn_loginLocatorMainCat(),
|
||||
// message sent from one other station to another other station
|
||||
boolean senderHasLocator = newMessageArrived.getSender().getQra() != null
|
||||
&& !newMessageArrived.getSender().getQra().isBlank();
|
||||
|
||||
boolean receiverHasLocator = newMessageArrived.getReceiver().getQra() != null
|
||||
&& !newMessageArrived.getReceiver().getQra().isBlank();
|
||||
|
||||
if (senderHasLocator && receiverHasLocator) {
|
||||
if (DirectionUtils.isInAngleAndRange(
|
||||
client.getChatPreferences().getStn_loginLocatorMainCat(),
|
||||
newMessageArrived.getSender().getQra(),
|
||||
newMessageArrived.getReceiver().getQra(),
|
||||
client.getChatPreferences().getStn_maxQRBDefault(),
|
||||
@@ -1456,17 +1368,24 @@ public class MessageBusManagementThread extends Thread {
|
||||
newMessageArrived.getSender().setInAngleAndRange(true);
|
||||
|
||||
} else {
|
||||
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Historic fallback senders/receivers may not have locators.
|
||||
* The message is still valid and should be displayed, but angle/range
|
||||
* analysis cannot be calculated without both locators.
|
||||
*/
|
||||
newMessageArrived.getSender().setInAngleAndRange(false);
|
||||
}
|
||||
|
||||
// this.client.getLst_globalChatMessageList().add(0, newMessageArrived);
|
||||
this.client.publishChatMessage(newMessageArrived); // sdtout to all message-List (new from v1.7)
|
||||
this.client.publishChatMessage(newMessageArrived);
|
||||
// System.out.println("MSGBS bgfx: tx call = " + newMessageArrived.getSender().getCallSign() + " / rx call = " + newMessageArrived.getReceiver().getCallSign());
|
||||
}
|
||||
} catch (NullPointerException referenceDeletedByUserLeftChatDuringMessageprocessing) {
|
||||
System.out.println("MSGBS bgfx, <<<catched error>>>: referenced user left the chat during messageprocessing or message got before user entered chat message: " + referenceDeletedByUserLeftChatDuringMessageprocessing.getStackTrace());
|
||||
// referenceDeletedByUserLeftChatDuringMessageprocessing.printStackTrace();
|
||||
System.out.println("MSGBS bgfx, <<<catched error>>>: referenced user left the chat during messageprocessing or message got before user entered chat message: "
|
||||
+ referenceDeletedByUserLeftChatDuringMessageprocessing.getMessage());
|
||||
referenceDeletedByUserLeftChatDuringMessageprocessing.printStackTrace();
|
||||
}
|
||||
|
||||
// sdtout to me message-List
|
||||
@@ -1479,7 +1398,8 @@ public class MessageBusManagementThread extends Thread {
|
||||
+ " " + newMessageArrived.getSender().getCallSign() + ", " + newMessageArrived.getMessageSenderName() + " -> "
|
||||
+ newMessageArrived.getReceiver().getCallSign() + ": " + newMessageArrived.getMessageText());
|
||||
} catch (Exception exceptionOccured) {
|
||||
System.out.println("[MSGMgtBus: ERROR CHATCHED ON MAYBE NULL ISSUE]: " + exceptionOccured.getMessage() + "\n" + exceptionOccured.getStackTrace());
|
||||
System.out.println("[MSGMgtBus: ERROR CHATCHED ON MAYBE NULL ISSUE]: " + exceptionOccured.getMessage());
|
||||
exceptionOccured.printStackTrace();
|
||||
}
|
||||
|
||||
// --- Band/QRG recognition (fills ChatMember.knownActiveBands) ---
|
||||
@@ -1534,7 +1454,7 @@ public class MessageBusManagementThread extends Thread {
|
||||
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
client.getLst_globalChatMessageList().add(pwErrorMsg);
|
||||
client.publishChatMessage(pwErrorMsg);
|
||||
// client.getLst_toMeMessageList().add(pwErrorMsg);
|
||||
// client.getLst_toAllMessageList().add(pwErrorMsg);
|
||||
}
|
||||
@@ -1546,6 +1466,10 @@ public class MessageBusManagementThread extends Thread {
|
||||
// this.client.disconnect();
|
||||
}
|
||||
|
||||
else if (splittedMessageLine[0].equals("DE")) {
|
||||
// DXCluster delimiter/end marker; intentionally ignored.
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
// bufwrtrDBGMSGOut.write(new Utils4KST().time_generateCurrentMMDDhhmmTimeString()
|
||||
@@ -1751,6 +1675,10 @@ public class MessageBusManagementThread extends Thread {
|
||||
} catch (SQLException e) {
|
||||
System.out.println("MsgBusMgt: process23001 went wrong / SQL Error");
|
||||
e.printStackTrace();
|
||||
} catch (RuntimeException e) {
|
||||
System.out.println("MsgBusMgt: process23001 went wrong / Runtime Error while processing: "
|
||||
+ messageTextRaw.getMessageText());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user