From dd8ef4dde6ac6604f0c19653e5f719190111feba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Sun, 9 Nov 2025 16:52:43 +0000 Subject: [PATCH] feat(cli): Update to gRPC v2 --- src/cli/apps.cmd.ts | 7 ++++++- src/cli/files.cmd.ts | 12 ++++++----- src/cli/seed.cmd.ts | 12 ++++++----- src/cli/tasks.cmd.ts | 4 ++-- src/cli/utils.ts | 8 ++++---- src/services/grpc/boss/v2/upload-file-ctr.ts | 9 +++++++++ src/services/grpc/boss/v2/upload-file-wup.ts | 21 ++++++++++---------- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/cli/apps.cmd.ts b/src/cli/apps.cmd.ts index 365ce72..0c61434 100644 --- a/src/cli/apps.cmd.ts +++ b/src/cli/apps.cmd.ts @@ -20,6 +20,11 @@ const listCmd = new Command('ls') if (key === 'name') { return prettyTrunc(value, 20); } + + if (key === 'titleId') { + return value.toString(16).toLowerCase().padStart(16, '0'); + } + return value; } }); @@ -41,7 +46,7 @@ const viewCmd = new Command('view') const obj = { appId: app.bossAppId, name: app.name, - titleId: app.titleId, + titleId: app.titleId.toString(16).toLowerCase().padStart(16, '0'), titleRegion: app.titleRegion, knownTasks: app.tasks }; diff --git a/src/cli/files.cmd.ts b/src/cli/files.cmd.ts index 5e51b0f..f0bab7f 100644 --- a/src/cli/files.cmd.ts +++ b/src/cli/files.cmd.ts @@ -4,6 +4,7 @@ import { Readable } from 'node:stream'; import { request } from 'undici'; import { Command } from 'commander'; import { decryptWiiU } from '@pretendonetwork/boss-crypto'; +import { PlatformType } from '@pretendonetwork/grpc/boss/v2/platform_type'; import { commandHandler, getCliContext } from './utils'; import { logOutputList, logOutputObject } from './output'; @@ -14,7 +15,7 @@ const listCmd = new Command('ls') .action(commandHandler<[string, string]>(async (cmd): Promise => { const [appId, taskId] = cmd.args; const ctx = getCliContext(); - const { files } = await ctx.grpc.listFiles({ + const { files } = await ctx.grpc.listFilesWUP({ bossAppId: appId, taskId: taskId }); @@ -38,7 +39,7 @@ const viewCmd = new Command('view') .action(commandHandler<[string, string, bigint]>(async (cmd): Promise => { const [appId, taskId, dataId] = cmd.args; const ctx = getCliContext(); - const { files } = await ctx.grpc.listFiles({ + const { files } = await ctx.grpc.listFilesWUP({ bossAppId: appId, taskId: taskId }); @@ -76,7 +77,7 @@ const downloadCmd = new Command('download') .action(commandHandler<[string, string, bigint]>(async (cmd): Promise => { const [appId, taskId, dataId] = cmd.args; const ctx = getCliContext(); - const { files } = await ctx.grpc.listFiles({ + const { files } = await ctx.grpc.listFilesWUP({ bossAppId: appId, taskId: taskId }); @@ -130,7 +131,7 @@ const createCmd = new Command('create') const opts = cmd.opts<{ name: string; country: string[]; notifyNew: string[]; notifyLed: boolean; lang: string[]; nameAsId?: boolean; type: string; file: string }>(); const fileBuf = await fs.readFile(opts.file); const ctx = getCliContext(); - const { file } = await ctx.grpc.uploadFile({ + const { file } = await ctx.grpc.uploadFileWUP({ taskId: taskId, bossAppId: appId, name: opts.name, @@ -160,7 +161,8 @@ const deleteCmd = new Command('delete') const ctx = getCliContext(); await ctx.grpc.deleteFile({ bossAppId: appId, - dataId: dataId + dataId: dataId, + platformType: PlatformType.PLATFORM_TYPE_WUP }); console.log(`Deleted task file with ID ${dataId}`); })); diff --git a/src/cli/seed.cmd.ts b/src/cli/seed.cmd.ts index 4b1d929..98d5473 100644 --- a/src/cli/seed.cmd.ts +++ b/src/cli/seed.cmd.ts @@ -3,6 +3,7 @@ import fs from 'fs/promises'; import { Command } from 'commander'; import { xml2js } from 'xml-js'; import { decryptWiiU } from '@pretendonetwork/boss-crypto'; +import { PlatformType } from '@pretendonetwork/grpc/boss/v2/platform_type'; import { getCliContext } from './utils'; import { seedFolder } from './root'; import type { CliContext } from './utils'; @@ -31,7 +32,7 @@ export async function uploadFileIfChanged(ops: UploadFileOptions): Promise fileContents = decryptedContents.content; } - const allExistingTaskFiles = await ops.ctx.grpc.listFiles({ + const allExistingTaskFiles = await ops.ctx.grpc.listFilesWUP({ bossAppId: ops.bossAppId, taskId: ops.taskId }); @@ -40,11 +41,12 @@ export async function uploadFileIfChanged(ops: UploadFileOptions): Promise console.warn(`${ops.dataId}: File already uploaded, reuploading`); await ops.ctx.grpc.deleteFile({ bossAppId: ops.bossAppId, - dataId: BigInt(ops.dataId) + dataId: BigInt(ops.dataId), + platformType: PlatformType.PLATFORM_TYPE_WUP }); } - await ops.ctx.grpc.uploadFile({ + await ops.ctx.grpc.uploadFileWUP({ bossAppId: ops.bossAppId, taskId: ops.taskId, name: ops.fileXml.Filename._text, @@ -78,7 +80,7 @@ export async function processTasksheet(ctx: CliContext, taskFiles: string[], fil await ctx.grpc.registerTask({ bossAppId: bossAppId, id: taskName, - titleId: xmlContents.TaskSheet.TitleId._text, + titleId: BigInt(parseInt(xmlContents.TaskSheet.TitleId._text, 16)), country: 'This value isnt used' }); console.log(`${filename}: Created task`); @@ -87,7 +89,7 @@ export async function processTasksheet(ctx: CliContext, taskFiles: string[], fil bossAppId: bossAppId, id: taskName, updateData: { - titleId: xmlContents.TaskSheet.TitleId._text, + titleId: BigInt(parseInt(xmlContents.TaskSheet.TitleId._text, 16)), status: xmlContents.TaskSheet.ServiceStatus._text } }); diff --git a/src/cli/tasks.cmd.ts b/src/cli/tasks.cmd.ts index ef41894..5b7ac21 100644 --- a/src/cli/tasks.cmd.ts +++ b/src/cli/tasks.cmd.ts @@ -38,7 +38,7 @@ const viewCmd = new Command('view') taskId: task.id, inGameId: task.inGameId, description: task.description, - titleId: task.titleId, + titleId: task.titleId.toString(16).toLowerCase().padStart(16, '0'), bossAppId: task.bossAppId, creatorPid: task.creatorPid, status: task.status, @@ -62,7 +62,7 @@ const createCmd = new Command('create') const { task } = await ctx.grpc.registerTask({ bossAppId: appId, id: opts.id, - titleId: opts.titleId, + titleId: BigInt(parseInt(opts.titleId, 16)), description: opts.desc ?? '', country: 'This value isnt used' }); diff --git a/src/cli/utils.ts b/src/cli/utils.ts index 6d7ab63..06ea1cb 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -1,7 +1,7 @@ -import { BOSSDefinition } from '@pretendonetwork/grpc/boss/boss_service'; +import { BossServiceDefinition } from '@pretendonetwork/grpc/boss/v2/boss_service'; import { createChannel, createClient, Metadata } from 'nice-grpc'; import dotenv from 'dotenv'; -import type { BOSSClient } from '@pretendonetwork/grpc/boss/boss_service'; +import type { BossServiceClient } from '@pretendonetwork/grpc/boss/v2/boss_service'; import type { Command } from 'commander'; import type { FormatOption } from './output'; @@ -12,7 +12,7 @@ export type NpdiUrl = { }; export type CliContext = { - grpc: BOSSClient; + grpc: BossServiceClient; getNpdiUrl: () => NpdiUrl; getWiiUKeys: () => WiiUKeys; }; @@ -30,7 +30,7 @@ export function getCliContext(): CliContext { } const channel = createChannel(grpcHost); - const client: BOSSClient = createClient(BOSSDefinition, channel, { + const client: BossServiceClient = createClient(BossServiceDefinition, channel, { '*': { metadata: new Metadata({ 'X-API-Key': grpcKey diff --git a/src/services/grpc/boss/v2/upload-file-ctr.ts b/src/services/grpc/boss/v2/upload-file-ctr.ts index e9090ad..b787ce6 100644 --- a/src/services/grpc/boss/v2/upload-file-ctr.ts +++ b/src/services/grpc/boss/v2/upload-file-ctr.ts @@ -61,6 +61,15 @@ export async function uploadFileCTR(request: UploadFileCTRRequest, context: Call throw new ServerError(Status.INVALID_ARGUMENT, 'Cannot upload empty file'); } + if (!request.attributes) { + request.attributes = { + attribute1: '', + attribute2: '', + attribute3: '', + description: '' + }; + } + const session = await databaseConnection().startSession(); await session.startTransaction(); diff --git a/src/services/grpc/boss/v2/upload-file-wup.ts b/src/services/grpc/boss/v2/upload-file-wup.ts index 47cde27..6eaf577 100644 --- a/src/services/grpc/boss/v2/upload-file-wup.ts +++ b/src/services/grpc/boss/v2/upload-file-wup.ts @@ -78,6 +78,15 @@ export async function uploadFileWUP(request: UploadFileWUPRequest, context: Call throw new ServerError(Status.INVALID_ARGUMENT, 'Cannot upload empty file'); } + if (!request.attributes) { + request.attributes = { + attribute1: '', + attribute2: '', + attribute3: '', + description: '' + }; + } + let encryptedData: Buffer; try { @@ -129,6 +138,7 @@ export async function uploadFileWUP(request: UploadFileWUPRequest, context: Call file_key: key, supported_countries: supportedCountries, supported_languages: supportedLanguages, + attributes: request.attributes, creator_pid: context.user?.pid, name: name, type: type, @@ -142,17 +152,6 @@ export async function uploadFileWUP(request: UploadFileWUPRequest, context: Call updated: Date.now() }); - if (request.attributes) { - file.attributes = { - attribute1: request.attributes.attribute1, - attribute2: request.attributes.attribute2, - attribute3: request.attributes.attribute3, - description: request.attributes.description - }; - - await file.save(); - } - if (nameEqualsDataID) { file.name = file.data_id.toString(16).padStart(8, '0'); await file.save();