mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
3dc50a2ef0
* refactor(orbit): extract constants, helpers, and state math First extraction step of the utils/orbit.ts split. Pure, no-I/O code moves into utils/orbit/ submodules; utils/orbit.ts becomes a re-export shim so every call site outside this directory keeps importing from '../utils/orbit' unchanged. - utils/orbit/constants.ts: ORBIT_HEARTBEAT_ALIVE_MS, ORBIT_ORPHAN_TTL_MS, ORBIT_SHUFFLE_INTERVAL_MS, ORBIT_REMOVED_TTL_MS. - utils/orbit/helpers.ts: generateSessionId, serialiseOrbitState + OrbitStateTooLarge, serialiseOutboxMeta, suggestionKey, parseOutboxPlaylistName. - utils/orbit/stateMath.ts: patchOrbitState, maybeShuffleQueue, effectiveShuffleIntervalMs, computeOrbitDriftMs, applyOutboxSnapshotsToState, OutboxSnapshot type. utils/orbit.ts: 989 → 806 LOC. * refactor(orbit): extract remote I/O + share link Pull readOrbitState / writeOrbitState / writeOrbitHeartbeat / findSessionPlaylistId into utils/orbit/remote.ts. Pull parseOrbitShareLink / buildOrbitShareLink + OrbitShareLink into utils/orbit/shareLink.ts. Re-exported from the orbit.ts shim. utils/orbit.ts: 806 → 721 LOC. * refactor(orbit): extract host lifecycle Pull startOrbitSession, endOrbitSession, triggerOrbitShuffleNow, updateOrbitSettings, hostEnqueueToOrbit (and the StartOrbitArgs interface) into utils/orbit/host.ts. Re-exported from the orbit.ts shim. utils/orbit.ts: 721 → 546 LOC. * refactor(orbit): extract host moderation Pull kickOrbitParticipant, removeOrbitParticipant, and setOrbitSuggestionBlocked into utils/orbit/moderation.ts. Re-exported from the orbit.ts shim. utils/orbit.ts: 546 → 422 LOC. * refactor(orbit): extract guest lifecycle + suggest pipeline Pull joinOrbitSession / leaveOrbitSession (+ OrbitJoinError), the suggest gate (evaluateOrbitSuggestGate / OrbitSuggestGateReason / OrbitSuggestBlockedError / suggestOrbitTrack), and the host-side approve / decline reactions into utils/orbit/guest.ts. Re-exported from the orbit.ts shim. utils/orbit.ts: 422 → 244 LOC. * refactor(orbit): extract sweep + cleanup, collapse shim Pull sweepGuestOutboxes (+ private listGuestOutboxes / readOutbox) into utils/orbit/sweep.ts and cleanupOrphanedOrbitPlaylists into utils/orbit/cleanup.ts. utils/orbit.ts collapses to a pure re-export shim — every external import path stays the same, the file just lists which symbol lives in which submodule. utils/orbit.ts: 244 → 77 LOC. Full split: 989 LOC monolith → 10 single-concern modules, none over 210 LOC.
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
import {
|
|
ORBIT_PLAYLIST_PREFIX,
|
|
ORBIT_STATE_MAX_BYTES,
|
|
type OrbitOutboxMeta,
|
|
type OrbitQueueItem,
|
|
type OrbitState,
|
|
} from '../../api/orbit';
|
|
|
|
/** 8 lowercase hex chars — unique enough for concurrent-session collision-free naming. */
|
|
export function generateSessionId(): string {
|
|
const bytes = new Uint8Array(4);
|
|
crypto.getRandomValues(bytes);
|
|
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
/**
|
|
* Serialise the state blob for writing into a playlist comment. Emits a
|
|
* plain JSON string. Throws when the output exceeds `ORBIT_STATE_MAX_BYTES`
|
|
* — callers should trim optional fields (oldest queue entries / kicked
|
|
* usernames) and retry, rather than write something truncated.
|
|
*/
|
|
export function serialiseOrbitState(state: OrbitState): string {
|
|
const json = JSON.stringify(state);
|
|
// Encode-length check — emoji-heavy session names could inflate UTF-8 bytes
|
|
// beyond the string's .length count.
|
|
const byteLen = new TextEncoder().encode(json).length;
|
|
if (byteLen > ORBIT_STATE_MAX_BYTES) {
|
|
throw new OrbitStateTooLarge(byteLen);
|
|
}
|
|
return json;
|
|
}
|
|
|
|
export class OrbitStateTooLarge extends Error {
|
|
constructor(public readonly bytes: number) {
|
|
super(`Orbit state blob (${bytes} bytes) exceeds ${ORBIT_STATE_MAX_BYTES} byte budget`);
|
|
this.name = 'OrbitStateTooLarge';
|
|
}
|
|
}
|
|
|
|
export function serialiseOutboxMeta(meta: OrbitOutboxMeta): string {
|
|
return JSON.stringify(meta);
|
|
}
|
|
|
|
/**
|
|
* Stable per-suggestion key across reshuffles — `addedBy`, `addedAt` and
|
|
* `trackId` are all immutable once the host sweep has written them.
|
|
* Shared between the host tick and the manual-approval UI.
|
|
*/
|
|
export const suggestionKey = (q: OrbitQueueItem): string =>
|
|
`${q.addedBy}:${q.addedAt}:${q.trackId}`;
|
|
|
|
/** Extract `<username>` from a filename matching `__psyorbit_<sid>_from_<username>__`. */
|
|
export function parseOutboxPlaylistName(name: string, sid: string): string | null {
|
|
const prefix = `${ORBIT_PLAYLIST_PREFIX}${sid}_from_`;
|
|
if (!name.startsWith(prefix) || !name.endsWith('__')) return null;
|
|
const user = name.slice(prefix.length, name.length - 2);
|
|
return user.length > 0 ? user : null;
|
|
}
|