mirror of
https://github.com/unraid/api.git
synced 2026-01-03 06:59:50 -06:00
refactor: improve code organization
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Cron, CronExpression, Timeout } from '@nestjs/schedule';
|
||||
|
||||
import { DockerPhpService } from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
import { DockerManifestService } from '@app/unraid-api/graph/resolvers/docker/docker-manifest.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class ContainerStatusJob {
|
||||
constructor(private readonly dockerPhpService: DockerPhpService) {}
|
||||
constructor(private readonly dockerManifestService: DockerManifestService) {}
|
||||
|
||||
@Cron(CronExpression.EVERY_DAY_AT_6AM)
|
||||
async refreshContainerDigests() {
|
||||
await this.dockerPhpService.refreshDigests();
|
||||
await this.dockerManifestService.refreshDigests();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -17,6 +17,6 @@ export class ContainerStatusJob {
|
||||
*/
|
||||
@Timeout(5_000)
|
||||
async refreshContainerDigestsAfterStartup() {
|
||||
await this.dockerPhpService.refreshDigests();
|
||||
await this.dockerManifestService.refreshDigests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ import { OrganizerV1, ResolvedOrganizerV1 } from '@app/unraid-api/organizer/orga
|
||||
@Resolver(() => DockerContainer)
|
||||
export class DockerContainerResolver {
|
||||
private readonly logger = new Logger(DockerContainerResolver.name);
|
||||
constructor(
|
||||
private readonly dockerManifestService: DockerManifestService,
|
||||
private readonly dockerPhpService: DockerPhpService
|
||||
) {}
|
||||
constructor(private readonly dockerManifestService: DockerManifestService) {}
|
||||
|
||||
@UsePermissions({
|
||||
action: AuthActionVerb.READ,
|
||||
@@ -62,6 +59,6 @@ export class DockerContainerResolver {
|
||||
})
|
||||
@Mutation(() => Boolean)
|
||||
public async refreshDockerDigests() {
|
||||
return this.dockerPhpService.refreshDigests();
|
||||
return this.dockerManifestService.refreshDigests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
import { ExtendOptions, Got, got as gotClient, OptionsOfTextResponseBody } from 'got';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { docker } from '@app/core/utils/index.js';
|
||||
|
||||
/** Accept header for Docker API manifest listing */
|
||||
const ACCEPT_MANIFEST =
|
||||
'application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.docker.distribution.manifest.v2+json,application/vnd.oci.image.index.v1+json';
|
||||
|
||||
export type CachedStatusEntry = {
|
||||
/** sha256 digest - "sha256:..." */
|
||||
local: string;
|
||||
/** sha256 digest - "sha256:..." */
|
||||
remote: string;
|
||||
/** whether update is available (true), not available (false), or unknown (null) */
|
||||
status: 'true' | 'false' | null;
|
||||
};
|
||||
import {
|
||||
CachedStatusEntry,
|
||||
DockerPhpService,
|
||||
} from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class DockerManifestService {
|
||||
constructor() {}
|
||||
constructor(private readonly dockerPhpService: DockerPhpService) {}
|
||||
|
||||
async readCachedUpdateStatus(cacheFile = '/var/lib/docker/unraid-update-status.json') {
|
||||
const cache = await readFile(cacheFile, 'utf8');
|
||||
const cacheData = JSON.parse(cache);
|
||||
return cacheData as Record<string, CachedStatusEntry>;
|
||||
private readonly refreshDigestsMutex = new AsyncMutex(() => {
|
||||
return this.dockerPhpService.refreshDigestsViaPhp();
|
||||
});
|
||||
|
||||
/**
|
||||
* Recomputes local/remote docker container digests and writes them to /var/lib/docker/unraid-update-status.json
|
||||
* @param mutex - Optional mutex to use for the operation. If not provided, a default mutex will be used.
|
||||
* @param dockerUpdatePath - Optional path to the DockerUpdate.php file. If not provided, the default path will be used.
|
||||
* @returns True if the digests were refreshed, false if the operation failed
|
||||
*/
|
||||
async refreshDigests(mutex = this.refreshDigestsMutex, dockerUpdatePath?: string) {
|
||||
return mutex.do(() => {
|
||||
return this.dockerPhpService.refreshDigestsViaPhp(dockerUpdatePath);
|
||||
});
|
||||
}
|
||||
|
||||
async isUpdateAvailableCached(imageRef: string, cacheData?: Record<string, CachedStatusEntry>) {
|
||||
let taggedRef = imageRef;
|
||||
if (!taggedRef.includes(':')) taggedRef += ':latest';
|
||||
|
||||
cacheData ??= await this.readCachedUpdateStatus();
|
||||
cacheData ??= await this.dockerPhpService.readCachedUpdateStatus();
|
||||
const containerData = cacheData[taggedRef];
|
||||
if (!containerData) return null;
|
||||
return containerData.status?.toLowerCase() === 'true';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
import { AsyncMutex } from '@unraid/shared/util/processing.js';
|
||||
|
||||
@@ -9,37 +10,35 @@ type ExplicitStatusItem = {
|
||||
name: string;
|
||||
updateStatus: 'up to date' | 'update available' | 'rebuild ready' | 'unknown';
|
||||
};
|
||||
export type CachedStatusEntry = {
|
||||
/** sha256 digest - "sha256:..." */
|
||||
local: string;
|
||||
/** sha256 digest - "sha256:..." */
|
||||
remote: string;
|
||||
/** whether update is available (true), not available (false), or unknown (null) */
|
||||
status: 'true' | 'false' | null;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class DockerPhpService {
|
||||
constructor() {}
|
||||
|
||||
async readCachedUpdateStatus(cacheFile = '/var/lib/docker/unraid-update-status.json') {
|
||||
const cache = await readFile(cacheFile, 'utf8');
|
||||
const cacheData = JSON.parse(cache);
|
||||
return cacheData as Record<string, CachedStatusEntry>;
|
||||
}
|
||||
|
||||
/**----------------------
|
||||
* Refresh Container Digests
|
||||
*------------------------**/
|
||||
|
||||
private readonly refreshDigestsMutex = new AsyncMutex(() => {
|
||||
return this.refreshDigestsViaPhp();
|
||||
});
|
||||
|
||||
/**
|
||||
* Recomputes local/remote docker container digests and writes them to /var/lib/docker/unraid-update-status.json
|
||||
* @param mutex - Optional mutex to use for the operation. If not provided, a default mutex will be used.
|
||||
* @param dockerUpdatePath - Optional path to the DockerUpdate.php file. If not provided, the default path will be used.
|
||||
* @returns True if the digests were refreshed, false if the operation failed
|
||||
*/
|
||||
async refreshDigests(mutex = this.refreshDigestsMutex, dockerUpdatePath?: string) {
|
||||
return mutex.do(() => {
|
||||
return this.refreshDigestsViaPhp(dockerUpdatePath);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recomputes local/remote digests by triggering `DockerTemplates->getAllInfo(true)` via DockerUpdate.php
|
||||
* @param dockerUpdatePath - Path to the DockerUpdate.php file
|
||||
* @returns True if the digests were refreshed, false if the file is not found or the operation failed
|
||||
*/
|
||||
private async refreshDigestsViaPhp(
|
||||
async refreshDigestsViaPhp(
|
||||
dockerUpdatePath = '/usr/local/emhttp/plugins/dynamix.docker.manager/include/DockerUpdate.php'
|
||||
) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user