troubleshooting kram

pull/41/head
eric 2025-08-11 19:06:39 +02:00
parent 65a7ef3e5f
commit 5531b57018
4 changed files with 91 additions and 28 deletions

View File

@ -23,6 +23,7 @@ package eric.Roullette.controller;
import java.util.Map; import java.util.Map;
// import java.util.Objects; // import java.util.Objects;
// import java.util.UUID; // import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
// import java.util.concurrent.TimeUnit; // import java.util.concurrent.TimeUnit;
@ -32,6 +33,8 @@ public class GameController {
private final GameWebSocketHandler webSocketHandler; private final GameWebSocketHandler webSocketHandler;
private final OkHttpClient httpClient = new OkHttpClient(); private final OkHttpClient httpClient = new OkHttpClient();
private String accessToken = ""; private String accessToken = "";
private Map<String, String> userAccessTokens = new ConcurrentHashMap<>();
// Map<username, accessToken>
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GameController.class); private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GameController.class);
public GameController(Javalin app, GameService gs, SpotifyAuthService sas, GameWebSocketHandler wsHandler) { public GameController(Javalin app, GameService gs, SpotifyAuthService sas, GameWebSocketHandler wsHandler) {
@ -50,21 +53,28 @@ public class GameController {
ctx.status(400).result("username fehlt"); ctx.status(400).result("username fehlt");
return; return;
} }
var accessToken = authService.getAccessTokenForUser(username); // spieler in map hinzufügen
String playerAccessToken = null;
if(!userAccessTokens.containsKey(username)) {
playerAccessToken = authService.getAccessTokenForUser(username);
if (playerAccessToken != null) {
userAccessTokens.put(username, playerAccessToken);
}
}
if (accessToken == null) { if (accessToken == null) {
ctx.status(401).result("Zugriffstoken fehlt oder ist ungültig"); ctx.status(401).result("Zugriffstoken fehlt oder ist ungültig");
return; return;
} }
setToken(accessToken);
var devices = authService.getDevices(accessToken); var devices = authService.getDevices(accessToken);
ctx.json(devices); ctx.json(devices);
}); });
} }
private void setToken(String accessToken) {
this.accessToken = accessToken;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void createGame(Context ctx) throws InterruptedException { private void createGame(Context ctx) throws InterruptedException {
Map<String, Object> body = (Map<String, Object>) ctx.bodyAsClass(Map.class); Map<String, Object> body = (Map<String, Object>) ctx.bodyAsClass(Map.class);
@ -144,6 +154,7 @@ public class GameController {
try { try {
//String accessToken = authService.getAccessTokenForUser(username); //String accessToken = authService.getAccessTokenForUser(username);
String accessToken = userAccessTokens.get(username);
OkHttpClient client = httpClient; OkHttpClient client = httpClient;
String trackId = trackUri.split(":")[2]; String trackId = trackUri.split(":")[2];
Request getTrack = new Request.Builder() Request getTrack = new Request.Builder()

View File

@ -20,7 +20,7 @@ import java.net.URI;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static com.neovisionaries.i18n.CountryCode.DE; //import static com.neovisionaries.i18n.CountryCode.DE;
public class SpotifyAuthService { public class SpotifyAuthService {
private final String clientId; private final String clientId;
@ -38,18 +38,27 @@ public class SpotifyAuthService {
public URI getAuthorizationUri(String user) { public URI getAuthorizationUri(String user) {
System.out.println("Erstelle Auth-URL für Benutzer: " + user); System.out.println("Erstelle Auth-URL für Benutzer: " + user);
// Temporäre API-Instanz nur für die Erstellung der Auth-URL // Temporäre API-Instanz nur für die Erstellung der Auth-URL
String scope = "user-read-recently-played user-library-read user-modify-playback-state user-read-playback-state streaming user-read-private";
//
SpotifyApi tempApi = new SpotifyApi.Builder() SpotifyApi tempApi = new SpotifyApi.Builder()
.setClientId(clientId) .setClientId(clientId)
.setClientSecret(clientSecret) .setClientSecret(clientSecret)
.setRedirectUri(redirectUri) .setRedirectUri(redirectUri)
.build(); .build();
//überprüfe, ob der nutzer ein Premium-User ist
return tempApi.authorizationCodeUri() return tempApi.authorizationCodeUri()
.scope("user-read-recently-played user-library-read user-read-playback-state user-modify-playback-state streaming") .scope(scope)
.state(user) // Der Benutzername wird im State mitgegeben .state(user) // Der Benutzername wird im State mitgegeben
.show_dialog(true)
.build() .build()
.execute(); .execute();
} }
// public boolean isPremiumUser(SpotifyApi api) throws IOException, SpotifyWebApiException, ParseException {
// var user = api.getCurrentUsersProfile().build().execute();
// return "premium".equalsIgnoreCase(String.valueOf(user.getProduct()));
// }
public void exchangeCode(String code, String user) throws IOException, ParseException, SpotifyWebApiException { public void exchangeCode(String code, String user) throws IOException, ParseException, SpotifyWebApiException {
// Erstellt eine neue, dedizierte API-Instanz für diesen Benutzer // Erstellt eine neue, dedizierte API-Instanz für diesen Benutzer
@ -63,6 +72,8 @@ public class SpotifyAuthService {
AuthorizationCodeCredentials creds = userApi.authorizationCode(code).build().execute(); AuthorizationCodeCredentials creds = userApi.authorizationCode(code).build().execute();
userApi.setAccessToken(creds.getAccessToken()); userApi.setAccessToken(creds.getAccessToken());
userApi.setRefreshToken(creds.getRefreshToken()); userApi.setRefreshToken(creds.getRefreshToken());
System.out.println("Granted scopes: " + creds.getScope()); // wichtig fürs Debugging
// Speichert die fertig konfigurierte API-Instanz für den Benutzer // Speichert die fertig konfigurierte API-Instanz für den Benutzer
userApis.put(user, userApi); userApis.put(user, userApi);
@ -70,26 +81,57 @@ public class SpotifyAuthService {
public List<String> getRecentTracks(String user) { public List<String> getRecentTracks(String user) {
System.out.println("Hole kürzlich gespielte Tracks für Benutzer: " + user); System.out.println("Hole kürzlich gespielte Tracks für Benutzer: " + user);
int limit = 2; int limit = 50;
SpotifyApi userApi = userApis.get(user); SpotifyApi userApi = userApis.get(user);
if (userApi == null) { if (userApi == null) {
System.err.println("Kein SpotifyApi-Client für Benutzer gefunden: " + user); System.out.println("Kein SpotifyApi-Client für Benutzer gefunden: " + user);
return Collections.emptyList();
}
System.out.println("SpotifyApi-Client für Benutzer gefunden: " + user);
System.out.println("AccessToken: " + userApi.getAccessToken());
System.out.println("RefreshToken: " + userApi.getRefreshToken());
try {
System.out.println("Hole Profil für Benutzer: " + user);
// Hole das Profil des Benutzers, um den Account-Typ zu überprüfen
var profile = userApi.getCurrentUsersProfile().build().execute();
System.out.println("Account-Typ: " + profile.getProduct());
System.out.println("Erstelle Anfrage für kürzlich gespielte Tracks...");
if (userApi.getRefreshToken() == null) {
System.out.println("Refresh Token für Benutzer " + user + " ist nicht gesetzt.");
}
System.out.println("Refresh Token für Benutzer " + user + " ist gesetzt.");
if( userApi.getAccessToken() == null) {
System.out.println("Access Token für Benutzer " + user + " ist nicht gesetzt.");
return Collections.emptyList(); return Collections.emptyList();
} }
try { System.out.println("Access Token für Benutzer " + user + " ist gesetzt.");
GetCurrentUsersRecentlyPlayedTracksRequest request = userApi.getCurrentUsersRecentlyPlayedTracks() GetCurrentUsersRecentlyPlayedTracksRequest request = userApi.getCurrentUsersRecentlyPlayedTracks()
.limit(limit) .limit(limit)
.build(); .build();
// Führe die Anfrage aus und erhalte die Ergebnisse
System.out.println("Führe paging Anfrage aus...");
PagingCursorbased<PlayHistory> history = request.execute(); PagingCursorbased<PlayHistory> history = request.execute();
System.out.println("Paging Anfrage erfolgreich ausgeführt.");
// Überprüfe, ob die Ergebnisse leer sind
System.out.println("Überprüfe, ob Ergebnisse vorhanden sind...");
if (history == null || history.getItems() == null) { if (history == null || history.getItems() == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
System.out.println("Verarbeite kürzlich gespielte Tracks...");
// Extrahiere die URIs der kürzlich gespielten Tracks
List<String> recentTracks = Arrays.stream(history.getItems()) List<String> recentTracks = Arrays.stream(history.getItems())
.map(item -> item.getTrack().getUri()) .map(item -> item.getTrack().getUri())
.distinct() .distinct()
.toList(); .toList();
System.out.println("Gefundene kürzlich gespielte Tracks: " + recentTracks.size());
if (recentTracks.size() < limit) { if (recentTracks.size() < limit) {
int newLimit = limit - recentTracks.size(); int newLimit = limit - recentTracks.size();
@ -106,7 +148,14 @@ public class SpotifyAuthService {
recentTracks.addAll(savedTracks2.subList(0, Math.min(newLimit, savedTracks2.size()))); recentTracks.addAll(savedTracks2.subList(0, Math.min(newLimit, savedTracks2.size())));
} }
} }
System.out.println("Endgültige Anzahl kürzlich gespielter Tracks: " + recentTracks.size());
return recentTracks.subList(0, Math.min(limit, recentTracks.size())); return recentTracks.subList(0, Math.min(limit, recentTracks.size()));
// } catch (se.michaelthelin.spotify.exceptions.detailed.ForbiddenException e) {
// System.out.println("ForbiddenException: " + e.getMessage());
// System.out.println("Möglicherweise hat der Benutzer keine Berechtigung, kürzlich gespielte Tracks abzurufen.");
//
//
// return Collections.emptyList();
} catch (IOException | SpotifyWebApiException | ParseException e) { } catch (IOException | SpotifyWebApiException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
return Collections.emptyList(); return Collections.emptyList();
@ -197,6 +246,7 @@ public class SpotifyAuthService {
.build(); .build();
try (Response resp = client.newCall(req).execute()) { try (Response resp = client.newCall(req).execute()) {
if (!resp.isSuccessful()) return List.of(); if (!resp.isSuccessful()) return List.of();
assert resp.body() != null;
String body = resp.body().string(); String body = resp.body().string();
// Parsen, z.B. mit Jackson // Parsen, z.B. mit Jackson
var node = new ObjectMapper().readTree(body); var node = new ObjectMapper().readTree(body);

View File

@ -22,10 +22,10 @@ public class GameWebSocketHandler {
// Spiel-ID → (Username → deren Guess) // Spiel-ID → (Username → deren Guess)
private final Map<String, Map<String, String>> currentGuesses = new ConcurrentHashMap<>(); private final Map<String, Map<String, String>> currentGuesses = new ConcurrentHashMap<>();
private final Map<String, List<String>> trackInfoCache = new ConcurrentHashMap<>(); // private final Map<String, List<String>> trackInfoCache = new ConcurrentHashMap<>();
private final Map<String, List<String>> allTracksCache = new ConcurrentHashMap<>(); // private final Map<String, List<String>> allTracksCache = new ConcurrentHashMap<>();
//Map<gameId, Map<player, List<String>> //Map<gameId, Map<player, List<String>>
private Map<String, Map<String, List<String>>> playerTracksCache = new ConcurrentHashMap<>(); //private Map<String, Map<String, List<String>>> playerTracksCache = new ConcurrentHashMap<>();
private Map<String, Map<String, List<String>>> playerTrackInfoCache = new ConcurrentHashMap<>(); private Map<String, Map<String, List<String>>> playerTrackInfoCache = new ConcurrentHashMap<>();
public GameWebSocketHandler(GameService gameService) { public GameWebSocketHandler(GameService gameService) {
@ -77,9 +77,7 @@ public class GameWebSocketHandler {
} }
case "requestPlayers" -> service.broadcastPlayers(gameId); case "requestPlayers" -> service.broadcastPlayers(gameId);
case "next-round" -> { case "next-round" -> nextround(gameId);
nextround(gameId);
}
case "start-round" -> { case "start-round" -> {
var currentGame = service.getOrCreateGame(gameId); var currentGame = service.getOrCreateGame(gameId);
if (currentGame.players().isEmpty()) return; if (currentGame.players().isEmpty()) return;
@ -94,10 +92,10 @@ public class GameWebSocketHandler {
service.startRound(gameId, allTracks); service.startRound(gameId, allTracks);
} }
// Trackinfos für alle Spieler sammeln // Trackinfos für alle Spieler sammeln
Map<String, List<String>> allTrackInfos = service.getTrackInfos(allPlayerTracks); //Map<String, List<String>> allTrackInfos = service.getTrackInfos(allPlayerTracks);
// Cache für Trackinfos pro Spiel-ID // Cache für Trackinfos pro Spiel-ID
playerTrackInfoCache.put(gameId, allTrackInfos); //playerTrackInfoCache.put(gameId, allTrackInfos);
System.out.println("TrackInfosCache für Spiel " + gameId + " hat " + allTrackInfos.size() + " Spieler (rundenstart)"); //System.out.println("TrackInfosCache für Spiel " + gameId + " hat " + allTrackInfos.size() + " Spieler (rundenstart)");
broadcastRoundStart(gameId); broadcastRoundStart(gameId);
} }
} }
@ -168,7 +166,7 @@ private void broadcastRoundResult(String gameId) {
// Prüfe auf Gewinner // Prüfe auf Gewinner
String winner = scores.entrySet().stream() String winner = scores.entrySet().stream()
.filter(e -> e.getValue() >= 30) .filter(e -> e.getValue() >= 6)
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@ -182,14 +180,15 @@ private void broadcastRoundResult(String gameId) {
broadcastToAll(gameId, winMsg); broadcastToAll(gameId, winMsg);
game.scores().replaceAll((user , pts) -> 0); // Reset Scores für alle Spieler game.scores().replaceAll((user , pts) -> 0); // Reset Scores für alle Spieler
}else{
// nächste Runde starten
// ...
// new Thread(() -> {
// try { Thread.sleep(2000); } catch (InterruptedException ignored) {}
// nextround(gameId);
// }).start();
} }
// else{
// // nächste Runde starten
// // ...
//// new Thread(() -> {
//// try { Thread.sleep(2000); } catch (InterruptedException ignored) {}
//// nextround(gameId);
//// }).start();
// }
} }
/** Hilfsmethode: Sendet eine Nachricht an alle WebSocket-Sessions eines Spiels. */ /** Hilfsmethode: Sendet eine Nachricht an alle WebSocket-Sessions eines Spiels. */

View File

@ -301,7 +301,10 @@ function handleRoundResult({ scores, guesses, owner }) {
// 8) Spielende -> Start-Button zurück // 8) Spielende -> Start-Button zurück
function handleGameEnd({ winner }) { function handleGameEnd({ winner }) {
const nextBtn = document.getElementById("nextRound");
resultP.textContent = `🎉 ${winner} hat gewonnen!`; resultP.textContent = `🎉 ${winner} hat gewonnen!`;
nextBtn.hidden = true;
nextBtn.disabled = true;
setTimeout(() => { setTimeout(() => {
startBtn.hidden = false; startBtn.hidden = false;
startBtn.disabled = false; startBtn.disabled = false;