Implemented getting buckets
This commit is contained in:
parent
e034bad71e
commit
ea5ff314ed
@ -16,16 +16,19 @@ import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
|||||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
import com.vaadin.flow.component.textfield.TextField;
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
import ru.dragonestia.loadbalancer.web.model.Bucket;
|
import ru.dragonestia.loadbalancer.web.model.Bucket;
|
||||||
|
import ru.dragonestia.loadbalancer.web.repository.BucketRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BucketList extends VerticalLayout {
|
public class BucketList extends VerticalLayout {
|
||||||
|
|
||||||
private final Grid<Bucket> bucketsGrid;
|
private final String nodeIdentifier;
|
||||||
|
private final Grid<BucketRepository.BucketInfo> bucketsGrid;
|
||||||
private final TextField searchField;
|
private final TextField searchField;
|
||||||
private List<Bucket> cachedBuckets;
|
private List<BucketRepository.BucketInfo> cachedBuckets;
|
||||||
|
|
||||||
public BucketList(List<Bucket> buckets) {
|
public BucketList(String nodeIdentifier, List<BucketRepository.BucketInfo> buckets) {
|
||||||
|
this.nodeIdentifier = nodeIdentifier;
|
||||||
cachedBuckets = buckets;
|
cachedBuckets = buckets;
|
||||||
|
|
||||||
add(new H2("Buckets"));
|
add(new H2("Buckets"));
|
||||||
@ -48,20 +51,20 @@ public class BucketList extends VerticalLayout {
|
|||||||
var temp = input.trim();
|
var temp = input.trim();
|
||||||
|
|
||||||
bucketsGrid.setItems(cachedBuckets.stream()
|
bucketsGrid.setItems(cachedBuckets.stream()
|
||||||
.filter(bucket -> bucket.getIdentifier().startsWith(temp))
|
.filter(bucket -> bucket.identifier().startsWith(temp))
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Grid<Bucket> createGrid() {
|
private Grid<BucketRepository.BucketInfo> createGrid() {
|
||||||
var grid = new Grid<>(Bucket.class, false);
|
var grid = new Grid<>(BucketRepository.BucketInfo.class, false);
|
||||||
grid.addColumn(Bucket::getIdentifier).setHeader("Identifier");
|
grid.addColumn(BucketRepository.BucketInfo::identifier).setHeader("Identifier");
|
||||||
grid.addComponentColumn(bucket -> {
|
grid.addComponentColumn(bucket -> {
|
||||||
var result = new Span();
|
var result = new Span();
|
||||||
if (bucket.getSlots().isUnlimited()) {
|
if (bucket.slots() == -1) {
|
||||||
result.setText("Unlimited");
|
result.setText("Unlimited");
|
||||||
result.getElement().getThemeList().add("badge contrast");
|
result.getElement().getThemeList().add("badge contrast");
|
||||||
} else {
|
} else {
|
||||||
result.setText(Integer.toString(bucket.getSlots().getSlots()));
|
result.setText(Integer.toString(bucket.slots()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER);
|
}).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER);
|
||||||
@ -69,7 +72,7 @@ public class BucketList extends VerticalLayout {
|
|||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HorizontalLayout createManageButtons(Bucket bucket) {
|
private HorizontalLayout createManageButtons(BucketRepository.BucketInfo bucket) {
|
||||||
var layout = new HorizontalLayout();
|
var layout = new HorizontalLayout();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -89,16 +92,16 @@ public class BucketList extends VerticalLayout {
|
|||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clickDetailsButton(Bucket bucket) {
|
private void clickDetailsButton(BucketRepository.BucketInfo bucket) {
|
||||||
getUI().ifPresent(ui -> {
|
getUI().ifPresent(ui -> {
|
||||||
ui.navigate("/nodes/" + bucket.getNodeIdentifier() +
|
ui.navigate("/nodes/" + nodeIdentifier +
|
||||||
"/buckets/" + bucket.getIdentifier());
|
"/buckets/" + bucket.identifier());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clickRemoveButton(Bucket bucket) {
|
private void clickRemoveButton(BucketRepository.BucketInfo bucket) {
|
||||||
var dialog = new Dialog("Confirm bucket deletion");
|
var dialog = new Dialog("Confirm bucket deletion");
|
||||||
dialog.add(new Paragraph("Confirm that you want to delete bucket. Enter '" + bucket.getIdentifier() + "' to field below and confirm."));
|
dialog.add(new Paragraph("Confirm that you want to delete bucket. Enter '" + bucket.identifier() + "' to field below and confirm."));
|
||||||
|
|
||||||
var inputField = new TextField();
|
var inputField = new TextField();
|
||||||
dialog.add(inputField);
|
dialog.add(inputField);
|
||||||
@ -107,14 +110,14 @@ public class BucketList extends VerticalLayout {
|
|||||||
var button = new Button("Confirm");
|
var button = new Button("Confirm");
|
||||||
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
|
||||||
button.addClickListener(event -> {
|
button.addClickListener(event -> {
|
||||||
if (!bucket.getIdentifier().equals(inputField.getValue())) {
|
if (!bucket.identifier().equals(inputField.getValue())) {
|
||||||
Notification.show("Invalid input", 3000, Notification.Position.TOP_END)
|
Notification.show("Invalid input", 3000, Notification.Position.TOP_END)
|
||||||
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBucket(bucket);
|
removeBucket(bucket);
|
||||||
Notification.show("Bucket '" + bucket.getIdentifier() + "' was successfully removed!", 3000, Notification.Position.TOP_END)
|
Notification.show("Bucket '" + bucket.identifier() + "' was successfully removed!", 3000, Notification.Position.TOP_END)
|
||||||
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
|
||||||
dialog.close();
|
dialog.close();
|
||||||
});
|
});
|
||||||
@ -131,12 +134,12 @@ public class BucketList extends VerticalLayout {
|
|||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(List<Bucket> buckets) {
|
public void update(List<BucketRepository.BucketInfo> buckets) {
|
||||||
cachedBuckets = buckets;
|
cachedBuckets = buckets;
|
||||||
applySearch(searchField.getValue());
|
applySearch(searchField.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeBucket(Bucket bucket) {
|
private void removeBucket(BucketRepository.BucketInfo bucket) {
|
||||||
// TODO: send remove request and getting list
|
// TODO: send remove request and getting list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import ru.dragonestia.loadbalancer.web.model.Bucket;
|
|||||||
import ru.dragonestia.loadbalancer.web.model.Node;
|
import ru.dragonestia.loadbalancer.web.model.Node;
|
||||||
import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod;
|
import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod;
|
||||||
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
|
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
|
||||||
|
import ru.dragonestia.loadbalancer.web.repository.BucketRepository;
|
||||||
import ru.dragonestia.loadbalancer.web.repository.NodeRepository;
|
import ru.dragonestia.loadbalancer.web.repository.NodeRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -30,12 +31,16 @@ import java.util.List;
|
|||||||
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {
|
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {
|
||||||
|
|
||||||
private final NodeRepository nodeRepository;
|
private final NodeRepository nodeRepository;
|
||||||
|
private final BucketRepository bucketRepository;
|
||||||
private Node node;
|
private Node node;
|
||||||
private RegisterBucket registerBucket;
|
private RegisterBucket registerBucket;
|
||||||
private BucketList bucketList;
|
private BucketList bucketList;
|
||||||
|
|
||||||
public NodeDetailsPage(@Autowired NodeRepository nodeRepository) {
|
public NodeDetailsPage(@Autowired NodeRepository nodeRepository,
|
||||||
|
@Autowired BucketRepository bucketRepository) {
|
||||||
|
|
||||||
this.nodeRepository = nodeRepository;
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.bucketRepository = bucketRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -56,19 +61,12 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
|
|||||||
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
node = nodeOpt.get();
|
||||||
|
|
||||||
node = nodeOpt.get(); // TODO: getting node
|
initComponents(node, bucketRepository.all(node));
|
||||||
|
|
||||||
// TODO: getting buckets
|
|
||||||
initComponents(node, List.of(
|
|
||||||
Bucket.create("test-1", node, SlotLimit.unlimited(), "Hello world!"),
|
|
||||||
Bucket.create("test-2", node, SlotLimit.of(12), "Hello world!"),
|
|
||||||
Bucket.create("test-3", node, SlotLimit.unlimited(), "Hello world!"),
|
|
||||||
Bucket.create("test-4", node, SlotLimit.of(32), "Hello world!"),
|
|
||||||
Bucket.create("test-5", node, SlotLimit.of(54), "Hello world!")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initComponents(Node node, List<Bucket> buckets) {
|
private void initComponents(Node node, List<BucketRepository.BucketInfo> buckets) {
|
||||||
printNodeDetails(node);
|
printNodeDetails(node);
|
||||||
add(new Hr());
|
add(new Hr());
|
||||||
add(registerBucket = new RegisterBucket(node, (bucket) -> {
|
add(registerBucket = new RegisterBucket(node, (bucket) -> {
|
||||||
@ -76,7 +74,7 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv
|
|||||||
return new RegisterBucket.Response(false, "");
|
return new RegisterBucket.Response(false, "");
|
||||||
}));
|
}));
|
||||||
add(new Hr());
|
add(new Hr());
|
||||||
add(bucketList = new BucketList(buckets));
|
add(bucketList = new BucketList(node.identifier(), buckets));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printNodeDetails(Node node) {
|
private void printNodeDetails(Node node) {
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.web.repository;
|
||||||
|
|
||||||
|
import ru.dragonestia.loadbalancer.web.model.Node;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BucketRepository {
|
||||||
|
|
||||||
|
List<BucketInfo> all(Node node);
|
||||||
|
|
||||||
|
record BucketInfo(String identifier, int slots) {}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.web.repository.impl;
|
||||||
|
|
||||||
|
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import ru.dragonestia.loadbalancer.web.model.Bucket;
|
||||||
|
import ru.dragonestia.loadbalancer.web.model.Node;
|
||||||
|
import ru.dragonestia.loadbalancer.web.repository.BucketRepository;
|
||||||
|
import ru.dragonestia.loadbalancer.web.repository.impl.response.BucketListResponse;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@SpringComponent
|
||||||
|
public class BucketRepositoryImpl implements BucketRepository {
|
||||||
|
|
||||||
|
private final RestUtil rest;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BucketInfo> all(Node node) {
|
||||||
|
var entity = rest.getEntity(URI.create("/nodes/" + node.identifier() + "/buckets"),
|
||||||
|
BucketListResponse.class);
|
||||||
|
|
||||||
|
if (entity.getStatusCode().value() == 404) {
|
||||||
|
throw new Error("Node with identifier '" + node.identifier() + "' does not exists'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entity.hasBody()) {
|
||||||
|
throw new Error("Bucket list did not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Objects.requireNonNull(entity.getBody()).buckets();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package ru.dragonestia.loadbalancer.web.repository.impl;
|
package ru.dragonestia.loadbalancer.web.repository.impl;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@ -24,6 +25,11 @@ public class RestUtil {
|
|||||||
return Objects.requireNonNull(template.getForObject(serverUrl.resolve(uri), responseType));
|
return Objects.requireNonNull(template.getForObject(serverUrl.resolve(uri), responseType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> ResponseEntity<T> getEntity(URI uri, Class<T> responseType) {
|
||||||
|
var template = restTemplate.get();
|
||||||
|
return template.getForEntity(serverUrl.resolve(uri), responseType);
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T get(URI uri, Class<T> responseType, Consumer<Map<String, String>> paramsConsumer) {
|
public <T> T get(URI uri, Class<T> responseType, Consumer<Map<String, String>> paramsConsumer) {
|
||||||
var params = new HashMap<String, String>();
|
var params = new HashMap<String, String>();
|
||||||
paramsConsumer.accept(params);
|
paramsConsumer.accept(params);
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.web.repository.impl.response;
|
||||||
|
|
||||||
|
import ru.dragonestia.loadbalancer.web.repository.BucketRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record BucketListResponse(String node, List<BucketRepository.BucketInfo> buckets) {}
|
||||||
@ -8,16 +8,22 @@ import org.springframework.lang.NonNull;
|
|||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
import ru.dragonestia.loadbalancer.interceptor.DebugInterceptor;
|
import ru.dragonestia.loadbalancer.interceptor.DebugInterceptor;
|
||||||
|
import ru.dragonestia.loadbalancer.model.Bucket;
|
||||||
import ru.dragonestia.loadbalancer.model.Node;
|
import ru.dragonestia.loadbalancer.model.Node;
|
||||||
import ru.dragonestia.loadbalancer.model.type.LoadBalancingMethod;
|
import ru.dragonestia.loadbalancer.model.type.LoadBalancingMethod;
|
||||||
|
import ru.dragonestia.loadbalancer.model.type.SlotLimit;
|
||||||
|
import ru.dragonestia.loadbalancer.repository.BucketRepository;
|
||||||
import ru.dragonestia.loadbalancer.repository.NodeRepository;
|
import ru.dragonestia.loadbalancer.repository.NodeRepository;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Profile("test")
|
@Profile("test")
|
||||||
@Configuration
|
@Configuration
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TestConfig implements WebMvcConfigurer {
|
public class TestConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
private final NodeRepository nodeRepository;
|
private final NodeRepository nodeRepository;
|
||||||
|
private final BucketRepository bucketRepository;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(@NonNull InterceptorRegistry registry) {
|
public void addInterceptors(@NonNull InterceptorRegistry registry) {
|
||||||
@ -26,8 +32,20 @@ public class TestConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
void createNodes() {
|
void createNodes() {
|
||||||
nodeRepository.createNode(new Node("game-servers", LoadBalancingMethod.ROUND_ROBIN));
|
createNodeWithContent(new Node("game-servers", LoadBalancingMethod.ROUND_ROBIN));
|
||||||
nodeRepository.createNode(new Node("game-lobbies", LoadBalancingMethod.LEAST_PICKED));
|
createNodeWithContent(new Node("game-lobbies", LoadBalancingMethod.LEAST_PICKED));
|
||||||
nodeRepository.createNode(new Node("hub", LoadBalancingMethod.SEQUENTIAL_FILLING));
|
createNodeWithContent(new Node("hub", LoadBalancingMethod.SEQUENTIAL_FILLING));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNodeWithContent(Node node) {
|
||||||
|
nodeRepository.createNode(node);
|
||||||
|
|
||||||
|
for (int i = 1; i <= 5; i++) {
|
||||||
|
bucketRepository.createBucket(Bucket.create("test-" + i, node, SlotLimit.of(5 * i), "Some payload"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
bucketRepository.createBucket(Bucket.create(UUID.randomUUID().toString(), node, SlotLimit.unlimited(), "Some payload"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.dragonestia.loadbalancer.controller.response.BucketListResponse;
|
||||||
|
import ru.dragonestia.loadbalancer.service.BucketService;
|
||||||
|
import ru.dragonestia.loadbalancer.service.NodeService;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/nodes/{nodeIdentifier}/buckets")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BucketController {
|
||||||
|
|
||||||
|
private final NodeService nodeService;
|
||||||
|
private final BucketService bucketService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
ResponseEntity<BucketListResponse> allBuckets(@PathVariable(name = "nodeIdentifier") String nodeId) {
|
||||||
|
var nodeOpt = nodeService.findNode(nodeId);
|
||||||
|
return nodeOpt.map(node -> ResponseEntity.ok(new BucketListResponse(nodeId,
|
||||||
|
bucketService.allBuckets(node).stream()
|
||||||
|
.map(bucket -> new BucketListResponse.BucketInfo(bucket.getIdentifier(), bucket.getSlots().getSlots()))
|
||||||
|
.toList()
|
||||||
|
))).orElseGet(() -> ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.dragonestia.loadbalancer.model.Bucket;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/users")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
Collection<Bucket> linkedBucketsForUser(@RequestParam(name = "user") String userIdentifier) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
String linkUserWithBucket(@RequestParam(name = "user") String userIdentifier,
|
||||||
|
@RequestParam(name = "bucket") String bucketIdentifier,
|
||||||
|
@RequestParam(name = "force") boolean force) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
String unlinkUsersForBucket(@RequestParam(name = "users") String userIdentifiers,
|
||||||
|
@RequestParam(name = "bucket") String bucketIdentifier) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package ru.dragonestia.loadbalancer.controller.response;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record BucketListResponse(String node, List<BucketInfo> buckets) {
|
||||||
|
|
||||||
|
public record BucketInfo(String identifier, int slots) {}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user