mirror of
https://github.com/janishutz/MusicPlayer.git
synced 2026-09-10 14:25:24 +02:00
feat: basic connection between frontend and backend
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
duration,
|
||||
playbackPercentage
|
||||
} from '../player/status-tracking';
|
||||
import {
|
||||
isPlaying,
|
||||
queue,
|
||||
queueIdx
|
||||
} from '../player/state';
|
||||
import {
|
||||
ref,
|
||||
watch
|
||||
} from 'vue';
|
||||
import request from '../request';
|
||||
|
||||
const RETRY_CAP = 10;
|
||||
|
||||
export const room = ref( localStorage.getItem( 'room' ) ?? '' );
|
||||
|
||||
export const isConnected = ref( false );
|
||||
|
||||
export const useAntiTamper = ref( false );
|
||||
|
||||
// const antiTamperClients = [];
|
||||
|
||||
let connection: null | EventSource = null;
|
||||
let retries = 0;
|
||||
|
||||
// TODO: Persist room name in local storage
|
||||
|
||||
const createRoom = async ( name: string, antiTamper: boolean ): Promise<boolean> => {
|
||||
if ( !( /^[a-zA-Z0-9-]{3,20}$/ ).test( name ) ) return false;
|
||||
|
||||
try {
|
||||
await request.get( '/room/create?room=' + name );
|
||||
} catch ( err ) {
|
||||
if ( err === 'ERR_409' ) {
|
||||
return await connect();
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.setItem( 'room', name );
|
||||
useAntiTamper.value = antiTamper;
|
||||
room.value = name;
|
||||
|
||||
return await connect();
|
||||
};
|
||||
|
||||
const closeRoom = async () => {
|
||||
// TODO: Trigger close on backend and disconnect.
|
||||
isConnected.value = false;
|
||||
localStorage.removeItem( 'room' );
|
||||
};
|
||||
|
||||
const connect = (): Promise<boolean> => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
if ( !useAntiTamper.value ) {
|
||||
isConnected.value = true;
|
||||
|
||||
return resolve( true );
|
||||
}
|
||||
|
||||
connection = new EventSource( request.backendURL + `/room/${ room.value }/admin`, {
|
||||
'withCredentials': true
|
||||
} );
|
||||
|
||||
connection.onopen = () => {
|
||||
isConnected.value = true;
|
||||
console.log( '[SSE] Connection established successfully' );
|
||||
resolve( true );
|
||||
};
|
||||
|
||||
connection.onmessage = msg => {
|
||||
console.log( msg );
|
||||
};
|
||||
|
||||
connection.onerror = () => {
|
||||
connection?.close();
|
||||
console.error( '[SSE] Reconnecting due to error' );
|
||||
|
||||
if ( !isConnected.value ) reject( 'ERR_CONNECT' );
|
||||
|
||||
if ( retries <= RETRY_CAP ) {
|
||||
retries += 1;
|
||||
|
||||
setTimeout( () => {
|
||||
createRoom( room.value, useAntiTamper.value );
|
||||
}, 1000 * retries );
|
||||
}
|
||||
};
|
||||
} );
|
||||
};
|
||||
|
||||
const useRoomWatchers = () => {
|
||||
watch( queue, () => {
|
||||
if ( isConnected.value )
|
||||
request.post( `/room/${ room.value }/update/playlist`, JSON.stringify( {
|
||||
'playlist': queue.value
|
||||
} ) );
|
||||
} );
|
||||
|
||||
watch( [
|
||||
isPlaying,
|
||||
queueIdx
|
||||
], () => {
|
||||
if ( isConnected.value )
|
||||
request.post( `/room/${ room.value }/update/state`, JSON.stringify( {
|
||||
'playing': isPlaying.value,
|
||||
'index': queueIdx.value,
|
||||
'start': new Date().getTime() - ( playbackPercentage.value * duration.value ) - 100
|
||||
} ) );
|
||||
} );
|
||||
|
||||
if ( room.value ) connect();
|
||||
};
|
||||
|
||||
export default {
|
||||
createRoom,
|
||||
useRoomWatchers,
|
||||
closeRoom
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ import type {
|
||||
import {
|
||||
load
|
||||
} from './playlists/loader';
|
||||
import messages from '../messages';
|
||||
import {
|
||||
playIndex
|
||||
} from './playlists';
|
||||
@@ -148,6 +149,7 @@ const addSongFromSource = async ( source: string ): Promise<boolean> => {
|
||||
return true;
|
||||
};
|
||||
|
||||
messages.useRoomWatchers();
|
||||
|
||||
export default {
|
||||
play,
|
||||
|
||||
@@ -9,6 +9,8 @@ const get = async ( url: string ): Promise<Response> => {
|
||||
} );
|
||||
};
|
||||
|
||||
const backendURL = import.meta.env.VITE_BACKEND_URL;
|
||||
|
||||
const post = async ( url: string, payload: string, mime: string = 'application/json' ): Promise<Response> => {
|
||||
return await wrapper( url, {
|
||||
'credentials': 'include',
|
||||
@@ -21,11 +23,12 @@ const post = async ( url: string, payload: string, mime: string = 'application/j
|
||||
};
|
||||
|
||||
const wrapper = async ( url: string, opts: RequestInit ): Promise<Response> => {
|
||||
const res = await fetch( import.meta.env.VITE_BACKEND_URL + url, opts );
|
||||
const res = await fetch( backendURL + url, opts );
|
||||
|
||||
if ( res.ok ) {
|
||||
return res;
|
||||
} else if ( res.status === 403 || res.status === 401 ) {
|
||||
// TODO: Handle these errors better (probably do something like in the old version, but better)
|
||||
throw new AuthError( 'ERR_USER_UNAUTHORIZED' );
|
||||
} else if ( res.status === 402 ) {
|
||||
throw new UnownedError( 'ERR_USER_UNOWNED' );
|
||||
@@ -36,5 +39,6 @@ const wrapper = async ( url: string, opts: RequestInit ): Promise<Response> => {
|
||||
|
||||
export default {
|
||||
get,
|
||||
post
|
||||
post,
|
||||
backendURL
|
||||
};
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import request from '../request';
|
||||
|
||||
const RETRY_CAP = 10;
|
||||
|
||||
let room = location.pathname;
|
||||
let connection: EventSource | null = null;
|
||||
let hasConnected = false;
|
||||
let retries = 0;
|
||||
|
||||
// TODO: Persist settings in local storage
|
||||
|
||||
const connect = (): Promise<void> => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
room = location.pathname.substring( location.pathname.lastIndexOf( '/' ) + 1 );
|
||||
connection = new EventSource( request.backendURL + `/room/${ room }/connect` );
|
||||
|
||||
connection.onopen = () => {
|
||||
hasConnected = true;
|
||||
console.log( '[SSE] Connection established successfully' );
|
||||
resolve();
|
||||
};
|
||||
|
||||
connection.onmessage = msg => {
|
||||
console.log( msg.data );
|
||||
// TODO: On connect, retrieve data from poll endpoint
|
||||
};
|
||||
|
||||
connection.onerror = () => {
|
||||
connection?.close();
|
||||
|
||||
if ( !hasConnected ) return reject( 'ERR_CONNECT' );
|
||||
|
||||
console.error( '[SSE] Connection failed, reconnecting' );
|
||||
|
||||
if ( retries <= RETRY_CAP ) {
|
||||
retries += 1;
|
||||
setTimeout( () => {
|
||||
connect();
|
||||
}, 1000 * retries );
|
||||
}
|
||||
};
|
||||
} );
|
||||
};
|
||||
|
||||
export default {
|
||||
connect
|
||||
};
|
||||
Reference in New Issue
Block a user