diff --git a/bot-players/Dockerfile b/bot-players/Dockerfile index 533cbfe..e467ae8 100644 --- a/bot-players/Dockerfile +++ b/bot-players/Dockerfile @@ -12,4 +12,6 @@ RUN npm run build ENV GAME_SERVER_URL=https://chage-to.nginx-route.openshiftapps.com -CMD ["npm", "start"] \ No newline at end of file +EXPOSE 8181 + +CMD ["npm", "start"] diff --git a/roshambo-backend/src/main/java/org/acme/GameResource.java b/roshambo-backend/src/main/java/org/acme/GameResource.java index bd367c3..85ebcb2 100644 --- a/roshambo-backend/src/main/java/org/acme/GameResource.java +++ b/roshambo-backend/src/main/java/org/acme/GameResource.java @@ -71,6 +71,9 @@ public class GameResource { @ConfigProperty(name = "roshambo.enable.camera") boolean enableCamera; + @ConfigProperty(name = "roshambo.enable.bot", defaultValue = "false") + boolean enableBot; + @Channel("next-round") Multi nextRoundStream; @Channel("status") Emitter statusStream; @@ -106,7 +109,7 @@ public void init() { logger.info("Random shape detector configured."); shapeDetectorService = new RandomShapeDetectorService(); } - + logger.infof("Bot enabled? %s", enableBot); logger.infof("Camera feature enabled? %s", enableCamera); } @@ -131,6 +134,19 @@ public Initialization configuration() { Configuration conf = new Configuration(roundTimeInSeconds.getSeconds(), timeBetweenRoundsInSeconds.getSeconds(), numberOfRounds, enableCamera, gameUUId); logger.infof("App Configured with Round Time: %d - Time Between Rounds: %d - Number of Rounds: %d - Manual next Round: %s - Camera Enabled: %s - Game UUID: %s", conf.roundTimeInSeconds, conf.roundTimeInSeconds, conf.numberOfRounds, manualRounds, conf.enableCamera, gameUUId); + + + if (enableBot) { + + // Creates a bot user + User botUser = this.userGenerator.getUser(); + botUser.id = User.BOT_ID; + if (usersInformation.findUserById(User.BOT_ID).isEmpty()) { + logger.infof("User Bot: %s registered at team: %d", botUser.name, botUser.team); + usersInformation.addUser(botUser); + } + } + return new Initialization(conf, state); } @@ -140,6 +156,8 @@ public User assignNameAndTeam() { User user = this.userGenerator.getUser(); logger.infof("User: %s registered at team: %d", user.name, user.team); usersInformation.addUser(user); + + return user; } @@ -153,20 +171,13 @@ public RestResponse shot(@PathParam("userId") int userId, @Min(1) @Max(2 long responseTime = calculateResponseTime(); if (image.startsWith("data:image/png;base64,") || image.startsWith("data:image/jpeg;base64,")) { - // Images are uploaded as base64 strings, e.g: data:image/png;base64,$DATA - // We need to strip the metadata before the comma, and convert to binary - String[] imageDataPortions = image.split(","); - String imageBase64 = imageDataPortions[1]; - if (uploadToS3) { - s3.uploadImage(imageBase64, image.startsWith("data:image/png;base64,") ? "png" : "jpeg"); + if (enableBot) { + generateBotResult(); } - final Shape shape = shapeDetectorService.detect(imageBase64); - logger.infof("Detected %s by team %d for the user %d", shape.name(), team, userId); + return detectImage(userId, team, image, responseTime); - this.afterDetection(shape, team, userId, responseTime); - return ResponseBuilder.create(200).entity(new ShotResult(responseTime, shape)).build(); } else { return ResponseBuilder.create(RestResponse.Status.BAD_REQUEST) .entity("expected a base64 encoded png image, e.g data:image/png;base64,$DATA") @@ -179,28 +190,62 @@ public RestResponse shot(@PathParam("userId") int userId, @Min(1) @Max(2 } } + private RestResponse detectImage(int userId, int team, String image, long responseTime) { + // Images are uploaded as base64 strings, e.g: data:image/png;base64,$DATA + // We need to strip the metadata before the comma, and convert to binary + String[] imageDataPortions = image.split(","); + String imageBase64 = imageDataPortions[1]; + + if (uploadToS3) { + s3.uploadImage(imageBase64, image.startsWith("data:image/png;base64,") ? "png" : "jpeg"); + } + + final Shape shape = shapeDetectorService.detect(imageBase64); + logger.infof("Detected %s by team %d for the user %d", shape.name(), team, userId); + + this.afterDetection(shape, team, userId, responseTime); + return ResponseBuilder.create(200).entity(new ShotResult(responseTime, shape)).build(); + } + @POST @Path("/detect/button/{team}/{userId}/{shape}") public ShotResult click(@PathParam("userId") int userId, @Min(1) @Max(2) @PathParam("team") int team, @PathParam("shape") String shape) { + + if (enableBot) { + generateBotResult(); + } + + return processButton(userId, team, shape); + } + + private ShotResult processButton(int userId, int team, String shape) { long responseTime = calculateResponseTime(); - + Shape valueOfShape = Shape.valueOf(shape); logger.infof("Pushed %s by team %d for the user %d", shape, team, userId); - this.afterDetection(valueOfShape, team, userId, responseTime); - + return new ShotResult(responseTime, valueOfShape); } + private void afterDetection(Shape shape, int team, int userId, long responseTime) { this.scoreInformation.incrementShape(team, shape); this.usersInformation.increasePlayedTime(userId, Duration.ofMillis(responseTime)); - final User u = this.usersInformation.findUserById(userId); + final User u = this.usersInformation.findUserById(userId).get(); this.sendToAdmin(new ServerSideEventDTO("usershape", CurrentUserShapeDTO.of(u.name, shape))); } + + private void generateBotResult() { + User botUser = usersInformation.findUserById(User.BOT_ID).get(); + // Store the generated result + RandomShapeDetectorService randomShapeDetectorService = new RandomShapeDetectorService(); + processButton(botUser.id, botUser.team, randomShapeDetectorService.detect(null).name()); + } + void sendToAdmin(ServerSideEventDTO serverSideEventDTO) { if (statusStream.hasRequests()) { Jsonb jsonb = JsonbBuilder.create(); diff --git a/roshambo-backend/src/main/java/org/acme/User.java b/roshambo-backend/src/main/java/org/acme/User.java index 5743cac..2161c6c 100644 --- a/roshambo-backend/src/main/java/org/acme/User.java +++ b/roshambo-backend/src/main/java/org/acme/User.java @@ -1,6 +1,9 @@ package org.acme; public class User { + + public static int BOT_ID = -1; + public int id; public String name; public int team; diff --git a/roshambo-backend/src/main/java/org/acme/game/UsersInformation.java b/roshambo-backend/src/main/java/org/acme/game/UsersInformation.java index f410d82..3abcf5a 100644 --- a/roshambo-backend/src/main/java/org/acme/game/UsersInformation.java +++ b/roshambo-backend/src/main/java/org/acme/game/UsersInformation.java @@ -37,7 +37,7 @@ public List bestUsers(int top) { .stream() .sorted(Map.Entry.comparingByValue()) .limit(top) - .map(e -> this.findUserById(e.getKey())) + .map(e -> this.findUserById(e.getKey()).get()) .collect(Collectors.toList()); } @@ -45,7 +45,7 @@ Duration getPlayedTimesById(int id) { return playedTimes.get(id); } - public User findUserById(int id) { + public Optional findUserById(int id) { Optional user = currentUsers .values() .stream() @@ -53,6 +53,6 @@ public User findUserById(int id) { .filter(Optional::isPresent) .map(Optional::get) .findAny(); - return user.get(); + return user; } }