Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.pricewagon.pricewagon.domain.alarm.service.AlarmService;

import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;

import org.springframework.scheduling.annotation.Scheduled;
Expand Down Expand Up @@ -39,101 +39,101 @@ public class AlarmServiceImpl implements AlarmService {
private final FirebaseMessaging firebaseMessaging;

@Override
@Scheduled(fixedRate = 120000) // Every 1 minute
@Transactional
@Scheduled(fixedRate = 120000)
public void checkAllAlarmsAndNotify() {
List<Alarm> activeAlarms = alarmRepository.findActiveAlarmsWithDetails(AlarmStatus.ACTIVE);

for (Alarm alarm : activeAlarms) {
Product product = alarm.getProduct();
User user = alarm.getUser();

if (productService.isPriceBelowDesired(alarm)) {
String messageBody =
product.getName() + "의 가격이 " + product.getCurrentPrice() + "원 μ΄ν•˜λ‘œ λ–¨μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.";
boolean notificationSent = sendNotification(user, messageBody);
if (notificationSent) {
updateAlarmStatus(alarm.getId(), AlarmStatus.INACTIVE, AlarmStatus.ACTIVE);
log.info("μ•Œλ¦Όμ΄ μ„±κ³΅μ μœΌλ‘œ 전솑 ν›„ λΉ„ν™œμ„±ν™”λ‘œ μ €μž₯ν•˜μ˜€μŠ΅λ‹ˆλ‹€." + user.getAccount());
}
try {
processAlarm(alarm);
} catch (Exception e) {
log.error("μ•ŒλžŒ 처리 쀑 였λ₯˜ λ°œμƒ: alarmId={}, error={}", alarm.getId(), e.getMessage());
}
}
}

@Transactional
protected void updateAlarmStatus(Long id, AlarmStatus status, AlarmStatus currentStatus) {
alarmRepository.updateAlarmStatus(id, status, currentStatus);
protected void processAlarm(Alarm alarm) {
Product product = alarm.getProduct();
User user = alarm.getUser();

if (productService.isPriceBelowDesired(alarm)) {
String messageBody = String.format("%s의 가격이 %d원 μ΄ν•˜λ‘œ λ–¨μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.",
product.getName(), product.getCurrentPrice());

boolean notificationSuccess = sendNotificationToUser(user, messageBody);
if (notificationSuccess) {
alarm.setStatus(AlarmStatus.INACTIVE);
alarmRepository.save(alarm);
log.info("μ•Œλ¦Ό 전솑 성곡 ν›„ μ•ŒλžŒ λΉ„ν™œμ„±ν™”: user={}", user.getAccount());
}
}
}

@Transactional
protected boolean sendNotification(User user, String messageBody) {

List<FcmToken> fcmTokens = user.getFcmTokens();
if (fcmTokens == null || fcmTokens.isEmpty()) {
protected boolean sendNotificationToUser(User user, String messageBody) {
List<FcmToken> tokens = new ArrayList<>(user.getFcmTokens());
if (tokens.isEmpty()) {
log.warn("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 μ‹€νŒ¨: FCM 토큰이 μ—†μŠ΅λ‹ˆλ‹€. μ‚¬μš©μž: {}", user.getAccount());
return false;
}

boolean allNotificationsSent = false;

log.debug("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 μ‹œμž‘: μ‚¬μš©μž: {}", user.getAccount());

Iterator<FcmToken> iterator = fcmTokens.iterator();
while (iterator.hasNext()) {
FcmToken token = iterator.next();

Message message = Message.builder()
.setToken(token.getToken())
.putData("title", "costFlower")
.putData("body", messageBody)
.build();
List<FcmToken> tokensToRemove = new ArrayList<>(); // λ³„λ„μ˜ 리슀트λ₯Ό μ‚¬μš©ν•΄μ„œ μ‚­μ œν•  토큰 λ”°λ‘œ μ €μž₯
boolean atLeastOneSuccess = false;

for (FcmToken token : tokens) {
try {
Message message = Message.builder()
.setToken(token.getToken())
.putData("title", "costFlower")
.putData("body", messageBody)
.build();

firebaseMessaging.send(message);
allNotificationsSent = true;
log.info("ν‘Έμ‹œ μ•Œλ¦Όμ΄ μ„±κ³΅μ μœΌλ‘œ μ „μ†‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ‚¬μš©μž: {}, FCM 토큰: {}", user.getAccount(), token.getToken());
atLeastOneSuccess = true;
log.info("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 성곡: user={}, token={}", user.getAccount(), token.getToken());
} catch (FirebaseMessagingException e) {
log.error("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 μ‹€νŒ¨: μ‚¬μš©μž: {}, FCM 토큰: {}, 이유: {}", user.getAccount(), token.getToken(),
e.getMessage());
log.error("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 μ‹€νŒ¨: user={}, token={}, error={}",
user.getAccount(), token.getToken(), e.getMessage());

// UNREGISTERED μ—λŸ¬ 처리: λ¬΄νš¨ν™”λœ 토큰 제거
if ("UNREGISTERED".equals(e.getMessagingErrorCode().name())) {
log.warn("μœ νš¨ν•˜μ§€ μ•Šμ€ FCM 토큰을 μ œκ±°ν•©λ‹ˆλ‹€. μ‚¬μš©μž: {}, FCM 토큰: {}", user.getAccount(), token.getToken());
iterator.remove();
user.removeFcmToken(token);
tokensToRemove.add(token);
log.warn("μœ νš¨ν•˜μ§€ μ•Šμ€ FCM 토큰 발견: user={}, token={}",
user.getAccount(), token.getToken());
}

allNotificationsSent = false;
}
}

if (!allNotificationsSent) {
userRepository.save(user);
log.info("FCM 토큰 변경사항이 μ‚¬μš©μž λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ‚¬μš©μž: {}", user.getAccount());
if (!tokensToRemove.isEmpty()) {
removeInvalidTokens(user, tokensToRemove);
}

log.debug("ν‘Έμ‹œ μ•Œλ¦Ό 전솑 μ™„λ£Œ: μ‚¬μš©μž: {}, κ²°κ³Ό: {}", user.getAccount(), allNotificationsSent);
return allNotificationsSent;
return atLeastOneSuccess;
}

@Transactional
protected void removeInvalidTokens(User user, List<FcmToken> tokensToRemove) {
tokensToRemove.forEach(token -> {
user.getFcmTokens().remove(token);

});
userRepository.save(user);
log.info("μœ νš¨ν•˜μ§€ μ•Šμ€ FCM 토큰듀 제거 μ™„λ£Œ: user={}, removedCount={}",
user.getAccount(), tokensToRemove.size());
}

@Override
@Transactional
public AlarmResponseDTO.registerAlarmDTO registerAlarm(AlarmRequestDTO.registerAlarm request, String username) {
Product product = productRepository.findByProductNumber(request.getProductNumber())
.orElseThrow(() -> new CustomException(ErrorCode.PRODUCT_NOT_FOUND));

User user = userRepository.findByAccount(username)
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
if (request.getFcmToken() != null && !request.getFcmToken().isEmpty()) {
boolean tokenExists = user.getFcmTokens().stream()
.anyMatch(token -> token.getToken().equals(request.getFcmToken()));

if (!tokenExists) {
FcmToken fcmToken = FcmToken.builder()
.token(request.getFcmToken())
.user(user)
.build();
user.addFcmToken(fcmToken);
userRepository.save(user);
log.info("μƒˆλ‘œμš΄ FCM 토큰 μ €μž₯: {}", request.getFcmToken());
}
if (request.getFcmToken() != null && !request.getFcmToken().isEmpty()) {
registerFcmToken(user, request.getFcmToken());
}

Alarm alarm = Alarm.builder()
Expand All @@ -142,6 +142,7 @@ public AlarmResponseDTO.registerAlarmDTO registerAlarm(AlarmRequestDTO.registerA
.desired_price(request.getPrice())
.status(AlarmStatus.ACTIVE)
.build();

alarmRepository.save(alarm);
product.updateAlarmCount(product.getAlarmCount() + 1);

Expand All @@ -152,4 +153,19 @@ public AlarmResponseDTO.registerAlarmDTO registerAlarm(AlarmRequestDTO.registerA
.build();
}

@Transactional
protected void registerFcmToken(User user, String tokenString) {
boolean tokenExists = user.getFcmTokens().stream()
.anyMatch(token -> token.getToken().equals(tokenString));

if (!tokenExists) {
FcmToken fcmToken = FcmToken.builder()
.token(tokenString)
.user(user)
.build();
user.addFcmToken(fcmToken);
userRepository.save(user);
log.info("μƒˆλ‘œμš΄ FCM 토큰 등둝: user={}, token={}", user.getAccount(), tokenString);
}
}
}
Loading