feat(plugins): share hosted admission resolution
This commit is contained in:
@@ -4,6 +4,10 @@ import path from 'node:path';
|
||||
import type { CodingPluginToolDefinition } from '../../../shared/coding-plugins';
|
||||
import { PiGameAssetTools } from '../../coding-runtime/pi/extensions/game-assets';
|
||||
import type { MarketplacePackageClientPort, PluginPackageStore } from '../package-store';
|
||||
import {
|
||||
MarketplaceHostedAdmissionError,
|
||||
MarketplaceHostedAdmissionResolver,
|
||||
} from '../hosted-admission';
|
||||
import {
|
||||
GameResourceClient,
|
||||
GameResourceClientError,
|
||||
@@ -28,6 +32,7 @@ export interface GameResourcePluginAdapterOptions {
|
||||
readonly marketplace: MarketplacePackageClientPort;
|
||||
readonly packageStore: Pick<PluginPackageStore, 'getInstalled' | 'getInstalledRelease'>;
|
||||
readonly makeloreVersion: string;
|
||||
readonly admissionResolver?: MarketplaceHostedAdmissionResolver;
|
||||
readonly gameAssets?: PiGameAssetTools;
|
||||
}
|
||||
|
||||
@@ -86,6 +91,9 @@ function clientFailure(error: unknown): AdapterInvocationResult {
|
||||
if (error instanceof GameResourceClientError) {
|
||||
return failure(error.code, error.message, error.status, error.retryable);
|
||||
}
|
||||
if (error instanceof MarketplaceHostedAdmissionError) {
|
||||
return failure(error.code, error.message, error.status, error.retryable);
|
||||
}
|
||||
return failure(
|
||||
'plugin_backend_unavailable',
|
||||
'Hosted game-resource service is temporarily unavailable',
|
||||
@@ -159,9 +167,15 @@ function templateConfig(value: unknown): Readonly<Record<string, unknown>> {
|
||||
export class GameResourcePluginAdapter implements CodingPluginAdapter {
|
||||
readonly pluginId = PLUGIN_ID;
|
||||
private readonly gameAssets: PiGameAssetTools;
|
||||
private readonly admissionResolver: MarketplaceHostedAdmissionResolver;
|
||||
|
||||
constructor(private readonly options: GameResourcePluginAdapterOptions) {
|
||||
this.gameAssets = options.gameAssets ?? new PiGameAssetTools();
|
||||
this.admissionResolver = options.admissionResolver ?? new MarketplaceHostedAdmissionResolver({
|
||||
marketplace: options.marketplace,
|
||||
packageStore: options.packageStore,
|
||||
makeloreVersion: options.makeloreVersion,
|
||||
});
|
||||
}
|
||||
|
||||
async inspect(): Promise<PluginBackendProjection> {
|
||||
@@ -287,28 +301,13 @@ export class GameResourcePluginAdapter implements CodingPluginAdapter {
|
||||
releaseId: string;
|
||||
releaseAdmissionId: string;
|
||||
}> {
|
||||
const installed = context.pluginReleaseId
|
||||
? await this.options.packageStore.getInstalledRelease(PLUGIN_ID, context.pluginReleaseId)
|
||||
: await this.options.packageStore.getInstalled(PLUGIN_ID);
|
||||
if (!installed || !installed.channel) {
|
||||
throw new GameResourceClientError('plugin_release_unavailable', 409, false, 'Installed game-resource Release is unavailable');
|
||||
}
|
||||
const resolved = await this.options.marketplace.resolve({
|
||||
resolveRequestId: context.requestId,
|
||||
makeloreVersion: this.options.makeloreVersion,
|
||||
channel: installed.channel,
|
||||
installed: [{
|
||||
pluginId: installed.pluginId,
|
||||
releaseId: installed.releaseId,
|
||||
sha256: installed.sha256,
|
||||
}],
|
||||
return this.admissionResolver.resolve({
|
||||
pluginId: PLUGIN_ID,
|
||||
workerSnapshot: {
|
||||
requestId: context.requestId,
|
||||
...(context.pluginReleaseId === undefined ? {} : { pluginReleaseId: context.pluginReleaseId }),
|
||||
},
|
||||
});
|
||||
const item = resolved.items.find(({ pluginId }) => pluginId === PLUGIN_ID);
|
||||
if (!item?.releaseId || !item.releaseAdmissionId || item.releaseId !== installed.releaseId
|
||||
|| (item.action !== 'keep' && item.action !== 'install')) {
|
||||
throw new GameResourceClientError('plugin_runtime_stale', 409, false, 'Game-resource worker Release is stale');
|
||||
}
|
||||
return { releaseId: item.releaseId, releaseAdmissionId: item.releaseAdmissionId };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user