This commit is contained in:
162
src/services/match3d-runtime/match3dRuntimeClient.ts
Normal file
162
src/services/match3d-runtime/match3dRuntimeClient.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import type {
|
||||
Match3DClickConfirmation,
|
||||
Match3DClickItemRequest,
|
||||
Match3DClickItemResult,
|
||||
Match3DClickRejectReason,
|
||||
Match3DClickResponse,
|
||||
Match3DRunResponse,
|
||||
StopMatch3DRunRequest,
|
||||
} from '../../../packages/shared/src/contracts/match3dRuntime';
|
||||
import { 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,
|
||||
};
|
||||
|
||||
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) {
|
||||
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 },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取抓大鹅运行态快照。
|
||||
*/
|
||||
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,
|
||||
};
|
||||
Reference in New Issue
Block a user