Skip to content

Commit

Permalink
ApResolver: Use OkHttpClient for requesting the list
Browse files Browse the repository at this point in the history
With the old implementation, the ap request wasn't going through the proxy (if there was one configured). Now, it uses the OkHttpClient we use in other parts of the app which will be configured to use the proxy if needed.
  • Loading branch information
iscle committed Dec 20, 2021
1 parent 18f53d5 commit 704ca19
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 44 deletions.
72 changes: 40 additions & 32 deletions lib/src/main/java/xyz/gianlu/librespot/core/ApResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -40,29 +40,36 @@
*/
public final class ApResolver {
private static final String BASE_URL = "http://apresolve.spotify.com/";
private static final Map<String, List<String>> pool = new HashMap<>(3);
private static final Logger LOGGER = LoggerFactory.getLogger(ApResolver.class);
private static volatile boolean poolReady = false;

public static void fillPool() throws IOException {
if (!poolReady) request("accesspoint", "dealer", "spclient");
private final OkHttpClient client;
private final Map<String, List<String>> pool = new HashMap<>(3);
private volatile boolean poolReady = false;

public ApResolver(OkHttpClient client) throws IOException {
this.client = client;
fillPool();
}

public static void refreshPool() throws IOException {
private void fillPool() throws IOException {
request("accesspoint", "dealer", "spclient");
}

public void refreshPool() throws IOException {
poolReady = false;
pool.clear();
request("accesspoint", "dealer", "spclient");
fillPool();
}

@NotNull
private static List<String> getUrls(@NotNull JsonObject body, @NotNull String type) {
private List<String> getUrls(@NotNull JsonObject body, @NotNull String type) {
JsonArray aps = body.getAsJsonArray(type);
List<String> list = new ArrayList<>(aps.size());
for (JsonElement ap : aps) list.add(ap.getAsString());
return list;
}

private static void request(@NotNull String... types) throws IOException {
private void request(@NotNull String... types) throws IOException {
if (types.length == 0) throw new IllegalArgumentException();

StringBuilder url = new StringBuilder(BASE_URL + "?");
Expand All @@ -71,28 +78,29 @@ private static void request(@NotNull String... types) throws IOException {
url.append("type=").append(types[i]);
}

HttpURLConnection conn = (HttpURLConnection) new URL(url.toString()).openConnection();
conn.connect();

try (Reader reader = new InputStreamReader(conn.getInputStream())) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
HashMap<String, List<String>> map = new HashMap<>();
for (String type : types)
map.put(type, getUrls(obj, type));
Request request = new Request.Builder()
.url(url.toString())
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
try (Reader reader = response.body().charStream()) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
HashMap<String, List<String>> map = new HashMap<>();
for (String type : types)
map.put(type, getUrls(obj, type));

synchronized (pool) {
pool.putAll(map);
poolReady = true;
pool.notifyAll();
}

synchronized (pool) {
pool.putAll(map);
poolReady = true;
pool.notifyAll();
LOGGER.info("Loaded aps into pool: " + pool);
}

LOGGER.info("Loaded aps into pool: " + pool);
} finally {
conn.disconnect();
}
}

private static void waitForPool() {
private void waitForPool() {
if (!poolReady) {
synchronized (pool) {
try {
Expand All @@ -105,7 +113,7 @@ private static void waitForPool() {
}

@NotNull
private static String getRandomOf(@NotNull String type) {
private String getRandomOf(@NotNull String type) {
waitForPool();

List<String> urls = pool.get(type);
Expand All @@ -114,17 +122,17 @@ private static String getRandomOf(@NotNull String type) {
}

@NotNull
public static String getRandomDealer() {
public String getRandomDealer() {
return getRandomOf("dealer");
}

@NotNull
public static String getRandomSpclient() {
public String getRandomSpclient() {
return getRandomOf("spclient");
}

@NotNull
public static String getRandomAccesspoint() {
public String getRandomAccesspoint() {
return getRandomOf("accesspoint");
}
}
25 changes: 16 additions & 9 deletions lib/src/main/java/xyz/gianlu/librespot/core/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public final class Session implements Closeable {
(byte) 0xeb, (byte) 0x00, (byte) 0x06, (byte) 0xa2, (byte) 0x5a, (byte) 0xee, (byte) 0xa1, (byte) 0x1b, (byte) 0x13, (byte) 0x87, (byte) 0x3c, (byte) 0xd7,
(byte) 0x19, (byte) 0xe6, (byte) 0x55, (byte) 0xbd
};
private final ApResolver apResolver;
private final DiffieHellman keys;
private final Inner inner;
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new NameThreadFactory(r -> "session-scheduler-" + r.hashCode()));
Expand Down Expand Up @@ -128,11 +129,13 @@ public final class Session implements Closeable {
private volatile boolean closing = false;
private volatile ScheduledFuture<?> scheduledReconnect = null;

private Session(@NotNull Inner inner, @NotNull String addr) throws IOException {
private Session(@NotNull Inner inner) throws IOException {
this.inner = inner;
this.keys = new DiffieHellman(inner.random);
this.conn = ConnectionHolder.create(addr, inner.conf);
this.client = createClient(inner.conf);
this.apResolver = new ApResolver(client);
String addr = apResolver.getRandomAccesspoint();
this.conn = ConnectionHolder.create(addr, inner.conf);

LOGGER.info("Created new session! {deviceId: {}, ap: {}, proxy: {}} ", inner.deviceId, addr, inner.conf.proxyEnabled);
}
Expand Down Expand Up @@ -566,6 +569,11 @@ public void send(Packet.Type cmd, byte[] payload) throws IOException {
}
}

@NotNull
public ApResolver apResolver() {
return apResolver;
}

@NotNull
public MercuryClient mercury() {
waitAuthLock();
Expand Down Expand Up @@ -710,14 +718,14 @@ private void reconnect() {
}

try {
ApResolver.refreshPool();
apResolver.refreshPool();

if (conn != null) {
conn.socket.close();
receiver.stop();
}

conn = ConnectionHolder.create(ApResolver.getRandomAccesspoint(), inner.conf);
conn = ConnectionHolder.create(apResolver.getRandomAccesspoint(), inner.conf);
connect();
authenticatePartial(Authentication.LoginCredentials.newBuilder()
.setUsername(apWelcome.getCanonicalUsername())
Expand Down Expand Up @@ -1021,10 +1029,9 @@ public Session create() throws IOException, GeneralSecurityException, SpotifyAut
if (loginCredentials == null)
throw new IllegalStateException("You must select an authentication method.");

ApResolver.fillPool();
TimeProvider.init(conf);

Session session = new Session(new Inner(deviceType, deviceName, deviceId, preferredLocale, conf), ApResolver.getRandomAccesspoint());
Session session = new Session(new Inner(deviceType, deviceName, deviceId, preferredLocale, conf));
session.connect();
session.authenticate(loginCredentials);
return session;
Expand Down Expand Up @@ -1253,9 +1260,9 @@ private ConnectionHolder(@NotNull Socket socket) throws IOException {

@NotNull
static ConnectionHolder create(@NotNull String addr, @NotNull Configuration conf) throws IOException {
int colon = addr.indexOf(':');
String apAddr = addr.substring(0, colon);
int apPort = Integer.parseInt(addr.substring(colon + 1));
String[] split = addr.split(":");
String apAddr = split[0];
int apPort = Integer.parseInt(split[1]);
if (!conf.proxyEnabled || conf.proxyType == Proxy.Type.DIRECT)
return new ConnectionHolder(new Socket(apAddr, apPort));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public final class ApiClient {

public ApiClient(@NotNull Session session) {
this.session = session;
this.baseUrl = "https://" + ApResolver.getRandomSpclient();
this.baseUrl = "https://" + session.apResolver().getRandomSpclient();
}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import xyz.gianlu.librespot.common.BytesArrayList;
import xyz.gianlu.librespot.common.NameThreadFactory;
import xyz.gianlu.librespot.common.Utils;
import xyz.gianlu.librespot.core.ApResolver;
import xyz.gianlu.librespot.core.Session;
import xyz.gianlu.librespot.mercury.MercuryClient;

Expand Down Expand Up @@ -76,7 +75,7 @@ private static Map<String, String> getHeaders(@NotNull JsonObject obj) {
*/
public synchronized void connect() throws IOException, MercuryClient.MercuryException {
conn = new ConnectionHolder(session, new Request.Builder()
.url(String.format("wss://%s/?access_token=%s", ApResolver.getRandomDealer(), session.tokens().get("playlist-read")))
.url(String.format("wss://%s/?access_token=%s", session.apResolver().getRandomDealer(), session.tokens().get("playlist-read")))
.build());
}

Expand Down

0 comments on commit 704ca19

Please sign in to comment.