updated
This commit is contained in:
parent
caaed1f71e
commit
ba69e99120
@ -437,9 +437,21 @@ model MatchReady {
|
||||
model ServerConfig {
|
||||
id String @id
|
||||
serverIp String
|
||||
serverPassword String? // ⬅️ neu
|
||||
serverPassword String?
|
||||
pterodactylServerId String
|
||||
pterodactylServerApiKey String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// ───── Live / GameBanner ─────
|
||||
activeMatchId String?
|
||||
activeMapKey String?
|
||||
activeMapLabel String?
|
||||
activeMapBg String?
|
||||
activeParticipants String[] // steamIds
|
||||
activeSince DateTime?
|
||||
bannerExpiresAt DateTime?
|
||||
|
||||
@@index([activeMatchId])
|
||||
}
|
||||
|
||||
|
||||
@ -274,25 +274,29 @@ export default function MiniPlayerCard({
|
||||
alt={u.name || 'Avatar'}
|
||||
className="h-12 w-12 rounded-full ring-1 ring-white/15"
|
||||
/>
|
||||
|
||||
<div className="min-w-0">
|
||||
{/* Name */}
|
||||
<div className="truncate text-sm font-semibold">
|
||||
{u.name ?? 'Unbekannt'}
|
||||
</div>
|
||||
{/* darunter: Premier + Faceit + Ban */}
|
||||
<div className="mt-1 flex items-center gap-2">
|
||||
<PremierRankBadge rank={u.premierRank ?? 0} />
|
||||
{faceit.nickname && <FaceitLevelImage elo={faceit.elo ?? 0} className="-ml-0.5" />}
|
||||
{/* Name + BAN/VAC direkt daneben (wie MatchDetails) */}
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="truncate text-sm font-semibold">
|
||||
{u.name ?? 'Unbekannt'}
|
||||
</span>
|
||||
{isBanned && (
|
||||
<span
|
||||
title={banTooltip}
|
||||
className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-bold"
|
||||
style={{ background: hasVac ? 'rgba(220,38,38,.9)' : 'rgba(234,88,12,.9)' }}
|
||||
className="ml-1 shrink-0 inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-bold bg-red-600 text-white"
|
||||
aria-label={hasVac ? 'Dieser Spieler hat einen VAC-Ban' : 'Dieser Spieler ist gebannt'}
|
||||
>
|
||||
{hasVac ? 'VAC' : 'BAN'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* darunter: Premier + Faceit (unverändert) */}
|
||||
<div className="mt-2 flex items-center gap-2">
|
||||
<PremierRankBadge rank={u.premierRank ?? 0} />
|
||||
{faceit.nickname && <FaceitLevelImage elo={faceit.elo ?? 0} className="-ml-0.5" />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
53
src/app/api/cs2/server/live/route.ts
Normal file
53
src/app/api/cs2/server/live/route.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const runtime = 'nodejs'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const cfg = await prisma.serverConfig.findUnique({
|
||||
where: { id: 'default' },
|
||||
select: {
|
||||
activeMatchId: true,
|
||||
activeMapKey: true,
|
||||
activeMapLabel: true,
|
||||
activeMapBg: true,
|
||||
activeParticipants: true,
|
||||
activeSince: true,
|
||||
bannerExpiresAt: true,
|
||||
updatedAt: true,
|
||||
},
|
||||
})
|
||||
return NextResponse.json({ ok: true, data: cfg ?? null }, { headers: { 'Cache-Control': 'no-store' }})
|
||||
} catch (e) {
|
||||
console.error('[server/live][GET]', e)
|
||||
return NextResponse.json({ ok: false }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
// Optional: Banner leeren (z.B. wenn Match beendet)
|
||||
try {
|
||||
const body = await req.json().catch(() => ({}))
|
||||
if (body?.action === 'clear') {
|
||||
await prisma.serverConfig.update({
|
||||
where: { id: 'default' },
|
||||
data: {
|
||||
activeMatchId: null,
|
||||
activeMapKey: null,
|
||||
activeMapLabel: null,
|
||||
activeMapBg: null,
|
||||
activeParticipants: [],
|
||||
activeSince: null,
|
||||
bannerExpiresAt: null,
|
||||
},
|
||||
})
|
||||
return NextResponse.json({ ok: true })
|
||||
}
|
||||
return NextResponse.json({ ok: false, message: 'Unsupported action' }, { status: 400 })
|
||||
} catch (e) {
|
||||
console.error('[server/live][POST]', e)
|
||||
return NextResponse.json({ ok: false }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@ -529,6 +529,47 @@ async function exportMatchToSftpDirect(match: any, vote: any) {
|
||||
}
|
||||
}
|
||||
|
||||
async function writeLiveStateToServerConfig(match: any, vote: any, mapVisuals: Record<string, any>) {
|
||||
try {
|
||||
// gewählte Maps (PICK/DECIDER), erste Map extrahieren
|
||||
const chosen = deriveChosenSteps(vote)
|
||||
const first = chosen[0]
|
||||
const key = first?.map ?? null
|
||||
const label = key ? (mapVisuals?.[key]?.label ?? key) : null
|
||||
const bg = key ? (mapVisuals?.[key]?.bg ?? `/assets/img/maps/${key}/1.jpg`) : null
|
||||
|
||||
const participants = collectParticipants(match)
|
||||
|
||||
// Wir gehen davon aus, dass es "default" gibt.
|
||||
await prisma.serverConfig.update({
|
||||
where: { id: 'default' },
|
||||
data: {
|
||||
activeMatchId: match.id,
|
||||
activeMapKey : key,
|
||||
activeMapLabel: label,
|
||||
activeMapBg : bg,
|
||||
activeParticipants: participants,
|
||||
activeSince : new Date(),
|
||||
// z.B. auf 2h Sichtbarkeit begrenzen (optional)
|
||||
bannerExpiresAt: new Date(Date.now() + 2 * 60 * 60 * 1000),
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn('[mapvote] writeLiveStateToServerConfig failed:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/** DRY: Wird in jedem "locked"-Pfad aufgerufen */
|
||||
async function afterVoteLocked(match: any, vote: any, mapVisuals: Record<string, any>) {
|
||||
// 1) Spieler für dieses Match festschreiben
|
||||
await persistMatchPlayers(match)
|
||||
// 2) Live-State für Banner speichern
|
||||
await writeLiveStateToServerConfig(match, vote, mapVisuals)
|
||||
// 3) Serverexport + Matchzy-Load
|
||||
await exportMatchToSftpDirect(match, vote)
|
||||
}
|
||||
|
||||
|
||||
/* ---------- kleine Helfer für match-ready Payload ---------- */
|
||||
|
||||
function deriveChosenSteps(vote: any) {
|
||||
@ -654,6 +695,8 @@ export async function POST(req: NextRequest, { params }: { params: { matchId: st
|
||||
firstMap: { key, label, bg },
|
||||
participants,
|
||||
});
|
||||
|
||||
await afterVoteLocked(match, updated, mapVisuals)
|
||||
|
||||
// Export serverseitig
|
||||
await exportMatchToSftpDirect(match, updated)
|
||||
@ -718,6 +761,8 @@ export async function POST(req: NextRequest, { params }: { params: { matchId: st
|
||||
participants,
|
||||
});
|
||||
|
||||
await afterVoteLocked(match, updated, mapVisuals)
|
||||
|
||||
// Export serverseitig
|
||||
await exportMatchToSftpDirect(match, updated)
|
||||
}
|
||||
@ -819,6 +864,8 @@ export async function POST(req: NextRequest, { params }: { params: { matchId: st
|
||||
participants,
|
||||
});
|
||||
|
||||
await afterVoteLocked(match, updated, mapVisuals)
|
||||
|
||||
await exportMatchToSftpDirect(match, updated)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -351,7 +351,14 @@ exports.Prisma.ServerConfigScalarFieldEnum = {
|
||||
pterodactylServerId: 'pterodactylServerId',
|
||||
pterodactylServerApiKey: 'pterodactylServerApiKey',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
updatedAt: 'updatedAt',
|
||||
activeMatchId: 'activeMatchId',
|
||||
activeMapKey: 'activeMapKey',
|
||||
activeMapLabel: 'activeMapLabel',
|
||||
activeMapBg: 'activeMapBg',
|
||||
activeParticipants: 'activeParticipants',
|
||||
activeSince: 'activeSince',
|
||||
bannerExpiresAt: 'bannerExpiresAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
|
||||
210
src/generated/prisma/index.d.ts
vendored
210
src/generated/prisma/index.d.ts
vendored
@ -21476,6 +21476,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string | null
|
||||
createdAt: Date | null
|
||||
updatedAt: Date | null
|
||||
activeMatchId: string | null
|
||||
activeMapKey: string | null
|
||||
activeMapLabel: string | null
|
||||
activeMapBg: string | null
|
||||
activeSince: Date | null
|
||||
bannerExpiresAt: Date | null
|
||||
}
|
||||
|
||||
export type ServerConfigMaxAggregateOutputType = {
|
||||
@ -21486,6 +21492,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string | null
|
||||
createdAt: Date | null
|
||||
updatedAt: Date | null
|
||||
activeMatchId: string | null
|
||||
activeMapKey: string | null
|
||||
activeMapLabel: string | null
|
||||
activeMapBg: string | null
|
||||
activeSince: Date | null
|
||||
bannerExpiresAt: Date | null
|
||||
}
|
||||
|
||||
export type ServerConfigCountAggregateOutputType = {
|
||||
@ -21496,6 +21508,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: number
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
activeMatchId: number
|
||||
activeMapKey: number
|
||||
activeMapLabel: number
|
||||
activeMapBg: number
|
||||
activeParticipants: number
|
||||
activeSince: number
|
||||
bannerExpiresAt: number
|
||||
_all: number
|
||||
}
|
||||
|
||||
@ -21508,6 +21527,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: true
|
||||
createdAt?: true
|
||||
updatedAt?: true
|
||||
activeMatchId?: true
|
||||
activeMapKey?: true
|
||||
activeMapLabel?: true
|
||||
activeMapBg?: true
|
||||
activeSince?: true
|
||||
bannerExpiresAt?: true
|
||||
}
|
||||
|
||||
export type ServerConfigMaxAggregateInputType = {
|
||||
@ -21518,6 +21543,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: true
|
||||
createdAt?: true
|
||||
updatedAt?: true
|
||||
activeMatchId?: true
|
||||
activeMapKey?: true
|
||||
activeMapLabel?: true
|
||||
activeMapBg?: true
|
||||
activeSince?: true
|
||||
bannerExpiresAt?: true
|
||||
}
|
||||
|
||||
export type ServerConfigCountAggregateInputType = {
|
||||
@ -21528,6 +21559,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: true
|
||||
createdAt?: true
|
||||
updatedAt?: true
|
||||
activeMatchId?: true
|
||||
activeMapKey?: true
|
||||
activeMapLabel?: true
|
||||
activeMapBg?: true
|
||||
activeParticipants?: true
|
||||
activeSince?: true
|
||||
bannerExpiresAt?: true
|
||||
_all?: true
|
||||
}
|
||||
|
||||
@ -21611,6 +21649,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
activeMatchId: string | null
|
||||
activeMapKey: string | null
|
||||
activeMapLabel: string | null
|
||||
activeMapBg: string | null
|
||||
activeParticipants: string[]
|
||||
activeSince: Date | null
|
||||
bannerExpiresAt: Date | null
|
||||
_count: ServerConfigCountAggregateOutputType | null
|
||||
_min: ServerConfigMinAggregateOutputType | null
|
||||
_max: ServerConfigMaxAggregateOutputType | null
|
||||
@ -21638,6 +21683,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
activeMatchId?: boolean
|
||||
activeMapKey?: boolean
|
||||
activeMapLabel?: boolean
|
||||
activeMapBg?: boolean
|
||||
activeParticipants?: boolean
|
||||
activeSince?: boolean
|
||||
bannerExpiresAt?: boolean
|
||||
}, ExtArgs["result"]["serverConfig"]>
|
||||
|
||||
export type ServerConfigSelectCreateManyAndReturn<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetSelect<{
|
||||
@ -21648,6 +21700,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
activeMatchId?: boolean
|
||||
activeMapKey?: boolean
|
||||
activeMapLabel?: boolean
|
||||
activeMapBg?: boolean
|
||||
activeParticipants?: boolean
|
||||
activeSince?: boolean
|
||||
bannerExpiresAt?: boolean
|
||||
}, ExtArgs["result"]["serverConfig"]>
|
||||
|
||||
export type ServerConfigSelectUpdateManyAndReturn<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetSelect<{
|
||||
@ -21658,6 +21717,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
activeMatchId?: boolean
|
||||
activeMapKey?: boolean
|
||||
activeMapLabel?: boolean
|
||||
activeMapBg?: boolean
|
||||
activeParticipants?: boolean
|
||||
activeSince?: boolean
|
||||
bannerExpiresAt?: boolean
|
||||
}, ExtArgs["result"]["serverConfig"]>
|
||||
|
||||
export type ServerConfigSelectScalar = {
|
||||
@ -21668,9 +21734,16 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
activeMatchId?: boolean
|
||||
activeMapKey?: boolean
|
||||
activeMapLabel?: boolean
|
||||
activeMapBg?: boolean
|
||||
activeParticipants?: boolean
|
||||
activeSince?: boolean
|
||||
bannerExpiresAt?: boolean
|
||||
}
|
||||
|
||||
export type ServerConfigOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "serverIp" | "serverPassword" | "pterodactylServerId" | "pterodactylServerApiKey" | "createdAt" | "updatedAt", ExtArgs["result"]["serverConfig"]>
|
||||
export type ServerConfigOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "serverIp" | "serverPassword" | "pterodactylServerId" | "pterodactylServerApiKey" | "createdAt" | "updatedAt" | "activeMatchId" | "activeMapKey" | "activeMapLabel" | "activeMapBg" | "activeParticipants" | "activeSince" | "bannerExpiresAt", ExtArgs["result"]["serverConfig"]>
|
||||
|
||||
export type $ServerConfigPayload<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
|
||||
name: "ServerConfig"
|
||||
@ -21683,6 +21756,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
activeMatchId: string | null
|
||||
activeMapKey: string | null
|
||||
activeMapLabel: string | null
|
||||
activeMapBg: string | null
|
||||
activeParticipants: string[]
|
||||
activeSince: Date | null
|
||||
bannerExpiresAt: Date | null
|
||||
}, ExtArgs["result"]["serverConfig"]>
|
||||
composites: {}
|
||||
}
|
||||
@ -22113,6 +22193,13 @@ export namespace Prisma {
|
||||
readonly pterodactylServerApiKey: FieldRef<"ServerConfig", 'String'>
|
||||
readonly createdAt: FieldRef<"ServerConfig", 'DateTime'>
|
||||
readonly updatedAt: FieldRef<"ServerConfig", 'DateTime'>
|
||||
readonly activeMatchId: FieldRef<"ServerConfig", 'String'>
|
||||
readonly activeMapKey: FieldRef<"ServerConfig", 'String'>
|
||||
readonly activeMapLabel: FieldRef<"ServerConfig", 'String'>
|
||||
readonly activeMapBg: FieldRef<"ServerConfig", 'String'>
|
||||
readonly activeParticipants: FieldRef<"ServerConfig", 'String[]'>
|
||||
readonly activeSince: FieldRef<"ServerConfig", 'DateTime'>
|
||||
readonly bannerExpiresAt: FieldRef<"ServerConfig", 'DateTime'>
|
||||
}
|
||||
|
||||
|
||||
@ -22769,7 +22856,14 @@ export namespace Prisma {
|
||||
pterodactylServerId: 'pterodactylServerId',
|
||||
pterodactylServerApiKey: 'pterodactylServerApiKey',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
updatedAt: 'updatedAt',
|
||||
activeMatchId: 'activeMatchId',
|
||||
activeMapKey: 'activeMapKey',
|
||||
activeMapLabel: 'activeMapLabel',
|
||||
activeMapBg: 'activeMapBg',
|
||||
activeParticipants: 'activeParticipants',
|
||||
activeSince: 'activeSince',
|
||||
bannerExpiresAt: 'bannerExpiresAt'
|
||||
};
|
||||
|
||||
export type ServerConfigScalarFieldEnum = (typeof ServerConfigScalarFieldEnum)[keyof typeof ServerConfigScalarFieldEnum]
|
||||
@ -24484,6 +24578,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFilter<"ServerConfig"> | string
|
||||
createdAt?: DateTimeFilter<"ServerConfig"> | Date | string
|
||||
updatedAt?: DateTimeFilter<"ServerConfig"> | Date | string
|
||||
activeMatchId?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapKey?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapLabel?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapBg?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeParticipants?: StringNullableListFilter<"ServerConfig">
|
||||
activeSince?: DateTimeNullableFilter<"ServerConfig"> | Date | string | null
|
||||
bannerExpiresAt?: DateTimeNullableFilter<"ServerConfig"> | Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigOrderByWithRelationInput = {
|
||||
@ -24494,6 +24595,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: SortOrder
|
||||
createdAt?: SortOrder
|
||||
updatedAt?: SortOrder
|
||||
activeMatchId?: SortOrderInput | SortOrder
|
||||
activeMapKey?: SortOrderInput | SortOrder
|
||||
activeMapLabel?: SortOrderInput | SortOrder
|
||||
activeMapBg?: SortOrderInput | SortOrder
|
||||
activeParticipants?: SortOrder
|
||||
activeSince?: SortOrderInput | SortOrder
|
||||
bannerExpiresAt?: SortOrderInput | SortOrder
|
||||
}
|
||||
|
||||
export type ServerConfigWhereUniqueInput = Prisma.AtLeast<{
|
||||
@ -24507,6 +24615,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFilter<"ServerConfig"> | string
|
||||
createdAt?: DateTimeFilter<"ServerConfig"> | Date | string
|
||||
updatedAt?: DateTimeFilter<"ServerConfig"> | Date | string
|
||||
activeMatchId?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapKey?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapLabel?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeMapBg?: StringNullableFilter<"ServerConfig"> | string | null
|
||||
activeParticipants?: StringNullableListFilter<"ServerConfig">
|
||||
activeSince?: DateTimeNullableFilter<"ServerConfig"> | Date | string | null
|
||||
bannerExpiresAt?: DateTimeNullableFilter<"ServerConfig"> | Date | string | null
|
||||
}, "id">
|
||||
|
||||
export type ServerConfigOrderByWithAggregationInput = {
|
||||
@ -24517,6 +24632,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: SortOrder
|
||||
createdAt?: SortOrder
|
||||
updatedAt?: SortOrder
|
||||
activeMatchId?: SortOrderInput | SortOrder
|
||||
activeMapKey?: SortOrderInput | SortOrder
|
||||
activeMapLabel?: SortOrderInput | SortOrder
|
||||
activeMapBg?: SortOrderInput | SortOrder
|
||||
activeParticipants?: SortOrder
|
||||
activeSince?: SortOrderInput | SortOrder
|
||||
bannerExpiresAt?: SortOrderInput | SortOrder
|
||||
_count?: ServerConfigCountOrderByAggregateInput
|
||||
_max?: ServerConfigMaxOrderByAggregateInput
|
||||
_min?: ServerConfigMinOrderByAggregateInput
|
||||
@ -24533,6 +24655,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringWithAggregatesFilter<"ServerConfig"> | string
|
||||
createdAt?: DateTimeWithAggregatesFilter<"ServerConfig"> | Date | string
|
||||
updatedAt?: DateTimeWithAggregatesFilter<"ServerConfig"> | Date | string
|
||||
activeMatchId?: StringNullableWithAggregatesFilter<"ServerConfig"> | string | null
|
||||
activeMapKey?: StringNullableWithAggregatesFilter<"ServerConfig"> | string | null
|
||||
activeMapLabel?: StringNullableWithAggregatesFilter<"ServerConfig"> | string | null
|
||||
activeMapBg?: StringNullableWithAggregatesFilter<"ServerConfig"> | string | null
|
||||
activeParticipants?: StringNullableListFilter<"ServerConfig">
|
||||
activeSince?: DateTimeNullableWithAggregatesFilter<"ServerConfig"> | Date | string | null
|
||||
bannerExpiresAt?: DateTimeNullableWithAggregatesFilter<"ServerConfig"> | Date | string | null
|
||||
}
|
||||
|
||||
export type UserCreateInput = {
|
||||
@ -26208,6 +26337,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
activeMatchId?: string | null
|
||||
activeMapKey?: string | null
|
||||
activeMapLabel?: string | null
|
||||
activeMapBg?: string | null
|
||||
activeParticipants?: ServerConfigCreateactiveParticipantsInput | string[]
|
||||
activeSince?: Date | string | null
|
||||
bannerExpiresAt?: Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigUncheckedCreateInput = {
|
||||
@ -26218,6 +26354,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
activeMatchId?: string | null
|
||||
activeMapKey?: string | null
|
||||
activeMapLabel?: string | null
|
||||
activeMapBg?: string | null
|
||||
activeParticipants?: ServerConfigCreateactiveParticipantsInput | string[]
|
||||
activeSince?: Date | string | null
|
||||
bannerExpiresAt?: Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigUpdateInput = {
|
||||
@ -26228,6 +26371,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFieldUpdateOperationsInput | string
|
||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
activeMatchId?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapKey?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapLabel?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapBg?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeParticipants?: ServerConfigUpdateactiveParticipantsInput | string[]
|
||||
activeSince?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
bannerExpiresAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigUncheckedUpdateInput = {
|
||||
@ -26238,6 +26388,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFieldUpdateOperationsInput | string
|
||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
activeMatchId?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapKey?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapLabel?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapBg?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeParticipants?: ServerConfigUpdateactiveParticipantsInput | string[]
|
||||
activeSince?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
bannerExpiresAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigCreateManyInput = {
|
||||
@ -26248,6 +26405,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
activeMatchId?: string | null
|
||||
activeMapKey?: string | null
|
||||
activeMapLabel?: string | null
|
||||
activeMapBg?: string | null
|
||||
activeParticipants?: ServerConfigCreateactiveParticipantsInput | string[]
|
||||
activeSince?: Date | string | null
|
||||
bannerExpiresAt?: Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigUpdateManyMutationInput = {
|
||||
@ -26258,6 +26422,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFieldUpdateOperationsInput | string
|
||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
activeMatchId?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapKey?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapLabel?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapBg?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeParticipants?: ServerConfigUpdateactiveParticipantsInput | string[]
|
||||
activeSince?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
bannerExpiresAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
}
|
||||
|
||||
export type ServerConfigUncheckedUpdateManyInput = {
|
||||
@ -26268,6 +26439,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: StringFieldUpdateOperationsInput | string
|
||||
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
|
||||
activeMatchId?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapKey?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapLabel?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeMapBg?: NullableStringFieldUpdateOperationsInput | string | null
|
||||
activeParticipants?: ServerConfigUpdateactiveParticipantsInput | string[]
|
||||
activeSince?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
bannerExpiresAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||
}
|
||||
|
||||
export type StringFilter<$PrismaModel = never> = {
|
||||
@ -27701,6 +27879,13 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: SortOrder
|
||||
createdAt?: SortOrder
|
||||
updatedAt?: SortOrder
|
||||
activeMatchId?: SortOrder
|
||||
activeMapKey?: SortOrder
|
||||
activeMapLabel?: SortOrder
|
||||
activeMapBg?: SortOrder
|
||||
activeParticipants?: SortOrder
|
||||
activeSince?: SortOrder
|
||||
bannerExpiresAt?: SortOrder
|
||||
}
|
||||
|
||||
export type ServerConfigMaxOrderByAggregateInput = {
|
||||
@ -27711,6 +27896,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: SortOrder
|
||||
createdAt?: SortOrder
|
||||
updatedAt?: SortOrder
|
||||
activeMatchId?: SortOrder
|
||||
activeMapKey?: SortOrder
|
||||
activeMapLabel?: SortOrder
|
||||
activeMapBg?: SortOrder
|
||||
activeSince?: SortOrder
|
||||
bannerExpiresAt?: SortOrder
|
||||
}
|
||||
|
||||
export type ServerConfigMinOrderByAggregateInput = {
|
||||
@ -27721,6 +27912,12 @@ export namespace Prisma {
|
||||
pterodactylServerApiKey?: SortOrder
|
||||
createdAt?: SortOrder
|
||||
updatedAt?: SortOrder
|
||||
activeMatchId?: SortOrder
|
||||
activeMapKey?: SortOrder
|
||||
activeMapLabel?: SortOrder
|
||||
activeMapBg?: SortOrder
|
||||
activeSince?: SortOrder
|
||||
bannerExpiresAt?: SortOrder
|
||||
}
|
||||
|
||||
export type TeamCreateNestedOneWithoutMembersInput = {
|
||||
@ -29524,6 +29721,15 @@ export namespace Prisma {
|
||||
update?: XOR<XOR<UserUpdateToOneWithWhereWithoutReadyAcceptancesInput, UserUpdateWithoutReadyAcceptancesInput>, UserUncheckedUpdateWithoutReadyAcceptancesInput>
|
||||
}
|
||||
|
||||
export type ServerConfigCreateactiveParticipantsInput = {
|
||||
set: string[]
|
||||
}
|
||||
|
||||
export type ServerConfigUpdateactiveParticipantsInput = {
|
||||
set?: string[]
|
||||
push?: string | string[]
|
||||
}
|
||||
|
||||
export type NestedStringFilter<$PrismaModel = never> = {
|
||||
equals?: string | StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | ListStringFieldRefInput<$PrismaModel>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "prisma-client-95b977b21ef98eb4d9fe600b3adfad15a11574a50aec075d54017df21315a04c",
|
||||
"name": "prisma-client-593c7e86a193b89a0b02a9e811c3a30c125592905a16d5c01f1f9522bc8c8086",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "default.js",
|
||||
|
||||
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp19348
Normal file
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp19348
Normal file
Binary file not shown.
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp28828
Normal file
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp28828
Normal file
Binary file not shown.
@ -437,9 +437,20 @@ model MatchReady {
|
||||
model ServerConfig {
|
||||
id String @id
|
||||
serverIp String
|
||||
serverPassword String? // ⬅️ neu
|
||||
serverPassword String?
|
||||
pterodactylServerId String
|
||||
pterodactylServerApiKey String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// ───── Live / GameBanner ─────
|
||||
activeMatchId String?
|
||||
activeMapKey String?
|
||||
activeMapLabel String?
|
||||
activeMapBg String?
|
||||
activeParticipants String[] // steamIds
|
||||
activeSince DateTime?
|
||||
bannerExpiresAt DateTime?
|
||||
|
||||
@@index([activeMatchId])
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
18
src/lib/useGameBannerStore.ts
Normal file
18
src/lib/useGameBannerStore.ts
Normal file
@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
import { create } from 'zustand'
|
||||
|
||||
type BannerState = {
|
||||
visible: boolean
|
||||
map: { key: string|null, label: string|null, bg: string|null }
|
||||
participants: string[]
|
||||
show: (p: { key: string|null, label: string|null, bg: string|null, participants: string[] }) => void
|
||||
hide: () => void
|
||||
}
|
||||
|
||||
export const useGameBannerStore = create<BannerState>((set) => ({
|
||||
visible: false,
|
||||
map: { key: null, label: null, bg: null },
|
||||
participants: [],
|
||||
show: ({ key, label, bg, participants }) => set({ visible: true, map: { key, label, bg }, participants }),
|
||||
hide: () => set({ visible: false, participants: [], map: { key: null, label: null, bg: null } }),
|
||||
}))
|
||||
@ -1,19 +1,21 @@
|
||||
// /src/worker/jobs/processUserMatches.ts
|
||||
// /src/worker/jobs/matchScannerCron.ts
|
||||
|
||||
import cron from 'node-cron';
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { decrypt } from '@/lib/crypto';
|
||||
import { processUserMatches } from '../tasks/processUserMatchesTask';
|
||||
import { refreshUserBansTask } from '../tasks/refreshUserBansTask';
|
||||
import { refreshFaceitProfilesTask } from '../tasks/refreshFaceitProfilesTask'; // ⬅️ NEU
|
||||
import { log } from '../lib/logger';
|
||||
|
||||
let runningMatches = false;
|
||||
let runningBans = false;
|
||||
let runningFaceit = false; // ⬅️ NEU
|
||||
|
||||
export function startCS2MatchCron() {
|
||||
log.info('🚀 CS2-CronJob Runner gestartet!');
|
||||
|
||||
// Matches – z. B. alle 10s (statt jede Sekunde)
|
||||
// Matches – z. B. alle 10s
|
||||
const jobMatches = cron.schedule('*/10 * * * * *', async () => {
|
||||
if (runningMatches) return;
|
||||
runningMatches = true;
|
||||
@ -31,8 +33,25 @@ export function startCS2MatchCron() {
|
||||
finally { runningBans = false; }
|
||||
});
|
||||
|
||||
// Faceit-Refresh – alle 15 Minuten (anpassbar)
|
||||
const jobFaceit = cron.schedule('*/15 * * * *', async () => {
|
||||
if (runningFaceit) return;
|
||||
runningFaceit = true;
|
||||
try {
|
||||
await refreshFaceitProfilesTask({ maxAgeMinutes: 24 * 60, limit: 500 });
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
} finally {
|
||||
runningFaceit = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Initiale Läufe beim Start
|
||||
refreshUserBansTask().catch(e => log.error(e));
|
||||
return { jobMatches, jobBans };
|
||||
refreshFaceitProfilesTask({ maxAgeMinutes: 30 * 24 * 60, limit: 2000 })
|
||||
.catch(e => log.error(e));
|
||||
|
||||
return { jobMatches, jobBans, jobFaceit };
|
||||
}
|
||||
|
||||
async function runMatchCheck() {
|
||||
@ -44,4 +63,4 @@ async function runMatchCheck() {
|
||||
const auth = decrypt(user.authCode!);
|
||||
await processUserMatches(user.steamId, auth, user.lastKnownShareCode!);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/worker/tasks/refreshFaceitProfilesTask.ts
Normal file
69
src/worker/tasks/refreshFaceitProfilesTask.ts
Normal file
@ -0,0 +1,69 @@
|
||||
// /src/worker/tasks/refreshFaceitProfilesTask.ts
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { syncFaceitProfile } from '@/lib/faceit'
|
||||
import { log } from '../lib/logger'
|
||||
|
||||
type Options = {
|
||||
/** nur Einträge aktualisieren, deren letzte cs2-Faceit-Stats älter sind als X Minuten */
|
||||
maxAgeMinutes?: number
|
||||
/** maximale Anzahl pro Lauf */
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export async function refreshFaceitProfilesTask(opts: Options = {}): Promise<void> {
|
||||
const {
|
||||
maxAgeMinutes = 12 * 60, // 12h
|
||||
limit = 500,
|
||||
} = opts
|
||||
|
||||
const since = new Date(Date.now() - maxAgeMinutes * 60_000)
|
||||
|
||||
// Nutzer auswählen, die (a) noch keine Faceit-Daten haben ODER (b) veraltete cs2-Stats
|
||||
const candidates = await prisma.user.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
// noch nie gesynct / keine Grunddaten
|
||||
{ faceitId: null },
|
||||
{ faceitNickname: null },
|
||||
{ faceitUrl: null },
|
||||
|
||||
// keine cs2-Game-Stats in FaceitGameStat
|
||||
{
|
||||
faceitGames: {
|
||||
none: { game: 'cs2' },
|
||||
},
|
||||
},
|
||||
|
||||
// cs2-Stats zu alt
|
||||
{
|
||||
faceitGames: {
|
||||
some: {
|
||||
game: 'cs2',
|
||||
// falls dein Model kein updatedAt hat, diesen Block entfernen
|
||||
updatedAt: { lt: since },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
select: { steamId: true },
|
||||
take: limit,
|
||||
})
|
||||
|
||||
if (candidates.length === 0) {
|
||||
log.info('[faceit] Keine Kandidaten für Refresh gefunden.')
|
||||
return
|
||||
}
|
||||
|
||||
log.info(`[faceit] Aktualisiere ${candidates.length} Nutzer…`)
|
||||
|
||||
for (const u of candidates) {
|
||||
try {
|
||||
await syncFaceitProfile(prisma, u.steamId)
|
||||
} catch (e) {
|
||||
log.warn(`[faceit] Fehler bei ${u.steamId}`, e)
|
||||
}
|
||||
}
|
||||
|
||||
log.info(`[faceit] Aktualisierung abgeschlossen.`)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user