package de.towerdefence.server.session; import de.towerdefence.server.player.Player; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.*; @Service @AllArgsConstructor public class SessionsService { private static final int TIME_TO_LIVE_SECONDS = 30; private final Map tokenGrants = new ConcurrentHashMap<>(); private final Map sessions = new ConcurrentHashMap<>(); private final Map> tokenGarbageCollectors = new ConcurrentHashMap<>(); @Autowired private final JwtService jwtService; private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); public String createSession(Player player, Channel channel){ String jwt = jwtService.generateToken(player.getUsername(), channel, TIME_TO_LIVE_SECONDS); if(tokenGrants.containsKey(jwt)){ throw new IllegalStateException("The exact same JWT allready exists"); } tokenGrants.put(jwt, channel); sessions.put(jwt, player); this.tokenGarbageCollectors.put(jwt, scheduler.schedule(() -> { tokenGrants.remove(jwt); sessions.remove(jwt); tokenGarbageCollectors.remove(jwt); }, TIME_TO_LIVE_SECONDS, TimeUnit.SECONDS)); return jwt; } public Optional getSession(String jwt, Channel channel){ Channel grantedChannel = tokenGrants.get(jwt); if (grantedChannel == null || !grantedChannel.equals(channel)) { return Optional.empty(); } Optional username = jwtService.verifyToken(jwt, channel); if (username.isEmpty()) { return Optional.empty(); } Player player = sessions.get(jwt); if (!Objects.equals(player.getUsername(), username.get())) { return Optional.empty(); } ScheduledFuture garbageCollector = tokenGarbageCollectors.get(jwt); if (garbageCollector != null && !garbageCollector.isCancelled() && !garbageCollector.isDone()) { garbageCollector.cancel(false); } tokenGarbageCollectors.remove(jwt); tokenGrants.remove(jwt); sessions.remove(jwt); return Optional.of(player); } }