267 lines
6.5 KiB
TypeScript
267 lines
6.5 KiB
TypeScript
import { eq, and, or } from "drizzle-orm";
|
|
import db from "../../db";
|
|
import { serverSessions } from "../../db/schema/serverSessions";
|
|
import { servers } from "../../db/schema/servers";
|
|
import { apps } from "../../db/schema/apps";
|
|
|
|
export type SessionMode = "stream" | "local";
|
|
export type SessionStatus = "starting" | "started" | "ending" | "ended";
|
|
|
|
export interface CreateSessionParams {
|
|
appId: string;
|
|
userId: string;
|
|
mode: SessionMode;
|
|
serverId?: string;
|
|
}
|
|
|
|
export interface UpdateSessionParams {
|
|
status?: SessionStatus;
|
|
appPid?: number;
|
|
cirrusPid?: number;
|
|
endAt?: Date;
|
|
}
|
|
|
|
/**
|
|
* Сервис для работы с игровыми/streaming сессиями
|
|
*/
|
|
export const serverSessionService = {
|
|
/**
|
|
* Найти сессию по ID
|
|
*/
|
|
async findById(sessionId: string) {
|
|
const session = await db.query.serverSessions.findFirst({
|
|
where: eq(serverSessions.id, sessionId),
|
|
with: {
|
|
app: true,
|
|
user: {
|
|
columns: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
},
|
|
},
|
|
server: true,
|
|
},
|
|
});
|
|
|
|
return session || null;
|
|
},
|
|
|
|
/**
|
|
* Найти сессию по ID для конкретного пользователя
|
|
*/
|
|
async findByIdForUser(sessionId: string, userId: string) {
|
|
const session = await db.query.serverSessions.findFirst({
|
|
where: and(
|
|
eq(serverSessions.id, sessionId),
|
|
eq(serverSessions.userId, userId)
|
|
),
|
|
with: {
|
|
app: true,
|
|
user: {
|
|
columns: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
},
|
|
},
|
|
server: true,
|
|
},
|
|
});
|
|
|
|
return session || null;
|
|
},
|
|
|
|
/**
|
|
* Получить все сессии пользователя
|
|
*/
|
|
async findByUserId(
|
|
userId: string,
|
|
filters?: {
|
|
status?: SessionStatus;
|
|
mode?: SessionMode;
|
|
}
|
|
) {
|
|
const conditions = [eq(serverSessions.userId, userId)];
|
|
|
|
if (filters?.status) {
|
|
conditions.push(eq(serverSessions.status, filters.status));
|
|
}
|
|
|
|
if (filters?.mode) {
|
|
conditions.push(eq(serverSessions.mode, filters.mode));
|
|
}
|
|
|
|
const sessions = await db
|
|
.select({
|
|
id: serverSessions.id,
|
|
serverId: serverSessions.serverId,
|
|
appId: serverSessions.appId,
|
|
userId: serverSessions.userId,
|
|
startAt: serverSessions.startAt,
|
|
endAt: serverSessions.endAt,
|
|
appPid: serverSessions.appPid,
|
|
cirrusPid: serverSessions.cirrusPid,
|
|
mode: serverSessions.mode,
|
|
status: serverSessions.status,
|
|
createdAt: serverSessions.createdAt,
|
|
updatedAt: serverSessions.updatedAt,
|
|
app: {
|
|
id: apps.id,
|
|
name: apps.name,
|
|
title: apps.title,
|
|
},
|
|
})
|
|
.from(serverSessions)
|
|
.leftJoin(apps, eq(serverSessions.appId, apps.id))
|
|
.where(and(...conditions))
|
|
.orderBy(serverSessions.createdAt);
|
|
|
|
return sessions;
|
|
},
|
|
|
|
/**
|
|
* Проверить, есть ли у пользователя активная сессия для данного приложения
|
|
*/
|
|
async hasActiveSession(userId: string, appId: string) {
|
|
const session = await db.query.serverSessions.findFirst({
|
|
where: and(
|
|
eq(serverSessions.userId, userId),
|
|
eq(serverSessions.appId, appId),
|
|
or(
|
|
eq(serverSessions.status, "starting"),
|
|
eq(serverSessions.status, "started")
|
|
)
|
|
),
|
|
});
|
|
|
|
return !!session;
|
|
},
|
|
|
|
/**
|
|
* Выбрать доступный сервер
|
|
*/
|
|
async selectAvailableServer(mode: SessionMode): Promise<string | undefined> {
|
|
if (mode === "stream") {
|
|
const server = await db.query.servers.findFirst({
|
|
where: and(eq(servers.type, "stream"), eq(servers.tier, "prod")),
|
|
});
|
|
return server?.id;
|
|
} else {
|
|
const server = await db.query.servers.findFirst({
|
|
where: eq(servers.type, "local"),
|
|
});
|
|
return server?.id;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Создать новую сессию
|
|
*/
|
|
async create(params: CreateSessionParams) {
|
|
const { appId, userId, mode, serverId } = params;
|
|
|
|
// Выбрать сервер (если не указан)
|
|
let selectedServerId = serverId;
|
|
if (!selectedServerId) {
|
|
selectedServerId = await this.selectAvailableServer(mode);
|
|
if (!selectedServerId) {
|
|
throw new Error(`No available ${mode} servers`);
|
|
}
|
|
}
|
|
|
|
// Вычислить время окончания (по умолчанию +30 минут)
|
|
const endAt = new Date();
|
|
endAt.setMinutes(endAt.getMinutes() + 30);
|
|
|
|
// Создать сессию
|
|
const [newSession] = await db
|
|
.insert(serverSessions)
|
|
.values({
|
|
serverId: selectedServerId,
|
|
appId,
|
|
userId,
|
|
mode,
|
|
status: "starting",
|
|
endAt,
|
|
})
|
|
.returning();
|
|
|
|
return newSession;
|
|
},
|
|
|
|
/**
|
|
* Обновить сессию
|
|
*/
|
|
async update(sessionId: string, params: UpdateSessionParams) {
|
|
const updateData: any = {
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
if (params.status) {
|
|
updateData.status = params.status;
|
|
}
|
|
|
|
if (params.appPid !== undefined) {
|
|
updateData.appPid = params.appPid;
|
|
}
|
|
|
|
if (params.cirrusPid !== undefined) {
|
|
updateData.cirrusPid = params.cirrusPid;
|
|
}
|
|
|
|
if (params.endAt) {
|
|
updateData.endAt = params.endAt;
|
|
}
|
|
|
|
const [updatedSession] = await db
|
|
.update(serverSessions)
|
|
.set(updateData)
|
|
.where(eq(serverSessions.id, sessionId))
|
|
.returning();
|
|
|
|
return updatedSession;
|
|
},
|
|
|
|
/**
|
|
* Завершить сессию (изменить статус на "ending")
|
|
*/
|
|
async end(sessionId: string) {
|
|
const [updatedSession] = await db
|
|
.update(serverSessions)
|
|
.set({
|
|
status: "ending",
|
|
updatedAt: new Date(),
|
|
})
|
|
.where(eq(serverSessions.id, sessionId))
|
|
.returning();
|
|
|
|
return updatedSession;
|
|
},
|
|
|
|
/**
|
|
* Продлить сессию
|
|
*/
|
|
async extend(sessionId: string, minutes: number) {
|
|
const session = await this.findById(sessionId);
|
|
|
|
if (!session) {
|
|
throw new Error("Session not found");
|
|
}
|
|
|
|
const newEndAt = session.endAt ? new Date(session.endAt) : new Date();
|
|
newEndAt.setMinutes(newEndAt.getMinutes() + minutes);
|
|
|
|
const [updatedSession] = await db
|
|
.update(serverSessions)
|
|
.set({
|
|
endAt: newEndAt,
|
|
updatedAt: new Date(),
|
|
})
|
|
.where(eq(serverSessions.id, sessionId))
|
|
.returning();
|
|
|
|
return updatedSession;
|
|
},
|
|
};
|