Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Used ReadWriteLock #27

Merged
merged 10 commits into from
Mar 13, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static boolean forNode(@NotNull String nodeId) {
}

public static boolean forRoom(@NotNull String roomId) {
return roomId.matches("^(?!-)[a-z\\d-]{0,31}[a-z\\d](?!-)$");
return roomId.matches("^(?!-)[a-z\\d-]{0,35}[a-z\\d](?!-)$");
}

public static boolean forUser(@NotNull String username) {
Expand Down
4 changes: 2 additions & 2 deletions client-api/src/test/java/util/IdentifierValidatorTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ void test_forRooms() {
Assertions.assertFalse(IdentifierValidator.forRoom("-"));
Assertions.assertFalse(IdentifierValidator.forRoom("-a"));
Assertions.assertFalse(IdentifierValidator.forRoom("a-"));
Assertions.assertTrue(IdentifierValidator.forRoom("a".repeat(32)));
Assertions.assertFalse(IdentifierValidator.forRoom("a".repeat(33)));
Assertions.assertTrue(IdentifierValidator.forRoom("a".repeat(36)));
Assertions.assertFalse(IdentifierValidator.forRoom("a".repeat(37)));
}

@Test
Expand Down
1 change: 1 addition & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ configurations {

dependencies {
implementation project(":client-api")
implementation 'org.jetbrains:annotations:24.1.0'
developmentOnly("org.springframework.boot:spring-boot-devtools")
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-security'
Expand Down
16 changes: 10 additions & 6 deletions server/src/main/java/ru/dragonestia/picker/config/TestConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import ru.dragonestia.picker.api.model.node.PickingMethod;
import ru.dragonestia.picker.api.model.room.IRoom;
import ru.dragonestia.picker.api.repository.type.NodeIdentifier;
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.interceptor.DebugInterceptor;
import ru.dragonestia.picker.model.Room;
import ru.dragonestia.picker.model.Node;
Expand Down Expand Up @@ -42,9 +46,9 @@ public void addInterceptors(@NonNull InterceptorRegistry registry) {

@Bean
void createNodes() {
createNodeWithContent(new Node("game-servers", PickingMethod.ROUND_ROBIN, false));
createNodeWithContent(new Node("game-lobbies", PickingMethod.LEAST_PICKED, false));
createNodeWithContent(new Node("hub", PickingMethod.SEQUENTIAL_FILLING, false));
createNodeWithContent(new Node(NodeIdentifier.of("game-servers"), PickingMethod.ROUND_ROBIN, false));
createNodeWithContent(new Node(NodeIdentifier.of("game-lobbies"), PickingMethod.LEAST_PICKED, false));
createNodeWithContent(new Node(NodeIdentifier.of("hub"), PickingMethod.SEQUENTIAL_FILLING, false));
}

@SneakyThrows
Expand All @@ -54,17 +58,17 @@ private void createNodeWithContent(Node node) {

for (int i = 1; i <= 5; i++) {
var slots = 5 * i;
var room = Room.create("test-" + i, node, SlotLimit.of(slots), json.writeValueAsString(generatePayload()), false);
var room = new Room(RoomIdentifier.of("test-" + i), node, slots, json.writeValueAsString(generatePayload()), false);
roomRepository.create(room);

for (int j = 0, n = rand.nextInt(slots + 1); j < n; j++) {
var user = new User("test-user-" + rand.nextInt(20));
var user = new User(UserIdentifier.of("test-user-" + rand.nextInt(20)));
userRepository.linkWithRoom(room, List.of(user), false);
}
}

for (int i = 0; i < 5; i++) {
var room = Room.create(randomUUID().toString(), node, SlotLimit.unlimited(), json.writeValueAsString(generatePayload()), false);
var room = new Room(RoomIdentifier.of(randomUUID().toString()), node, IRoom.UNLIMITED_SLOTS, json.writeValueAsString(generatePayload()), false);
room.setLocked((i & 1) == 0);
roomRepository.create(room);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import ru.dragonestia.picker.api.repository.response.NodeDetailsResponse;
import ru.dragonestia.picker.api.repository.response.NodeListResponse;
import ru.dragonestia.picker.api.repository.response.PickedRoomResponse;
import ru.dragonestia.picker.api.repository.type.NodeIdentifier;
import ru.dragonestia.picker.model.Node;
import ru.dragonestia.picker.service.NodeService;
import ru.dragonestia.picker.service.RoomService;
Expand Down Expand Up @@ -45,7 +46,7 @@ ResponseEntity<?> registerNode(
@Parameter(description = "Picking method method") @RequestParam(name = "method") PickingMethod method,
@Parameter(description = "Save node") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist
) {
nodeService.create(new Node(nodeId, method, persist));
nodeService.create(new Node(NodeIdentifier.of(nodeId), method, persist));
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import ru.dragonestia.picker.api.exception.RoomNotFoundException;
import ru.dragonestia.picker.api.repository.response.RoomInfoResponse;
import ru.dragonestia.picker.api.repository.response.RoomListResponse;
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;
import ru.dragonestia.picker.model.Room;
import ru.dragonestia.picker.model.type.SlotLimit;
import ru.dragonestia.picker.service.RoomService;
import ru.dragonestia.picker.service.NodeService;
import ru.dragonestia.picker.util.DetailsParser;
Expand Down Expand Up @@ -54,7 +54,7 @@ ResponseEntity<?> register(
@Parameter(description = "Save room") @RequestParam(name = "persist", required = false, defaultValue = "false") boolean persist
) {
var node = nodeService.find(nodeId).orElseThrow(() -> new NodeNotFoundException(nodeId));
var room = Room.create(roomId, node, SlotLimit.of(slots), payload, persist);
var room = new Room(RoomIdentifier.of(roomId), node, slots, payload, persist);
room.setLocked(locked);
roomService.create(room);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import ru.dragonestia.picker.api.repository.response.LinkedRoomsWithUserResponse;
import ru.dragonestia.picker.api.repository.response.SearchUserResponse;
import ru.dragonestia.picker.api.repository.response.UserDetailsResponse;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;
import ru.dragonestia.picker.model.User;
import ru.dragonestia.picker.service.UserService;
import ru.dragonestia.picker.util.DetailsParser;
Expand Down Expand Up @@ -62,6 +63,6 @@ LinkedRoomsWithUserResponse roomsOf(
return new LinkedRoomsWithUserResponse(List.of());
}

return new LinkedRoomsWithUserResponse(userService.getUserRoomsWithDetails(new User(userId), detailsParser.parseRoomDetails(detailsSeq)));
return new LinkedRoomsWithUserResponse(userService.getUserRoomsWithDetails(new User(UserIdentifier.of(userId)), detailsParser.parseRoomDetails(detailsSeq)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ ResponseEntity<RoomUserListResponse> usersInsideRoom(
var room = getNodeAndRoom(nodeId, roomId).room();
var users = userService.getRoomUsersWithDetailsResponse(room, detailsParser.parseUserDetails(detailsSeq));

return ResponseEntity.ok(new RoomUserListResponse(room.getSlots().getSlots(), users.size(), users));
return ResponseEntity.ok(new RoomUserListResponse(room.getMaxSlots(), users.size(), users));
}

@Operation(summary = "Link users with room")
Expand All @@ -56,7 +56,7 @@ ResponseEntity<LinkUsersWithRoomResponse> linkUserWithRoom(
var room = getNodeAndRoom(nodeId, roomId).room();
var users = namingValidator.validateUserIds(Arrays.stream(userIds.split(",")).toList());
var usedSlots = userService.linkUsersWithRoom(room, users, force);
return ResponseEntity.ok(new LinkUsersWithRoomResponse(usedSlots, room.getSlots().getSlots()));
return ResponseEntity.ok(new LinkUsersWithRoomResponse(usedSlots, room.getMaxSlots()));
}

@Operation(summary = "Unlink users from room")
Expand Down
50 changes: 42 additions & 8 deletions server/src/main/java/ru/dragonestia/picker/model/Node.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,61 @@
package ru.dragonestia.picker.model;

import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.picker.api.model.node.INode;
import ru.dragonestia.picker.api.model.node.NodeDetails;
import ru.dragonestia.picker.api.model.node.PickingMethod;
import ru.dragonestia.picker.api.model.node.ResponseNode;
import ru.dragonestia.picker.api.repository.type.NodeIdentifier;

public record Node(@NonNull String id, @NonNull PickingMethod method, boolean persist) {
public class Node implements INode {

private final String identifier;
private final PickingMethod pickingMethod;
private final boolean persist;

public Node(@NotNull NodeIdentifier identifier, @NotNull PickingMethod pickingMethod, boolean persist) {
this.identifier = identifier.getValue();
this.pickingMethod = pickingMethod;
this.persist = persist;
}

@Override
public @NotNull String getIdentifier() {
return identifier;
}

@Override
public @NotNull PickingMethod getPickingMethod() {
return pickingMethod;
}

@Override
public @NotNull Boolean isPersist() {
return persist;
}

@Override
public @Nullable String getDetail(@NotNull NodeDetails detail) {
throw new UnsupportedOperationException();
}

public @NotNull ResponseNode toResponseObject() {
return new ResponseNode(identifier, pickingMethod);
}

@Override
public int hashCode() {
return id.hashCode();
return identifier.hashCode();
}

@Override
public boolean equals(Object object) {
if (object == this) return true;
if (object == null) return false;
if (object instanceof Node other) {
return id.equals(other.id);
return identifier.equals(other.identifier);
}
return false;
}

public ResponseNode toResponseObject() {
return new ResponseNode(id, method);
}
}
88 changes: 62 additions & 26 deletions server/src/main/java/ru/dragonestia/picker/model/Room.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,95 @@
package ru.dragonestia.picker.model;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.picker.api.model.room.IRoom;
import ru.dragonestia.picker.api.model.room.ResponseRoom;
import ru.dragonestia.picker.api.model.room.RoomDetails;
import ru.dragonestia.picker.api.model.room.ShortResponseRoom;
import ru.dragonestia.picker.model.type.SlotLimit;
import ru.dragonestia.picker.api.repository.type.RoomIdentifier;

import java.util.HashMap;
public class Room implements IRoom {

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class Room {

private final String id;
private final String nodeId;
private final SlotLimit slots;
private final String identifier;
private final String nodeIdentifier;
private final int slots;
private final String payload;
private final boolean persist;
private boolean locked = false;

public static Room create(String roomId, Node node, SlotLimit limit, String payload, boolean persist) {
return new Room(roomId, node.id(), limit, payload, persist);
public Room(@NotNull RoomIdentifier identifier, @NotNull Node node, int slots, @NotNull String payload, boolean persist) {
this.identifier = identifier.getValue();
this.nodeIdentifier = node.getIdentifier();
this.slots = slots;
this.payload = payload;
this.persist = persist;
}

@Override
public @NotNull String getIdentifier() {
return identifier;
}

@Override
public @NotNull String getNodeIdentifier() {
return nodeIdentifier;
}

@Override
public int getMaxSlots() {
return slots;
}

@Override
public boolean isLocked() {
return locked;
}

public void setLocked(boolean value) {
locked = value;
}

@Override
public @NotNull Boolean isPersist() {
return persist;
}

@Override
public @NotNull String getPayload() {
return payload;
}

@Override
public @Nullable String getDetail(@NotNull RoomDetails detail) {
throw new UnsupportedOperationException();
}

public boolean isAvailable(int usedSlots, int requiredSlots) {
if (locked) return false;
if (slots.isUnlimited()) return true;
return slots.getSlots() >= usedSlots + requiredSlots;
if (hasUnlimitedSlots()) return true;
return slots >= usedSlots + requiredSlots;
}

public @NotNull ResponseRoom toResponseObject() {
return new ResponseRoom(identifier, nodeIdentifier, slots, locked, payload);
}

public @NotNull ShortResponseRoom toShortResponseObject() {
return new ShortResponseRoom(identifier, nodeIdentifier, slots, locked);
}

@Override
public int hashCode() {
return id.hashCode();
return identifier.hashCode();
}

@Override
public boolean equals(Object object) {
if (object == this) return true;
if (object == null) return false;
if (object instanceof Room other) {
return id.equals(other.id);
return identifier.equals(other.identifier);
}
return false;
}

public ResponseRoom toResponseObject() {
return new ResponseRoom(id, nodeId, slots.getSlots(), locked, payload);
}

public ShortResponseRoom toShortResponseObject() {
return new ShortResponseRoom(id, nodeId, slots.getSlots(), locked);
}
}
36 changes: 28 additions & 8 deletions server/src/main/java/ru/dragonestia/picker/model/User.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
package ru.dragonestia.picker.model;

import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.picker.api.model.user.IUser;
import ru.dragonestia.picker.api.model.user.ResponseUser;
import ru.dragonestia.picker.api.model.user.UserDetails;
import ru.dragonestia.picker.api.repository.type.UserIdentifier;

public record User(@NonNull String id) {
public class User implements IUser {

private final String identifier;

public User(@NotNull UserIdentifier identifier) {
this.identifier = identifier.getValue();
}

@Override
public @NotNull String getIdentifier() {
return identifier;
}

@Override
public @Nullable String getDetail(@NotNull UserDetails detail) {
throw new UnsupportedOperationException();
}

public @NotNull ResponseUser toResponseObject() {
return new ResponseUser(identifier);
}

@Override
public int hashCode() {
return id.hashCode();
return identifier.hashCode();
}

@Override
public boolean equals(Object object) {
if (object == this) return true;
if (object == null) return false;
if (object instanceof User other) {
return id.equals(other.id);
return identifier.equals(other.identifier);
}
return false;
}

public ResponseUser toResponseObject() {
return new ResponseUser(id);
}
}
Loading
Loading