-
Notifications
You must be signed in to change notification settings - Fork 16
feat(docker): add real-time container update progress streaming #1869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,5 @@ | |
| "plugins": [ | ||
| "unraid-api-plugin-connect" | ||
| ] | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| import { Field, Float, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; | ||
|
|
||
| import { PrefixedID } from '@unraid/shared/prefixed-id-scalar.js'; | ||
|
|
||
| export enum DockerUpdateEventType { | ||
| STARTED = 'STARTED', | ||
| LAYER_DOWNLOADING = 'LAYER_DOWNLOADING', | ||
| LAYER_EXTRACTING = 'LAYER_EXTRACTING', | ||
| LAYER_COMPLETE = 'LAYER_COMPLETE', | ||
| LAYER_ALREADY_EXISTS = 'LAYER_ALREADY_EXISTS', | ||
| PULLING = 'PULLING', | ||
| LOG = 'LOG', | ||
| COMPLETE = 'COMPLETE', | ||
| ERROR = 'ERROR', | ||
| } | ||
|
|
||
| registerEnumType(DockerUpdateEventType, { | ||
| name: 'DockerUpdateEventType', | ||
| description: 'Type of Docker update progress event', | ||
| }); | ||
|
|
||
| @ObjectType({ description: 'Progress information for a single image layer' }) | ||
| export class DockerLayerProgress { | ||
| @Field(() => String, { description: 'Layer ID (short hash)' }) | ||
| layerId!: string; | ||
|
|
||
| @Field(() => String, { description: 'Current status of the layer' }) | ||
| status!: string; | ||
|
|
||
| @Field(() => Float, { nullable: true, description: 'Download/extract progress percentage (0-100)' }) | ||
| progress?: number; | ||
|
|
||
| @Field(() => Int, { nullable: true, description: 'Bytes downloaded/processed' }) | ||
| current?: number; | ||
|
|
||
| @Field(() => Int, { nullable: true, description: 'Total bytes for this layer' }) | ||
| total?: number; | ||
|
Comment on lines
+33
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The Useful? React with 👍 / 👎. |
||
| } | ||
|
Comment on lines
+22
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for 64-bit scalar registrations (Long/BigInt)
rg -n --hidden -S "registerScalarType\(|GraphQLBigInt|BigIntResolver|LongResolver|GraphQLLong|class .*Long|scalar\s+Long|scalar\s+BigInt" .Repository: unraid/api Length of output: 3432 🏁 Script executed: # List files in the GraphQL resolvers directory
find api/src/unraid-api/graph -type f -name "*.ts" | head -20Repository: unraid/api Length of output: 1247 🏁 Script executed: # Check the docker-update-progress.model.ts file
cat -n api/src/unraid-api/graph/resolvers/docker/docker-update-progress.model.tsRepository: unraid/api Length of output: 2961 🏁 Script executed: # Search for other byte counter patterns in the codebase
rg -n "bytes|Bytes" api/src --type ts -A 2 | head -50Repository: unraid/api Length of output: 3544 Use The Required changes-import { Field, Float, Int, ObjectType, registerEnumType } from '@nestjs/graphql';
+import { Field, Float, ObjectType, registerEnumType } from '@nestjs/graphql';
+import { GraphQLBigInt } from 'graphql-scalars';
import { PrefixedID } from '@unraid/shared/prefixed-id-scalar.js';
@ObjectType({ description: 'Progress information for a single image layer' })
export class DockerLayerProgress {
@Field(() => String, { description: 'Layer ID (short hash)' })
layerId!: string;
@Field(() => String, { description: 'Current status of the layer' })
status!: string;
@Field(() => Float, { nullable: true, description: 'Download/extract progress percentage (0-100)' })
progress?: number;
- @Field(() => Int, { nullable: true, description: 'Bytes downloaded/processed' })
+ @Field(() => GraphQLBigInt, { nullable: true, description: 'Bytes downloaded/processed' })
current?: number;
- @Field(() => Int, { nullable: true, description: 'Total bytes for this layer' })
+ @Field(() => GraphQLBigInt, { nullable: true, description: 'Total bytes for this layer' })
total?: number;
}
🤖 Prompt for AI Agents |
||
|
|
||
| @ObjectType({ description: 'Real-time progress update for a Docker container update operation' }) | ||
| export class DockerUpdateProgress { | ||
| @Field(() => PrefixedID, { description: 'Container ID being updated' }) | ||
| containerId!: string; | ||
|
|
||
| @Field(() => String, { description: 'Container name being updated' }) | ||
| containerName!: string; | ||
|
|
||
| @Field(() => DockerUpdateEventType, { description: 'Type of progress event' }) | ||
| type!: DockerUpdateEventType; | ||
|
|
||
| @Field(() => String, { nullable: true, description: 'Human-readable message or log line' }) | ||
| message?: string; | ||
|
|
||
| @Field(() => String, { nullable: true, description: 'Layer ID for layer-specific events' }) | ||
| layerId?: string; | ||
|
|
||
| @Field(() => Float, { | ||
| nullable: true, | ||
| description: 'Overall progress percentage (0-100) for the current operation', | ||
| }) | ||
| overallProgress?: number; | ||
|
|
||
| @Field(() => [DockerLayerProgress], { | ||
| nullable: true, | ||
| description: 'Per-layer progress details', | ||
| }) | ||
| layers?: DockerLayerProgress[]; | ||
|
|
||
| @Field(() => String, { nullable: true, description: 'Error message if type is ERROR' }) | ||
| error?: string; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current/totalshould not be GraphQLInt(32-bit) for byte counts; useBigInt(orFloat) instead.Large layers can exceed
Intlimits and break the subscription payload.