mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
fix(orbit): tear down session on server switch + raise cleanup TTL
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+6
-6
@@ -732,13 +732,13 @@ export async function sweepGuestOutboxes(sid: string, hostUsername: string): Pro
|
|||||||
export const ORBIT_HEARTBEAT_ALIVE_MS = 30_000;
|
export const ORBIT_HEARTBEAT_ALIVE_MS = 30_000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grace window for the app-start orphan sweep. Has to be comfortably
|
* Grace window for the app-start orphan sweep. A session on the user's
|
||||||
* larger than the outbox heartbeat interval (10 s) and the session state
|
* other device or a browser that briefly restarted must NOT be deleted
|
||||||
* tick (2.5 s) so a session running on the user's other device doesn't
|
* by this sweep. 5 min matches the guest-side host-timeout threshold:
|
||||||
* get deleted on a transient slow tick. 2× ALIVE window is the minimum
|
* if a session is silent for that long, it's fair to treat it as dead;
|
||||||
* sane value.
|
* anything shorter is a real restart and must survive.
|
||||||
*/
|
*/
|
||||||
export const ORBIT_ORPHAN_TTL_MS = 60_000;
|
export const ORBIT_ORPHAN_TTL_MS = 5 * 60_000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy / fallback shuffle cadence. New sessions store their own interval
|
* Legacy / fallback shuffle cadence. New sessions store their own interval
|
||||||
|
|||||||
@@ -1,11 +1,31 @@
|
|||||||
import { pingWithCredentials, scheduleInstantMixProbeForServer } from '../api/subsonic';
|
import { pingWithCredentials, scheduleInstantMixProbeForServer } from '../api/subsonic';
|
||||||
import type { ServerProfile } from '../store/authStore';
|
import type { ServerProfile } from '../store/authStore';
|
||||||
import { useAuthStore } from '../store/authStore';
|
import { useAuthStore } from '../store/authStore';
|
||||||
|
import { useOrbitStore } from '../store/orbitStore';
|
||||||
|
import { endOrbitSession, leaveOrbitSession } from './orbit';
|
||||||
|
|
||||||
export async function switchActiveServer(server: ServerProfile): Promise<boolean> {
|
export async function switchActiveServer(server: ServerProfile): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const ping = await pingWithCredentials(server.url, server.username, server.password);
|
const ping = await pingWithCredentials(server.url, server.username, server.password);
|
||||||
if (!ping.ok) return false;
|
if (!ping.ok) return false;
|
||||||
|
|
||||||
|
// Tear down any active Orbit session before we actually switch. The
|
||||||
|
// session's playlists live on the *old* server — once we flip the
|
||||||
|
// active server, every API call from the orbit hooks would hit the
|
||||||
|
// wrong backend, heartbeats would silently fail, and the next
|
||||||
|
// app-start cleanup would prune the still-live session as stale.
|
||||||
|
// Capped at 1.5 s so a slow network doesn't freeze the UI.
|
||||||
|
const role = useOrbitStore.getState().role;
|
||||||
|
if (role === 'host' || role === 'guest') {
|
||||||
|
const teardown = role === 'host' ? endOrbitSession() : leaveOrbitSession();
|
||||||
|
await Promise.race([
|
||||||
|
teardown.catch(() => {}),
|
||||||
|
new Promise<void>(r => setTimeout(r, 1500)),
|
||||||
|
]);
|
||||||
|
// Ensure local store is idle even if the remote call timed out.
|
||||||
|
useOrbitStore.getState().reset();
|
||||||
|
}
|
||||||
|
|
||||||
const identity = {
|
const identity = {
|
||||||
type: ping.type,
|
type: ping.type,
|
||||||
serverVersion: ping.serverVersion,
|
serverVersion: ping.serverVersion,
|
||||||
|
|||||||
Reference in New Issue
Block a user