Refactor Protected and Public Routes for Consistent Loading UI; Enhance HomePage with User Company and Branch Details; Update LoginPage Layout; Introduce User Relations in Auth Services
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
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;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user