hiscore panel: fix lookup to run on edt

It modifies various fields in the ui and should be running on edt.
Additionally add a clear listener to reset the search state when the
input is cleared.

This requires changing the hiscore client to be async so that the
response can be properly applied on the edt
This commit is contained in:
Adam
2020-08-22 13:36:45 -04:00
parent a89202e230
commit c9859f36b6
3 changed files with 109 additions and 65 deletions

View File

@@ -25,8 +25,11 @@
package net.runelite.http.api.hiscore; package net.runelite.http.api.hiscore;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
@@ -46,16 +49,14 @@ public class HiscoreClient
return lookup(username, endpoint.getHiscoreURL()); return lookup(username, endpoint.getHiscoreURL());
} }
public CompletableFuture<HiscoreResult> lookupAsync(String username, HiscoreEndpoint endpoint)
{
return lookupAsync(username, endpoint.getHiscoreURL());
}
public HiscoreResult lookup(String username, HttpUrl endpoint) throws IOException public HiscoreResult lookup(String username, HttpUrl endpoint) throws IOException
{ {
HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint); return lookupSync(username, endpoint);
if (resultBuilder == null)
{
return null;
}
return resultBuilder.build();
} }
public HiscoreResult lookup(String username) throws IOException public HiscoreResult lookup(String username) throws IOException
@@ -65,15 +66,13 @@ public class HiscoreClient
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill, HiscoreEndpoint endpoint) throws IOException public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill, HiscoreEndpoint endpoint) throws IOException
{ {
HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint.getHiscoreURL()); HiscoreResult result = lookupSync(username, endpoint.getHiscoreURL());
if (resultBuilder == null) if (result == null)
{ {
return null; return null;
} }
HiscoreResult result = resultBuilder.build();
Skill requested = result.getSkill(skill); Skill requested = result.getSkill(skill);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult(); SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
skillResult.setPlayer(username); skillResult.setPlayer(username);
@@ -87,7 +86,44 @@ public class HiscoreClient
return lookup(username, skill, HiscoreEndpoint.NORMAL); return lookup(username, skill, HiscoreEndpoint.NORMAL);
} }
private HiscoreResultBuilder lookupUsername(String username, HttpUrl hiscoreUrl) throws IOException private HiscoreResult lookupSync(String username, HttpUrl hiscoreUrl) throws IOException
{
try (Response response = client.newCall(buildRequest(username, hiscoreUrl)).execute())
{
return processResponse(username, response);
}
}
private CompletableFuture<HiscoreResult> lookupAsync(String username, HttpUrl hiscoreUrl)
{
CompletableFuture<HiscoreResult> future = new CompletableFuture<>();
client.newCall(buildRequest(username, hiscoreUrl)).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
future.completeExceptionally(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
try
{
future.complete(processResponse(username, response));
}
finally
{
response.close();
}
}
});
return future;
}
private static Request buildRequest(String username, HttpUrl hiscoreUrl)
{ {
HttpUrl url = hiscoreUrl.newBuilder() HttpUrl url = hiscoreUrl.newBuilder()
.addQueryParameter("player", username) .addQueryParameter("player", username)
@@ -95,28 +131,29 @@ public class HiscoreClient
log.debug("Built URL {}", url); log.debug("Built URL {}", url);
Request okrequest = new Request.Builder() return new Request.Builder()
.url(url) .url(url)
.build(); .build();
}
String responseStr; private static HiscoreResult processResponse(String username, Response response) throws IOException
{
try (Response okresponse = client.newCall(okrequest).execute()) if (!response.isSuccessful())
{ {
if (!okresponse.isSuccessful()) if (response.code() == 404)
{ {
switch (okresponse.code()) return null;
{
case 404:
return null;
default:
throw new IOException("Error retrieving data from Jagex Hiscores: " + okresponse);
}
} }
responseStr = okresponse.body().string(); throw new IOException("Error retrieving data from Jagex Hiscores: " + response);
} }
String responseStr = response.body().string();
return parseResponse(username, responseStr);
}
private static HiscoreResult parseResponse(String username, String responseStr) throws IOException
{
CSVParser parser = CSVParser.parse(responseStr, CSVFormat.DEFAULT); CSVParser parser = CSVParser.parse(responseStr, CSVFormat.DEFAULT);
HiscoreResultBuilder hiscoreBuilder = new HiscoreResultBuilder(); HiscoreResultBuilder hiscoreBuilder = new HiscoreResultBuilder();
@@ -147,6 +184,6 @@ public class HiscoreClient
hiscoreBuilder.setNextSkill(skill); hiscoreBuilder.setNextSkill(skill);
} }
return hiscoreBuilder; return hiscoreBuilder.build();
} }
} }

View File

@@ -38,17 +38,16 @@ import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
@@ -119,7 +118,6 @@ public class HiscorePanel extends PluginPanel
HiscoreEndpoint.NORMAL, HiscoreEndpoint.IRONMAN, HiscoreEndpoint.HARDCORE_IRONMAN, HiscoreEndpoint.ULTIMATE_IRONMAN, HiscoreEndpoint.DEADMAN, HiscoreEndpoint.TOURNAMENT HiscoreEndpoint.NORMAL, HiscoreEndpoint.IRONMAN, HiscoreEndpoint.HARDCORE_IRONMAN, HiscoreEndpoint.ULTIMATE_IRONMAN, HiscoreEndpoint.DEADMAN, HiscoreEndpoint.TOURNAMENT
}; };
private final ScheduledExecutorService executor;
private final Client client; private final Client client;
private final HiscoreConfig config; private final HiscoreConfig config;
private final NameAutocompleter nameAutocompleter; private final NameAutocompleter nameAutocompleter;
@@ -140,10 +138,9 @@ public class HiscorePanel extends PluginPanel
private boolean loading = false; private boolean loading = false;
@Inject @Inject
public HiscorePanel(ScheduledExecutorService scheduledExecutorService, @Nullable Client client, public HiscorePanel(@Nullable Client client,
HiscoreConfig config, NameAutocompleter nameAutocompleter, OkHttpClient okHttpClient) HiscoreConfig config, NameAutocompleter nameAutocompleter, OkHttpClient okHttpClient)
{ {
this.executor = scheduledExecutorService;
this.client = client; this.client = client;
this.config = config; this.config = config;
this.nameAutocompleter = nameAutocompleter; this.nameAutocompleter = nameAutocompleter;
@@ -171,7 +168,7 @@ public class HiscorePanel extends PluginPanel
searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR); searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR);
searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
searchBar.setMinimumSize(new Dimension(0, 30)); searchBar.setMinimumSize(new Dimension(0, 30));
searchBar.addActionListener(e -> executor.execute(this::lookup)); searchBar.addActionListener(e -> lookup());
searchBar.addMouseListener(new MouseAdapter() searchBar.addMouseListener(new MouseAdapter()
{ {
@Override @Override
@@ -194,6 +191,12 @@ public class HiscorePanel extends PluginPanel
} }
} }
}); });
searchBar.addClearListener(() ->
{
searchBar.setIcon(IconTextField.Icon.SEARCH);
searchBar.setEditable(true);
loading = false;
});
add(searchBar, c); add(searchBar, c);
c.gridy++; c.gridy++;
@@ -231,7 +234,7 @@ public class HiscorePanel extends PluginPanel
return; return;
} }
executor.execute(HiscorePanel.this::lookup); lookup();
} }
}); });
@@ -359,14 +362,12 @@ public class HiscorePanel extends PluginPanel
{ {
searchBar.setText(username); searchBar.setText(username);
resetEndpoints(); resetEndpoints();
executor.execute(this::lookup); lookup();
} }
private void lookup() private void lookup()
{ {
String lookup = searchBar.getText(); final String lookup = sanitize(searchBar.getText());
lookup = sanitize(lookup);
if (Strings.isNullOrEmpty(lookup)) if (Strings.isNullOrEmpty(lookup))
{ {
@@ -401,33 +402,40 @@ public class HiscorePanel extends PluginPanel
selectedEndPoint = HiscoreEndpoint.NORMAL; selectedEndPoint = HiscoreEndpoint.NORMAL;
} }
HiscoreResult result; hiscoreClient.lookupAsync(lookup, selectedEndPoint).whenCompleteAsync((result, ex) ->
try SwingUtilities.invokeLater(() ->
{ {
log.debug("Hiscore endpoint " + selectedEndPoint.name() + " selected"); if (!sanitize(searchBar.getText()).equals(lookup))
result = hiscoreClient.lookup(lookup, selectedEndPoint); {
} // search has changed in the meantime
catch (IOException ex) return;
{ }
log.warn("Error fetching Hiscore data " + ex.getMessage());
searchBar.setIcon(IconTextField.Icon.ERROR);
searchBar.setEditable(true);
loading = false;
return;
}
if (result == null) if (result == null || ex != null)
{ {
searchBar.setIcon(IconTextField.Icon.ERROR); if (ex != null)
searchBar.setEditable(true); {
loading = false; log.warn("Error fetching Hiscore data " + ex.getMessage());
return; }
}
//successful player search searchBar.setIcon(IconTextField.Icon.ERROR);
searchBar.setIcon(IconTextField.Icon.SEARCH); searchBar.setEditable(true);
searchBar.setEditable(true); loading = false;
loading = false; return;
}
//successful player search
searchBar.setIcon(IconTextField.Icon.SEARCH);
searchBar.setEditable(true);
loading = false;
applyHiscoreResult(result);
}));
}
private void applyHiscoreResult(HiscoreResult result)
{
assert SwingUtilities.isEventDispatchThread();
nameAutocompleter.addToSearchHistory(result.getPlayer().toLowerCase()); nameAutocompleter.addToSearchHistory(result.getPlayer().toLowerCase());

View File

@@ -24,7 +24,6 @@
*/ */
package net.runelite.client.plugins.hiscore; package net.runelite.client.plugins.hiscore;
import java.util.concurrent.ScheduledExecutorService;
import static net.runelite.client.plugins.hiscore.HiscorePanel.formatLevel; import static net.runelite.client.plugins.hiscore.HiscorePanel.formatLevel;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -36,7 +35,7 @@ public class HiscorePanelTest
@Test @Test
public void testConstructor() public void testConstructor()
{ {
new HiscorePanel(mock(ScheduledExecutorService.class), null, mock(HiscoreConfig.class), mock(NameAutocompleter.class), mock(OkHttpClient.class)); new HiscorePanel(null, mock(HiscoreConfig.class), mock(NameAutocompleter.class), mock(OkHttpClient.class));
} }
@Test @Test