Files
Genarrative/src/services/match3d-runtime/match3dRuntimeClient.ts

179 lines
4.7 KiB
TypeScript

import type {
Match3DClickConfirmation,
Match3DClickItemRequest,
Match3DClickItemResult,
Match3DClickRejectReason,
Match3DClickResponse,
Match3DRunResponse,
StopMatch3DRunRequest,
} from '../../../packages/shared/src/contracts/match3dRuntime';
import {
type ApiRequestOptions,
type ApiRetryOptions,
requestJson,
} from '../apiClient';
const MATCH3D_RUNTIME_READ_RETRY: ApiRetryOptions = {
maxRetries: 1,
baseDelayMs: 120,
maxDelayMs: 360,
};
const MATCH3D_RUNTIME_WRITE_RETRY: ApiRetryOptions = {
maxRetries: 1,
baseDelayMs: 120,
maxDelayMs: 360,
retryUnsafeMethods: true,
};
type Match3DRuntimeRequestOptions = Pick<
ApiRequestOptions,
'skipRefresh' | 'notifyAuthStateChange' | 'clearAuthOnUnauthorized'
>;
function normalizeRejectStatus(reason?: Match3DClickRejectReason | null) {
switch (reason) {
case 'snapshot_version_mismatch':
return 'VersionConflict';
case 'tray_full':
return 'RejectedTrayFull';
case 'run_not_active':
return 'RunFinished';
case 'item_not_found':
case 'item_not_in_board':
return 'RejectedAlreadyMoved';
case 'item_not_clickable':
default:
return 'RejectedNotClickable';
}
}
function mapClickConfirmation(
request: Match3DClickItemRequest,
confirmation: Match3DClickConfirmation,
): Match3DClickItemResult {
return {
status: confirmation.accepted
? 'Accepted'
: normalizeRejectStatus(confirmation.rejectReason),
run: confirmation.run,
acceptedItemInstanceId: confirmation.accepted
? request.itemInstanceId
: undefined,
clearedItemInstanceIds: confirmation.clearedItemInstanceIds,
failureReason: confirmation.run.failureReason,
};
}
/**
* 基于作品启动一局抓大鹅正式 run。
*/
export function startMatch3DRun(
profileId: string,
options: Match3DRuntimeRequestOptions = {},
) {
return requestJson<Match3DRunResponse>(
`/api/runtime/match3d/works/${encodeURIComponent(profileId)}/runs`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ profileId }),
},
'启动抓大鹅玩法失败',
{
retry: MATCH3D_RUNTIME_WRITE_RETRY,
skipRefresh: options.skipRefresh,
notifyAuthStateChange: options.notifyAuthStateChange,
clearAuthOnUnauthorized: options.clearAuthOnUnauthorized,
},
);
}
/**
* 读取抓大鹅运行态快照。
*/
export function getMatch3DRun(runId: string) {
return requestJson<Match3DRunResponse>(
`/api/runtime/match3d/runs/${encodeURIComponent(runId)}`,
{ method: 'GET' },
'读取抓大鹅运行快照失败',
{ retry: MATCH3D_RUNTIME_READ_RETRY },
);
}
/**
* 提交一次点击,由后端做权威确认;返回值适配运行壳已实现的即时反馈语义。
*/
export async function clickMatch3DItem(
runId: string,
payload: Match3DClickItemRequest,
) {
const response = await requestJson<Match3DClickResponse>(
`/api/runtime/match3d/runs/${encodeURIComponent(runId)}/click`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...payload,
runId: payload.runId ?? runId,
}),
},
'确认抓大鹅点击失败',
{ retry: MATCH3D_RUNTIME_WRITE_RETRY },
);
return mapClickConfirmation(payload, response.confirmation);
}
/**
* 停止当前抓大鹅运行态。
*/
export function stopMatch3DRun(
runId: string,
payload: StopMatch3DRunRequest = {
clientActionId: `match3d-stop-${Date.now()}`,
},
) {
return requestJson<Match3DRunResponse>(
`/api/runtime/match3d/runs/${encodeURIComponent(runId)}/stop`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'停止抓大鹅玩法失败',
{ retry: MATCH3D_RUNTIME_WRITE_RETRY },
);
}
/**
* 基于当前 run 重开一局。
*/
export function restartMatch3DRun(runId: string) {
return requestJson<Match3DRunResponse>(
`/api/runtime/match3d/runs/${encodeURIComponent(runId)}/restart`,
{ method: 'POST' },
'重新开始抓大鹅玩法失败',
{ retry: MATCH3D_RUNTIME_WRITE_RETRY },
);
}
/**
* 前端倒计时归零后通知后端确认失败状态。
*/
export function finishMatch3DTimeUp(runId: string) {
return requestJson<Match3DRunResponse>(
`/api/runtime/match3d/runs/${encodeURIComponent(runId)}/time-up`,
{ method: 'POST' },
'同步抓大鹅倒计时失败',
{ retry: MATCH3D_RUNTIME_WRITE_RETRY },
);
}
export const match3dRuntimeClient = {
clickItem: clickMatch3DItem,
finishTimeUp: finishMatch3DTimeUp,
getRun: getMatch3DRun,
restartRun: restartMatch3DRun,
startRun: startMatch3DRun,
stopRun: stopMatch3DRun,
};