Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile.chat-service
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]
ENTRYPOINT ["java", "-XX:+UseG1GC", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
Empty file modified chat-service/mvnw
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -165,10 +166,12 @@ public Message sendMessage(String conversationId, String senderId, String body)
}

private void broadcast(Message msg) {
var resp = new com.blink.chatservice.websocket.dto.RealtimeMessageResponse(msg.getId(), msg.getConversationId(), msg.getSenderId(), msg.getRecipientId(), msg.getBody(), msg.getCreatedAt());
messagingTemplate.convertAndSend("/topic/conversations/" + msg.getConversationId(), resp);
if (msg.getRecipientId() != null) messagingTemplate.convertAndSendToUser(msg.getRecipientId(), "/queue/messages", resp);
messagingTemplate.convertAndSendToUser(msg.getSenderId(), "/queue/messages", resp);
CompletableFuture.runAsync(() -> {
var resp = new com.blink.chatservice.websocket.dto.RealtimeMessageResponse(msg.getId(), msg.getConversationId(), msg.getSenderId(), msg.getRecipientId(), msg.getBody(), msg.getCreatedAt());
messagingTemplate.convertAndSend("/topic/conversations/" + msg.getConversationId(), resp);
if (msg.getRecipientId() != null) messagingTemplate.convertAndSendToUser(msg.getRecipientId(), "/queue/messages", resp);
messagingTemplate.convertAndSendToUser(msg.getSenderId(), "/queue/messages", resp);
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
"/swagger-ui/**",
"/swagger-ui.html",
"/swagger-ui/index.html",
"/actuator/health",
"/actuator/info",
// Allowing public access to ws handshake, socket security is handled separately.
"/ws/**"
).permitAll()
Expand Down
1 change: 1 addition & 0 deletions chat-service/src/main/resources/application-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ spring:
data:
mongodb:
uri: ${MONGODB_URI}
auto-index-creation: false
redis:
host: ${SPRING_DATA_REDIS_HOST}
port: ${SPRING_DATA_REDIS_PORT:6379}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void sendMessage_shouldSaveMessageAndBroadcast() {
assertNotNull(result);
assertEquals("Hello", result.getBody());
verify(messageRepository).save(any(Message.class));
verify(messagingTemplate, atLeastOnce()).convertAndSend(anyString(), any(Object.class));
verify(messagingTemplate, timeout(1000).atLeastOnce()).convertAndSend(anyString(), any(Object.class));
}

@Test
Expand Down
8 changes: 4 additions & 4 deletions frontend-v2/src/components/chat/MessageList.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useInfiniteQuery, useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
import { useEffect, useRef, useState, useLayoutEffect, useCallback } from 'react';
import { useEffect, useRef, useState, useLayoutEffect, useCallback, memo } from 'react';
import { chatService, socketService, userService } from '../../services';
import { queryKeys } from '../../lib/queryClient';
import { useAuthStore, useChatStore } from '../../stores';
Expand Down Expand Up @@ -588,7 +588,7 @@ function renderMessageWithLinks(text, isOwn) {
}

// ─── Message bubble ──────────────────────────────────────────────────
function MessageBubble({
const MessageBubble = memo(({
message,
isOwn,
showAvatar,
Expand All @@ -598,7 +598,7 @@ function MessageBubble({
fallbackName,
isGroup,
isAI
}) {
}) => {
const [isHovered, setIsHovered] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const queryClient = useQueryClient();
Expand Down Expand Up @@ -766,4 +766,4 @@ function MessageBubble({
</div>
</div>
);
}
});
3 changes: 2 additions & 1 deletion nginxv2.conf
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ http {
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' ws: wss: https:;" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https: blob:; font-src 'self' data:; connect-src 'self' ws: wss: https:; object-src 'none'; frame-ancestors 'self'; base-uri 'self';" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# Health check endpoint
Expand Down
Loading