From 43a6e3596f2782e6bc78df588592ef0b7506c522 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sat, 6 Jan 2024 01:21:00 +0100 Subject: [PATCH] exception clean-up and prepared buy package function ~2.5h work --- .../nanopenguin/mtcg/application/Package.java | 24 +++++- .../mtcg/application/SessionHandler.java | 47 ++++------- .../application/service/PackagesService.java | 45 +++++------ .../mtcg/application/service/Service.java | 4 +- .../mtcg/application/service/UserService.java | 77 ++++++++----------- .../nanopenguin/mtcg/http/RequestHandler.java | 13 ++-- 6 files changed, 101 insertions(+), 109 deletions(-) diff --git a/src/at/nanopenguin/mtcg/application/Package.java b/src/at/nanopenguin/mtcg/application/Package.java index de28afc..21c75c1 100644 --- a/src/at/nanopenguin/mtcg/application/Package.java +++ b/src/at/nanopenguin/mtcg/application/Package.java @@ -17,7 +17,7 @@ public class Package { val result = DbQuery.builder() .command(SqlCommand.INSERT) .table(Table.PACKAGES) - .parameter("cost", 5) + .parameter("uuid", UUID.randomUUID()) .returnColumn("uuid") .executeQuery(); if (result.isEmpty()) throw new SQLException(); // maybe change to different exception @@ -41,4 +41,26 @@ public class Package { return true; } + + public static boolean addToUser(UUID userUuid) throws SQLException { + return DbQuery.builder() + .customSql(""" + DO $$ + DECLARE user_uuid uuid; + DECLARE package_uuid uuid; + DECLARE cost int; + BEGIN + cost = ?; + user_uuid = ?::uuid; + IF (SELECT coins FROM users WHERE uuid = user_uuid) >= cost THEN + package_uuid = (SELECT uuid FROM packages ORDER BY created_at LIMIT 1); + UPDATE cards SET owner = user_uuid WHERE package = package_uuid; + UPDATE users SET coins = coins - cost WHERE uuid = user_uuid; + DELETE FROM packages WHERE uuid = package_uuid; + END IF; + END $$;""") + .value(5) // TODO: don't hardcode cost + .value(userUuid) + .executeUpdate() > 0; + } } diff --git a/src/at/nanopenguin/mtcg/application/SessionHandler.java b/src/at/nanopenguin/mtcg/application/SessionHandler.java index bb0e0ee..435d149 100644 --- a/src/at/nanopenguin/mtcg/application/SessionHandler.java +++ b/src/at/nanopenguin/mtcg/application/SessionHandler.java @@ -13,7 +13,7 @@ import java.util.UUID; public final class SessionHandler { private static SessionHandler INSTANCE; - private final Map Sessions = new HashMap<>(); + private final Map sessions = new HashMap<>(); private SessionHandler() { @@ -27,7 +27,13 @@ public final class SessionHandler { return INSTANCE; } - public UUID login(UserCredentials userCredentials) throws SQLException { + public synchronized UUID login(UserCredentials userCredentials) throws SQLException { // avoid multiple logins of same user + for (val session : this.sessions.entrySet()) { + if (userCredentials.username().equals(session.getValue().username())) { + this.sessions.remove(session.getKey()); + } + } + val result = DbQuery.builder() .command(SqlCommand.SELECT) .table(Table.USERS) @@ -48,7 +54,7 @@ public final class SessionHandler { } UUID uuid = UUID.randomUUID(); - this.Sessions.put(uuid, new UserInfo((UUID) row1.get("uuid"), userCredentials.username(), (boolean) row1.get("admin"))); + this.sessions.put(uuid, new UserInfo((UUID) row1.get("uuid"), userCredentials.username(), (boolean) row1.get("admin"))); return uuid; } @@ -62,8 +68,8 @@ public final class SessionHandler { public TokenValidity verifyUUID(UUID uuid, boolean requireAdmin) { if (uuid == null) return TokenValidity.MISSING; - if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; - if (Sessions.get(uuid).admin() || !requireAdmin) return TokenValidity.VALID; + if (!sessions.containsKey(uuid)) return TokenValidity.INVALID; + if (sessions.get(uuid).admin() || !requireAdmin) return TokenValidity.VALID; return TokenValidity.FORBIDDEN; } @@ -73,33 +79,10 @@ public final class SessionHandler { public TokenValidity verifyUUID(UUID uuid, String username, boolean allowAdmin) { if (uuid == null) return TokenValidity.MISSING; - if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; - if (username.equals(Sessions.get(uuid).username())) return TokenValidity.VALID; - if (allowAdmin && Sessions.get(uuid).admin()) return TokenValidity.VALID; + if (!sessions.containsKey(uuid)) return TokenValidity.INVALID; + if (username.equals(sessions.get(uuid).username())) return TokenValidity.VALID; + if (allowAdmin && sessions.get(uuid).admin()) return TokenValidity.VALID; return TokenValidity.FORBIDDEN; } -} - -/* -* -* join() { -* lock() -* checks if someone waiting -* no -> { -* var waiting = true // sets self as waiting idk -* unlock() -* wait() -* response = battle log -* // process stuff -* unlock() -* } -* yes -> { -* start battle -* var battle log = battle log // no na ned -* // process stuff -* notifyAll() -* } -* } -* -* */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/at/nanopenguin/mtcg/application/service/PackagesService.java b/src/at/nanopenguin/mtcg/application/service/PackagesService.java index b3b294c..337d978 100644 --- a/src/at/nanopenguin/mtcg/application/service/PackagesService.java +++ b/src/at/nanopenguin/mtcg/application/service/PackagesService.java @@ -20,34 +20,27 @@ import java.util.UUID; public class PackagesService implements Service { @Override - public Response handleRequest(HttpRequest request) throws JsonProcessingException { - try { - if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) { - UUID uuid; - return switch (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), true)) { - case MISSING, INVALID -> new Response(HttpStatus.UNAUTHORIZED); - case FORBIDDEN -> new Response(HttpStatus.FORBIDDEN); - case VALID -> new Response( - Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference>() {})) ? - HttpStatus.CREATED : - HttpStatus.CONFLICT); - }; - } + public Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException { - if (String.join("/", Arrays.copyOfRange(request.getPath().split("/"), 1, 2)).equals("transactions/packages") && request.getMethod() == HttpMethod.POST) { - return new Response(SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) != TokenValidity.VALID ? + if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) { + UUID uuid; + return switch (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), true)) { + case MISSING, INVALID -> new Response(HttpStatus.UNAUTHORIZED); + case FORBIDDEN -> new Response(HttpStatus.FORBIDDEN); + case VALID -> new Response( + Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference>() { + })) ? + HttpStatus.CREATED : + HttpStatus.CONFLICT); + }; + } + + if (String.join("/", Arrays.copyOfRange(request.getPath().split("/"), 1, 2)).equals("transactions/packages") && request.getMethod() == HttpMethod.POST) { + return new Response(SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) != TokenValidity.VALID ? HttpStatus.UNAUTHORIZED : - HttpStatus.NOT_IMPLEMENTED); - } + HttpStatus.NOT_IMPLEMENTED); // Package.addToUser(); + } - return new Response(HttpStatus.NOT_FOUND); - } - catch (ArrayIndexOutOfBoundsException e) { - return new Response(HttpStatus.BAD_REQUEST); - } - catch (SQLException e) { - System.out.println(e.getMessage()); - return new Response(HttpStatus.INTERNAL); - } + return new Response(HttpStatus.NOT_FOUND); } } diff --git a/src/at/nanopenguin/mtcg/application/service/Service.java b/src/at/nanopenguin/mtcg/application/service/Service.java index 072ee8c..d55460b 100644 --- a/src/at/nanopenguin/mtcg/application/service/Service.java +++ b/src/at/nanopenguin/mtcg/application/service/Service.java @@ -4,7 +4,9 @@ import at.nanopenguin.mtcg.http.HttpRequest; import at.nanopenguin.mtcg.http.Response; import com.fasterxml.jackson.core.JsonProcessingException; +import java.sql.SQLException; + public interface Service { - Response handleRequest(HttpRequest request) throws JsonProcessingException; + Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException; } diff --git a/src/at/nanopenguin/mtcg/application/service/UserService.java b/src/at/nanopenguin/mtcg/application/service/UserService.java index 452ad90..929ce94 100644 --- a/src/at/nanopenguin/mtcg/application/service/UserService.java +++ b/src/at/nanopenguin/mtcg/application/service/UserService.java @@ -19,50 +19,41 @@ import java.util.UUID; public class UserService implements Service { @Override - public Response handleRequest(HttpRequest request) throws JsonProcessingException { - try { - if (request.getPath().split("/")[1].equals("sessions") && request.getMethod() == HttpMethod.POST) { - // login - UUID uuid = SessionHandler.getInstance().login(new ObjectMapper().readValue(request.getBody(), UserCredentials.class)); - return uuid != null ? - new Response(HttpStatus.OK, "application/json", uuid.toString()) : - new Response(HttpStatus.UNAUTHORIZED); - } + public Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException { + if (request.getPath().split("/")[1].equals("sessions") && request.getMethod() == HttpMethod.POST) { + // login + UUID uuid = SessionHandler.getInstance().login(new ObjectMapper().readValue(request.getBody(), UserCredentials.class)); + return uuid != null ? + new Response(HttpStatus.OK, "application/json", uuid.toString()) : + new Response(HttpStatus.UNAUTHORIZED); + } - if (request.getPath().split("/")[1].equals("users")) { - return switch (request.getMethod()) { - case GET -> { - String username = request.getPath().split("/")[2]; - if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.VALID) - yield new Response(HttpStatus.UNAUTHORIZED); - val userData = User.retrieve(username); - yield userData != null ? - new Response(HttpStatus.OK, "application/json", new ObjectMapper().writeValueAsString(userData)) : - new Response(HttpStatus.NOT_FOUND); - } - case POST -> { // register new user - UserCredentials userCredentials = new ObjectMapper().readValue(request.getBody(), UserCredentials.class); - yield new Response(User.create(userCredentials) ? HttpStatus.CREATED : HttpStatus.CONFLICT); - } - case PUT -> { - String username = request.getPath().split("/")[2]; - UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class); - if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.FORBIDDEN) - yield new Response(HttpStatus.UNAUTHORIZED); - yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND); - } - default -> new Response(HttpStatus.NOT_FOUND); - }; - } + if (request.getPath().split("/")[1].equals("users")) { + return switch (request.getMethod()) { + case GET -> { + String username = request.getPath().split("/")[2]; + if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.VALID) + yield new Response(HttpStatus.UNAUTHORIZED); + val userData = User.retrieve(username); + yield userData != null ? + new Response(HttpStatus.OK, "application/json", new ObjectMapper().writeValueAsString(userData)) : + new Response(HttpStatus.NOT_FOUND); + } + case POST -> { // register new user + UserCredentials userCredentials = new ObjectMapper().readValue(request.getBody(), UserCredentials.class); + yield new Response(User.create(userCredentials) ? HttpStatus.CREATED : HttpStatus.CONFLICT); + } + case PUT -> { + String username = request.getPath().split("/")[2]; + UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class); + if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.FORBIDDEN) + yield new Response(HttpStatus.UNAUTHORIZED); + yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND); + } + default -> new Response(HttpStatus.NOT_FOUND); + }; + } - return new Response(HttpStatus.NOT_FOUND); - } - catch (ArrayIndexOutOfBoundsException e) { - return new Response(HttpStatus.BAD_REQUEST); - } - catch (SQLException e) { - System.out.println(e.getMessage()); - return new Response(HttpStatus.INTERNAL); - } + return new Response(HttpStatus.NOT_FOUND); } } \ No newline at end of file diff --git a/src/at/nanopenguin/mtcg/http/RequestHandler.java b/src/at/nanopenguin/mtcg/http/RequestHandler.java index ab13d28..f8b6f3a 100644 --- a/src/at/nanopenguin/mtcg/http/RequestHandler.java +++ b/src/at/nanopenguin/mtcg/http/RequestHandler.java @@ -4,10 +4,7 @@ import at.nanopenguin.mtcg.application.service.Service; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.RequiredArgsConstructor; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; +import java.io.*; import java.net.Socket; @RequiredArgsConstructor @@ -42,8 +39,12 @@ public class RequestHandler implements Runnable { try { response = service.handleRequest(httpRequest); } - catch (JsonProcessingException e) { - response = new Response(HttpStatus.BAD_REQUEST, "application/json", ""); + catch (JsonProcessingException | ArrayIndexOutOfBoundsException e) { + response = new Response(HttpStatus.BAD_REQUEST); + } + catch (Exception e) { + System.out.println(e.getMessage()); // TODO: more info + response = new Response(HttpStatus.INTERNAL); } }