exception clean-up and prepared buy package function

~2.5h work
This commit is contained in:
Benedikt Galbavy 2024-01-06 01:21:00 +01:00
parent 5a0b03a75f
commit 43a6e3596f
6 changed files with 101 additions and 109 deletions

View File

@ -17,7 +17,7 @@ public class Package {
val result = DbQuery.builder() val result = DbQuery.builder()
.command(SqlCommand.INSERT) .command(SqlCommand.INSERT)
.table(Table.PACKAGES) .table(Table.PACKAGES)
.parameter("cost", 5) .parameter("uuid", UUID.randomUUID())
.returnColumn("uuid") .returnColumn("uuid")
.executeQuery(); .executeQuery();
if (result.isEmpty()) throw new SQLException(); // maybe change to different exception if (result.isEmpty()) throw new SQLException(); // maybe change to different exception
@ -41,4 +41,26 @@ public class Package {
return true; 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;
}
} }

View File

@ -13,7 +13,7 @@ import java.util.UUID;
public final class SessionHandler { public final class SessionHandler {
private static SessionHandler INSTANCE; private static SessionHandler INSTANCE;
private final Map<UUID, UserInfo> Sessions = new HashMap<>(); private final Map<UUID, UserInfo> sessions = new HashMap<>();
private SessionHandler() { private SessionHandler() {
@ -27,7 +27,13 @@ public final class SessionHandler {
return INSTANCE; 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() val result = DbQuery.builder()
.command(SqlCommand.SELECT) .command(SqlCommand.SELECT)
.table(Table.USERS) .table(Table.USERS)
@ -48,7 +54,7 @@ public final class SessionHandler {
} }
UUID uuid = UUID.randomUUID(); 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; return uuid;
} }
@ -62,8 +68,8 @@ public final class SessionHandler {
public TokenValidity verifyUUID(UUID uuid, boolean requireAdmin) { public TokenValidity verifyUUID(UUID uuid, boolean requireAdmin) {
if (uuid == null) return TokenValidity.MISSING; if (uuid == null) return TokenValidity.MISSING;
if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; if (!sessions.containsKey(uuid)) return TokenValidity.INVALID;
if (Sessions.get(uuid).admin() || !requireAdmin) return TokenValidity.VALID; if (sessions.get(uuid).admin() || !requireAdmin) return TokenValidity.VALID;
return TokenValidity.FORBIDDEN; return TokenValidity.FORBIDDEN;
} }
@ -73,33 +79,10 @@ public final class SessionHandler {
public TokenValidity verifyUUID(UUID uuid, String username, boolean allowAdmin) { public TokenValidity verifyUUID(UUID uuid, String username, boolean allowAdmin) {
if (uuid == null) return TokenValidity.MISSING; if (uuid == null) return TokenValidity.MISSING;
if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; if (!sessions.containsKey(uuid)) return TokenValidity.INVALID;
if (username.equals(Sessions.get(uuid).username())) return TokenValidity.VALID; if (username.equals(sessions.get(uuid).username())) return TokenValidity.VALID;
if (allowAdmin && Sessions.get(uuid).admin()) return TokenValidity.VALID; if (allowAdmin && sessions.get(uuid).admin()) return TokenValidity.VALID;
return TokenValidity.FORBIDDEN; 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()
* }
* }
*
* */

View File

@ -20,34 +20,27 @@ import java.util.UUID;
public class PackagesService implements Service { public class PackagesService implements Service {
@Override @Override
public Response handleRequest(HttpRequest request) throws JsonProcessingException { public Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException {
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<List<Card>>() {})) ?
HttpStatus.CREATED :
HttpStatus.CONFLICT);
};
}
if (String.join("/", Arrays.copyOfRange(request.getPath().split("/"), 1, 2)).equals("transactions/packages") && request.getMethod() == HttpMethod.POST) { if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) {
return new Response(SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) != TokenValidity.VALID ? 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<List<Card>>() {
})) ?
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.UNAUTHORIZED :
HttpStatus.NOT_IMPLEMENTED); HttpStatus.NOT_IMPLEMENTED); // Package.addToUser();
} }
return 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);
}
} }
} }

View File

@ -4,7 +4,9 @@ import at.nanopenguin.mtcg.http.HttpRequest;
import at.nanopenguin.mtcg.http.Response; import at.nanopenguin.mtcg.http.Response;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import java.sql.SQLException;
public interface Service { public interface Service {
Response handleRequest(HttpRequest request) throws JsonProcessingException; Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException;
} }

View File

@ -19,50 +19,41 @@ import java.util.UUID;
public class UserService implements Service { public class UserService implements Service {
@Override @Override
public Response handleRequest(HttpRequest request) throws JsonProcessingException { public Response handleRequest(HttpRequest request) throws JsonProcessingException, SQLException, ArrayIndexOutOfBoundsException {
try { if (request.getPath().split("/")[1].equals("sessions") && request.getMethod() == HttpMethod.POST) {
if (request.getPath().split("/")[1].equals("sessions") && request.getMethod() == HttpMethod.POST) { // login
// login UUID uuid = SessionHandler.getInstance().login(new ObjectMapper().readValue(request.getBody(), UserCredentials.class));
UUID uuid = SessionHandler.getInstance().login(new ObjectMapper().readValue(request.getBody(), UserCredentials.class)); return uuid != null ?
return uuid != null ? new Response(HttpStatus.OK, "application/json", uuid.toString()) :
new Response(HttpStatus.OK, "application/json", uuid.toString()) : new Response(HttpStatus.UNAUTHORIZED);
new Response(HttpStatus.UNAUTHORIZED); }
}
if (request.getPath().split("/")[1].equals("users")) { if (request.getPath().split("/")[1].equals("users")) {
return switch (request.getMethod()) { return switch (request.getMethod()) {
case GET -> { case GET -> {
String username = request.getPath().split("/")[2]; String username = request.getPath().split("/")[2];
if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.VALID) if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.VALID)
yield new Response(HttpStatus.UNAUTHORIZED); yield new Response(HttpStatus.UNAUTHORIZED);
val userData = User.retrieve(username); val userData = User.retrieve(username);
yield userData != null ? yield userData != null ?
new Response(HttpStatus.OK, "application/json", new ObjectMapper().writeValueAsString(userData)) : new Response(HttpStatus.OK, "application/json", new ObjectMapper().writeValueAsString(userData)) :
new Response(HttpStatus.NOT_FOUND); new Response(HttpStatus.NOT_FOUND);
} }
case POST -> { // register new user case POST -> { // register new user
UserCredentials userCredentials = new ObjectMapper().readValue(request.getBody(), UserCredentials.class); UserCredentials userCredentials = new ObjectMapper().readValue(request.getBody(), UserCredentials.class);
yield new Response(User.create(userCredentials) ? HttpStatus.CREATED : HttpStatus.CONFLICT); yield new Response(User.create(userCredentials) ? HttpStatus.CREATED : HttpStatus.CONFLICT);
} }
case PUT -> { case PUT -> {
String username = request.getPath().split("/")[2]; String username = request.getPath().split("/")[2];
UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class); UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class);
if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.FORBIDDEN) if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.FORBIDDEN)
yield new Response(HttpStatus.UNAUTHORIZED); yield new Response(HttpStatus.UNAUTHORIZED);
yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND); yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND);
} }
default -> new Response(HttpStatus.NOT_FOUND); default -> new Response(HttpStatus.NOT_FOUND);
}; };
} }
return 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);
}
} }
} }

View File

@ -4,10 +4,7 @@ import at.nanopenguin.mtcg.application.service.Service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.io.BufferedReader; import java.io.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
@RequiredArgsConstructor @RequiredArgsConstructor
@ -42,8 +39,12 @@ public class RequestHandler implements Runnable {
try { try {
response = service.handleRequest(httpRequest); response = service.handleRequest(httpRequest);
} }
catch (JsonProcessingException e) { catch (JsonProcessingException | ArrayIndexOutOfBoundsException e) {
response = new Response(HttpStatus.BAD_REQUEST, "application/json", ""); response = new Response(HttpStatus.BAD_REQUEST);
}
catch (Exception e) {
System.out.println(e.getMessage()); // TODO: more info
response = new Response(HttpStatus.INTERNAL);
} }
} }