Add internal daemon routes and service management scripts
This commit is contained in:
parent
c9fe2bd9fe
commit
614d25c189
|
|
@ -7,6 +7,7 @@ dist/
|
|||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
daemon-dev.yml
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
|
|
@ -36,4 +37,4 @@ build/
|
|||
|
||||
# Claude
|
||||
.claude/
|
||||
plans.md
|
||||
plans.md
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import dbPlugin from './plugins/db.js';
|
|||
import authPlugin from './plugins/auth.js';
|
||||
import authRoutes from './routes/auth/index.js';
|
||||
import organizationRoutes from './routes/organizations/index.js';
|
||||
import internalRoutes from './routes/internal/index.js';
|
||||
import daemonNodeRoutes from './routes/nodes/daemon.js';
|
||||
import nodeRoutes from './routes/nodes/index.js';
|
||||
import serverRoutes from './routes/servers/index.js';
|
||||
|
|
@ -85,6 +86,7 @@ await app.register(authRoutes, { prefix: '/api/auth' });
|
|||
await app.register(organizationRoutes, { prefix: '/api/organizations' });
|
||||
await app.register(adminRoutes, { prefix: '/api/admin' });
|
||||
await app.register(daemonNodeRoutes, { prefix: '/api/nodes' });
|
||||
await app.register(internalRoutes, { prefix: '/api/internal' });
|
||||
|
||||
// Nested org routes: nodes and servers are scoped to an org
|
||||
await app.register(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
import { Type } from '@sinclair/typebox';
|
||||
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { nodes } from '@source/database';
|
||||
import { AppError } from '../../lib/errors.js';
|
||||
|
||||
function extractBearerToken(authHeader?: string): string | null {
|
||||
if (!authHeader) return null;
|
||||
const [scheme, token] = authHeader.split(' ');
|
||||
if (!scheme || !token || scheme.toLowerCase() !== 'bearer') return null;
|
||||
return token;
|
||||
}
|
||||
|
||||
async function requireDaemonToken(app: FastifyInstance, request: FastifyRequest): Promise<void> {
|
||||
const token = extractBearerToken(
|
||||
typeof request.headers.authorization === 'string'
|
||||
? request.headers.authorization
|
||||
: undefined,
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw AppError.unauthorized('Missing daemon bearer token', 'DAEMON_AUTH_MISSING');
|
||||
}
|
||||
|
||||
const node = await app.db.query.nodes.findFirst({
|
||||
where: eq(nodes.daemonToken, token),
|
||||
columns: { id: true },
|
||||
});
|
||||
|
||||
if (!node) {
|
||||
throw AppError.unauthorized('Invalid daemon token', 'DAEMON_AUTH_INVALID');
|
||||
}
|
||||
}
|
||||
|
||||
export default async function internalRoutes(app: FastifyInstance) {
|
||||
app.get('/schedules/due', async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
return { tasks: [] };
|
||||
});
|
||||
|
||||
app.post(
|
||||
'/schedules/:taskId/ack',
|
||||
{
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
taskId: Type.String(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
const { taskId } = request.params as { taskId: string };
|
||||
return { success: true, taskId };
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/servers/:serverUuid/backup',
|
||||
{
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
serverUuid: Type.String(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
const { serverUuid } = request.params as { serverUuid: string };
|
||||
return { success: true, serverUuid };
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="/root/codex/source-gamepanel"
|
||||
PNPM="/root/.nvm/versions/node/v24.13.1/bin/pnpm"
|
||||
SERVICES=(
|
||||
"source-gamepanel-api.service"
|
||||
"source-gamepanel-web.service"
|
||||
"source-gamepanel-daemon.service"
|
||||
)
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: panelctl <command>
|
||||
|
||||
Commands:
|
||||
start Start all services
|
||||
stop Stop all services
|
||||
restart Restart all services
|
||||
status Show status of all services
|
||||
logs Tail logs of all services
|
||||
rebuild Rebuild API/Web/Daemon binaries
|
||||
update Pull latest code, rebuild, migrate DB, restart services
|
||||
deploy Rebuild current code, migrate DB, restart services
|
||||
EOF
|
||||
}
|
||||
|
||||
rebuild_all() {
|
||||
cd "$ROOT"
|
||||
"$PNPM" install --frozen-lockfile
|
||||
"$PNPM" --filter @source/api build
|
||||
"$PNPM" --filter @source/web build
|
||||
source "$HOME/.cargo/env"
|
||||
cd "$ROOT/apps/daemon"
|
||||
cargo build --release
|
||||
}
|
||||
|
||||
migrate_db() {
|
||||
cd "$ROOT"
|
||||
"$PNPM" db:migrate
|
||||
}
|
||||
|
||||
cmd="${1:-}"
|
||||
case "$cmd" in
|
||||
start)
|
||||
systemctl start "${SERVICES[@]}"
|
||||
;;
|
||||
stop)
|
||||
systemctl stop "${SERVICES[@]}"
|
||||
;;
|
||||
restart)
|
||||
systemctl restart "${SERVICES[@]}"
|
||||
;;
|
||||
status)
|
||||
systemctl --no-pager --full status "${SERVICES[@]}"
|
||||
;;
|
||||
logs)
|
||||
journalctl -u "${SERVICES[0]}" -u "${SERVICES[1]}" -u "${SERVICES[2]}" -f
|
||||
;;
|
||||
rebuild)
|
||||
rebuild_all
|
||||
;;
|
||||
update)
|
||||
cd "$ROOT"
|
||||
git pull --ff-only
|
||||
rebuild_all
|
||||
migrate_db
|
||||
systemctl restart "${SERVICES[@]}"
|
||||
systemctl --no-pager --full status "${SERVICES[@]}"
|
||||
;;
|
||||
deploy)
|
||||
rebuild_all
|
||||
migrate_db
|
||||
systemctl restart "${SERVICES[@]}"
|
||||
systemctl --no-pager --full status "${SERVICES[@]}"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd /root/codex/source-gamepanel/apps/api
|
||||
exec /root/.nvm/versions/node/v24.13.1/bin/pnpm dev
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd /root/codex/source-gamepanel/apps/daemon
|
||||
export DAEMON_CONFIG=/root/codex/source-gamepanel/daemon-dev.yml
|
||||
exec /root/codex/source-gamepanel/apps/daemon/target/release/gamepanel-daemon
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd /root/codex/source-gamepanel/apps/web
|
||||
exec /root/.nvm/versions/node/v24.13.1/bin/pnpm dev --host 0.0.0.0 --port 5173
|
||||
Loading…
Reference in New Issue