Improved client view of servers.

This commit is contained in:
Andrew Lalis 2021-07-09 09:59:01 +02:00
parent ec86b8cf69
commit 532aacdd11
3 changed files with 63 additions and 37 deletions

View File

@ -45,6 +45,7 @@ public record PublicServerInfo(
panel.add(addressLabel, c); panel.add(addressLabel, c);
c.gridy++; c.gridy++;
JTextArea descriptionArea = new JTextArea(value.description()); JTextArea descriptionArea = new JTextArea(value.description());
descriptionArea.setFont(new Font("monospaced", Font.PLAIN, 12));
descriptionArea.setEditable(false); descriptionArea.setEditable(false);
descriptionArea.setWrapStyleWord(true); descriptionArea.setWrapStyleWord(true);
descriptionArea.setLineWrap(true); descriptionArea.setLineWrap(true);
@ -64,6 +65,8 @@ public record PublicServerInfo(
descriptionArea.setBackground(list.getBackground()); descriptionArea.setBackground(list.getBackground());
} }
panel.revalidate();
return panel; return panel;
}; };
} }

View File

@ -23,7 +23,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class PublicServerListModel extends AbstractListModel<PublicServerInfo> { public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
private final List<PublicServerInfo> currentPageItems; private final List<PublicServerInfo> currentPageItems;
@ -38,14 +40,12 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
private final HttpClient client; private final HttpClient client;
private final ObjectMapper mapper; private final ObjectMapper mapper;
private final ScheduledExecutorService executorService; private final ScheduledExecutorService executorService;
private ScheduledFuture<?> pageFetchFuture;
private final List<Consumer<PublicServerListModel>> modelUpdateListeners;
private final JButton prevButton; public PublicServerListModel() {
private final JButton nextButton;
public PublicServerListModel(JButton prevButton, JButton nextButton) {
this.currentPageItems = new ArrayList<>(); this.currentPageItems = new ArrayList<>();
this.prevButton = prevButton; this.modelUpdateListeners = new ArrayList<>();
this.nextButton = nextButton;
this.executorService = Executors.newSingleThreadScheduledExecutor(); this.executorService = Executors.newSingleThreadScheduledExecutor();
this.client = HttpClient.newBuilder() this.client = HttpClient.newBuilder()
.executor(this.executorService) .executor(this.executorService)
@ -53,14 +53,21 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
.build(); .build();
this.mapper = new ObjectMapper(); this.mapper = new ObjectMapper();
this.fetchPage(0, null, null, null); this.fetchPage(0, null, null, null);
this.executorService.scheduleAtFixedRate( }
() -> this.fetchPage(this.currentPage, this.currentQuery, this.currentOrder, this.currentOrderDir),
5, public void scheduleAutoPageFetch() {
5, this.pageFetchFuture = this.executorService.scheduleAtFixedRate(
TimeUnit.SECONDS () -> this.fetchPage(this.currentPage, this.currentQuery, this.currentOrder, this.currentOrderDir),
5,
5,
TimeUnit.SECONDS
); );
} }
public void addListener(Consumer<PublicServerListModel> listener) {
this.modelUpdateListeners.add(listener);
}
public void fetchPage(int page) { public void fetchPage(int page) {
this.fetchPage(page, this.currentQuery); this.fetchPage(page, this.currentQuery);
} }
@ -70,6 +77,10 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
} }
public void fetchPage(int page, String query, String order, String orderDir) { public void fetchPage(int page, String query, String order, String orderDir) {
System.out.println("Fetching...");
if (this.pageFetchFuture != null && !this.pageFetchFuture.isDone()) {
this.pageFetchFuture.cancel(false);
}
String uri = "http://localhost:8567/serverInfo?page=" + page + "&size=" + this.pageSize; String uri = "http://localhost:8567/serverInfo?page=" + page + "&size=" + this.pageSize;
if (query != null && !query.isBlank()) { if (query != null && !query.isBlank()) {
uri += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); uri += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
@ -88,29 +99,35 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
return; return;
} }
this.client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()).thenAcceptAsync(response -> { var requestFuture = this.client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream());
if (response.statusCode() != 200) { requestFuture.whenCompleteAsync((response, throwable) -> {
this.currentPageItems.clear();
this.firstPage = true;
this.lastPage = true;
if (throwable != null) {
System.err.println("Could not request data from registry: " + throwable);
} else if (response.statusCode() != 200) {
System.err.println("Non-OK status code: " + response.statusCode()); System.err.println("Non-OK status code: " + response.statusCode());
} } else {
try { try {
JsonNode json = this.mapper.readValue(response.body(), JsonNode.class); JsonNode json = this.mapper.readValue(response.body(), JsonNode.class);
this.firstPage = json.get("firstPage").asBoolean(); this.firstPage = json.get("firstPage").asBoolean();
this.prevButton.setEnabled(!this.firstPage); this.lastPage = json.get("lastPage").asBoolean();
this.lastPage = json.get("lastPage").asBoolean(); this.currentPage = json.get("currentPage").asInt();
this.nextButton.setEnabled(!this.lastPage); this.pageSize = json.get("pageSize").asInt();
this.currentPage = json.get("currentPage").asInt(); this.currentQuery = query;
this.pageSize = json.get("pageSize").asInt(); this.currentOrder = json.get("order").asText();
this.currentQuery = query; this.currentOrderDir = json.get("orderDirection").asText();
this.currentOrder = json.get("order").asText(); for (Iterator<JsonNode> it = json.get("contents").elements(); it.hasNext(); ) {
this.currentOrderDir = json.get("orderDirection").asText(); this.addServerInfoFromJson(it.next());
this.currentPageItems.clear(); }
for (Iterator<JsonNode> it = json.get("contents").elements(); it.hasNext();) { this.scheduleAutoPageFetch();
this.addServerInfoFromJson(it.next()); } catch (IOException e) {
e.printStackTrace();
} }
this.fireContentsChanged(this, 0, this.getSize());
} catch (IOException e) {
e.printStackTrace();
} }
this.fireContentsChanged(this, 0, this.getSize());
this.modelUpdateListeners.forEach(l -> l.accept(this));
}); });
} }
@ -160,6 +177,7 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
} }
public void dispose() { public void dispose() {
this.modelUpdateListeners.clear();
this.executorService.shutdown(); this.executorService.shutdown();
} }
} }

View File

@ -11,8 +11,6 @@ import java.awt.event.MouseEvent;
import java.io.IOException; import java.io.IOException;
public class SearchServersDialog extends JDialog { public class SearchServersDialog extends JDialog {
private final JButton prevButton;
private final JButton nextButton;
private final PublicServerListModel listModel; private final PublicServerListModel listModel;
public SearchServersDialog(Frame frame, ServerInfoListModel serverInfoListModel) { public SearchServersDialog(Frame frame, ServerInfoListModel serverInfoListModel) {
@ -20,9 +18,7 @@ public class SearchServersDialog extends JDialog {
this.setTitle("Search for Servers"); this.setTitle("Search for Servers");
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.prevButton = new JButton("<"); this.listModel = new PublicServerListModel();
this.nextButton = new JButton(">");
this.listModel = new PublicServerListModel(prevButton, nextButton);
this.setContentPane(this.getContent(serverInfoListModel)); this.setContentPane(this.getContent(serverInfoListModel));
this.pack(); this.pack();
@ -40,13 +36,22 @@ public class SearchServersDialog extends JDialog {
panel.add(scrollPane, BorderLayout.CENTER); panel.add(scrollPane, BorderLayout.CENTER);
JPanel filtersPanel = new JPanel(new FlowLayout()); JPanel filtersPanel = new JPanel(new FlowLayout());
JTextField searchField = new JTextField(20); JTextField searchField = new JTextField(15);
searchField.setToolTipText("Search for a server by name."); searchField.setToolTipText("Search for a server by name.");
filtersPanel.add(searchField); filtersPanel.add(searchField);
var prevButton = new JButton("<");
var nextButton = new JButton(">");
var refreshButton = new JButton("Refresh");
prevButton.addActionListener(e -> listModel.fetchPage(listModel.getCurrentPage() - 1)); prevButton.addActionListener(e -> listModel.fetchPage(listModel.getCurrentPage() - 1));
filtersPanel.add(prevButton); filtersPanel.add(prevButton);
nextButton.addActionListener(e -> listModel.fetchPage(listModel.getCurrentPage() + 1)); nextButton.addActionListener(e -> listModel.fetchPage(listModel.getCurrentPage() + 1));
filtersPanel.add(nextButton); filtersPanel.add(nextButton);
refreshButton.addActionListener(e -> listModel.fetchPage(listModel.getCurrentPage()));
filtersPanel.add(refreshButton);
listModel.addListener(model -> {
prevButton.setEnabled(!model.isFirstPage());
nextButton.setEnabled(!model.isLastPage());
});
panel.add(filtersPanel, BorderLayout.NORTH); panel.add(filtersPanel, BorderLayout.NORTH);