implement sessions; retry to create spotify client
This commit is contained in:
parent
11778e2629
commit
46dc3dc83f
@ -1,6 +1,6 @@
|
||||
import { store } from "../store.mjs";
|
||||
import { randomString } from "../lib/randomString.mjs";
|
||||
import { UserStore } from "../db/schemas.mjs";
|
||||
import { SessionStore, UserStore } from "../db/schemas.mjs";
|
||||
import { createLocalUser, findUserBySpotifyId } from "../lib/helpers.mjs";
|
||||
|
||||
export const applyAuthRoutes = (router) => {
|
||||
@ -29,7 +29,6 @@ export const applyAuthRoutes = (router) => {
|
||||
{ 'spotify.userId': newUser.client.user.id },
|
||||
{
|
||||
accessToken,
|
||||
role: 'none',
|
||||
spotify: {
|
||||
refreshToken: newUser.client.refreshMeta.refreshToken,
|
||||
userId: newUser.client.user.id,
|
||||
@ -39,6 +38,13 @@ export const applyAuthRoutes = (router) => {
|
||||
{ upsert: true },
|
||||
);
|
||||
|
||||
if (!await SessionStore.findOne().bySpotifyId(newUser.client.user.id))
|
||||
await new SessionStore({
|
||||
host: userStore,
|
||||
clients: [],
|
||||
queue: [],
|
||||
}).save();
|
||||
|
||||
res.status(200);
|
||||
res.send({ message: 'authorized', accessToken });
|
||||
} catch (e) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { applyUserRoutes, applyUserRoutesPublic } from "./user.mjs";
|
||||
import { applySessionRoutes } from "./session.mjs";
|
||||
|
||||
export const applyApiRoutes = (router) => {
|
||||
|
||||
@ -8,6 +9,7 @@ export const applyApiRoutes = (router) => {
|
||||
});
|
||||
|
||||
applyUserRoutes(router);
|
||||
applySessionRoutes(router);
|
||||
|
||||
};
|
||||
|
||||
|
95
backend/api/session.mjs
Normal file
95
backend/api/session.mjs
Normal file
@ -0,0 +1,95 @@
|
||||
import { SessionStore } from "../db/schemas.mjs";
|
||||
|
||||
export const applySessionRoutes = (router) => {
|
||||
|
||||
router.post('/session', async (req, res) => {
|
||||
const user = res.locals.user;
|
||||
if (await SessionStore.findOne().bySpotifyId(user.id)) {
|
||||
res.status(400);
|
||||
res.send({ message: 'you are already in a session' });
|
||||
return;
|
||||
}
|
||||
const sessionStore = new SessionStore({
|
||||
host: user,
|
||||
clients: [],
|
||||
});
|
||||
await sessionStore.save();
|
||||
|
||||
res.status(201);
|
||||
res.send({ message: 'created' });
|
||||
});
|
||||
|
||||
router.get('/session', async (req, res) => {
|
||||
const user = res.locals.user;
|
||||
const sessionStore = await SessionStore.findOne().byHostSpotifyId(user.id);
|
||||
|
||||
if (!sessionStore) {
|
||||
res.status(404);
|
||||
res.send('you are not hosting a session');
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200);
|
||||
res.send({ session: sessionStore });
|
||||
});
|
||||
|
||||
router.delete('/session', async (req, res) => {
|
||||
const user = res.locals.user;
|
||||
const sessionStore = await SessionStore.findOne().byHostSpotifyId(user.id);
|
||||
|
||||
if (!sessionStore) {
|
||||
res.status(404);
|
||||
res.send('you are not hosting a session');
|
||||
return;
|
||||
}
|
||||
|
||||
await sessionStore.delete();
|
||||
|
||||
res.status(204);
|
||||
res.send({ message: 'session deleted' });
|
||||
});
|
||||
|
||||
router.post('/session/join', async (req, res) => {
|
||||
if (!req.body?.hostId) {
|
||||
res.status(400);
|
||||
res.send({ message: 'hostId is undefined' });
|
||||
return;
|
||||
}
|
||||
const { hostId } = req.body.hostId;
|
||||
const user = await res.locals.user;
|
||||
if (await SessionStore.findOne().bySpotifyId(user.id)) {
|
||||
res.status(400);
|
||||
res.send({ message: 'you are already in a session' });
|
||||
return;
|
||||
}
|
||||
const sessionStore = SessionStore.findOne().byHostSpotifyId(hostId);
|
||||
if (!sessionStore) {
|
||||
res.status(400);
|
||||
res.send({ message: 'session does not exist' });
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStore.clients.push(user);
|
||||
await sessionStore.save();
|
||||
|
||||
res.status(200);
|
||||
res.send({ message: 'you joined' });
|
||||
});
|
||||
|
||||
router.post('/session/leave', async (req, res) => {
|
||||
const user = await res.locals.user;
|
||||
const sessionStore = SessionStore.findOne().byClientSpotifyId(user.id);
|
||||
if (!sessionStore) {
|
||||
res.status(400);
|
||||
res.send({ message: 'you are not a client of any session' });
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStore.clients = sessionStore.clients.filter(client => client.id !== user.id);
|
||||
await sessionStore.save();
|
||||
|
||||
res.status(200);
|
||||
res.send({ message: 'you left' });
|
||||
});
|
||||
|
||||
};
|
@ -1,79 +1,21 @@
|
||||
import { store } from "../store.mjs";
|
||||
import { UserStore } from "../db/schemas.mjs";
|
||||
import { SessionStore, UserStore } from "../db/schemas.mjs";
|
||||
|
||||
export const applyUserRoutes = (router) => {
|
||||
|
||||
applyUserRoutesPublic(router);
|
||||
|
||||
router.post('/user/joinSession', async (req, res) => {
|
||||
if (!req.body?.userId) {
|
||||
res.status(400);
|
||||
res.send({ message: 'userId is undefined' });
|
||||
return;
|
||||
}
|
||||
const { userId } = req.body.userId;
|
||||
if (res.locals.user.role === 'host') {
|
||||
res.status(400);
|
||||
res.send({ message: 'user is host' });
|
||||
return;
|
||||
}
|
||||
const host = store.users.find(({ client }) => client.user.id === userId)
|
||||
host.listeners.push(res.locals.user);
|
||||
res.locals.user.role = 'listener';
|
||||
res.locals.user.listeningTo = host;
|
||||
res.status(200);
|
||||
res.send({ message: 'joined' });
|
||||
});
|
||||
|
||||
router.delete('/user/leaveSession', async (req, res) => {
|
||||
if (res.locals.user.role === 'host') {
|
||||
res.status(400);
|
||||
res.send({ message: 'user is host' });
|
||||
return;
|
||||
}
|
||||
const host = store.users.find(({ client }) => client.user.id === userId)
|
||||
host.listeners.push(res.locals.user);
|
||||
res.locals.user.role = 'none';
|
||||
res.locals.user.listeningTo.listeners = res.locals.user.listeningTo.listeners.filter(
|
||||
({ client }) => client.user.id !== res.locals.user.client.user.id
|
||||
);
|
||||
res.locals.user.listeningTo = null;
|
||||
res.status(200);
|
||||
res.send({ message: 'left' });
|
||||
});
|
||||
|
||||
router.get('/user/currentlyPlaying', async (req, res) => {
|
||||
router.get('/me/currentlyPlaying', async (req, res) => {
|
||||
const currentlyPlaying = await (await res.locals.user.spotify.local)?.player?.getCurrentlyPlaying('track');
|
||||
res.status(200);
|
||||
res.send({ currentlyPlaying });
|
||||
});
|
||||
|
||||
router.get('/user/role', (req, res) => {
|
||||
router.get('/me/role', (req, res) => {
|
||||
res.status(200);
|
||||
res.send({ role: res.locals.user?.role });
|
||||
});
|
||||
|
||||
/*router.post('/user/role', async (req, res) => {
|
||||
if (
|
||||
req.body.role !== 'host' ||
|
||||
req.body.role !== 'listener' ||
|
||||
req.body.role !== 'none'
|
||||
) {
|
||||
res.status(400);
|
||||
res.send({ message: 'role value is invalid' });
|
||||
}
|
||||
const { role } = req.body;
|
||||
try {
|
||||
res.locals.user.listeners = [];
|
||||
res.locals.user.role = role;
|
||||
res.status(200);
|
||||
res.send({ role });
|
||||
} catch (e) {
|
||||
res.status(500);
|
||||
res.send({ message: 'server error' });
|
||||
}
|
||||
});*/
|
||||
|
||||
};
|
||||
|
||||
export const applyUserRoutesPublic = (router) => {
|
||||
|
@ -30,4 +30,26 @@ const userSchema = new Schema({
|
||||
},
|
||||
});
|
||||
|
||||
const sessionSchema = new Schema({
|
||||
host: userSchema,
|
||||
clients: Array,
|
||||
queue: Array,
|
||||
}, {
|
||||
query: {
|
||||
byHostSpotifyId(id) {
|
||||
return this.where({ 'host.spotify.userId': id });
|
||||
},
|
||||
byClientSpotifyId(id) {
|
||||
return this.where({ 'clients.userId': id });
|
||||
},
|
||||
bySpotifyId(id) {
|
||||
return this.where({ '$or': [
|
||||
{ 'host.spotify.userId': id },
|
||||
{ 'clients.spotify.userId': id },
|
||||
]});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const UserStore = model('User', userSchema);
|
||||
export const SessionStore = model('Session', sessionSchema);
|
||||
|
@ -2,26 +2,33 @@ import { Client, Player } from "spotify-api.js";
|
||||
import { store } from "../store.mjs";
|
||||
import { UserStore } from "../db/schemas.mjs";
|
||||
|
||||
export const createLocalUser = async ({ refreshToken = undefined, code = undefined }) => {
|
||||
const client = await Client.create({
|
||||
refreshToken: true,
|
||||
retryOnRateLimit: true,
|
||||
token: {
|
||||
clientID: store.clientID,
|
||||
clientSecret: store.clientSecret,
|
||||
redirectURL: store.redirectURL,
|
||||
refreshToken,
|
||||
code,
|
||||
},
|
||||
async onRefresh() {
|
||||
await UserStore.findOneAndUpdate(
|
||||
{ 'spotify.userId': client.user.id },
|
||||
{ 'spotify.refreshToken': client.refreshMeta.refreshToken },
|
||||
);
|
||||
},
|
||||
});
|
||||
const player = new Player(client);
|
||||
return { client, player };
|
||||
export const createLocalUser = async ({ refreshToken = undefined, code = undefined }, retry = 4) => {
|
||||
try {
|
||||
const client = await Client.create({
|
||||
refreshToken: true,
|
||||
retryOnRateLimit: true,
|
||||
token: {
|
||||
clientID: store.clientID,
|
||||
clientSecret: store.clientSecret,
|
||||
redirectURL: store.redirectURL,
|
||||
refreshToken,
|
||||
code,
|
||||
},
|
||||
async onRefresh() {
|
||||
await UserStore.findOneAndUpdate(
|
||||
{ 'spotify.userId': client.user.id },
|
||||
{ 'spotify.refreshToken': client.refreshMeta.refreshToken },
|
||||
);
|
||||
},
|
||||
});
|
||||
const player = new Player(client);
|
||||
return { client, player };
|
||||
} catch (e) {
|
||||
if (retry-- < 1) throw e;
|
||||
if (e.response.data.status === 503) await new Promise(_ => setTimeout(_, 500));
|
||||
else throw e;
|
||||
return await createLocalUser({ refreshToken, code }, retry);
|
||||
}
|
||||
};
|
||||
|
||||
export const findUserBySpotifyId = async (
|
||||
|
2
frontend
2
frontend
@ -1 +1 @@
|
||||
Subproject commit f3b95916688df6b4a9834bb5d4adfb9ceec6093d
|
||||
Subproject commit cf9626402434ff2e2449457c40182bab92a8ad55
|
Loading…
Reference in New Issue
Block a user