NotificationService.java

package com.learning.yasminishop.notification;

import com.learning.yasminishop.common.configs.security.JwtService;
import com.learning.yasminishop.common.entity.Notification;
import com.learning.yasminishop.common.entity.User;
import com.learning.yasminishop.common.exception.AppException;
import com.learning.yasminishop.common.exception.ErrorCode;
import com.learning.yasminishop.notification.dto.response.NotificationResponse;
import com.learning.yasminishop.notification.mapper.NotificationMapper;
import com.learning.yasminishop.user.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class NotificationService {

    private final NotificationRepository notificationRepository;
    private final UserRepository userRepository;
    private final NotificationMapper notificationMapper;

    private final JwtService jwtService;
    private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();


    public void addEmitter(SseEmitter emitter, String token) {

        if(!jwtService.isTokenValid(token)) {
            log.error("Token is not valid");
            emitter.completeWithError(new AppException(ErrorCode.INVALID_TOKEN));
            return;
        }

        String email = jwtService.extractUserEmail(token);
        log.info("User with email {} subscribed to notifications", email);
        emitters.put(email, emitter);
    }

    public void sendNotification(String clientId, NotificationResponse notificationResponse) {
        SseEmitter emitter = emitters.get(clientId);
        if (emitter != null) {
            try {
                emitter.send(notificationResponse);
            } catch (IOException e) {
                emitter.completeWithError(e);
                emitters.remove(clientId);
            }
        }
    }

    public List<NotificationResponse> getNotifications() {
        String email = SecurityContextHolder.getContext().getAuthentication().getName();

        User user = userRepository.findByEmail(email)
                .orElseThrow(() -> new AppException(ErrorCode.USER_NOT_FOUND));

        List<Notification> notifications = notificationRepository.findAllByUserOrderByCreatedDateDesc(user);
        return notifications
                .stream()
                .map(notificationMapper::toNotificationResponse)
                .toList();
    }

    public void createNotification(Notification notification) {
        notificationRepository.save(notification);
        sendNotification(notification.getUser().getEmail(), notificationMapper.toNotificationResponse(notification));
    }

}