mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
fix websocket refactor mess
This commit is contained in:
parent
fea21b5057
commit
53639a8448
19 changed files with 179 additions and 209 deletions
|
|
@ -1,7 +1,6 @@
|
|||
const captured = vi.hoisted(() => ({
|
||||
wsOptions: null as WebSocketServiceConfig | null,
|
||||
pbOptions: null as SocketTransport | null,
|
||||
pbEvents: null as EventRegistries | null,
|
||||
}));
|
||||
|
||||
vi.mock('./services/WebSocketService', () => ({
|
||||
|
|
@ -18,9 +17,8 @@ vi.mock('./services/WebSocketService', () => ({
|
|||
}));
|
||||
|
||||
vi.mock('./services/ProtobufService', () => ({
|
||||
ProtobufService: vi.fn().mockImplementation(function ProtobufServiceImpl(transport: SocketTransport, events: EventRegistries) {
|
||||
ProtobufService: vi.fn().mockImplementation(function ProtobufServiceImpl(transport: SocketTransport) {
|
||||
captured.pbOptions = transport;
|
||||
captured.pbEvents = events;
|
||||
return {
|
||||
handleMessageEvent: vi.fn(),
|
||||
resetCommands: vi.fn(),
|
||||
|
|
@ -34,10 +32,10 @@ import { ProtobufService } from './services/ProtobufService';
|
|||
import { StatusEnum } from './interfaces/StatusEnum';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Mock } from 'vitest';
|
||||
import { SocketTransport, EventRegistries } from './services/ProtobufService';
|
||||
import { SocketTransport } from './services/ProtobufService';
|
||||
import { WebSocketServiceConfig } from './services/WebSocketService';
|
||||
import type { IWebClientResponse } from './interfaces';
|
||||
import type { WebClientConfig, ConnectTarget } from './interfaces/WebClientConfig';
|
||||
import type { IWebClientResponse, IWebClientRequest } from './interfaces';
|
||||
import type { ConnectTarget } from './interfaces/WebClientConfig';
|
||||
import { installMockWebSocket } from './__mocks__/helpers';
|
||||
|
||||
function makeMockResponse(): IWebClientResponse {
|
||||
|
|
@ -58,28 +56,21 @@ function makeMockResponse(): IWebClientResponse {
|
|||
} as unknown as IWebClientResponse;
|
||||
}
|
||||
|
||||
function makeMockConfig(response: IWebClientResponse): WebClientConfig {
|
||||
return {
|
||||
response,
|
||||
sessionEvents: [],
|
||||
roomEvents: [],
|
||||
gameEvents: [],
|
||||
keepAliveFn: vi.fn(),
|
||||
};
|
||||
function makeMockRequest(): IWebClientRequest {
|
||||
return {} as IWebClientRequest;
|
||||
}
|
||||
|
||||
describe('WebClient', () => {
|
||||
let client: WebClient;
|
||||
let mockResponse: IWebClientResponse;
|
||||
let mockConfig: WebClientConfig;
|
||||
let mockRequest: IWebClientRequest;
|
||||
let messageSubject: Subject<MessageEvent>;
|
||||
|
||||
beforeEach(() => {
|
||||
(WebClient as unknown as { _instance: WebClient | null })._instance = null;
|
||||
|
||||
(ProtobufService as Mock).mockImplementation(function ProtobufServiceImpl(transport: SocketTransport, events: EventRegistries) {
|
||||
(ProtobufService as Mock).mockImplementation(function ProtobufServiceImpl(transport: SocketTransport) {
|
||||
captured.pbOptions = transport;
|
||||
captured.pbEvents = events;
|
||||
return {
|
||||
handleMessageEvent: vi.fn(),
|
||||
resetCommands: vi.fn(),
|
||||
|
|
@ -99,8 +90,8 @@ describe('WebClient', () => {
|
|||
vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
mockResponse = makeMockResponse();
|
||||
mockConfig = makeMockConfig(mockResponse);
|
||||
client = new WebClient(mockConfig);
|
||||
mockRequest = makeMockRequest();
|
||||
client = new WebClient(mockRequest, mockResponse);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -109,9 +100,9 @@ describe('WebClient', () => {
|
|||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('stores the response and config on the instance', () => {
|
||||
it('stores the request and response on the instance', () => {
|
||||
expect(client.request).toBe(mockRequest);
|
||||
expect(client.response).toBe(mockResponse);
|
||||
expect(client.config).toBe(mockConfig);
|
||||
});
|
||||
|
||||
it('subscribes socket.message$ to protobuf.handleMessageEvent', () => {
|
||||
|
|
@ -129,7 +120,7 @@ describe('WebClient', () => {
|
|||
});
|
||||
|
||||
it('throws when instantiated more than once', () => {
|
||||
expect(() => new WebClient(makeMockConfig(makeMockResponse()))).toThrow(/singleton/);
|
||||
expect(() => new WebClient(makeMockRequest(), makeMockResponse())).toThrow(/singleton/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -224,10 +215,9 @@ describe('WebClient', () => {
|
|||
});
|
||||
|
||||
describe('constructor closures', () => {
|
||||
it('keepAliveFn forwards from config to WebSocketService', () => {
|
||||
const cb = vi.fn();
|
||||
captured.wsOptions!.keepAliveFn(cb);
|
||||
expect(mockConfig.keepAliveFn).toHaveBeenCalledWith(cb);
|
||||
it('keepAliveFn is set to ping function in WebSocketService', () => {
|
||||
expect(captured.wsOptions!.keepAliveFn).toBeDefined();
|
||||
expect(typeof captured.wsOptions!.keepAliveFn).toBe('function');
|
||||
});
|
||||
|
||||
it('onStatusChange routes to response.session.updateStatus and updates own status', () => {
|
||||
|
|
@ -241,12 +231,6 @@ describe('WebClient', () => {
|
|||
expect(mockResponse.session.connectionFailed).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('passes event registries from config to ProtobufService', () => {
|
||||
expect(captured.pbEvents!.sessionEvents).toBe(mockConfig.sessionEvents);
|
||||
expect(captured.pbEvents!.roomEvents).toBe(mockConfig.roomEvents);
|
||||
expect(captured.pbEvents!.gameEvents).toBe(mockConfig.gameEvents);
|
||||
});
|
||||
|
||||
it('send closure delegates to socket.send', () => {
|
||||
const data = new Uint8Array([1, 2, 3]);
|
||||
captured.pbOptions!.send(data);
|
||||
|
|
|
|||
|
|
@ -1,39 +1,40 @@
|
|||
import { StatusEnum } from './interfaces/StatusEnum';
|
||||
import { ping } from './commands/session';
|
||||
import { CLIENT_OPTIONS } from './config';
|
||||
import type {
|
||||
ConnectTarget,
|
||||
IWebClientRequest,
|
||||
IWebClientResponse,
|
||||
} from './interfaces';
|
||||
import { StatusEnum } from './interfaces';
|
||||
import { ProtobufService } from './services/ProtobufService';
|
||||
import { WebSocketService } from './services/WebSocketService';
|
||||
import { CLIENT_OPTIONS } from './config';
|
||||
import type { IWebClientResponse } from './interfaces';
|
||||
import type { WebClientConfig, ConnectTarget } from './interfaces/WebClientConfig';
|
||||
|
||||
export class WebClient {
|
||||
private static _instance: WebClient | null = null;
|
||||
|
||||
public static get instance(): WebClient {
|
||||
static get instance(): WebClient {
|
||||
if (!WebClient._instance) {
|
||||
throw new Error(
|
||||
'WebClient has not been initialized. Instantiate it via `new WebClient(config)` before accessing `WebClient.instance`.'
|
||||
'WebClient has not been initialized. Instantiate it via `new WebClient()` before accessing `WebClient.instance`.'
|
||||
);
|
||||
}
|
||||
return WebClient._instance;
|
||||
}
|
||||
|
||||
public socket: WebSocketService;
|
||||
public protobuf: ProtobufService;
|
||||
public response: IWebClientResponse;
|
||||
public config: WebClientConfig;
|
||||
protobuf: ProtobufService;
|
||||
socket: WebSocketService;
|
||||
status: StatusEnum;
|
||||
|
||||
public status: StatusEnum;
|
||||
|
||||
constructor(config: WebClientConfig) {
|
||||
constructor(
|
||||
public request: IWebClientRequest,
|
||||
public response: IWebClientResponse
|
||||
) {
|
||||
if (WebClient._instance) {
|
||||
throw new Error('WebClient is a singleton and has already been initialized.');
|
||||
}
|
||||
|
||||
this.config = config;
|
||||
this.response = config.response;
|
||||
|
||||
this.socket = new WebSocketService({
|
||||
keepAliveFn: config.keepAliveFn,
|
||||
keepAliveFn: ping,
|
||||
onStatusChange: (status, description) => {
|
||||
this.response.session.updateStatus(status, description);
|
||||
this.updateStatus(status);
|
||||
|
|
@ -47,12 +48,7 @@ export class WebClient {
|
|||
{
|
||||
send: (data) => this.socket.send(data),
|
||||
isOpen: () => this.socket.checkReadyState(WebSocket.OPEN),
|
||||
},
|
||||
{
|
||||
sessionEvents: config.sessionEvents,
|
||||
roomEvents: config.roomEvents,
|
||||
gameEvents: config.gameEvents,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.socket.message$.subscribe((message: MessageEvent) => {
|
||||
|
|
|
|||
|
|
@ -17,3 +17,7 @@ export type {
|
|||
IModeratorRequest,
|
||||
IWebClientRequest,
|
||||
} from './WebClientRequest';
|
||||
|
||||
export * from './WebClientConfig';
|
||||
export * from './WebSocketConfig';
|
||||
export * from './StatusEnum';
|
||||
|
|
|
|||
|
|
@ -7,13 +7,25 @@ vi.mock('@bufbuild/protobuf', async (importOriginal) => ({
|
|||
setExtension: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../WebClient');
|
||||
vi.mock('../events/game', () => ({
|
||||
GameEvents: [],
|
||||
}));
|
||||
|
||||
vi.mock('../events/room', () => ({
|
||||
RoomEvents: [],
|
||||
}));
|
||||
|
||||
vi.mock('../events/session', () => ({
|
||||
SessionEvents: [],
|
||||
}));
|
||||
|
||||
import { create, fromBinary, hasExtension, getExtension } from '@bufbuild/protobuf';
|
||||
import type { GenExtension } from '@bufbuild/protobuf/codegenv2';
|
||||
|
||||
import { ProtobufService } from './ProtobufService';
|
||||
import type { EventRegistries } from './ProtobufService';
|
||||
import { GameEvents } from '../events/game';
|
||||
import { RoomEvents } from '../events/room';
|
||||
import { SessionEvents } from '../events/session';
|
||||
|
||||
import type {
|
||||
AdminCommand,
|
||||
|
|
@ -43,18 +55,17 @@ type ProtobufInternal = ProtobufService & {
|
|||
};
|
||||
|
||||
let mockSocket: { isOpen: ReturnType<typeof vi.fn>; send: ReturnType<typeof vi.fn> };
|
||||
let mockEvents: EventRegistries;
|
||||
|
||||
beforeEach(() => {
|
||||
mockSocket = {
|
||||
isOpen: vi.fn().mockReturnValue(true),
|
||||
send: vi.fn(),
|
||||
};
|
||||
mockEvents = {
|
||||
sessionEvents: [],
|
||||
roomEvents: [],
|
||||
gameEvents: [],
|
||||
};
|
||||
|
||||
// Reset event registries
|
||||
(GameEvents as any).length = 0;
|
||||
(RoomEvents as any).length = 0;
|
||||
(SessionEvents as any).length = 0;
|
||||
});
|
||||
|
||||
describe('ProtobufService', () => {
|
||||
|
|
@ -67,7 +78,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('resetCommands', () => {
|
||||
it('resets cmdId and pendingCommands', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendSessionCommand(sessionExt, vi.fn());
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
service.resetCommands();
|
||||
|
|
@ -78,7 +89,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendCommand', () => {
|
||||
it('increments cmdId and stores callback', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendCommand(create(CommandContainerSchema), cb);
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
|
|
@ -86,14 +97,14 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('sends encoded data when socket is OPEN', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
mockSocket.isOpen.mockReturnValue(true);
|
||||
service.sendCommand(create(CommandContainerSchema), vi.fn());
|
||||
expect(mockSocket.send).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not register callback or increment cmdId when transport is closed', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
mockSocket.isOpen.mockReturnValue(false);
|
||||
const cb = vi.fn();
|
||||
service.sendCommand(create(CommandContainerSchema), cb);
|
||||
|
|
@ -105,14 +116,14 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendSessionCommand', () => {
|
||||
it('stores callback and increments cmdId', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendSessionCommand(sessionExt, {});
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
expect((service as ProtobufInternal).pendingCommands.get(1)).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
it('invokes onResponse with raw response when the pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendSessionCommand(sessionExt, {}, { onResponse: cb });
|
||||
|
||||
|
|
@ -123,7 +134,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does not throw when no callback is provided and pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendSessionCommand(sessionExt, {});
|
||||
|
||||
const storedCb = (service as ProtobufInternal).pendingCommands.get(1)!;
|
||||
|
|
@ -133,13 +144,13 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendRoomCommand', () => {
|
||||
it('stores callback and increments cmdId', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendRoomCommand(42, roomExt, {});
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
});
|
||||
|
||||
it('invokes onResponse with raw response when the pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendRoomCommand(42, roomExt, {}, { onResponse: cb });
|
||||
|
||||
|
|
@ -150,7 +161,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does not throw when no callback is provided and pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendRoomCommand(42, roomExt, {});
|
||||
|
||||
const storedCb = (service as ProtobufInternal).pendingCommands.get(1)!;
|
||||
|
|
@ -160,13 +171,13 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendGameCommand', () => {
|
||||
it('stores callback and increments cmdId', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendGameCommand(7, gameExt, {});
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
});
|
||||
|
||||
it('invokes onResponse with raw response when the pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendGameCommand(7, gameExt, {}, { onResponse: cb });
|
||||
|
||||
|
|
@ -177,7 +188,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does not throw when no callback is provided and pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendGameCommand(7, gameExt, {});
|
||||
|
||||
const storedCb = (service as ProtobufInternal).pendingCommands.get(1)!;
|
||||
|
|
@ -187,13 +198,13 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendModeratorCommand', () => {
|
||||
it('stores callback and increments cmdId', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendModeratorCommand(moderatorExt, {});
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
});
|
||||
|
||||
it('invokes onResponse with raw response when the pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendModeratorCommand(moderatorExt, {}, { onResponse: cb });
|
||||
|
||||
|
|
@ -204,7 +215,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does not throw when no callback is provided and pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendModeratorCommand(moderatorExt, {});
|
||||
|
||||
const storedCb = (service as ProtobufInternal).pendingCommands.get(1)!;
|
||||
|
|
@ -214,13 +225,13 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('sendAdminCommand', () => {
|
||||
it('stores callback and increments cmdId', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendAdminCommand(adminExt, {});
|
||||
expect((service as ProtobufInternal).cmdId).toBe(1);
|
||||
});
|
||||
|
||||
it('invokes onResponse with raw response when the pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
service.sendAdminCommand(adminExt, {}, { onResponse: cb });
|
||||
|
||||
|
|
@ -231,7 +242,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does not throw when no callback is provided and pending command is triggered', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
service.sendAdminCommand(adminExt, {});
|
||||
|
||||
const storedCb = (service as ProtobufInternal).pendingCommands.get(1)!;
|
||||
|
|
@ -241,7 +252,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('handleMessageEvent', () => {
|
||||
it('routes RESPONSE message to processServerResponse', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const cb = vi.fn();
|
||||
(service as ProtobufInternal).cmdId = 1;
|
||||
(service as ProtobufInternal).pendingCommands.set(1, cb);
|
||||
|
|
@ -259,7 +270,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('routes ROOM_EVENT message', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const processRoomEvent = vi.spyOn(service as ProtobufInternal, 'processRoomEvent');
|
||||
|
||||
vi.mocked(fromBinary).mockReturnValue(
|
||||
|
|
@ -273,7 +284,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('routes SESSION_EVENT message', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const processSessionEvent = vi.spyOn(service as ProtobufInternal, 'processSessionEvent');
|
||||
|
||||
vi.mocked(fromBinary).mockReturnValue(
|
||||
|
|
@ -287,7 +298,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('routes GAME_EVENT_CONTAINER message', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const processGameEvent = vi.spyOn(service as ProtobufInternal, 'processGameEvent');
|
||||
|
||||
vi.mocked(fromBinary).mockReturnValue(
|
||||
|
|
@ -301,7 +312,7 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('logs unknown message types (default case)', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
vi.mocked(fromBinary).mockReturnValue(
|
||||
|
|
@ -316,13 +327,13 @@ describe('ProtobufService', () => {
|
|||
});
|
||||
|
||||
it('does nothing when decoded message is null', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(fromBinary).mockReturnValue(null!);
|
||||
expect(() => service.handleMessageEvent({ data: new ArrayBuffer(0) } as MessageEvent)).not.toThrow();
|
||||
});
|
||||
|
||||
it('catches and logs decode errors', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
vi.mocked(fromBinary).mockImplementation(() => {
|
||||
throw new Error('decode error');
|
||||
|
|
@ -335,7 +346,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('processGameEvent', () => {
|
||||
it('returns early when container has no eventList', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(false);
|
||||
(service as ProtobufInternal).processGameEvent(null, {});
|
||||
expect(hasExtension).not.toHaveBeenCalled();
|
||||
|
|
@ -346,8 +357,8 @@ describe('ProtobufService', () => {
|
|||
const mockExt = {} as GenExtension<GameEvent, unknown>;
|
||||
const payload = { someData: 1 };
|
||||
|
||||
mockEvents.gameEvents.push([mockExt, handler] as any);
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
(GameEvents as any).push([mockExt, handler]);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(true);
|
||||
vi.mocked(getExtension).mockReturnValue(payload);
|
||||
|
||||
|
|
@ -364,8 +375,8 @@ describe('ProtobufService', () => {
|
|||
const mockExt = {} as GenExtension<GameEvent, unknown>;
|
||||
const payload = { someData: 1 };
|
||||
|
||||
mockEvents.gameEvents.push([mockExt, handler] as any);
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
(GameEvents as any).push([mockExt, handler]);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(true);
|
||||
vi.mocked(getExtension).mockReturnValue(payload);
|
||||
|
||||
|
|
@ -380,7 +391,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('processServerResponse', () => {
|
||||
it('returns early when response is undefined', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
(service as ProtobufInternal).pendingCommands.set(1, vi.fn());
|
||||
(service as ProtobufInternal).processServerResponse(undefined);
|
||||
expect((service as ProtobufInternal).pendingCommands.size).toBe(1);
|
||||
|
|
@ -389,7 +400,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('processRoomEvent', () => {
|
||||
it('returns early when event is undefined', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(false);
|
||||
(service as ProtobufInternal).processRoomEvent(undefined);
|
||||
expect(hasExtension).not.toHaveBeenCalled();
|
||||
|
|
@ -400,8 +411,8 @@ describe('ProtobufService', () => {
|
|||
const mockExt = {} as GenExtension<RoomEvent, unknown>;
|
||||
const payload = { roomData: 1 };
|
||||
|
||||
mockEvents.roomEvents.push([mockExt, handler] as any);
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
(RoomEvents as any).push([mockExt, handler]);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(true);
|
||||
vi.mocked(getExtension).mockReturnValue(payload);
|
||||
|
||||
|
|
@ -414,7 +425,7 @@ describe('ProtobufService', () => {
|
|||
|
||||
describe('processSessionEvent', () => {
|
||||
it('returns early when event is undefined', () => {
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(false);
|
||||
(service as ProtobufInternal).processSessionEvent(undefined);
|
||||
expect(hasExtension).not.toHaveBeenCalled();
|
||||
|
|
@ -425,8 +436,8 @@ describe('ProtobufService', () => {
|
|||
const mockExt = {} as GenExtension<SessionEvent, unknown>;
|
||||
const payload = { sessionData: 1 };
|
||||
|
||||
mockEvents.sessionEvents.push([mockExt, handler] as any);
|
||||
const service = new ProtobufService(mockSocket, mockEvents);
|
||||
(SessionEvents as any).push([mockExt, handler]);
|
||||
const service = new ProtobufService(mockSocket);
|
||||
vi.mocked(hasExtension).mockReturnValue(true);
|
||||
vi.mocked(getExtension).mockReturnValue(payload);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@ import {
|
|||
type GameEventContainer,
|
||||
type SessionEvent,
|
||||
type RoomEvent,
|
||||
type RegistryEntry,
|
||||
type GameEvent,
|
||||
} from '@app/generated';
|
||||
|
||||
import { GameEvents } from '../events/game';
|
||||
import { RoomEvents } from '../events/room';
|
||||
import { SessionEvents } from '../events/session';
|
||||
import type { GameEventMeta } from '../interfaces/WebSocketConfig';
|
||||
import { type CommandOptions, handleResponse } from './command-options';
|
||||
|
||||
|
|
@ -33,23 +34,11 @@ export interface SocketTransport {
|
|||
isOpen(): boolean;
|
||||
}
|
||||
|
||||
export interface EventRegistries {
|
||||
sessionEvents: RegistryEntry<unknown, SessionEvent>[];
|
||||
roomEvents: RegistryEntry<unknown, RoomEvent, RoomEvent>[];
|
||||
gameEvents: RegistryEntry<unknown, GameEvent, GameEventMeta>[];
|
||||
}
|
||||
|
||||
export class ProtobufService {
|
||||
private cmdId = 0;
|
||||
private pendingCommands = new Map<number, (response: Response) => void>();
|
||||
|
||||
private transport: SocketTransport;
|
||||
private events: EventRegistries;
|
||||
|
||||
constructor(transport: SocketTransport, events: EventRegistries) {
|
||||
this.transport = transport;
|
||||
this.events = events;
|
||||
}
|
||||
constructor(private transport: SocketTransport) {}
|
||||
|
||||
public resetCommands() {
|
||||
this.cmdId = 0;
|
||||
|
|
@ -189,7 +178,7 @@ export class ProtobufService {
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
for (const [ext, handler] of this.events.roomEvents) {
|
||||
for (const [ext, handler] of RoomEvents) {
|
||||
if (hasExtension(event, ext)) {
|
||||
handler(getExtension(event, ext), event);
|
||||
return;
|
||||
|
|
@ -201,7 +190,7 @@ export class ProtobufService {
|
|||
if (!event) {
|
||||
return;
|
||||
}
|
||||
for (const [ext, handler] of this.events.sessionEvents) {
|
||||
for (const [ext, handler] of SessionEvents) {
|
||||
if (hasExtension(event, ext)) {
|
||||
handler(getExtension(event, ext), undefined);
|
||||
return;
|
||||
|
|
@ -225,7 +214,7 @@ export class ProtobufService {
|
|||
forcedByJudge: forcedByJudge ?? 0,
|
||||
};
|
||||
|
||||
for (const [ext, handler] of this.events.gameEvents) {
|
||||
for (const [ext, handler] of GameEvents) {
|
||||
if (hasExtension(event, ext)) {
|
||||
handler(getExtension(event, ext), meta);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue