209 lines
6.1 KiB
TypeScript
209 lines
6.1 KiB
TypeScript
import { Elysia, t } from "elysia";
|
|
import { authMiddleware } from "../middlewares/auth";
|
|
import { eq } from "drizzle-orm";
|
|
import db from "../db";
|
|
import { apps } from "../db/schema/apps";
|
|
import { serverSessionService } from "../services/serverSession";
|
|
|
|
export const sessionController = new Elysia({ prefix: "/sessions" })
|
|
// Все роуты требуют авторизации
|
|
.use(authMiddleware)
|
|
// GET /sessions - получить список сессий пользователя
|
|
.get("/", async ({ currentUser, query }) => {
|
|
const { status, mode } = query as {
|
|
status?: "starting" | "started" | "ending" | "ended";
|
|
mode?: "stream" | "local";
|
|
};
|
|
|
|
const sessions = await serverSessionService.findByUserId(currentUser.id, {
|
|
status,
|
|
mode,
|
|
});
|
|
|
|
return { sessions };
|
|
})
|
|
// GET /sessions/:id - получить информацию о конкретной сессии
|
|
.get("/:id", async ({ params, currentUser, status }) => {
|
|
const { id } = params;
|
|
|
|
const session = await serverSessionService.findByIdForUser(
|
|
id,
|
|
currentUser.id
|
|
);
|
|
|
|
if (!session) {
|
|
return status(404, "Session not found");
|
|
}
|
|
|
|
return { session };
|
|
})
|
|
// POST /sessions - создать новую сессию
|
|
.post(
|
|
"/",
|
|
async ({ body, currentUser, status }) => {
|
|
const { appId, mode, serverId } = body as {
|
|
appId: string;
|
|
mode: "stream" | "local";
|
|
serverId?: string;
|
|
};
|
|
|
|
// Проверить, что приложение существует
|
|
const app = await db.query.apps.findFirst({
|
|
where: eq(apps.id, appId),
|
|
});
|
|
|
|
if (!app) {
|
|
return status(404, "App not found");
|
|
}
|
|
|
|
// Проверить, что пользователь не имеет активных сессий этого приложения
|
|
const hasActive = await serverSessionService.hasActiveSession(
|
|
currentUser.id,
|
|
appId
|
|
);
|
|
|
|
if (hasActive) {
|
|
return status(409, "User already has an active session for this app");
|
|
}
|
|
|
|
// Создать сессию
|
|
try {
|
|
const newSession = await serverSessionService.create({
|
|
appId,
|
|
userId: currentUser.id,
|
|
mode,
|
|
serverId,
|
|
});
|
|
|
|
return { session: newSession };
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
return status(503, error.message);
|
|
}
|
|
return status(500, "Failed to create session");
|
|
}
|
|
},
|
|
{
|
|
body: t.Object({
|
|
appId: t.String({ format: "uuid" }),
|
|
mode: t.Union([t.Literal("stream"), t.Literal("local")]),
|
|
serverId: t.Optional(t.String({ format: "uuid" })),
|
|
}),
|
|
}
|
|
)
|
|
// PATCH /sessions/:id - обновить статус сессии
|
|
.patch(
|
|
"/:id",
|
|
async ({ params, body, currentUser, status }) => {
|
|
const { id } = params;
|
|
const {
|
|
status: sessionStatus,
|
|
appPid,
|
|
cirrusPid,
|
|
endAt,
|
|
} = body as {
|
|
status?: "starting" | "started" | "ending" | "ended";
|
|
appPid?: number;
|
|
cirrusPid?: number;
|
|
endAt?: string;
|
|
};
|
|
|
|
// Проверить, что сессия существует и принадлежит пользователю
|
|
const session = await serverSessionService.findByIdForUser(
|
|
id,
|
|
currentUser.id
|
|
);
|
|
|
|
if (!session) {
|
|
return status(404, "Session not found");
|
|
}
|
|
|
|
// Обновить сессию
|
|
const updatedSession = await serverSessionService.update(id, {
|
|
status: sessionStatus,
|
|
appPid,
|
|
cirrusPid,
|
|
endAt: endAt ? new Date(endAt) : undefined,
|
|
});
|
|
|
|
return { session: updatedSession };
|
|
},
|
|
{
|
|
body: t.Object({
|
|
status: t.Optional(
|
|
t.Union([
|
|
t.Literal("starting"),
|
|
t.Literal("started"),
|
|
t.Literal("ending"),
|
|
t.Literal("ended"),
|
|
])
|
|
),
|
|
appPid: t.Optional(t.Number()),
|
|
cirrusPid: t.Optional(t.Number()),
|
|
endAt: t.Optional(t.String({ format: "date-time" })),
|
|
}),
|
|
}
|
|
)
|
|
// DELETE /sessions/:id - удалить (завершить) сессию
|
|
.delete("/:id", async ({ params, currentUser, status }) => {
|
|
const { id } = params;
|
|
|
|
// Проверить, что сессия существует и принадлежит пользователю
|
|
const session = await serverSessionService.findByIdForUser(
|
|
id,
|
|
currentUser.id
|
|
);
|
|
|
|
if (!session) {
|
|
return status(404, "Session not found");
|
|
}
|
|
|
|
// Если сессия активна, изменить статус на "ending"
|
|
if (session.status === "started" || session.status === "starting") {
|
|
await serverSessionService.end(id);
|
|
return { message: "Session is ending" };
|
|
}
|
|
|
|
// Если сессия уже завершена или завершается
|
|
return { message: "Session already ended or ending" };
|
|
})
|
|
// POST /sessions/:id/extend - продлить сессию
|
|
.post(
|
|
"/:id/extend",
|
|
async ({ params, body, currentUser, status }) => {
|
|
const { id } = params;
|
|
const { minutes } = body as { minutes: number };
|
|
|
|
// Проверить, что сессия существует и принадлежит пользователю
|
|
const session = await serverSessionService.findByIdForUser(
|
|
id,
|
|
currentUser.id
|
|
);
|
|
|
|
if (!session) {
|
|
return status(404, "Session not found");
|
|
}
|
|
|
|
// Проверить, что сессия активна
|
|
if (session.status !== "started") {
|
|
return status(400, "Can only extend active sessions");
|
|
}
|
|
|
|
// Продлить сессию
|
|
try {
|
|
const updatedSession = await serverSessionService.extend(id, minutes);
|
|
return { session: updatedSession };
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
return status(400, error.message);
|
|
}
|
|
return status(500, "Failed to extend session");
|
|
}
|
|
},
|
|
{
|
|
body: t.Object({
|
|
minutes: t.Number({ minimum: 1, maximum: 120 }),
|
|
}),
|
|
}
|
|
);
|