com.infusers.core.stats.users.ActiveUserService Maven / Gradle / Ivy
package com.infusers.core.stats.users;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.infusers.core.audit.AuditService;
import com.infusers.core.cache.redis.RedisCacheKeys;
import com.infusers.core.logger.ILogger;
import com.infusers.core.reports.dto.ReportColumn;
import com.infusers.core.reports.dto.ReportData;
import com.infusers.core.reports.dto.ReportRow;
import com.infusers.core.security.common.UserLoggedInEvent;
import com.infusers.core.security.common.UserLoggedOutEvent;
import com.infusers.core.sse.requests.ActiveRequestEntryEvent;
import com.infusers.core.sse.requests.HTTPRequestDto;
import com.infusers.core.user.util.UserUtility;
import com.infusers.core.util.InfusersUtility;
import jakarta.annotation.PostConstruct;
@Service
@EnableScheduling
public class ActiveUserService {
private final ILogger log = new ILogger(ActiveUserService.class);
private static final String CLASS_NAME = "ActiveUserService";
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy");
@Autowired
private UserUtility userUtility;
@Autowired
private Gson gson;
@Autowired
private AuditService auditService;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;
@PostConstruct
public void init() {
redisTemplate.expire(RedisCacheKeys.ACTIVE_REQUEST_COUNT_KEY, userUtility.getAutoLogoutTimeMinutes(), TimeUnit.MINUTES);
}
@EventListener
public void handleUserLoggedInEvent(UserLoggedInEvent event) {
try {
updateUserActivity(event);
}
catch(Exception e) {
log.error(CLASS_NAME + ".handleUserLoggedInEvent() -> Error hadling user logged in event: "+ e+" :: User Name = "+event.getUserName());
}
}
@EventListener
public void handleActiveRequestEntryEvent(ActiveRequestEntryEvent event) {
try {
HTTPRequestDto requestDto = event.getReqDto();
if(requestDto.getUserName()!=null) {
updateUserRequestActivity(requestDto);
}
}
catch(Exception e) {
log.error(CLASS_NAME + ".handleActiveRequestEntryEvent() -> Error hadling active reqeust event: "+ e+" :: event = "+event.getReqDto());
}
}
private void updateUserRequestActivity(HTTPRequestDto requestDto) {
ActiveUserDto activeUserDto = getDto(null, requestDto);
redisTemplate.opsForHash().put(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY, activeUserDto.getKey(), gson.toJson(activeUserDto));
}
// Method to update the user's activity timestamp
private void updateUserActivity(UserLoggedInEvent event) {
ActiveUserDto activeUserDto = getDto(event, null);
redisTemplate.opsForHash().put(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY, activeUserDto.getKey(), gson.toJson(activeUserDto));
publishActiveUsersCount();
}
private ActiveUserDto getDto(UserLoggedInEvent event, HTTPRequestDto requestDto) {
String userName = null;
if(event!=null) {
userName = event.getUserName();
}
else if (requestDto!=null) {
userName = requestDto.getUserName();
}
else {
log.error(CLASS_NAME + ".getDto() -> Needs attendion!! Both Logged In event & HTTP Request are NULL! event = "+event+" :: requestDto = "+requestDto);
}
String dtoJson = (String) redisTemplate.opsForHash().get(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY, userName);
ActiveUserDto activeUserDto = gson.fromJson(dtoJson, ActiveUserDto.class);
if (activeUserDto == null) {
if(event!=null) {
activeUserDto = new ActiveUserDto(event);
}
else if (requestDto!=null) {
activeUserDto = new ActiveUserDto(requestDto);
}
else {
log.error(CLASS_NAME + ".getDto() -> Needs attendion!! activeUserDto is NULL! Also, both Logged In event & HTTP Request are NULL! event = "+event+" :: requestDto = "+requestDto);
}
}
else if(requestDto!=null){
activeUserDto.set(requestDto);
}
else {
log.error(CLASS_NAME + ".getDto() -> Needs attendion!! Cached update will fail!! userName = "+userName+" :: event = "+event.toString()+" :: requestDto = "+requestDto+" :: activeUserDto = "+activeUserDto.toString());
}
return activeUserDto;
}
@EventListener
public void handleUserLoggedOutEvent(UserLoggedOutEvent event) {
logout(event.getUserName());
}
private void logout(String userName) {
// Deleting a specific user entry from the Redis hash
Long deletedCount = redisTemplate.opsForHash().delete(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY, userName);
publishActiveUsersCount();
if (deletedCount <= 0) {
auditService.log(log, ILogger.LogTypes.ERROR, CLASS_NAME, "logout", "", "User exists?? Failed to remove user: " + userName + " :: Active Users# " + getActiveUserCount());
}
}
// Scheduled task to clean up inactive users
@Scheduled(fixedRate = 60000) // Runs every 60 seconds
public void cleanupInactiveUsers() {
// No need for manual cleanup; Redis will automatically expire entries
publishActiveUsersCount();
}
private void publishActiveUsersCount() {
long count = getActiveUserCount();
eventPublisher.publishEvent(new ActiveUserCountEvent(this, count));
}
// Method to get the number of active users
public long getActiveUserCount() {
// Get the total number of active users
long totalActiveUsers = redisTemplate.opsForHash().size(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY);
// Check if "anonymousUser" is present in the cache
Boolean hasAnonymousUser = redisTemplate.opsForHash()
.hasKey(RedisCacheKeys.ACTIVE_USERS_COUNT_PREFIX_KEY, InfusersUtility.ANONYMOUS_USER);
// Subtract 1 from the count if "anonymousUser" is present
if (hasAnonymousUser != null && hasAnonymousUser) {
return totalActiveUsers - 1;
}
return totalActiveUsers;
}
private List getActiveUsersFromCache() {
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy