-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: rotate static game servers (#119)
- Loading branch information
1 parent
21a9e26
commit 374ab79
Showing
17 changed files
with
307 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,14 @@ | ||
import type { User } from '../../../../auth/types/user' | ||
import { Admin } from '../../../views/html/admin' | ||
import { StaticGameServerList } from './static-game-server-list' | ||
|
||
export function GameServersPage(props: { user: User }) { | ||
export async function GameServersPage(props: { user: User }) { | ||
return ( | ||
<Admin activePage="game-servers" user={props.user}> | ||
<div class="admin-panel-set"></div> | ||
<div class="admin-panel-set"> | ||
<h4 class="pb-4">Static servers</h4> | ||
<StaticGameServerList /> | ||
</div> | ||
</Admin> | ||
) | ||
} |
72 changes: 72 additions & 0 deletions
72
src/admin/game-servers/views/html/static-game-server-list.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { collections } from '../../../../database/collections' | ||
import type { StaticGameServerModel } from '../../../../database/models/static-game-server.model' | ||
import { IconCheck, IconMinus, IconSquareXFilled, IconX } from '../../../../html/components/icons' | ||
|
||
export async function StaticGameServerList() { | ||
const staticGameServers = await collections.staticGameServers | ||
.find() | ||
.sort({ isOnline: -1, lastHeartbeatAt: -1, priority: -1 }) | ||
.toArray() | ||
|
||
return ( | ||
<table class="w-full table-auto" id="admin-panel-static-game-server-list"> | ||
<thead> | ||
<tr> | ||
<th class="border-b border-ash/50 pb-3 text-left">Name</th> | ||
<th class="border-b border-ash/50 pb-3 text-left">IP address</th> | ||
<th class="border-b border-ash/50 pb-3 text-left">Internal IP address</th> | ||
<th class="border-b border-ash/50 pb-3 text-left">RCON password</th> | ||
<th class="border-b border-ash/50 pb-3 text-left">Online</th> | ||
<th class="border-b border-ash/50 pb-3 text-left">Assigned to game</th> | ||
</tr> | ||
</thead> | ||
|
||
<tbody> | ||
{staticGameServers.map(gameServer => ( | ||
<StaticGameServerItem gameServer={gameServer} /> | ||
))} | ||
</tbody> | ||
</table> | ||
) | ||
} | ||
|
||
function StaticGameServerItem(props: { gameServer: StaticGameServerModel }) { | ||
return ( | ||
<tr> | ||
<td class="border-b border-ash/20 py-4 font-bold" safe> | ||
{props.gameServer.name} | ||
</td> | ||
<td class="border-b border-ash/20 py-4" safe> | ||
{props.gameServer.address}:{props.gameServer.port} | ||
</td> | ||
<td class="border-b border-ash/20 py-4" safe> | ||
{props.gameServer.internalIpAddress}:{props.gameServer.port} | ||
</td> | ||
<td class="border-b border-ash/20 py-4" safe> | ||
{props.gameServer.rconPassword} | ||
</td> | ||
<td class="border-b border-ash/20 py-4"> | ||
{props.gameServer.isOnline ? ( | ||
<IconCheck class="text-green-600" /> | ||
) : ( | ||
<IconX class="text-red-600" /> | ||
)} | ||
</td> | ||
<td class="border-b border-ash/20 py-4"> | ||
{props.gameServer.game ? ( | ||
<div class="flex flex-row gap-2 align-middle"> | ||
<a href={`/games/${props.gameServer.game}`} safe> | ||
#{props.gameServer.game} | ||
</a> | ||
<button hx-delete={`/static-game-servers/${props.gameServer.id}/game`}> | ||
<span class="sr-only">Remove game assignment</span> | ||
<IconSquareXFilled /> | ||
</button> | ||
</div> | ||
) : ( | ||
<IconMinus /> | ||
)} | ||
</td> | ||
</tr> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { makeIcon } from './make-icon' | ||
|
||
export const IconCheck = makeIcon( | ||
'check', | ||
<> | ||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | ||
<path d="M5 12l5 5l10 -10" /> | ||
</>, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { makeIconFilled } from './make-icon' | ||
|
||
export const IconSquareXFilled = makeIconFilled( | ||
'square-x-filled', | ||
<> | ||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | ||
<path d="M19 2h-14a3 3 0 0 0 -3 3v14a3 3 0 0 0 3 3h14a3 3 0 0 0 3 -3v-14a3 3 0 0 0 -3 -3zm-9.387 6.21l.094 .083l2.293 2.292l2.293 -2.292a1 1 0 0 1 1.497 1.32l-.083 .094l-2.292 2.293l2.292 2.293a1 1 0 0 1 -1.32 1.497l-.094 -.083l-2.293 -2.292l-2.293 2.292a1 1 0 0 1 -1.497 -1.32l.083 -.094l2.292 -2.293l-2.292 -2.293a1 1 0 0 1 1.32 -1.497z" /> | ||
</>, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { makeIcon } from './make-icon' | ||
|
||
export const IconSquareX = makeIcon( | ||
'square-x', | ||
<> | ||
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | ||
<path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z" /> | ||
<path d="M9 9l6 6m0 -6l-6 6" /> | ||
</>, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Mutex } from 'async-mutex' | ||
import type { GameModel } from '../database/models/game.model' | ||
import { findFree } from './find-free' | ||
import { update } from './update' | ||
|
||
const mutex = new Mutex() | ||
|
||
export async function assign(game: GameModel) { | ||
return await mutex.runExclusive(async () => { | ||
const before = await findFree() | ||
if (!before) { | ||
throw new Error(`no free servers available for game ${game.number}`) | ||
} | ||
|
||
return await update( | ||
{ | ||
id: before.id, | ||
}, | ||
{ | ||
$set: { | ||
game: game.number, | ||
}, | ||
}, | ||
) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import fp from 'fastify-plugin' | ||
import { events } from '../../events' | ||
import { update } from '../update' | ||
import { tasks } from '../../tasks' | ||
import { secondsToMilliseconds } from 'date-fns' | ||
import { whenGameEnds } from '../../games/when-game-ends' | ||
import { GameServerProvider, GameState } from '../../database/models/game.model' | ||
|
||
const freeGameServerDelay = secondsToMilliseconds(30) | ||
|
||
export default fp( | ||
async () => { | ||
tasks.register('staticGameServers:free', async ({ id }) => { | ||
await update({ id }, { $unset: { game: 1 } }) | ||
}) | ||
|
||
events.on( | ||
'game:updated', | ||
whenGameEnds(async ({ after }) => { | ||
if (after.gameServer?.provider !== GameServerProvider.static) { | ||
return | ||
} | ||
|
||
if (after.state === GameState.interrupted) { | ||
await update({ id: after.gameServer.id }, { $unset: { game: 1 } }) | ||
} else { | ||
tasks.schedule('staticGameServers:free', freeGameServerDelay, { id: after.gameServer.id }) | ||
} | ||
}), | ||
) | ||
}, | ||
{ | ||
name: 'free static game servers', | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.