Ensure unique timestamps for chat messages to prevent collisions and fix date formatting in chat-box UI.
This commit is contained in:
parent
564582a6f9
commit
9e5148fa8c
|
|
@ -2,6 +2,7 @@ package com.alttd.altitudeweb.controllers.chat;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -11,7 +12,8 @@ import java.util.UUID;
|
||||||
public class ChatMessage {
|
public class ChatMessage {
|
||||||
|
|
||||||
private final UUID uuid;
|
private final UUID uuid;
|
||||||
private final Instant timestamp;
|
@Setter
|
||||||
|
private Instant timestamp;
|
||||||
private final String server;
|
private final String server;
|
||||||
//TODO [Stijn] [2026-07-18]: Handle channel types
|
//TODO [Stijn] [2026-07-18]: Handle channel types
|
||||||
//private final String channel;
|
//private final String channel;
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,18 @@ import com.alttd.altitudeweb.database.chat.ChatLogDao;
|
||||||
import com.alttd.altitudeweb.model.ChatMessageDto;
|
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ChatMessageMapper {
|
public class ChatMessageMapper {
|
||||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
|
||||||
.registerModule(new JavaTimeModule());
|
.registerModule(new JavaTimeModule())
|
||||||
|
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||||
|
.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
|
||||||
|
|
||||||
public ChatMessage fromDto(ChatMessageDto dto) {
|
public ChatMessage fromDto(ChatMessageDto dto) {
|
||||||
return ChatMessage.builder()
|
return ChatMessage.builder()
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ public class ChatService {
|
||||||
private String[] allowedServers;
|
private String[] allowedServers;
|
||||||
private final NavigableMap<Instant, ChatMessage> chatMessages = new TreeMap<>();
|
private final NavigableMap<Instant, ChatMessage> chatMessages = new TreeMap<>();
|
||||||
private final EventPublisher eventPublisher;
|
private final EventPublisher eventPublisher;
|
||||||
|
private long lastMillis = 0;
|
||||||
|
|
||||||
@Scheduled(cron = "0 * * * * *")
|
@Scheduled(cron = "0 * * * * *")
|
||||||
public void clearOldMessages() {
|
public void clearOldMessages() {
|
||||||
|
|
@ -50,7 +51,8 @@ public class ChatService {
|
||||||
try {
|
try {
|
||||||
sqlSession.getMapper(ChatLogMapper.class)
|
sqlSession.getMapper(ChatLogMapper.class)
|
||||||
.getChatLogs(Instant.now().minus(Duration.ofHours(1)).toEpochMilli())
|
.getChatLogs(Instant.now().minus(Duration.ofHours(1)).toEpochMilli())
|
||||||
.stream().map(ChatMessageMapper::fromDao)
|
.stream()
|
||||||
|
.map(ChatMessageMapper::fromDao)
|
||||||
.forEach(this::putChatMessage);
|
.forEach(this::putChatMessage);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to load history count", e);
|
log.error("Failed to load history count", e);
|
||||||
|
|
@ -58,7 +60,19 @@ public class ChatService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void setUniqueTimestamp(ChatMessage chatMessage) {
|
||||||
|
long timestamp = chatMessage.getTimestamp().toEpochMilli();
|
||||||
|
if (timestamp == lastMillis) {
|
||||||
|
timestamp += 1;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastMillis = timestamp;
|
||||||
|
chatMessage.setTimestamp(Instant.ofEpochMilli(timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
private void putChatMessage(ChatMessage chatMessage) {
|
private void putChatMessage(ChatMessage chatMessage) {
|
||||||
|
setUniqueTimestamp(chatMessage);
|
||||||
chatMessages.put(chatMessage.getTimestamp(), chatMessage);
|
chatMessages.put(chatMessage.getTimestamp(), chatMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@for (message of messages(); track message.timestamp) {
|
@for (message of messages(); track message.timestamp) {
|
||||||
<p class="message">
|
<p class="message">
|
||||||
<span class="date-time" [class.blocked]="!message.notBlocked">
|
<span class="date-time" [class.blocked]="!message.notBlocked">
|
||||||
[{{ message.timestamp * 1000 | date: 'mediumTime' }}]
|
[{{ message.timestamp | date: 'mediumTime' }}]
|
||||||
</span>
|
</span>
|
||||||
<mini-message [node]="message.messageJson"></mini-message>
|
<mini-message [node]="message.messageJson"></mini-message>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user