mirror of
https://github.com/nestriness/nestri.git
synced 2026-11-03 14:12:39 +02:00
feat(box): a listed box names its machine's host and whether it is the fleet
The desktop app gives a new cloud user a fleet box and then opens that machine's Steam sign-in on its hostname; GET /box now says which hostname, and which box is the fleet one.
This commit is contained in:
@@ -123,6 +123,18 @@ describe('POST /box on the fleet', () => {
|
||||
expect((await Box.listByUser(p.owner.userId)).length).toBe(1);
|
||||
});
|
||||
|
||||
test('a listed fleet box names the machine whose Steam sign-in it opens', async () => {
|
||||
const f = await fleet(1);
|
||||
useFleet(f.organisationId);
|
||||
const p = await person('fleet-host');
|
||||
expect((await createBox(p.headers, { on: 'fleet' })).status).toBe(201);
|
||||
const listed = ((await (await app.request('/box', { headers: p.headers })).json()) as any).data;
|
||||
const [slug] = await sql`select slug from machine where id = ${f.machines[0]!.id}`;
|
||||
expect(listed).toHaveLength(1);
|
||||
expect(listed[0].fleet).toBe(true);
|
||||
expect(listed[0].host).toBe(slug!.slug);
|
||||
});
|
||||
|
||||
test('`on` defaults to your own host', async () => {
|
||||
const f = await fleet(1);
|
||||
useFleet(f.organisationId);
|
||||
|
||||
@@ -56,6 +56,15 @@ export namespace Box {
|
||||
description:
|
||||
'The card it runs on, as its host reports it: what a person recognises the box by. Null until the host has reported one',
|
||||
example: Examples.Box.gpu
|
||||
}),
|
||||
host: z.string().nullable().optional().meta({
|
||||
description:
|
||||
"The DNS label of the machine it is placed on: that machine's Steam sign-in is at `https://<host>.<edge zone>/_nestri/auth`. Listed boxes only",
|
||||
example: Examples.Box.host
|
||||
}),
|
||||
fleet: z.boolean().optional().meta({
|
||||
description: 'Whether it is on Nestri GPUs rather than your own host. Listed boxes only',
|
||||
example: Examples.Box.fleet
|
||||
})
|
||||
})
|
||||
.meta({
|
||||
@@ -124,12 +133,21 @@ export namespace Box {
|
||||
export const listByUser = fn(Info.shape.userId, async (userId) => {
|
||||
return Database.use(async (tx) => {
|
||||
return tx
|
||||
.select({ box: BoxTable, gpus: MachineTable.gpus })
|
||||
.select({
|
||||
box: BoxTable,
|
||||
gpus: MachineTable.gpus,
|
||||
host: MachineTable.slug,
|
||||
organisationId: MachineTable.organisationId
|
||||
})
|
||||
.from(BoxTable)
|
||||
.leftJoin(MachineTable, eq(MachineTable.id, BoxTable.machineId))
|
||||
.where(and(eq(BoxTable.userId, userId), isNull(BoxTable.timeDeleted)))
|
||||
.orderBy(BoxTable.timeCreated)
|
||||
.then((rows) => rows.map((r) => serialize(r.box, Machine.gpuName(r.gpus))));
|
||||
.then((rows) =>
|
||||
rows.map((r) =>
|
||||
serialize(r.box, Machine.gpuName(r.gpus), { host: r.host, fleet: r.organisationId !== null })
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -385,7 +403,11 @@ export namespace Box {
|
||||
}
|
||||
);
|
||||
|
||||
export function serialize(input: typeof BoxTable.$inferSelect, gpu: string | null = null): z.infer<typeof Info> {
|
||||
export function serialize(
|
||||
input: typeof BoxTable.$inferSelect,
|
||||
gpu: string | null = null,
|
||||
machine?: { host: string | null; fleet: boolean }
|
||||
): z.infer<typeof Info> {
|
||||
return {
|
||||
id: input.id,
|
||||
userId: input.userId,
|
||||
@@ -395,7 +417,8 @@ export namespace Box {
|
||||
state: input.state as Info['state'],
|
||||
stopReason: input.stopReason,
|
||||
stopClean: input.stopClean,
|
||||
gpu
|
||||
gpu,
|
||||
...machine
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,9 @@ export namespace Examples {
|
||||
state: 'created' as const,
|
||||
stopReason: null,
|
||||
stopClean: null,
|
||||
gpu: 'NVIDIA GeForce RTX 3060'
|
||||
gpu: 'NVIDIA GeForce RTX 3060',
|
||||
host: 'm7k2q9',
|
||||
fleet: false
|
||||
};
|
||||
|
||||
export const Session = {
|
||||
|
||||
Reference in New Issue
Block a user