mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
websocket cleanup
This commit is contained in:
parent
2aeb1542b1
commit
2afa2922e9
18 changed files with 82 additions and 93 deletions
|
|
@ -15,6 +15,14 @@ export class ModeratorRequestImpl implements WebsocketTypes.IModeratorRequest {
|
|||
ModeratorCommands.banFromServer(minutes, userName, address, reason, visibleReason, clientid, removeMessages);
|
||||
}
|
||||
|
||||
forceActivateUser(usernameToActivate: string, moderatorName: string): void {
|
||||
ModeratorCommands.forceActivateUser(usernameToActivate, moderatorName);
|
||||
}
|
||||
|
||||
getAdminNotes(userName: string): void {
|
||||
ModeratorCommands.getAdminNotes(userName);
|
||||
}
|
||||
|
||||
getBanHistory(userName: string): void {
|
||||
ModeratorCommands.getBanHistory(userName);
|
||||
}
|
||||
|
|
@ -27,6 +35,14 @@ export class ModeratorRequestImpl implements WebsocketTypes.IModeratorRequest {
|
|||
ModeratorCommands.getWarnList(modName, userName, userClientid);
|
||||
}
|
||||
|
||||
grantReplayAccess(replayId: number, moderatorName: string): void {
|
||||
ModeratorCommands.grantReplayAccess(replayId, moderatorName);
|
||||
}
|
||||
|
||||
updateAdminNotes(userName: string, notes: string): void {
|
||||
ModeratorCommands.updateAdminNotes(userName, notes);
|
||||
}
|
||||
|
||||
viewLogHistory(filters: Data.ViewLogHistoryParams): void {
|
||||
ModeratorCommands.viewLogHistory(filters);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { roomsSlice } from './rooms.reducer';
|
||||
|
||||
export const Actions = roomsSlice.actions;
|
||||
const SignalActions = {
|
||||
gameCreated: createAction<{ roomId: number }>('rooms/gameCreated'),
|
||||
};
|
||||
|
||||
export const Actions = { ...roomsSlice.actions, ...SignalActions };
|
||||
|
||||
export type RoomsAction = ReturnType<typeof Actions[keyof typeof Actions]>;
|
||||
|
|
|
|||
|
|
@ -318,14 +318,6 @@ describe('REMOVE_MESSAGES', () => {
|
|||
});
|
||||
|
||||
|
||||
describe('GAME_CREATED', () => {
|
||||
it('returns state unchanged', () => {
|
||||
const state = makeRoomsState();
|
||||
const result = roomsReducer(state, Actions.gameCreated({ roomId: 1 }));
|
||||
expect(result).toEqual(state);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('JOINED_GAME', () => {
|
||||
it('sets joinedGameIds[roomId][gameId] = true', () => {
|
||||
|
|
|
|||
|
|
@ -190,9 +190,6 @@ export const roomsSlice = createSlice({
|
|||
state.joinedGameIds[roomId][gameId] = true;
|
||||
},
|
||||
|
||||
// Signal-only; kept for discriminated-union exhaustiveness.
|
||||
gameCreated: (_state, _action: PayloadAction<{ roomId: number }>) => {},
|
||||
|
||||
selectGame: (state, action: PayloadAction<{ roomId: number; gameId: number | undefined }>) => {
|
||||
const { roomId, gameId } = action.payload;
|
||||
state.selectedGameIds[roomId] = gameId;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { roomsSlice } from './rooms.reducer';
|
||||
import { Actions } from './rooms.actions';
|
||||
|
||||
const a = roomsSlice.actions;
|
||||
const a = Actions;
|
||||
|
||||
export const Types = {
|
||||
CLEAR_STORE: a.clearStore.type,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,36 @@
|
|||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { WebsocketTypes } from '@app/websocket/types';
|
||||
|
||||
import { serverSlice } from './server.reducer';
|
||||
|
||||
export const Actions = serverSlice.actions;
|
||||
const SignalActions = {
|
||||
accountAwaitingActivation: createAction<{ options: WebsocketTypes.PendingActivationContext }>('server/accountAwaitingActivation'),
|
||||
accountActivationFailed: createAction('server/accountActivationFailed'),
|
||||
accountActivationSuccess: createAction('server/accountActivationSuccess'),
|
||||
loginSuccessful: createAction<{ options: WebsocketTypes.LoginSuccessContext }>('server/loginSuccessful'),
|
||||
loginFailed: createAction('server/loginFailed'),
|
||||
connectionFailed: createAction('server/connectionFailed'),
|
||||
testConnectionSuccessful: createAction('server/testConnectionSuccessful'),
|
||||
testConnectionFailed: createAction('server/testConnectionFailed'),
|
||||
registrationRequiresEmail: createAction('server/registrationRequiresEmail'),
|
||||
registrationSuccess: createAction('server/registrationSuccess'),
|
||||
registrationEmailError: createAction<{ error: string }>('server/registrationEmailError'),
|
||||
registrationPasswordError: createAction<{ error: string }>('server/registrationPasswordError'),
|
||||
registrationUserNameError: createAction<{ error: string }>('server/registrationUserNameError'),
|
||||
resetPassword: createAction('server/resetPassword'),
|
||||
resetPasswordFailed: createAction('server/resetPasswordFailed'),
|
||||
resetPasswordChallenge: createAction('server/resetPasswordChallenge'),
|
||||
resetPasswordSuccess: createAction('server/resetPasswordSuccess'),
|
||||
reloadConfig: createAction('server/reloadConfig'),
|
||||
shutdownServer: createAction('server/shutdownServer'),
|
||||
updateServerMessage: createAction('server/updateServerMessage'),
|
||||
accountPasswordChange: createAction('server/accountPasswordChange'),
|
||||
addToList: createAction<{ list: string; userName: string }>('server/addToList'),
|
||||
removeFromList: createAction<{ list: string; userName: string }>('server/removeFromList'),
|
||||
grantReplayAccess: createAction<{ replayId: number; moderatorName: string }>('server/grantReplayAccess'),
|
||||
forceActivateUser: createAction<{ usernameToActivate: string; moderatorName: string }>('server/forceActivateUser'),
|
||||
};
|
||||
|
||||
export const Actions = { ...serverSlice.actions, ...SignalActions };
|
||||
|
||||
export type ServerAction = ReturnType<typeof Actions[keyof typeof Actions]>;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { serverReducer, MAX_USER_MESSAGES } from './server.reducer';
|
|||
import { Actions } from './server.actions';
|
||||
import {
|
||||
makeBanHistoryItem,
|
||||
makePendingActivationContext,
|
||||
makeDeckList,
|
||||
makeDeckTreeItem,
|
||||
makeGame,
|
||||
|
|
@ -62,24 +61,6 @@ describe('Account & Connection', () => {
|
|||
expect(result.status.connectionAttemptMade).toBe(true);
|
||||
});
|
||||
|
||||
it('ACCOUNT_AWAITING_ACTIVATION → returns state unchanged', () => {
|
||||
const options = makePendingActivationContext();
|
||||
const state = makeServerState();
|
||||
const result = serverReducer(state, Actions.accountAwaitingActivation({ options }));
|
||||
expect(result).toEqual(state);
|
||||
});
|
||||
|
||||
it('ACCOUNT_ACTIVATION_SUCCESS → returns state unchanged', () => {
|
||||
const state = makeServerState();
|
||||
const result = serverReducer(state, Actions.accountActivationSuccess());
|
||||
expect(result).toEqual(state);
|
||||
});
|
||||
|
||||
it('ACCOUNT_ACTIVATION_FAILED → returns state unchanged', () => {
|
||||
const state = makeServerState();
|
||||
const result = serverReducer(state, Actions.accountActivationFailed());
|
||||
expect(result).toEqual(state);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ export const serverSlice = createSlice({
|
|||
|
||||
updateUser: (state, action: PayloadAction<{ user: Partial<Data.ServerInfo_User> }>) => {
|
||||
if (state.user) {
|
||||
Object.assign(state.user, action.payload.user);
|
||||
state.user = create(Data.ServerInfo_UserSchema, { ...state.user, ...action.payload.user });
|
||||
} else {
|
||||
state.user = action.payload.user as Data.ServerInfo_User;
|
||||
}
|
||||
|
|
@ -393,42 +393,15 @@ export const serverSlice = createSlice({
|
|||
|
||||
accountEditChanged: (state, action: PayloadAction<{ user: Partial<Data.ServerInfo_User> }>) => {
|
||||
if (state.user) {
|
||||
Object.assign(state.user, action.payload.user);
|
||||
state.user = create(Data.ServerInfo_UserSchema, { ...state.user, ...action.payload.user });
|
||||
}
|
||||
},
|
||||
|
||||
accountImageChanged: (state, action: PayloadAction<{ user: Partial<Data.ServerInfo_User> }>) => {
|
||||
if (state.user) {
|
||||
Object.assign(state.user, action.payload.user);
|
||||
state.user = create(Data.ServerInfo_UserSchema, { ...state.user, ...action.payload.user });
|
||||
}
|
||||
},
|
||||
|
||||
// Signal-only action types — no state mutation, defined so type strings are generated
|
||||
accountAwaitingActivation: (_state, _action: PayloadAction<{ options: WebsocketTypes.PendingActivationContext }>) => {},
|
||||
accountActivationFailed: (_state) => {},
|
||||
accountActivationSuccess: (_state) => {},
|
||||
loginSuccessful: (_state, _action: PayloadAction<{ options: WebsocketTypes.LoginSuccessContext }>) => {},
|
||||
loginFailed: (_state) => {},
|
||||
connectionFailed: (_state) => {},
|
||||
testConnectionSuccessful: (_state) => {},
|
||||
testConnectionFailed: (_state) => {},
|
||||
registrationRequiresEmail: (_state) => {},
|
||||
registrationSuccess: (_state) => {},
|
||||
registrationEmailError: (_state, _action: PayloadAction<{ error: string }>) => {},
|
||||
registrationPasswordError: (_state, _action: PayloadAction<{ error: string }>) => {},
|
||||
registrationUserNameError: (_state, _action: PayloadAction<{ error: string }>) => {},
|
||||
resetPassword: (_state) => {},
|
||||
resetPasswordFailed: (_state) => {},
|
||||
resetPasswordChallenge: (_state) => {},
|
||||
resetPasswordSuccess: (_state) => {},
|
||||
reloadConfig: (_state) => {},
|
||||
shutdownServer: (_state) => {},
|
||||
updateServerMessage: (_state) => {},
|
||||
accountPasswordChange: (_state) => {},
|
||||
addToList: (_state, _action: PayloadAction<{ list: string; userName: string }>) => {},
|
||||
removeFromList: (_state, _action: PayloadAction<{ list: string; userName: string }>) => {},
|
||||
grantReplayAccess: (_state, _action: PayloadAction<{ replayId: number; moderatorName: string }>) => {},
|
||||
forceActivateUser: (_state, _action: PayloadAction<{ usernameToActivate: string; moderatorName: string }>) => {},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { serverSlice } from './server.reducer';
|
||||
import { Actions } from './server.actions';
|
||||
|
||||
const a = serverSlice.actions;
|
||||
const a = Actions;
|
||||
|
||||
export const Types = {
|
||||
INITIALIZED: a.initialized.type,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const ERROR_MESSAGES: Record<number, string> = {
|
|||
[Response_ResponseCode.RespGameFull]: 'The game is already full.',
|
||||
[Response_ResponseCode.RespWrongPassword]: 'Wrong password.',
|
||||
[Response_ResponseCode.RespSpectatorsNotAllowed]: 'Spectators are not allowed in this game.',
|
||||
[Response_ResponseCode.RespOnlyBuddies]: "This game is only open to its creator's buddies.",
|
||||
[Response_ResponseCode.RespOnlyBuddies]: 'This game is only open to its creator\'s buddies.',
|
||||
[Response_ResponseCode.RespUserLevelTooLow]: 'This game is only open to registered users.',
|
||||
[Response_ResponseCode.RespInIgnoreList]: 'You are being ignored by the creator of this game.',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ describe('joinGame', () => {
|
|||
[Response_ResponseCode.RespGameFull, 'The game is already full.'],
|
||||
[Response_ResponseCode.RespWrongPassword, 'Wrong password.'],
|
||||
[Response_ResponseCode.RespSpectatorsNotAllowed, 'Spectators are not allowed in this game.'],
|
||||
[Response_ResponseCode.RespOnlyBuddies, "This game is only open to its creator's buddies."],
|
||||
[Response_ResponseCode.RespOnlyBuddies, 'This game is only open to its creator\'s buddies.'],
|
||||
[Response_ResponseCode.RespUserLevelTooLow, 'This game is only open to registered users.'],
|
||||
[Response_ResponseCode.RespInIgnoreList, 'You are being ignored by the creator of this game.'],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { WebClient } from '../../WebClient';
|
|||
import { Command_Ping_ext, Command_PingSchema } from '@app/generated';
|
||||
|
||||
export function ping(pingReceived: () => void): void {
|
||||
// Uses `onResponse` (not `onSuccess`) so KeepAliveService treats any server
|
||||
// reply as proof of life, independent of responseCode.
|
||||
WebClient.instance.protobuf.sendSessionCommand(Command_Ping_ext, create(Command_PingSchema), {
|
||||
onResponse: () => pingReceived(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ import { Command_ReplaySubmitCode_ext, Command_ReplaySubmitCodeSchema } from '@a
|
|||
|
||||
export function replaySubmitCode(
|
||||
replayCode: string,
|
||||
onSuccess?: () => void,
|
||||
onError?: (responseCode: number) => void,
|
||||
onSubmitted?: () => void,
|
||||
onFailure?: (responseCode: number) => void,
|
||||
): void {
|
||||
WebClient.instance.protobuf.sendSessionCommand(
|
||||
Command_ReplaySubmitCode_ext,
|
||||
create(Command_ReplaySubmitCodeSchema, { replayCode }),
|
||||
{
|
||||
onSuccess,
|
||||
onError,
|
||||
onSuccess: onSubmitted,
|
||||
onError: onFailure,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,18 +468,18 @@ describe('replaySubmitCode', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('forwards onSuccess callback', () => {
|
||||
const onSuccess = vi.fn();
|
||||
replaySubmitCode('42-abc123', onSuccess);
|
||||
it('forwards onSubmitted callback', () => {
|
||||
const onSubmitted = vi.fn();
|
||||
replaySubmitCode('42-abc123', onSubmitted);
|
||||
invokeOnSuccess();
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
expect(onSubmitted).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('forwards onError callback', () => {
|
||||
const onError = vi.fn();
|
||||
replaySubmitCode('42-abc123', undefined, onError);
|
||||
it('forwards onFailure callback', () => {
|
||||
const onFailure = vi.fn();
|
||||
replaySubmitCode('42-abc123', undefined, onFailure);
|
||||
invokeCallback('onError', 404);
|
||||
expect(onError).toHaveBeenCalledWith(404);
|
||||
expect(onFailure).toHaveBeenCalledWith(404);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
import { CommonEvents } from './index';
|
||||
|
||||
describe('CommonEvents', () => {
|
||||
it('is an empty event map (all common events were moved to game/session events)', () => {
|
||||
expect(CommonEvents).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import type { SessionExtensionRegistry } from '../session';
|
||||
|
||||
export const CommonEvents: SessionExtensionRegistry = [];
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// Event_PlayerPropertiesChanged is handled as a game event in websocket/events/game/playerPropertiesChanged.ts
|
||||
// This file is retained for reference but is no longer registered in CommonEvents.
|
||||
export {};
|
||||
|
|
@ -107,9 +107,13 @@ export interface IModeratorRequest {
|
|||
clientid?: string,
|
||||
removeMessages?: number
|
||||
): void;
|
||||
forceActivateUser(usernameToActivate: string, moderatorName: string): void;
|
||||
getAdminNotes(userName: string): void;
|
||||
getBanHistory(userName: string): void;
|
||||
getWarnHistory(userName: string): void;
|
||||
getWarnList(modName: string, userName: string, userClientid: string): void;
|
||||
grantReplayAccess(replayId: number, moderatorName: string): void;
|
||||
updateAdminNotes(userName: string, notes: string): void;
|
||||
viewLogHistory(filters: ViewLogHistoryParams): void;
|
||||
warnUser(userName: string, reason: string, clientid?: string, removeMessages?: number): void;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue