Skip to content

Commit 91b247d

Browse files
committed
Allow reconnection from same user if device is not active (#210)
1 parent 6dd1cf9 commit 91b247d

7 files changed

Lines changed: 38 additions & 15 deletions

File tree

api/src/main/java/xyz/gianlu/librespot/api/SessionWrapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private void clear() {
6565
public Session get() {
6666
Session s = ref.get();
6767
if (s != null) {
68-
if (s.valid()) return s;
68+
if (s.isValid()) return s;
6969
else clear();
7070
}
7171

api/src/main/java/xyz/gianlu/librespot/api/handlers/AbsSessionHandler.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import io.undertow.server.HttpHandler;
44
import io.undertow.server.HttpServerExchange;
55
import io.undertow.util.Headers;
6-
import io.undertow.util.HttpString;
76
import io.undertow.util.StatusCodes;
87
import org.jetbrains.annotations.NotNull;
98
import xyz.gianlu.librespot.api.SessionWrapper;
@@ -33,7 +32,7 @@ public final void handleRequest(HttpServerExchange exchange) throws Exception {
3332
return;
3433
}
3534

36-
if (!s.valid()) {
35+
if (!s.isValid()) {
3736
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
3837
return;
3938
}

core/src/main/java/xyz/gianlu/librespot/connectstate/DeviceStateHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ private synchronized long startedPlayingAt() {
180180
return putState.getStartedPlayingAt();
181181
}
182182

183-
private synchronized boolean isActive() {
183+
public synchronized boolean isActive() {
184184
return putState.getIsActive();
185185
}
186186

core/src/main/java/xyz/gianlu/librespot/core/Session.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,11 @@ public Authentication.APWelcome apWelcome() {
603603
return apWelcome;
604604
}
605605

606-
public boolean valid() {
606+
public boolean isActive() {
607+
return player().isActive();
608+
}
609+
610+
public boolean isValid() {
607611
if (closed) return false;
608612

609613
waitAuthLock();

core/src/main/java/xyz/gianlu/librespot/core/ZeroconfServer.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.concurrent.ExecutorService;
3232
import java.util.concurrent.Executors;
3333
import java.util.concurrent.ThreadLocalRandom;
34+
import java.util.concurrent.TimeUnit;
3435

3536
/**
3637
* @author Gianlu
@@ -94,6 +95,7 @@ public class ZeroconfServer implements Closeable {
9495
private final List<SessionListener> sessionListeners;
9596
private final Zeroconf zeroconf;
9697
private volatile Session session;
98+
private volatile long connectionTime;
9799

98100
private ZeroconfServer(Session.Inner inner, Configuration conf) throws IOException {
99101
this.inner = inner;
@@ -214,17 +216,24 @@ public void close() throws IOException {
214216

215217
public void closeSession() throws IOException {
216218
if (session != null) session.close();
219+
220+
session = null;
221+
connectionTime = 0;
217222
}
218223

219-
public boolean hasValidSession() {
220-
boolean valid = session != null && session.valid();
221-
if (!valid) session = null;
224+
private boolean hasActiveSession() {
225+
boolean valid = session != null && session.isValid() && session.isActive();
226+
if (!valid) {
227+
session = null;
228+
connectionTime = 0;
229+
}
230+
222231
return valid;
223232
}
224233

225234
private void handleGetInfo(OutputStream out, String httpVersion) throws IOException {
226235
JsonObject info = DEFAULT_GET_INFO_FIELDS.deepCopy();
227-
info.addProperty("activeUser", hasValidSession() ? session.username() : "");
236+
info.addProperty("activeUser", hasActiveSession() ? session.username() : "");
228237
info.addProperty("deviceID", inner.deviceId);
229238
info.addProperty("remoteName", inner.deviceName);
230239
info.addProperty("publicKey", Base64.getEncoder().encodeToString(keys.publicKeyArray()));
@@ -263,14 +272,13 @@ private void handleAddUser(OutputStream out, Map<String, String> params, String
263272
return;
264273
}
265274

266-
if (hasValidSession()) {
275+
if (hasActiveSession() && System.currentTimeMillis() - connectionTime > TimeUnit.SECONDS.toMillis(60)) {
267276
if (session.username().equals(username)) {
268277
LOGGER.debug(String.format("Dropped connection attempt because user is already connected. {username: %s}", session.username()));
269-
return;
278+
} else {
279+
session.close();
280+
LOGGER.trace(String.format("Closed previous session to accept new. {deviceId: %s}", session.deviceId()));
270281
}
271-
272-
session.close();
273-
LOGGER.trace(String.format("Closed previous session to accept new. {deviceId: %s}", session.deviceId()));
274282
}
275283

276284
byte[] sharedKey = Utils.toByteArray(keys.computeSharedKey(Base64.getDecoder().decode(clientKeyStr)));
@@ -326,6 +334,7 @@ private void handleAddUser(OutputStream out, Map<String, String> params, String
326334
Authentication.LoginCredentials credentials = inner.decryptBlob(username, decrypted);
327335

328336
session = Session.from(inner);
337+
connectionTime = System.currentTimeMillis();
329338
LOGGER.info(String.format("Accepted new user from %s. {deviceId: %s}", params.get("deviceName"), session.deviceId()));
330339

331340
session.connect();
@@ -429,7 +438,7 @@ private void handle(@NotNull Socket socket) throws IOException {
429438
headers.put(split[0], split[1].trim());
430439
}
431440

432-
if (!hasValidSession())
441+
if (!hasActiveSession())
433442
LOGGER.trace(String.format("Handling request: %s %s %s, headers: %s", method, path, httpVersion, headers));
434443

435444
Map<String, String> params;

core/src/main/java/xyz/gianlu/librespot/player/Player.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,13 @@ public long time() {
722722
}
723723
}
724724

725+
/**
726+
* @return Whether the player is active
727+
*/
728+
public boolean isActive() {
729+
return state.isActive();
730+
}
731+
725732
public interface Configuration {
726733
@NotNull
727734
AudioQuality preferredQuality();

core/src/main/java/xyz/gianlu/librespot/player/StateWrapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ private boolean shouldPlay(@NotNull ContextTrack track) {
100100
return !Boolean.parseBoolean(track.getMetadataOrDefault("is_explicit", "false"));
101101
}
102102

103+
boolean isActive() {
104+
return device.isActive();
105+
}
106+
103107
void setBuffering(boolean buffering) {
104108
setState(state.getIsPlaying(), state.getIsPaused(), buffering);
105109
}

0 commit comments

Comments
 (0)