179 lines
7.4 KiB
Java
179 lines
7.4 KiB
Java
package eric.Roullette.controller;
|
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
import io.javalin.Javalin;
|
|
import io.javalin.http.Context;
|
|
import eric.Roullette.service.GameService;
|
|
import eric.Roullette.service.SpotifyAuthService;
|
|
import eric.Roullette.websocket.GameWebSocketHandler;
|
|
import okhttp3.OkHttpClient;
|
|
import okhttp3.Request;
|
|
import okhttp3.RequestBody;
|
|
import okhttp3.Response;
|
|
import okhttp3.MediaType;
|
|
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import java.awt.*;
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
public class GameController {
|
|
private final GameService gameService;
|
|
private final SpotifyAuthService authService;
|
|
private final GameWebSocketHandler webSocketHandler;
|
|
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GameController.class);
|
|
|
|
public GameController(Javalin app, GameService gs, SpotifyAuthService sas, GameWebSocketHandler wsHandler) {
|
|
this.gameService = gs;
|
|
this.authService = sas;
|
|
this.webSocketHandler = wsHandler;
|
|
app.post("/api/create-game", this::createGame);
|
|
app.post("/api/join-game", this::joinGame);
|
|
app.get("/api/game/{gameId}/players", this::getPlayers);
|
|
app.post("/api/game/{gameId}/start-round", this::startRound);
|
|
app.post("/api/game/{gameId}/guess", this::guess);
|
|
app.post("/api/spotify/play", this::playTrack);
|
|
app.get("/api/spotify/devices", ctx -> {
|
|
String username = ctx.queryParam("username");
|
|
if (username == null) {
|
|
ctx.status(400).result("username fehlt");
|
|
return;
|
|
}
|
|
var devices = authService.getDevices(username); // Diese Methode muss es im SpotifyAuthService geben
|
|
ctx.json(Map.of("devices", devices));
|
|
});
|
|
}
|
|
|
|
private void createGame(Context ctx) {
|
|
Map<String, Object> body = ctx.bodyAsClass(Map.class);
|
|
String user = (String) body.get("username");
|
|
if (user == null || user.isBlank()) {
|
|
ctx.status(400).result("username fehlt");
|
|
return;
|
|
}
|
|
|
|
String gameId;
|
|
do {
|
|
gameId = String.format("%04d", ThreadLocalRandom.current().nextInt(0, 10000));
|
|
} while (gameService.gameExists(gameId));
|
|
gameService.createGame(gameId);
|
|
gameService.addPlayer(gameId, user);
|
|
gameService.broadcastPlayers(gameId);
|
|
|
|
ctx.json(Map.of("status", "ok", "gameId", gameId));
|
|
}
|
|
|
|
private void joinGame(Context ctx) {
|
|
Map<String, String> body = ctx.bodyAsClass(Map.class);
|
|
String user = body.get("username");
|
|
String gameId = body.get("gameId");
|
|
if (user == null || gameId == null) {
|
|
ctx.status(400).result("username oder gameId fehlt");
|
|
return;
|
|
}
|
|
gameService.addPlayer(gameId, user);
|
|
gameService.broadcastPlayers(gameId);
|
|
ctx.json(Map.of("status", "ok"));
|
|
}
|
|
|
|
private void getPlayers(Context ctx) {
|
|
String gameId = ctx.pathParam("gameId");
|
|
var game = gameService.getOrCreateGame(gameId);
|
|
ctx.json(Map.of(
|
|
"players", game.players()
|
|
));
|
|
}
|
|
|
|
private void startRound(Context ctx) {
|
|
String gameId = ctx.pathParam("gameId");
|
|
ctx.json(Map.of("status", "ok"));
|
|
webSocketHandler.broadcastRoundStart(gameId);
|
|
}
|
|
|
|
private void guess(Context ctx) {
|
|
String gameId = ctx.pathParam("gameId");
|
|
Map<String, String> body = ctx.bodyAsClass(Map.class);
|
|
String guess = body.get("guess");
|
|
String user = body.get("username");
|
|
GameService.Game game = gameService.getOrCreateGame(gameId);
|
|
String owner = game.currentOwner();
|
|
if (owner == null || guess == null) {
|
|
ctx.status(400).result("ungültig");
|
|
return;
|
|
}
|
|
boolean correct = guess.equals(owner);
|
|
if (correct) game.scores().merge(user, 1, Integer::sum);
|
|
ctx.json(Map.of(
|
|
"correct", correct,
|
|
"owner", owner,
|
|
"scores", game.scores()
|
|
));
|
|
}
|
|
private void playTrack(Context ctx) {
|
|
Map<String, String> body = ctx.bodyAsClass(Map.class);
|
|
String username = body.get("username");
|
|
String deviceId = body.get("device_id");
|
|
String trackUri = body.get("track_uri");
|
|
if (username == null || deviceId == null || trackUri == null) {
|
|
ctx.status(400).result("Fehlende Parameter: username, device_id oder track_uri");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
String accessToken = authService.getAccessTokenForUser(username);
|
|
OkHttpClient client = new OkHttpClient();
|
|
|
|
// 1. Track-Details holen
|
|
String trackId = trackUri.split(":")[2];
|
|
Request getTrack = new Request.Builder()
|
|
.url("https://api.spotify.com/v1/tracks/" + trackId)
|
|
.addHeader("Authorization", "Bearer " + accessToken)
|
|
.build();
|
|
try (Response trackResp = client.newCall(getTrack).execute()) {
|
|
if (!trackResp.isSuccessful()) {
|
|
ctx.status(500).result("Fehler beim Laden der Track-Details");
|
|
return;
|
|
}
|
|
var node = new com.fasterxml.jackson.databind.ObjectMapper().readTree(trackResp.body().string());
|
|
long durationMs = node.get("duration_ms").asLong();
|
|
long startOffset = durationMs / 2;
|
|
|
|
// 2. Play-Request mit position_ms
|
|
ObjectNode jsonNode = JsonNodeFactory.instance.objectNode();
|
|
jsonNode.putArray("uris").add(trackUri);
|
|
jsonNode.put("position_ms", startOffset);
|
|
String jsonBody = jsonNode.toString();
|
|
|
|
Request playReq = new Request.Builder()
|
|
.url("https://api.spotify.com/v1/me/player/play?device_id=" + deviceId)
|
|
.addHeader("Authorization", "Bearer " + accessToken)
|
|
.put(RequestBody.create(jsonBody, MediaType.parse("application/json")))
|
|
.build();
|
|
|
|
try (Response playResp = client.newCall(playReq).execute()) {
|
|
if (playResp.isSuccessful()) {
|
|
ctx.status(204).result("Track erfolgreich abgespielt");
|
|
} else {
|
|
ctx.status(playResp.code()).result("Fehler: " + playResp.body().string());
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
log.error("Fehler beim Abspielen des Tracks", e);
|
|
ctx.status(500).result("Interner Fehler");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
} |