hermes/hermes-1e775b03 #13
@@ -6,51 +6,64 @@ import type {
|
||||
} from '../packages/shared/src/contracts/match3dRuntime';
|
||||
import { Match3DRuntimeShell } from './components/match3d-runtime';
|
||||
import {
|
||||
confirmLocalMatch3DClick,
|
||||
resolveLocalMatch3DTimer,
|
||||
createLocalMatch3DRuntimeAdapter,
|
||||
type Match3DRuntimeAdapter,
|
||||
startLocalMatch3DRun,
|
||||
} from './services/match3d-runtime';
|
||||
|
||||
function buildInitialRun() {
|
||||
type LocalMatch3DRuntimeSession = {
|
||||
adapter: Match3DRuntimeAdapter;
|
||||
initialRun: Match3DRunSnapshot;
|
||||
};
|
||||
|
||||
function resolveClearCountParam() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const clearCountParam = params.get('clearCount') ?? params.get('count');
|
||||
const clearCount =
|
||||
clearCountParam === null ? 12 : Number.parseInt(clearCountParam, 10);
|
||||
return startLocalMatch3DRun(
|
||||
Number.isFinite(clearCount) && clearCount > 0 ? clearCount : 12,
|
||||
);
|
||||
return Number.isFinite(clearCount) && clearCount > 0 ? clearCount : 12;
|
||||
}
|
||||
|
||||
function buildInitialRuntimeSession(): LocalMatch3DRuntimeSession {
|
||||
const initialRun = startLocalMatch3DRun(resolveClearCountParam());
|
||||
return {
|
||||
adapter: createLocalMatch3DRuntimeAdapter({ initialRun }),
|
||||
initialRun,
|
||||
};
|
||||
}
|
||||
|
||||
export default function Match3DPlaygroundApp() {
|
||||
const [run, setRun] = useState<Match3DRunSnapshot>(buildInitialRun);
|
||||
const authorityRunRef = useRef(run);
|
||||
const runtimeSessionRef = useRef(buildInitialRuntimeSession());
|
||||
const [run, setRun] = useState<Match3DRunSnapshot>(
|
||||
runtimeSessionRef.current.initialRun,
|
||||
);
|
||||
|
||||
const syncRun = useCallback((nextRun: Match3DRunSnapshot) => {
|
||||
setRun(nextRun);
|
||||
}, []);
|
||||
|
||||
const handleClickItem = useCallback(async (payload: Match3DClickItemRequest) => {
|
||||
const result = await confirmLocalMatch3DClick(authorityRunRef.current, payload);
|
||||
authorityRunRef.current = result.run;
|
||||
const runId = payload.runId ?? runtimeSessionRef.current.initialRun.runId;
|
||||
const result = await runtimeSessionRef.current.adapter.clickItem(runId, payload);
|
||||
setRun(result.run);
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
const handleRestart = useCallback(() => {
|
||||
const nextRun = buildInitialRun();
|
||||
authorityRunRef.current = nextRun;
|
||||
setRun(nextRun);
|
||||
}, []);
|
||||
void runtimeSessionRef.current.adapter.restartRun(run.runId).then(({ run }) => {
|
||||
setRun(run);
|
||||
});
|
||||
}, [run.runId]);
|
||||
|
||||
const handleExit = useCallback(() => {
|
||||
window.location.assign('/');
|
||||
}, []);
|
||||
|
||||
const handleTimeExpired = useCallback(() => {
|
||||
const nextRun = resolveLocalMatch3DTimer(authorityRunRef.current);
|
||||
authorityRunRef.current = nextRun;
|
||||
setRun(nextRun);
|
||||
}, []);
|
||||
void runtimeSessionRef.current.adapter.finishTimeUp(run.runId).then(({ run }) => {
|
||||
setRun(run);
|
||||
});
|
||||
}, [run.runId]);
|
||||
|
||||
return (
|
||||
<Match3DRuntimeShell
|
||||
|
||||
@@ -104,10 +104,6 @@ import {
|
||||
ApiClientError,
|
||||
BACKGROUND_AUTH_REQUEST_OPTIONS,
|
||||
} from '../../services/apiClient';
|
||||
import {
|
||||
fetchCreationEntryConfig,
|
||||
type CreationEntryConfig,
|
||||
} from '../../services/creationEntryConfigService';
|
||||
import {
|
||||
getPublicAuthUserByCode,
|
||||
getPublicAuthUserById,
|
||||
@@ -132,6 +128,10 @@ import {
|
||||
deleteBigFishWork,
|
||||
listBigFishWorks,
|
||||
} from '../../services/big-fish-works';
|
||||
import {
|
||||
type CreationEntryConfig,
|
||||
fetchCreationEntryConfig,
|
||||
} from '../../services/creationEntryConfigService';
|
||||
import {
|
||||
cancelCreativeAgentSession,
|
||||
confirmCreativePuzzleTemplate,
|
||||
@@ -144,13 +144,7 @@ import {
|
||||
shouldRestoreCustomWorldAgentUiState,
|
||||
} from '../../services/customWorldAgentUiState';
|
||||
import { match3dCreationClient } from '../../services/match3d-creation';
|
||||
import {
|
||||
clickMatch3DItem,
|
||||
finishMatch3DTimeUp,
|
||||
restartMatch3DRun,
|
||||
startMatch3DRun,
|
||||
stopMatch3DRun,
|
||||
} from '../../services/match3d-runtime';
|
||||
import { createServerMatch3DRuntimeAdapter } from '../../services/match3d-runtime';
|
||||
import {
|
||||
deleteMatch3DWork,
|
||||
getMatch3DWorkDetail,
|
||||
@@ -2599,6 +2593,10 @@ export function PlatformEntryFlowShellImpl({
|
||||
},
|
||||
});
|
||||
|
||||
const match3dRuntimeAdapter = useMemo(
|
||||
() => createServerMatch3DRuntimeAdapter(),
|
||||
[],
|
||||
);
|
||||
const match3dFlow = usePlatformCreationAgentFlowController<
|
||||
Match3DAgentSessionSnapshot,
|
||||
CreateMatch3DSessionRequest,
|
||||
@@ -4376,11 +4374,11 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
try {
|
||||
const { run } = options.embedded
|
||||
? await startMatch3DRun(
|
||||
? await match3dRuntimeAdapter.startRun(
|
||||
profile.profileId,
|
||||
RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS,
|
||||
)
|
||||
: await startMatch3DRun(profile.profileId);
|
||||
: await match3dRuntimeAdapter.startRun(profile.profileId);
|
||||
setMatch3DRun(run);
|
||||
setMatch3DRuntimeReturnStage(returnStage);
|
||||
if (!options.embedded) {
|
||||
@@ -4412,6 +4410,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
[
|
||||
isMatch3DBusy,
|
||||
match3dFlow,
|
||||
match3dRuntimeAdapter,
|
||||
resolveMatch3DErrorMessage,
|
||||
setMatch3DError,
|
||||
setSelectionStage,
|
||||
@@ -6671,7 +6670,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
match3dFlow.setIsBusy(true);
|
||||
setMatch3DError(null);
|
||||
void restartMatch3DRun(match3dRun.runId)
|
||||
void match3dRuntimeAdapter.restartRun(match3dRun.runId)
|
||||
.then(({ run }) => {
|
||||
setMatch3DRun(run);
|
||||
})
|
||||
@@ -6693,14 +6692,14 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (!runId) {
|
||||
return Promise.reject(new Error('抓大鹅运行态缺少 runId。'));
|
||||
}
|
||||
return clickMatch3DItem(runId, payload);
|
||||
return match3dRuntimeAdapter.clickItem(runId, payload);
|
||||
}}
|
||||
onTimeExpired={() => {
|
||||
if (!match3dRun?.runId) {
|
||||
return;
|
||||
}
|
||||
|
||||
void finishMatch3DTimeUp(match3dRun.runId)
|
||||
void match3dRuntimeAdapter.finishTimeUp(match3dRun.runId)
|
||||
.then(({ run }) => {
|
||||
setMatch3DRun(run);
|
||||
})
|
||||
@@ -6868,6 +6867,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
match3dError,
|
||||
match3dFlow,
|
||||
match3dRun,
|
||||
match3dRuntimeAdapter,
|
||||
platformBootstrap.platformTab,
|
||||
platformThemeClass,
|
||||
puzzleError,
|
||||
@@ -8560,7 +8560,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
error={match3dError}
|
||||
onBack={() => {
|
||||
if (match3dRun?.runId && match3dRun.status === 'running') {
|
||||
void stopMatch3DRun(match3dRun.runId).catch(
|
||||
void match3dRuntimeAdapter.stopRun(match3dRun.runId).catch(
|
||||
() => undefined,
|
||||
);
|
||||
}
|
||||
@@ -8573,7 +8573,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
match3dFlow.setIsBusy(true);
|
||||
setMatch3DError(null);
|
||||
void restartMatch3DRun(match3dRun.runId)
|
||||
void match3dRuntimeAdapter.restartRun(match3dRun.runId)
|
||||
.then(({ run }) => {
|
||||
setMatch3DRun(run);
|
||||
})
|
||||
@@ -8597,14 +8597,14 @@ export function PlatformEntryFlowShellImpl({
|
||||
new Error('抓大鹅运行态缺少 runId。'),
|
||||
);
|
||||
}
|
||||
return clickMatch3DItem(runId, payload);
|
||||
return match3dRuntimeAdapter.clickItem(runId, payload);
|
||||
}}
|
||||
onTimeExpired={() => {
|
||||
if (!match3dRun?.runId) {
|
||||
return;
|
||||
}
|
||||
|
||||
void finishMatch3DTimeUp(match3dRun.runId)
|
||||
void match3dRuntimeAdapter.finishTimeUp(match3dRun.runId)
|
||||
.then(({ run }) => {
|
||||
setMatch3DRun(run);
|
||||
})
|
||||
|
||||
@@ -54,6 +54,7 @@ import {
|
||||
import { match3dCreationClient } from '../../services/match3d-creation';
|
||||
import {
|
||||
clickMatch3DItem,
|
||||
createServerMatch3DRuntimeAdapter,
|
||||
finishMatch3DTimeUp,
|
||||
restartMatch3DRun,
|
||||
startMatch3DRun,
|
||||
@@ -348,14 +349,35 @@ vi.mock('../../services/match3d-works', () => ({
|
||||
listMatch3DWorks: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/match3d-runtime', () => ({
|
||||
const match3dRuntimeServiceMocks = vi.hoisted(() => ({
|
||||
clickMatch3DItem: vi.fn(),
|
||||
createServerMatch3DRuntimeAdapter: vi.fn(),
|
||||
finishMatch3DTimeUp: vi.fn(),
|
||||
restartMatch3DRun: vi.fn(),
|
||||
startMatch3DRun: vi.fn(),
|
||||
stopMatch3DRun: vi.fn(),
|
||||
}));
|
||||
|
||||
const match3dServerRuntimeAdapterMock = vi.hoisted(() => ({
|
||||
clickItem: vi.fn(),
|
||||
finishTimeUp: vi.fn(),
|
||||
getRun: vi.fn(),
|
||||
restartRun: vi.fn(),
|
||||
startRun: vi.fn(),
|
||||
stopRun: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/match3d-runtime', async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import('../../services/match3d-runtime')
|
||||
>('../../services/match3d-runtime');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
...match3dRuntimeServiceMocks,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../services/square-hole-creation', () => ({
|
||||
squareHoleCreationClient: {
|
||||
createSession: vi.fn(),
|
||||
@@ -1453,6 +1475,24 @@ function TestWrapper({
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.mocked(createServerMatch3DRuntimeAdapter).mockReturnValue(
|
||||
match3dServerRuntimeAdapterMock,
|
||||
);
|
||||
match3dServerRuntimeAdapterMock.startRun.mockRejectedValue(
|
||||
new Error('未启动抓大鹅运行态'),
|
||||
);
|
||||
match3dServerRuntimeAdapterMock.clickItem.mockRejectedValue(
|
||||
new Error('未执行抓大鹅点击'),
|
||||
);
|
||||
match3dServerRuntimeAdapterMock.restartRun.mockRejectedValue(
|
||||
new Error('未重新开始抓大鹅运行态'),
|
||||
);
|
||||
match3dServerRuntimeAdapterMock.finishTimeUp.mockResolvedValue({
|
||||
run: buildMockMatch3DRun('match3d-profile-time-up'),
|
||||
});
|
||||
match3dServerRuntimeAdapterMock.stopRun.mockResolvedValue({
|
||||
run: buildMockMatch3DRun('match3d-profile-stopped'),
|
||||
});
|
||||
window.history.replaceState(null, '', '/');
|
||||
window.sessionStorage.clear();
|
||||
window.localStorage.clear();
|
||||
@@ -4465,7 +4505,7 @@ test('public code search opens a published Match3D work by M3 code and starts ru
|
||||
vi.mocked(listMatch3DGallery).mockResolvedValue({
|
||||
items: [match3dWork],
|
||||
});
|
||||
vi.mocked(startMatch3DRun).mockResolvedValue({
|
||||
match3dServerRuntimeAdapterMock.startRun.mockResolvedValue({
|
||||
run: buildMockMatch3DRun(match3dWork.profileId),
|
||||
});
|
||||
|
||||
@@ -4483,7 +4523,9 @@ test('public code search opens a published Match3D work by M3 code and starts ru
|
||||
await user.click(screen.getByRole('button', { name: '启动' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(startMatch3DRun).toHaveBeenCalledWith('match3d-profile-public-1');
|
||||
expect(match3dServerRuntimeAdapterMock.startRun).toHaveBeenCalledWith(
|
||||
'match3d-profile-public-1',
|
||||
);
|
||||
});
|
||||
expect(
|
||||
await screen.findByText('抓大鹅运行态:match3d-run-match3d-profile-public-1'),
|
||||
|
||||
@@ -6,6 +6,11 @@ export {
|
||||
startLocalMatch3DRun,
|
||||
stopLocalMatch3DRun,
|
||||
} from './match3dLocalRuntime';
|
||||
export {
|
||||
createLocalMatch3DRuntimeAdapter,
|
||||
createServerMatch3DRuntimeAdapter,
|
||||
type Match3DRuntimeAdapter,
|
||||
} from './match3dRuntimeAdapter';
|
||||
export {
|
||||
clickMatch3DItem,
|
||||
finishMatch3DTimeUp,
|
||||
|
||||
@@ -481,12 +481,17 @@ export function buildLocalMatch3DOptimisticRun(
|
||||
};
|
||||
}
|
||||
|
||||
function waitForLocalConfirmation(delayMs: number) {
|
||||
const scheduler = globalThis.setTimeout;
|
||||
return new Promise((resolve) => scheduler(resolve, delayMs));
|
||||
}
|
||||
|
||||
export async function confirmLocalMatch3DClick(
|
||||
run: Match3DRunSnapshot,
|
||||
request: Match3DClickItemRequest,
|
||||
): Promise<Match3DClickItemResult> {
|
||||
// 中文注释:F3 阶段用本地函数模拟后端权威确认,真实接口接入后保留同一结果语义。
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 180));
|
||||
await waitForLocalConfirmation(180);
|
||||
const timedRun = normalizeRemainingMs(run);
|
||||
if (timedRun.status !== 'Running') {
|
||||
return {
|
||||
|
||||
144
src/services/match3d-runtime/match3dRuntimeAdapter.test.ts
Normal file
144
src/services/match3d-runtime/match3dRuntimeAdapter.test.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import type {
|
||||
Match3DClickItemRequest,
|
||||
Match3DRunResponse,
|
||||
Match3DRunSnapshot,
|
||||
} from '../../../packages/shared/src/contracts/match3dRuntime';
|
||||
import {
|
||||
createLocalMatch3DRuntimeAdapter,
|
||||
createServerMatch3DRuntimeAdapter,
|
||||
type Match3DRuntimeAdapter,
|
||||
startLocalMatch3DRun,
|
||||
} from './index';
|
||||
|
||||
function buildMockRun(runId: string): Match3DRunSnapshot {
|
||||
return {
|
||||
runId,
|
||||
profileId: 'server-profile-1',
|
||||
ownerUserId: 'server-owner-1',
|
||||
status: 'Running',
|
||||
snapshotVersion: 1,
|
||||
startedAtMs: 1_700_000_000_000,
|
||||
durationLimitMs: 30_000,
|
||||
serverNowMs: 1_700_000_000_000,
|
||||
remainingMs: 30_000,
|
||||
clearCount: 3,
|
||||
totalItemCount: 0,
|
||||
clearedItemCount: 0,
|
||||
boardVersion: 1,
|
||||
items: [],
|
||||
traySlots: [],
|
||||
failureReason: null,
|
||||
lastConfirmedActionId: null,
|
||||
};
|
||||
}
|
||||
|
||||
test('server Match3D runtime adapter forwards the full runtime seam lazily', async () => {
|
||||
const startResponse: Match3DRunResponse = { run: buildMockRun('server-run-start') };
|
||||
const getResponse: Match3DRunResponse = { run: buildMockRun('server-run-get') };
|
||||
const restartResponse: Match3DRunResponse = { run: buildMockRun('server-run-restart') };
|
||||
const stopResponse: Match3DRunResponse = {
|
||||
run: { ...buildMockRun('server-run-stop'), status: 'Stopped' },
|
||||
};
|
||||
const finishResponse: Match3DRunResponse = {
|
||||
run: { ...buildMockRun('server-run-finish'), status: 'Timeout' },
|
||||
};
|
||||
const clickPayload: Match3DClickItemRequest = {
|
||||
runId: 'server-run-start',
|
||||
itemInstanceId: 'item-1',
|
||||
clientActionId: 'action-1',
|
||||
clientEventId: 'event-1',
|
||||
clickedAtMs: 1_700_000_000_001,
|
||||
clientSnapshotVersion: 1,
|
||||
};
|
||||
const dependencies = {
|
||||
clickItem: vi.fn().mockResolvedValue({
|
||||
status: 'Accepted' as const,
|
||||
run: buildMockRun('server-run-click'),
|
||||
}),
|
||||
finishTimeUp: vi.fn().mockResolvedValue(finishResponse),
|
||||
getRun: vi.fn().mockResolvedValue(getResponse),
|
||||
restartRun: vi.fn().mockResolvedValue(restartResponse),
|
||||
startRun: vi.fn().mockResolvedValue(startResponse),
|
||||
stopRun: vi.fn().mockResolvedValue(stopResponse),
|
||||
};
|
||||
const adapter = createServerMatch3DRuntimeAdapter(dependencies);
|
||||
|
||||
expect(await adapter.startRun('server-profile-1', { skipRefresh: true })).toBe(
|
||||
startResponse,
|
||||
);
|
||||
expect(await adapter.getRun('server-run-start')).toBe(getResponse);
|
||||
expect(await adapter.clickItem('server-run-start', clickPayload)).toEqual({
|
||||
status: 'Accepted',
|
||||
run: buildMockRun('server-run-click'),
|
||||
});
|
||||
expect(await adapter.restartRun('server-run-start')).toBe(restartResponse);
|
||||
expect(await adapter.stopRun('server-run-restart')).toBe(stopResponse);
|
||||
expect(await adapter.finishTimeUp('server-run-start')).toBe(finishResponse);
|
||||
|
||||
expect(dependencies.startRun).toHaveBeenCalledWith('server-profile-1', {
|
||||
skipRefresh: true,
|
||||
});
|
||||
expect(dependencies.getRun).toHaveBeenCalledWith('server-run-start');
|
||||
expect(dependencies.clickItem).toHaveBeenCalledWith(
|
||||
'server-run-start',
|
||||
clickPayload,
|
||||
);
|
||||
expect(dependencies.restartRun).toHaveBeenCalledWith('server-run-start');
|
||||
expect(dependencies.stopRun).toHaveBeenCalledWith('server-run-restart');
|
||||
expect(dependencies.finishTimeUp).toHaveBeenCalledWith('server-run-start');
|
||||
});
|
||||
|
||||
test('local Match3D runtime adapter exposes the same runtime seam as the server client', async () => {
|
||||
const adapter = createLocalMatch3DRuntimeAdapter({ clearCount: 1 });
|
||||
const started = await adapter.startRun('ignored-local-profile');
|
||||
const clickableItem = started.run.items.find((item) => item.clickable);
|
||||
|
||||
expect(started.run.profileId).toBe('local-match3d-profile');
|
||||
expect(clickableItem).toBeTruthy();
|
||||
|
||||
const clickResult = await adapter.clickItem(started.run.runId, {
|
||||
runId: started.run.runId,
|
||||
itemInstanceId: clickableItem!.itemInstanceId,
|
||||
clientActionId: 'local-click-1',
|
||||
clientEventId: 'local-event-1',
|
||||
clickedAtMs: started.run.serverNowMs ?? Date.now(),
|
||||
clientSnapshotVersion: started.run.snapshotVersion,
|
||||
});
|
||||
|
||||
expect(clickResult.status).toBe('Accepted');
|
||||
expect(clickResult.run.snapshotVersion).toBe(started.run.snapshotVersion + 1);
|
||||
|
||||
const restarted = await adapter.restartRun(started.run.runId);
|
||||
expect(restarted.run.runId).not.toBe(started.run.runId);
|
||||
|
||||
const stopped = await adapter.stopRun(restarted.run.runId);
|
||||
expect(stopped.run.status).toBe('Stopped');
|
||||
});
|
||||
|
||||
test('local Match3D runtime adapter keeps authority run local to the adapter', async () => {
|
||||
const adapter = createLocalMatch3DRuntimeAdapter({ initialRun: startLocalMatch3DRun(1) });
|
||||
const first = await adapter.getRun('unused-run-id');
|
||||
const timedOut = await adapter.finishTimeUp(first.run.runId);
|
||||
|
||||
expect(timedOut.run.status).toBe('Running');
|
||||
expect(timedOut.run.runId).toBe(first.run.runId);
|
||||
});
|
||||
|
||||
test('server and local Match3D runtime adapters share the same runtime seam', () => {
|
||||
const adapters: Match3DRuntimeAdapter[] = [
|
||||
createLocalMatch3DRuntimeAdapter({ clearCount: 1 }),
|
||||
createServerMatch3DRuntimeAdapter(),
|
||||
];
|
||||
|
||||
expect(adapters).toHaveLength(2);
|
||||
for (const adapter of adapters) {
|
||||
expect(typeof adapter.startRun).toBe('function');
|
||||
expect(typeof adapter.getRun).toBe('function');
|
||||
expect(typeof adapter.clickItem).toBe('function');
|
||||
expect(typeof adapter.restartRun).toBe('function');
|
||||
expect(typeof adapter.stopRun).toBe('function');
|
||||
expect(typeof adapter.finishTimeUp).toBe('function');
|
||||
}
|
||||
});
|
||||
106
src/services/match3d-runtime/match3dRuntimeAdapter.ts
Normal file
106
src/services/match3d-runtime/match3dRuntimeAdapter.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type {
|
||||
Match3DClickItemRequest,
|
||||
Match3DClickItemResult,
|
||||
Match3DRunResponse,
|
||||
} from '../../../packages/shared/src/contracts/match3dRuntime';
|
||||
import {
|
||||
confirmLocalMatch3DClick,
|
||||
resolveLocalMatch3DTimer,
|
||||
startLocalMatch3DRun,
|
||||
stopLocalMatch3DRun,
|
||||
} from './match3dLocalRuntime';
|
||||
import {
|
||||
clickMatch3DItem,
|
||||
finishMatch3DTimeUp,
|
||||
getMatch3DRun,
|
||||
type Match3DRuntimeRequestOptions,
|
||||
restartMatch3DRun,
|
||||
startMatch3DRun,
|
||||
stopMatch3DRun,
|
||||
} from './match3dRuntimeClient';
|
||||
|
||||
export type Match3DRuntimeAdapter = {
|
||||
startRun: (
|
||||
profileId: string,
|
||||
options?: Match3DRuntimeRequestOptions,
|
||||
) => Promise<Match3DRunResponse>;
|
||||
getRun: (runId: string) => Promise<Match3DRunResponse>;
|
||||
clickItem: (
|
||||
runId: string,
|
||||
payload: Match3DClickItemRequest,
|
||||
) => Promise<Match3DClickItemResult>;
|
||||
restartRun: (runId: string) => Promise<Match3DRunResponse>;
|
||||
stopRun: (runId: string) => Promise<Match3DRunResponse>;
|
||||
finishTimeUp: (runId: string) => Promise<Match3DRunResponse>;
|
||||
};
|
||||
|
||||
export type LocalMatch3DRuntimeAdapterOptions = {
|
||||
clearCount?: number;
|
||||
initialRun?: Match3DRunResponse['run'];
|
||||
};
|
||||
|
||||
type ServerMatch3DRuntimeAdapterDependencies = {
|
||||
clickItem: typeof clickMatch3DItem;
|
||||
finishTimeUp: typeof finishMatch3DTimeUp;
|
||||
getRun: typeof getMatch3DRun;
|
||||
restartRun: typeof restartMatch3DRun;
|
||||
startRun: typeof startMatch3DRun;
|
||||
stopRun: typeof stopMatch3DRun;
|
||||
};
|
||||
|
||||
const defaultServerMatch3DRuntimeAdapterDependencies: ServerMatch3DRuntimeAdapterDependencies = {
|
||||
clickItem: clickMatch3DItem,
|
||||
finishTimeUp: finishMatch3DTimeUp,
|
||||
getRun: getMatch3DRun,
|
||||
restartRun: restartMatch3DRun,
|
||||
startRun: startMatch3DRun,
|
||||
stopRun: stopMatch3DRun,
|
||||
};
|
||||
|
||||
export function createServerMatch3DRuntimeAdapter(
|
||||
dependencies: ServerMatch3DRuntimeAdapterDependencies =
|
||||
defaultServerMatch3DRuntimeAdapterDependencies,
|
||||
): Match3DRuntimeAdapter {
|
||||
return {
|
||||
clickItem: (runId, payload) => dependencies.clickItem(runId, payload),
|
||||
finishTimeUp: (runId) => dependencies.finishTimeUp(runId),
|
||||
getRun: (runId) => dependencies.getRun(runId),
|
||||
restartRun: (runId) => dependencies.restartRun(runId),
|
||||
startRun: (profileId, options) => dependencies.startRun(profileId, options),
|
||||
stopRun: (runId) => dependencies.stopRun(runId),
|
||||
};
|
||||
}
|
||||
|
||||
export function createLocalMatch3DRuntimeAdapter(
|
||||
options: LocalMatch3DRuntimeAdapterOptions = {},
|
||||
): Match3DRuntimeAdapter {
|
||||
let authorityRun = options.initialRun ?? startLocalMatch3DRun(options.clearCount);
|
||||
|
||||
return {
|
||||
async startRun() {
|
||||
authorityRun = startLocalMatch3DRun(options.clearCount);
|
||||
return { run: authorityRun };
|
||||
},
|
||||
async getRun() {
|
||||
authorityRun = resolveLocalMatch3DTimer(authorityRun);
|
||||
return { run: authorityRun };
|
||||
},
|
||||
async clickItem(_runId, payload) {
|
||||
const result = await confirmLocalMatch3DClick(authorityRun, payload);
|
||||
authorityRun = result.run;
|
||||
return result;
|
||||
},
|
||||
async restartRun() {
|
||||
authorityRun = startLocalMatch3DRun(options.clearCount);
|
||||
return { run: authorityRun };
|
||||
},
|
||||
async stopRun() {
|
||||
authorityRun = stopLocalMatch3DRun(authorityRun);
|
||||
return { run: authorityRun };
|
||||
},
|
||||
async finishTimeUp() {
|
||||
authorityRun = resolveLocalMatch3DTimer(authorityRun);
|
||||
return { run: authorityRun };
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -24,7 +24,7 @@ const MATCH3D_RUNTIME_WRITE_RETRY: ApiRetryOptions = {
|
||||
maxDelayMs: 360,
|
||||
retryUnsafeMethods: true,
|
||||
};
|
||||
type Match3DRuntimeRequestOptions = Pick<
|
||||
export type Match3DRuntimeRequestOptions = Pick<
|
||||
ApiRequestOptions,
|
||||
| 'authImpact'
|
||||
| 'skipRefresh'
|
||||
|
||||
Reference in New Issue
Block a user