Initial implementation completion and refactor (#6806)
Some checks failed
Build Desktop / Configure (push) Has been cancelled
Build Docker Image / amd64 & arm64 (push) Has been cancelled
Build Web / React (Node 16) (push) Has been cancelled
Build Web / React (Node lts/*) (push) Has been cancelled
Build Desktop / Debian 11 (push) Has been cancelled
Build Desktop / Debian 13 (push) Has been cancelled
Build Desktop / Debian 12 (push) Has been cancelled
Build Desktop / Fedora 43 (push) Has been cancelled
Build Desktop / Fedora 42 (push) Has been cancelled
Build Desktop / Servatrice_Debian 11 (push) Has been cancelled
Build Desktop / Ubuntu 24.04 (push) Has been cancelled
Build Desktop / Ubuntu 26.04 (push) Has been cancelled
Build Desktop / Ubuntu 22.04 (push) Has been cancelled
Build Desktop / Arch (push) Has been cancelled
Build Desktop / macOS 14 (push) Has been cancelled
Build Desktop / macOS 15 (push) Has been cancelled
Build Desktop / macOS 13 Intel (push) Has been cancelled
Build Desktop / macOS 15 Debug (push) Has been cancelled
Build Desktop / Windows 10 (push) Has been cancelled

This commit is contained in:
Jeremy Letto 2026-04-11 22:51:10 -05:00 committed by GitHub
parent 2e10b2f5d5
commit 8cc65b8967
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 897 additions and 890 deletions

View file

@ -1,5 +1,6 @@
import { StatusEnum, User, WebSocketConnectReason, WebSocketConnectOptions } from 'types'; import { StatusEnum, User, WebSocketConnectReason, WebSocketConnectOptions } from 'types';
import { SessionCommands, webClient } from 'websocket'; import { SessionCommands, webClient } from 'websocket';
import { ProtoController } from 'websocket/services/ProtoController';
export class AuthenticationService { export class AuthenticationService {
static login(options: WebSocketConnectOptions): void { static login(options: WebSocketConnectOptions): void {
@ -39,7 +40,7 @@ export class AuthenticationService {
} }
static isModerator(user: User): boolean { static isModerator(user: User): boolean {
const moderatorLevel = webClient.protobuf.controller.ServerInfo_User.UserLevelFlag.IsModerator; const moderatorLevel = ProtoController.root.ServerInfo_User.UserLevelFlag.IsModerator;
// @TODO tell cockatrice not to do this so shittily // @TODO tell cockatrice not to do this so shittily
return (user.userLevel & moderatorLevel) === moderatorLevel; return (user.userLevel & moderatorLevel) === moderatorLevel;
} }

View file

@ -23,7 +23,7 @@ export class ModeratorService {
ModeratorCommands.viewLogHistory(filters); ModeratorCommands.viewLogHistory(filters);
} }
static warnUser(userName: string, reason: string, clientid?: string, removeMessage?: boolean): void { static warnUser(userName: string, reason: string, clientid?: string, removeMessages?: number): void {
ModeratorCommands.warnUser(userName, reason, clientid, removeMessage); ModeratorCommands.warnUser(userName, reason, clientid, removeMessages);
} }
} }

View file

@ -1,6 +1,4 @@
import { SessionCommands } from 'websocket'; import { SessionCommands } from 'websocket';
import { common } from 'protobufjs';
import IBytesValue = common.IBytesValue;
export class SessionService { export class SessionService {
static addToBuddyList(userName: string) { static addToBuddyList(userName: string) {
@ -27,7 +25,7 @@ export class SessionService {
SessionCommands.accountEdit(passwordCheck, realName, email, country); SessionCommands.accountEdit(passwordCheck, realName, email, country);
} }
static changeAccountImage(image: IBytesValue): void { static changeAccountImage(image: Uint8Array): void {
SessionCommands.accountImage(image); SessionCommands.accountImage(image);
} }

View file

@ -1,4 +1,4 @@
import { WebSocketConnectOptions } from 'types'; import { DeckList, DeckStorageTreeItem, ReplayMatch, WebSocketConnectOptions } from 'types';
import { Types } from './server.types'; import { Types } from './server.types';
export const Actions = { export const Actions = {
@ -210,4 +210,33 @@ export const Actions = {
type: Types.WARN_USER, type: Types.WARN_USER,
userName, userName,
}), }),
grantReplayAccess: (replayId: number, moderatorName: string) => ({
type: Types.GRANT_REPLAY_ACCESS,
replayId,
moderatorName,
}),
forceActivateUser: (usernameToActivate: string, moderatorName: string) => ({
type: Types.FORCE_ACTIVATE_USER,
usernameToActivate,
moderatorName,
}),
getAdminNotes: (userName: string, notes: string) => ({
type: Types.GET_ADMIN_NOTES,
userName,
notes,
}),
updateAdminNotes: (userName: string, notes: string) => ({
type: Types.UPDATE_ADMIN_NOTES,
userName,
notes,
}),
replayList: (matchList: ReplayMatch[]) => ({ type: Types.REPLAY_LIST, matchList }),
replayAdded: (matchInfo: ReplayMatch) => ({ type: Types.REPLAY_ADDED, matchInfo }),
replayModifyMatch: (gameId: number, doNotHide: boolean) => ({ type: Types.REPLAY_MODIFY_MATCH, gameId, doNotHide }),
replayDeleteMatch: (gameId: number) => ({ type: Types.REPLAY_DELETE_MATCH, gameId }),
backendDecks: (deckList: DeckList) => ({ type: Types.BACKEND_DECKS, deckList }),
deckNewDir: (path: string, dirName: string) => ({ type: Types.DECK_NEW_DIR, path, dirName }),
deckDelDir: (path: string) => ({ type: Types.DECK_DEL_DIR, path }),
deckUpload: (path: string, treeItem: DeckStorageTreeItem) => ({ type: Types.DECK_UPLOAD, path, treeItem }),
deckDelete: (deckId: number) => ({ type: Types.DECK_DELETE, deckId }),
} }

View file

@ -1,7 +1,7 @@
import { reset } from 'redux-form'; import { reset } from 'redux-form';
import { Actions } from './server.actions'; import { Actions } from './server.actions';
import { store } from 'store'; import { store } from 'store';
import { WebSocketConnectOptions } from 'types'; import { DeckList, DeckStorageTreeItem, ReplayMatch, WebSocketConnectOptions } from 'types';
export const Dispatch = { export const Dispatch = {
initialized: () => { initialized: () => {
@ -177,4 +177,43 @@ export const Dispatch = {
warnUser: (userName) => { warnUser: (userName) => {
store.dispatch(Actions.warnUser(userName)) store.dispatch(Actions.warnUser(userName))
}, },
grantReplayAccess: (replayId: number, moderatorName: string) => {
store.dispatch(Actions.grantReplayAccess(replayId, moderatorName));
},
forceActivateUser: (usernameToActivate: string, moderatorName: string) => {
store.dispatch(Actions.forceActivateUser(usernameToActivate, moderatorName));
},
getAdminNotes: (userName: string, notes: string) => {
store.dispatch(Actions.getAdminNotes(userName, notes));
},
updateAdminNotes: (userName: string, notes: string) => {
store.dispatch(Actions.updateAdminNotes(userName, notes));
},
replayList: (matchList: ReplayMatch[]) => {
store.dispatch(Actions.replayList(matchList));
},
replayAdded: (matchInfo: ReplayMatch) => {
store.dispatch(Actions.replayAdded(matchInfo));
},
replayModifyMatch: (gameId: number, doNotHide: boolean) => {
store.dispatch(Actions.replayModifyMatch(gameId, doNotHide));
},
replayDeleteMatch: (gameId: number) => {
store.dispatch(Actions.replayDeleteMatch(gameId));
},
backendDecks: (deckList: DeckList) => {
store.dispatch(Actions.backendDecks(deckList));
},
deckNewDir: (path: string, dirName: string) => {
store.dispatch(Actions.deckNewDir(path, dirName));
},
deckDelDir: (path: string) => {
store.dispatch(Actions.deckDelDir(path));
},
deckUpload: (path: string, treeItem: DeckStorageTreeItem) => {
store.dispatch(Actions.deckUpload(path, treeItem));
},
deckDelete: (deckId: number) => {
store.dispatch(Actions.deckDelete(deckId));
},
} }

View file

@ -1,4 +1,6 @@
import { WarnHistoryItem, BanHistoryItem, LogItem, SortBy, User, UserSortField, WebSocketConnectOptions, WarnListItem } from 'types'; import {
WarnHistoryItem, BanHistoryItem, DeckList, LogItem, ReplayMatch, SortBy, User, UserSortField, WebSocketConnectOptions, WarnListItem
} from 'types';
import { NotifyUserData, ServerShutdownData, UserMessageData } from 'websocket/events/session/interfaces'; import { NotifyUserData, ServerShutdownData, UserMessageData } from 'websocket/events/session/interfaces';
export interface ServerConnectParams { export interface ServerConnectParams {
@ -67,6 +69,9 @@ export interface ServerState {
}; };
warnListOptions: WarnListItem[]; warnListOptions: WarnListItem[];
warnUser: string; warnUser: string;
adminNotes: { [userName: string]: string };
replays: ReplayMatch[];
backendDecks: DeckList | null;
} }
export interface ServerStateStatus { export interface ServerStateStatus {

View file

@ -1,10 +1,60 @@
import { SortDirection, StatusEnum, UserLevelFlag, UserSortField } from 'types'; import { DeckStorageFolder, DeckStorageTreeItem, SortDirection, StatusEnum, UserLevelFlag, UserSortField } from 'types';
import { SortUtil } from '../common'; import { SortUtil } from '../common';
import { ServerState } from './server.interfaces' import { ServerState } from './server.interfaces'
import { Types } from './server.types'; import { Types } from './server.types';
function splitPath(path: string): string[] {
return path ? path.split('/') : [];
}
function insertAtPath(folder: DeckStorageFolder, pathSegments: string[], item: DeckStorageTreeItem): DeckStorageFolder {
if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === '')) {
return { items: [...folder.items, item] };
}
const [head, ...tail] = pathSegments;
const match = folder.items.find(child => child.name === head && child.folder);
if (match) {
return {
items: folder.items.map(child =>
child === match
? { ...child, folder: insertAtPath(child.folder!, tail, item) }
: child
),
};
}
const created: DeckStorageTreeItem = { id: 0, name: head, file: null, folder: insertAtPath({ items: [] }, tail, item) };
return { items: [...folder.items, created] };
}
function removeById(folder: DeckStorageFolder, id: number): DeckStorageFolder {
return {
items: folder.items
.filter(item => item.id !== id)
.map(item =>
item.folder ? { ...item, folder: removeById(item.folder, id) } : item
),
};
}
function removeByPath(folder: DeckStorageFolder, pathSegments: string[]): DeckStorageFolder {
if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === '')) {
return folder;
}
const [head, ...tail] = pathSegments;
if (tail.length === 0) {
return { items: folder.items.filter(item => !(item.name === head && item.folder !== null)) };
}
return {
items: folder.items.map(item =>
item.name === head && item.folder
? { ...item, folder: removeByPath(item.folder, tail) }
: item
),
};
}
const initialState: ServerState = { const initialState: ServerState = {
initialized: false, initialized: false,
buddyList: [], buddyList: [],
@ -40,6 +90,9 @@ const initialState: ServerState = {
warnHistory: {}, warnHistory: {},
warnListOptions: [], warnListOptions: [],
warnUser: '', warnUser: '',
adminNotes: {},
replays: [],
backendDecks: null,
}; };
export const serverReducer = (state = initialState, action: any) => { export const serverReducer = (state = initialState, action: any) => {
@ -247,7 +300,7 @@ export const serverReducer = (state = initialState, action: any) => {
messages: { messages: {
...state.messages, ...state.messages,
[userName]: [ [userName]: [
...state.messages[userName], ...(state.messages[userName] ?? []),
action.messageData, action.messageData,
], ],
} }
@ -328,6 +381,17 @@ export const serverReducer = (state = initialState, action: any) => {
warnUser: userName, warnUser: userName,
}; };
} }
case Types.GET_ADMIN_NOTES:
case Types.UPDATE_ADMIN_NOTES: {
const { userName, notes } = action;
return {
...state,
adminNotes: {
...state.adminNotes,
[userName]: notes,
}
};
}
case Types.ADJUST_MOD: { case Types.ADJUST_MOD: {
const { userName, shouldBeMod, shouldBeJudge } = action; const { userName, shouldBeMod, shouldBeJudge } = action;
@ -346,6 +410,71 @@ export const serverReducer = (state = initialState, action: any) => {
}) })
}; };
} }
case Types.REPLAY_LIST: {
return { ...state, replays: [...action.matchList] };
}
case Types.REPLAY_ADDED: {
return { ...state, replays: [...state.replays, action.matchInfo] };
}
case Types.REPLAY_MODIFY_MATCH: {
return {
...state,
replays: state.replays.map(r =>
r.gameId === action.gameId ? { ...r, doNotHide: action.doNotHide } : r
),
};
}
case Types.REPLAY_DELETE_MATCH: {
return { ...state, replays: state.replays.filter(r => r.gameId !== action.gameId) };
}
case Types.BACKEND_DECKS: {
return { ...state, backendDecks: action.deckList };
}
case Types.DECK_UPLOAD: {
if (!state.backendDecks) {
return state;
}
return {
...state,
backendDecks: {
root: insertAtPath(state.backendDecks.root, splitPath(action.path), action.treeItem),
},
};
}
case Types.DECK_DELETE: {
if (!state.backendDecks) {
return state;
}
return {
...state,
backendDecks: {
root: removeById(state.backendDecks.root, action.deckId),
},
};
}
case Types.DECK_NEW_DIR: {
if (!state.backendDecks) {
return state;
}
const newFolder: DeckStorageTreeItem = { id: 0, name: action.dirName, file: null, folder: { items: [] } };
return {
...state,
backendDecks: {
root: insertAtPath(state.backendDecks.root, splitPath(action.path), newFolder),
},
};
}
case Types.DECK_DEL_DIR: {
if (!state.backendDecks) {
return state;
}
return {
...state,
backendDecks: {
root: removeByPath(state.backendDecks.root, splitPath(action.path)),
},
};
}
default: default:
return state; return state;
} }

View file

@ -16,5 +16,7 @@ export const Selectors = {
getUsers: ({ server }: State) => server.users, getUsers: ({ server }: State) => server.users,
getLogs: ({ server }: State) => server.logs, getLogs: ({ server }: State) => server.logs,
getBuddyList: ({ server }: State) => server.buddyList, getBuddyList: ({ server }: State) => server.buddyList,
getIgnoreList: ({ server }: State) => server.ignoreList getIgnoreList: ({ server }: State) => server.ignoreList,
getReplays: ({ server }: State) => server.replays,
getBackendDecks: ({ server }: State) => server.backendDecks,
} }

View file

@ -54,4 +54,19 @@ export const Types = {
WARN_HISTORY: '[Server] Warn History', WARN_HISTORY: '[Server] Warn History',
WARN_LIST_OPTIONS: '[Server] Warn List Options', WARN_LIST_OPTIONS: '[Server] Warn List Options',
WARN_USER: '[Server] Warn User', WARN_USER: '[Server] Warn User',
GRANT_REPLAY_ACCESS: '[Server] Grant Replay Access',
FORCE_ACTIVATE_USER: '[Server] Force Activate User',
GET_ADMIN_NOTES: '[Server] Get Admin Notes',
UPDATE_ADMIN_NOTES: '[Server] Update Admin Notes',
// Replay
REPLAY_LIST: '[Server] Replay List',
REPLAY_ADDED: '[Server] Replay Added',
REPLAY_MODIFY_MATCH: '[Server] Replay Modify Match',
REPLAY_DELETE_MATCH: '[Server] Replay Delete Match',
// Deck Storage
BACKEND_DECKS: '[Server] Backend Decks',
DECK_NEW_DIR: '[Server] Deck New Dir',
DECK_DEL_DIR: '[Server] Deck Del Dir',
DECK_UPLOAD: '[Server] Deck Upload',
DECK_DELETE: '[Server] Deck Delete',
}; };

View file

@ -13,6 +13,6 @@ export interface DeckStorageFile {
export interface DeckStorageTreeItem { export interface DeckStorageTreeItem {
id: number; id: number;
name: string; name: string;
file: DeckStorageFile; file: DeckStorageFile | null;
folder: DeckStorageFolder; folder: DeckStorageFolder | null;
} }

View file

@ -16,3 +16,4 @@ export * from './logs';
export * from './session'; export * from './session';
export * from './deckList'; export * from './deckList';
export * from './moderator'; export * from './moderator';
export * from './replay';

View file

@ -1,8 +1,10 @@
export interface LogFilters { export interface LogFilters {
userName: string; userName?: string;
ipAddress: string; ipAddress?: string;
gameName: string; gameName?: string;
gameId: string; gameId?: string;
message: string; message?: string;
logLocation: string; logLocation?: string[];
dateRange: number;
maximumResults?: number;
} }

View file

@ -0,0 +1,16 @@
export interface Replay {
replayId: number;
replayName: string;
duration: number;
}
export interface ReplayMatch {
replayList: Replay[];
gameId: number;
roomName: string;
timeStarted: number;
length: number;
gameName: string;
playerNames: string[];
doNotHide: boolean;
}

View file

@ -1,26 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { AdminPersistence } from '../../persistence'; import { AdminPersistence } from '../../persistence';
export function adjustMod(userName: string, shouldBeMod?: boolean, shouldBeJudge?: boolean): void { export function adjustMod(userName: string, shouldBeMod?: boolean, shouldBeJudge?: boolean): void {
const command = webClient.protobuf.controller.Command_AdjustMod.create({ userName, shouldBeMod, shouldBeJudge }); BackendService.sendAdminCommand('Command_AdjustMod', { userName, shouldBeMod, shouldBeJudge }, {
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_AdjustMod.ext': command }); onSuccess: () => {
webClient.protobuf.sendAdminCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
AdminPersistence.adjustMod(userName, shouldBeMod, shouldBeJudge); AdminPersistence.adjustMod(userName, shouldBeMod, shouldBeJudge);
return; },
default:
error = 'Failed to reload config.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,26 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { AdminPersistence } from '../../persistence'; import { AdminPersistence } from '../../persistence';
export function reloadConfig(): void { export function reloadConfig(): void {
const command = webClient.protobuf.controller.Command_ReloadConfig.create(); BackendService.sendAdminCommand('Command_ReloadConfig', {}, {
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_ReloadConfig.ext': command }); onSuccess: () => {
webClient.protobuf.sendAdminCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
AdminPersistence.reloadConfig(); AdminPersistence.reloadConfig();
return; },
default:
error = 'Failed to reload config.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,26 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { AdminPersistence } from '../../persistence'; import { AdminPersistence } from '../../persistence';
export function shutdownServer(reason: string, minutes: number): void { export function shutdownServer(reason: string, minutes: number): void {
const command = webClient.protobuf.controller.Command_ShutdownServer.create({ reason, minutes }); BackendService.sendAdminCommand('Command_ShutdownServer', { reason, minutes }, {
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_ShutdownServer.ext': command }); onSuccess: () => {
webClient.protobuf.sendAdminCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
AdminPersistence.shutdownServer(); AdminPersistence.shutdownServer();
return; },
default:
error = 'Failed to update server message.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,26 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { AdminPersistence } from '../../persistence'; import { AdminPersistence } from '../../persistence';
export function updateServerMessage(): void { export function updateServerMessage(): void {
const command = webClient.protobuf.controller.Command_UpdateServerMessage.create(); BackendService.sendAdminCommand('Command_UpdateServerMessage', {}, {
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_UpdateServerMessage.ext': command }); onSuccess: () => {
webClient.protobuf.sendAdminCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
AdminPersistence.updateServerMessage(); AdminPersistence.updateServerMessage();
return; },
default:
error = 'Failed to update server message.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,29 +1,13 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
export function banFromServer(minutes: number, userName?: string, address?: string, reason?: string, export function banFromServer(minutes: number, userName?: string, address?: string, reason?: string,
visibleReason?: string, clientid?: string, removeMessages?: number): void { visibleReason?: string, clientid?: string, removeMessages?: number): void {
const command = webClient.protobuf.controller.Command_BanFromServer.create({ BackendService.sendModeratorCommand('Command_BanFromServer', {
minutes, userName, address, reason, visibleReason, clientid, removeMessages minutes, userName, address, reason, visibleReason, clientid, removeMessages
}); }, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_BanFromServer.ext': command }); onSuccess: () => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
ModeratorPersistence.banFromServer(userName); ModeratorPersistence.banFromServer(userName);
return; },
default:
error = 'Failed to ban user.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -0,0 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence';
export function forceActivateUser(usernameToActivate: string, moderatorName: string): void {
BackendService.sendModeratorCommand('Command_ForceActivateUser', { usernameToActivate, moderatorName }, {
onSuccess: () => {
ModeratorPersistence.forceActivateUser(usernameToActivate, moderatorName);
},
});
}

View file

@ -0,0 +1,11 @@
import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence';
export function getAdminNotes(userName: string): void {
BackendService.sendModeratorCommand('Command_GetAdminNotes', { userName }, {
responseName: 'Response_GetAdminNotes',
onSuccess: (response) => {
ModeratorPersistence.getAdminNotes(userName, response.notes);
},
});
}

View file

@ -1,27 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
export function getBanHistory(userName: string): void { export function getBanHistory(userName: string): void {
const command = webClient.protobuf.controller.Command_GetBanHistory.create({ userName }); BackendService.sendModeratorCommand('Command_GetBanHistory', { userName }, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetBanHistory.ext': command }); responseName: 'Response_BanHistory',
onSuccess: (response) => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => { ModeratorPersistence.banHistory(userName, response.banList);
const { responseCode } = raw; },
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { banList } = raw['.Response_BanHistory.ext'];
ModeratorPersistence.banHistory(userName, banList);
return;
default:
error = 'Failed to get ban history.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,27 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
export function getWarnHistory(userName: string): void { export function getWarnHistory(userName: string): void {
const command = webClient.protobuf.controller.Command_GetWarnHistory.create({ userName }); BackendService.sendModeratorCommand('Command_GetWarnHistory', { userName }, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetWarnHistory.ext': command }); responseName: 'Response_WarnHistory',
onSuccess: (response) => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => { ModeratorPersistence.warnHistory(userName, response.warnList);
const { responseCode } = raw; },
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { warnList } = raw['.Response_WarnHistory.ext'];
ModeratorPersistence.warnHistory(userName, warnList);
return;
default:
error = 'Failed to get warn history.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,27 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
export function getWarnList(modName: string, userName: string, userClientid: string): void { export function getWarnList(modName: string, userName: string, userClientid: string): void {
const command = webClient.protobuf.controller.Command_GetWarnList.create({ modName, userName, userClientid }); BackendService.sendModeratorCommand('Command_GetWarnList', { modName, userName, userClientid }, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetWarnList.ext': command }); responseName: 'Response_WarnList',
onSuccess: (response) => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => { ModeratorPersistence.warnListOptions(response.warning);
const { responseCode } = raw; },
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { warning } = raw['.Response_WarnList.ext'];
ModeratorPersistence.warnListOptions(warning);
return;
default:
error = 'Failed to get warn list.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -0,0 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence';
export function grantReplayAccess(replayId: number, moderatorName: string): void {
BackendService.sendModeratorCommand('Command_GrantReplayAccess', { replayId, moderatorName }, {
onSuccess: () => {
ModeratorPersistence.grantReplayAccess(replayId, moderatorName);
},
});
}

View file

@ -1,6 +1,10 @@
export * from './banFromServer'; export * from './banFromServer';
export * from './forceActivateUser';
export * from './getAdminNotes';
export * from './getBanHistory'; export * from './getBanHistory';
export * from './getWarnHistory'; export * from './getWarnHistory';
export * from './getWarnList'; export * from './getWarnList';
export * from './grantReplayAccess';
export * from './updateAdminNotes';
export * from './viewLogHistory'; export * from './viewLogHistory';
export * from './warnUser'; export * from './warnUser';

View file

@ -0,0 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence';
export function updateAdminNotes(userName: string, notes: string): void {
BackendService.sendModeratorCommand('Command_UpdateAdminNotes', { userName, notes }, {
onSuccess: () => {
ModeratorPersistence.updateAdminNotes(userName, notes);
},
});
}

View file

@ -1,28 +1,12 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
import { LogFilters } from 'types'; import { LogFilters } from 'types';
export function viewLogHistory(filters: LogFilters): void { export function viewLogHistory(filters: LogFilters): void {
const command = webClient.protobuf.controller.Command_ViewLogHistory.create(filters); BackendService.sendModeratorCommand('Command_ViewLogHistory', filters, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_ViewLogHistory.ext': command }); responseName: 'Response_ViewLogHistory',
onSuccess: (response) => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => { ModeratorPersistence.viewLogs(response.logMessage);
const { responseCode } = raw; },
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { logMessage } = raw['.Response_ViewLogHistory.ext'];
ModeratorPersistence.viewLogs(logMessage)
return;
default:
error = 'Failed to retrieve log history.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,26 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { ModeratorPersistence } from '../../persistence'; import { ModeratorPersistence } from '../../persistence';
export function warnUser(userName: string, reason: string, clientid?: string, removeMessage?: boolean): void { export function warnUser(userName: string, reason: string, clientid?: string, removeMessages?: number): void {
const command = webClient.protobuf.controller.Command_WarnUser.create({ userName, reason, clientid, removeMessage }); BackendService.sendModeratorCommand('Command_WarnUser', { userName, reason, clientid, removeMessages }, {
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_WarnUser.ext': command }); onSuccess: () => {
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
const { responseCode } = raw;
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
ModeratorPersistence.warnUser(userName); ModeratorPersistence.warnUser(userName);
return; },
default:
error = 'Failed to warn user.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,21 +1,11 @@
import { BackendService } from '../../services/BackendService';
import { RoomPersistence } from '../../persistence'; import { RoomPersistence } from '../../persistence';
import webClient from '../../WebClient';
import { GameConfig } from 'types'; import { GameConfig } from 'types';
export function createGame(roomId: number, gameConfig: GameConfig): void { export function createGame(roomId: number, gameConfig: GameConfig): void {
const command = webClient.protobuf.controller.Command_CreateGame.create(gameConfig); BackendService.sendRoomCommand(roomId, 'Command_CreateGame', gameConfig, {
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_CreateGame.ext': command }); onSuccess: () => {
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
RoomPersistence.gameCreated(roomId); RoomPersistence.gameCreated(roomId);
break; },
default:
console.log('Failed to do the thing');
}
}); });
} }

View file

@ -1,21 +1,11 @@
import { BackendService } from '../../services/BackendService';
import { RoomPersistence } from '../../persistence'; import { RoomPersistence } from '../../persistence';
import webClient from '../../WebClient'; import { JoinGameParams } from 'types';
import { GameConfig, JoinGameParams } from 'types';
export function joinGame(roomId: number, joinGameParams: JoinGameParams): void { export function joinGame(roomId: number, joinGameParams: JoinGameParams): void {
const command = webClient.protobuf.controller.Command_JoinGame.create(joinGameParams); BackendService.sendRoomCommand(roomId, 'Command_JoinGame', joinGameParams, {
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_JoinGame.ext': command }); onSuccess: () => {
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
RoomPersistence.joinedGame(roomId, joinGameParams.gameId); RoomPersistence.joinedGame(roomId, joinGameParams.gameId);
break; },
default:
console.log('Failed to do the thing');
}
}); });
} }

View file

@ -1,19 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { RoomPersistence } from '../../persistence'; import { RoomPersistence } from '../../persistence';
import webClient from '../../WebClient';
export function leaveRoom(roomId: number): void { export function leaveRoom(roomId: number): void {
const command = webClient.protobuf.controller.Command_LeaveRoom.create(); BackendService.sendRoomCommand(roomId, 'Command_LeaveRoom', {}, {
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_LeaveRoom.ext': command }); onSuccess: () => {
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
RoomPersistence.leaveRoom(roomId); RoomPersistence.leaveRoom(roomId);
break; },
default:
console.log(`Failed to leave Room ${roomId} [${responseCode}] : `, raw);
}
}); });
} }

View file

@ -1,4 +1,4 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
export function roomSay(roomId: number, message: string): void { export function roomSay(roomId: number, message: string): void {
const trimmed = message.trim(); const trimmed = message.trim();
@ -7,8 +7,5 @@ export function roomSay(roomId: number, message: string): void {
return; return;
} }
const command = webClient.protobuf.controller.Command_RoomSay.create({ 'message': trimmed }); BackendService.sendRoomCommand(roomId, 'Command_RoomSay', { message: trimmed }, {});
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_RoomSay.ext': command });
webClient.protobuf.sendRoomCommand(roomId, rc);
} }

View file

@ -1,25 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function accountEdit(passwordCheck: string, realName?: string, email?: string, country?: string): void { export function accountEdit(passwordCheck: string, realName?: string, email?: string, country?: string): void {
const command = webClient.protobuf.controller.Command_AccountEdit.create({ passwordCheck, realName, email, country }); BackendService.sendSessionCommand('Command_AccountEdit', { passwordCheck, realName, email, country }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountEdit.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.accountEditChanged(realName, email, country); SessionPersistence.accountEditChanged(realName, email, country);
break; },
case webClient.protobuf.controller.Response.ResponseCode.RespFunctionNotAllowed:
console.log('Not allowed');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
console.log('Wrong password');
break;
default:
console.log('Failed to update information');
}
}); });
} }

View file

@ -1,27 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { common } from 'protobufjs';
import IBytesValue = common.IBytesValue;
export function accountImage(image: IBytesValue): void { export function accountImage(image: Uint8Array): void {
const command = webClient.protobuf.controller.Command_AccountImage.create({ image }); BackendService.sendSessionCommand('Command_AccountImage', { image }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountImage.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.accountImageChanged(image); SessionPersistence.accountImageChanged(image);
break; },
case webClient.protobuf.controller.Response.ResponseCode.RespFunctionNotAllowed:
console.log('Not allowed');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
console.log('Wrong password');
break;
default:
console.log('Failed to update information');
}
}); });
} }

View file

@ -1,19 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function accountPassword(oldPassword: string, newPassword: string, hashedNewPassword: string): void { export function accountPassword(oldPassword: string, newPassword: string, hashedNewPassword: string): void {
const command = webClient.protobuf.controller.Command_AccountPassword.create({ oldPassword, newPassword, hashedNewPassword }); BackendService.sendSessionCommand('Command_AccountPassword', { oldPassword, newPassword, hashedNewPassword }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountPassword.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.accountPasswordChange(); SessionPersistence.accountPasswordChange();
break; },
default:
console.log('Failed to change password');
}
}); });
} }

View file

@ -2,6 +2,8 @@ import { AccountActivationParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { ProtoController } from '../../services/ProtoController';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { disconnect, login, updateStatus } from './'; import { disconnect, login, updateStatus } from './';
@ -9,23 +11,21 @@ import { disconnect, login, updateStatus } from './';
export function activate(options: WebSocketConnectOptions, passwordSalt?: string): void { export function activate(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token } = options as unknown as AccountActivationParams; const { userName, token } = options as unknown as AccountActivationParams;
const accountActivationConfig = { BackendService.sendSessionCommand('Command_Activate', {
...webClient.clientConfig, ...webClient.clientConfig,
userName, userName,
token, token,
}; }, {
onResponseCode: {
const command = webClient.protobuf.controller.Command_Activate.create(accountActivationConfig); [ProtoController.root.Response.ResponseCode.RespActivationAccepted]: () => {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Activate.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
SessionPersistence.accountActivationSuccess(); SessionPersistence.accountActivationSuccess();
login(options, passwordSalt); login(options, passwordSalt);
} else { },
},
onError: () => {
updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed'); updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
disconnect(); disconnect();
SessionPersistence.accountActivationFailed(); SessionPersistence.accountActivationFailed();
} },
}); });
} }

View file

@ -1,4 +1,4 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function addToBuddyList(userName: string): void { export function addToBuddyList(userName: string): void {
@ -10,16 +10,9 @@ export function addToIgnoreList(userName: string): void {
} }
export function addToList(list: string, userName: string): void { export function addToList(list: string, userName: string): void {
const command = webClient.protobuf.controller.Command_AddToList.create({ list, userName }); BackendService.sendSessionCommand('Command_AddToList', { list, userName }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AddToList.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.addToList(list, userName); SessionPersistence.addToList(list, userName);
break; },
default:
console.error('Failed to add to list', responseCode);
}
}); });
} }

View file

@ -1,19 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function deckDel(deckId: number): void { export function deckDel(deckId: number): void {
const command = webClient.protobuf.controller.Command_DeckDel.create({ deckId }); BackendService.sendSessionCommand('Command_DeckDel', { deckId }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckDel.ext': command }); onSuccess: () => {
SessionPersistence.deleteServerDeck(deckId);
webClient.protobuf.sendSessionCommand(sc, raw => { },
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckDelete(deckId);
break;
default:
console.log('Failed to do the thing');
}
}); });
} }

View file

@ -1,19 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function deckDelDir(path: string): void { export function deckDelDir(path: string): void {
const command = webClient.protobuf.controller.Command_DeckDelDir.create({ path }); BackendService.sendSessionCommand('Command_DeckDelDir', { path }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckDelDir.ext': command }); onSuccess: () => {
SessionPersistence.deleteServerDeckDir(path);
webClient.protobuf.sendSessionCommand(sc, raw => { },
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckDeleteDir(path);
break;
default:
console.log('Failed to do the thing');
}
}); });
} }

View file

@ -1,19 +0,0 @@
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
export function deckDownload(deckId: number): void {
const command = webClient.protobuf.controller.Command_DeckDownload.create({ deckId });
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckDownload.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckDownload(deckId);
break;
default:
console.log('Failed to do the thing');
}
});
}

View file

@ -1,22 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function deckList(): void { export function deckList(): void {
const command = webClient.protobuf.controller.Command_DeckList.create(); BackendService.sendSessionCommand('Command_DeckList', {}, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckList.ext': command }); responseName: 'Response_DeckList',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, raw => { SessionPersistence.updateServerDecks(response);
const { responseCode } = raw; },
const response = raw['.Response_DeckList.ext'];
if (response) {
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckList(response);
break;
default:
console.log('Failed to do the thing');
}
}
}); });
} }

View file

@ -1,19 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function deckNewDir(path: string, dirName: string): void { export function deckNewDir(path: string, dirName: string): void {
const command = webClient.protobuf.controller.Command_DeckNewDir.create({ path, dirName }); BackendService.sendSessionCommand('Command_DeckNewDir', { path, dirName }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckNewDir.ext': command }); onSuccess: () => {
SessionPersistence.createServerDeckDir(path, dirName);
webClient.protobuf.sendSessionCommand(sc, raw => { },
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckNewDir(path, dirName);
break;
default:
console.log('Failed to do the thing');
}
}); });
} }

View file

@ -1,23 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function deckUpload(path: string, deckId: number, deckList: string): void { export function deckUpload(path: string, deckId: number, deckList: string): void {
const command = webClient.protobuf.controller.Command_DeckUpload.create({ path, deckId, deckList }); BackendService.sendSessionCommand('Command_DeckUpload', { path, deckId, deckList }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckUpload.ext': command }); responseName: 'Response_DeckUpload',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, raw => { SessionPersistence.uploadServerDeck(path, response.newFile);
const { responseCode } = raw; },
const response = raw['.Response_DeckUpload.ext'];
if (response) {
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.deckUpload(response);
break;
default:
console.log('Failed to do the thing');
}
}
}); });
} }

View file

@ -2,30 +2,27 @@ import { ForgotPasswordChallengeParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { disconnect, updateStatus } from './'; import { disconnect, updateStatus } from './';
export function forgotPasswordChallenge(options: WebSocketConnectOptions): void { export function forgotPasswordChallenge(options: WebSocketConnectOptions): void {
const { userName, email } = options as unknown as ForgotPasswordChallengeParams; const { userName, email } = options as unknown as ForgotPasswordChallengeParams;
const forgotPasswordChallengeConfig = { BackendService.sendSessionCommand('Command_ForgotPasswordChallenge', {
...webClient.clientConfig, ...webClient.clientConfig,
userName, userName,
email, email,
}; }, {
onSuccess: () => {
const command = webClient.protobuf.controller.Command_ForgotPasswordChallenge.create(forgotPasswordChallengeConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ForgotPasswordChallenge.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPassword(); SessionPersistence.resetPassword();
} else { disconnect();
},
onError: () => {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed(); SessionPersistence.resetPasswordFailed();
}
disconnect(); disconnect();
},
}); });
} }

View file

@ -2,6 +2,7 @@ import { ForgotPasswordParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { disconnect, updateStatus } from './'; import { disconnect, updateStatus } from './';
@ -9,30 +10,25 @@ import { disconnect, updateStatus } from './';
export function forgotPasswordRequest(options: WebSocketConnectOptions): void { export function forgotPasswordRequest(options: WebSocketConnectOptions): void {
const { userName } = options as unknown as ForgotPasswordParams; const { userName } = options as unknown as ForgotPasswordParams;
const forgotPasswordConfig = { BackendService.sendSessionCommand('Command_ForgotPasswordRequest', {
...webClient.clientConfig, ...webClient.clientConfig,
userName, userName,
}; }, {
responseName: 'Response_ForgotPasswordRequest',
const command = webClient.protobuf.controller.Command_ForgotPasswordRequest.create(forgotPasswordConfig); onSuccess: (resp) => {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ForgotPasswordRequest.ext': command }); if (resp?.challengeEmail) {
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
const resp = raw['.Response_ForgotPasswordRequest.ext'];
if (resp.challengeEmail) {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordChallenge(); SessionPersistence.resetPasswordChallenge();
} else { } else {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPassword(); SessionPersistence.resetPassword();
} }
} else { disconnect();
},
onError: () => {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed(); SessionPersistence.resetPasswordFailed();
}
disconnect(); disconnect();
},
}); });
} }

View file

@ -2,6 +2,7 @@ import { ForgotPasswordResetParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { hashPassword } from '../../utils'; import { hashPassword } from '../../utils';
@ -10,30 +11,28 @@ import { disconnect, updateStatus } from '.';
export function forgotPasswordReset(options: WebSocketConnectOptions, passwordSalt?: string): void { export function forgotPasswordReset(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token, newPassword } = options as unknown as ForgotPasswordResetParams; const { userName, token, newPassword } = options as unknown as ForgotPasswordResetParams;
const forgotPasswordResetConfig: any = { const params: any = {
...webClient.clientConfig, ...webClient.clientConfig,
userName, userName,
token, token,
}; };
if (passwordSalt) { if (passwordSalt) {
forgotPasswordResetConfig.hashedNewPassword = hashPassword(passwordSalt, newPassword); params.hashedNewPassword = hashPassword(passwordSalt, newPassword);
} else { } else {
forgotPasswordResetConfig.newPassword = newPassword; params.newPassword = newPassword;
} }
const command = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig); BackendService.sendSessionCommand('Command_ForgotPasswordReset', params, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ForgotPasswordReset.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordSuccess(); SessionPersistence.resetPasswordSuccess();
} else { disconnect();
},
onError: () => {
updateStatus(StatusEnum.DISCONNECTED, null); updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed(); SessionPersistence.resetPasswordFailed();
}
disconnect(); disconnect();
},
}); });
} }

View file

@ -1,26 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function getGamesOfUser(userName: string): void { export function getGamesOfUser(userName: string): void {
const command = webClient.protobuf.controller.Command_GetGamesOfUser.create({ userName }); BackendService.sendSessionCommand('Command_GetGamesOfUser', { userName }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_GetGamesOfUser.ext': command }); responseName: 'Response_GetGamesOfUser',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
const response = raw['.Response_GetGamesOfUser.ext'];
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.getGamesOfUser(userName, response); SessionPersistence.getGamesOfUser(userName, response);
break; },
case webClient.protobuf.controller.Response.ResponseCode.RespFunctionNotAllowed:
console.log('Not allowed');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
console.log('Wrong password');
break;
default:
console.log('Failed to update information');
}
}); });
} }

View file

@ -1,26 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function getUserInfo(userName: string): void { export function getUserInfo(userName: string): void {
const command = webClient.protobuf.controller.Command_GetUserInfo.create({ userName }); BackendService.sendSessionCommand('Command_GetUserInfo', { userName }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_GetUserInfo.ext': command }); responseName: 'Response_GetUserInfo',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, raw => { SessionPersistence.getUserInfo(response.userInfo);
const { responseCode } = raw; },
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { userInfo } = raw['.Response_GetUserInfo.ext'];
SessionPersistence.getUserInfo(userInfo);
break;
case webClient.protobuf.controller.Response.ResponseCode.RespFunctionNotAllowed:
console.log('Not allowed');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
console.log('Wrong password');
break;
default:
console.log('Failed to update information');
}
}); });
} }

View file

@ -6,12 +6,11 @@ export * from './addToList';
export * from './connect'; export * from './connect';
export * from './deckDel'; export * from './deckDel';
export * from './deckDelDir'; export * from './deckDelDir';
export * from './deckDownload';
export * from './deckList'; export * from './deckList';
export * from './deckNewDir'; export * from './deckNewDir';
export * from './deckUpload'; export * from './deckUpload';
export * from './disconnect'; export * from './disconnect';
export * from './forgotPasswordChallenge' export * from './forgotPasswordChallenge';
export * from './forgotPasswordRequest'; export * from './forgotPasswordRequest';
export * from './forgotPasswordReset'; export * from './forgotPasswordReset';
export * from './getGamesOfUser'; export * from './getGamesOfUser';
@ -24,12 +23,8 @@ export * from './message';
export * from './ping'; export * from './ping';
export * from './register'; export * from './register';
export * from './removeFromList'; export * from './removeFromList';
export * from './replayDeleteMatch';
export * from './replayList';
export * from './replayModifyMatch';
export * from './requestPasswordSalt'; export * from './requestPasswordSalt';
export * from './updateStatus'; export * from './updateStatus';
/** TODO
* REPLAY_DELETE_MATCH
* REPLAY_DOWNLOAD
* REPLAY_LIST
* REPLAY_MODIFY_MATCH
*/

View file

@ -1,37 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { RoomPersistence } from '../../persistence'; import { RoomPersistence } from '../../persistence';
export function joinRoom(roomId: number): void { export function joinRoom(roomId: number): void {
const command = webClient.protobuf.controller.Command_JoinRoom.create({ roomId }); BackendService.sendSessionCommand('Command_JoinRoom', { roomId }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_JoinRoom.ext': command }); responseName: 'Response_JoinRoom',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, (raw) => { RoomPersistence.joinRoom(response.roomInfo);
const { responseCode } = raw; },
let error: string;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { roomInfo } = raw['.Response_JoinRoom.ext'];
RoomPersistence.joinRoom(roomInfo);
return;
case webClient.protobuf.controller.Response.ResponseCode.RespNameNotFound:
error = 'Failed to join the room: it doesn\'t exist on the server.';
break;
case webClient.protobuf.controller.Response.ResponseCode.RespContextError:
error = 'The server thinks you are in the room but Cockatrice is unable to display it. Try restarting Cockatrice.';
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUserLevelTooLow:
error = 'You do not have the required permission to join this room.';
break;
default:
error = 'Failed to join the room due to an unknown error.';
break;
}
if (error) {
console.error(responseCode, error);
}
}); });
} }

View file

@ -1,8 +1,5 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
export function listRooms(): void { export function listRooms(): void {
const command = webClient.protobuf.controller.Command_ListRooms.create(); BackendService.sendSessionCommand('Command_ListRooms', {}, {});
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ListRooms.ext': command });
webClient.protobuf.sendSessionCommand(sc);
} }

View file

@ -1,23 +1,11 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function listUsers(): void { export function listUsers(): void {
const command = webClient.protobuf.controller.Command_ListUsers.create(); BackendService.sendSessionCommand('Command_ListUsers', {}, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ListUsers.ext': command }); responseName: 'Response_ListUsers',
onSuccess: (response) => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
const response = raw['.Response_ListUsers.ext'];
if (response) {
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.updateUsers(response.userList); SessionPersistence.updateUsers(response.userList);
break; },
default:
console.log(`Failed to fetch Server Rooms [${responseCode}] : `, raw);
}
}
}); });
} }

View file

@ -1,5 +1,7 @@
import { StatusEnum, WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { ProtoController } from '../../services/ProtoController';
import { hashPassword } from '../../utils'; import { hashPassword } from '../../utils';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
@ -25,13 +27,18 @@ export function login(options: WebSocketConnectOptions, passwordSalt?: string):
loginConfig.password = password; loginConfig.password = password;
} }
const command = webClient.protobuf.controller.Command_Login.create(loginConfig); const { ResponseCode } = ProtoController.root.Response;
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Login.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => { const onLoginError = (message: string, extra?: () => void) => {
const resp = raw['.Response_Login.ext']; updateStatus(StatusEnum.DISCONNECTED, message);
extra?.();
SessionPersistence.loginFailed();
disconnect();
};
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) { BackendService.sendSessionCommand('Command_Login', loginConfig, {
responseName: 'Response_Login',
onSuccess: (resp) => {
const { buddyList, ignoreList, userInfo } = resp; const { buddyList, ignoreList, userInfo } = resp;
SessionPersistence.updateBuddyList(buddyList); SessionPersistence.updateBuddyList(buddyList);
@ -43,50 +50,30 @@ export function login(options: WebSocketConnectOptions, passwordSalt?: string):
listRooms(); listRooms();
updateStatus(StatusEnum.LOGGED_IN, 'Logged in.'); updateStatus(StatusEnum.LOGGED_IN, 'Logged in.');
},
return; onResponseCode: {
} [ResponseCode.RespClientUpdateRequired]: () =>
onLoginError('Login failed: missing features'),
switch (raw.responseCode) { [ResponseCode.RespWrongPassword]: () =>
case webClient.protobuf.controller.Response.ResponseCode.RespClientUpdateRequired: onLoginError('Login failed: incorrect username or password'),
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: missing features'); [ResponseCode.RespUsernameInvalid]: () =>
break; onLoginError('Login failed: incorrect username or password'),
[ResponseCode.RespWouldOverwriteOldSession]: () =>
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword: onLoginError('Login failed: duplicated user session'),
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid: [ResponseCode.RespUserIsBanned]: () =>
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: incorrect username or password'); onLoginError('Login failed: banned user'),
break; [ResponseCode.RespRegistrationRequired]: () =>
onLoginError('Login failed: registration required'),
case webClient.protobuf.controller.Response.ResponseCode.RespWouldOverwriteOldSession: [ResponseCode.RespClientIdRequired]: () =>
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: duplicated user session'); onLoginError('Login failed: missing client ID'),
break; [ResponseCode.RespContextError]: () =>
onLoginError('Login failed: server error'),
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned: [ResponseCode.RespAccountNotActivated]: () =>
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: banned user'); onLoginError('Login failed: account not activated',
break; () => SessionPersistence.accountAwaitingActivation(options)
),
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired: },
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required'); onError: (responseCode) =>
break; onLoginError(`Login failed: unknown error: ${responseCode}`),
case webClient.protobuf.controller.Response.ResponseCode.RespClientIdRequired:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: missing client ID');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespContextError:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: server error');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespAccountNotActivated:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: account not activated');
SessionPersistence.accountAwaitingActivation(options);
break;
default:
updateStatus(StatusEnum.DISCONNECTED, `Login failed: unknown error: ${raw.responseCode}`);
}
SessionPersistence.loginFailed();
disconnect();
}); });
} }

View file

@ -1,31 +1,10 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function message(userName: string, message: string): void { export function message(userName: string, message: string): void {
const command = webClient.protobuf.controller.Command_Message.create({ userName, message }); BackendService.sendSessionCommand('Command_Message', { userName, message }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Message.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, raw => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.directMessageSent(userName, message); SessionPersistence.directMessageSent(userName, message);
break; },
case webClient.protobuf.controller.Response.ResponseCode.RespNameNotFound:
console.log('Name not found');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespInIgnoreList:
console.log('On ignore list');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespChatFlood:
console.log('Flooding chat');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
console.log('Wrong password');
break;
default:
console.log('Failed to send direct message');
}
}); });
} }

View file

@ -1,8 +1,7 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
export function ping(pingReceived: Function): void { export function ping(pingReceived: Function): void {
const command = webClient.protobuf.controller.Command_Ping.create(); BackendService.sendSessionCommand('Command_Ping', {}, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Ping.ext': command }); onResponse: (raw) => pingReceived(raw),
});
webClient.protobuf.sendSessionCommand(sc, pingReceived);
} }

View file

@ -1,17 +1,18 @@
import { ServerRegisterParams } from 'store'; import { ServerRegisterParams } from 'store';
import { WebSocketConnectOptions } from 'types'; import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { ProtoController } from '../../services/ProtoController';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { hashPassword } from '../../utils'; import { hashPassword } from '../../utils';
import NormalizeService from '../../utils/NormalizeService';
import { login, disconnect } from './'; import { login, disconnect, updateStatus } from './';
export function register(options: WebSocketConnectOptions, passwordSalt?: string): void { export function register(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, password, email, country, realName } = options as ServerRegisterParams; const { userName, password, email, country, realName } = options as ServerRegisterParams;
const registerConfig: any = { const params: any = {
...webClient.clientConfig, ...webClient.clientConfig,
userName, userName,
email, email,
@ -20,55 +21,57 @@ export function register(options: WebSocketConnectOptions, passwordSalt?: string
}; };
if (passwordSalt) { if (passwordSalt) {
registerConfig.hashedPassword = hashPassword(passwordSalt, password); params.hashedPassword = hashPassword(passwordSalt, password);
} else { } else {
registerConfig.password = password; params.password = password;
} }
const command = webClient.protobuf.controller.Command_Register.create(registerConfig); const { ResponseCode } = ProtoController.root.Response;
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Register.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAccepted) {
login(options, passwordSalt);
SessionPersistence.registrationSuccess()
return;
}
switch (raw.responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation:
SessionPersistence.accountAwaitingActivation(options);
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUserAlreadyExists:
SessionPersistence.registrationUserNameError('Username is taken');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
SessionPersistence.registrationUserNameError('Invalid username');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespPasswordTooShort:
SessionPersistence.registrationPasswordError('Your password was too short');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespEmailRequiredToRegister:
SessionPersistence.registrationRequiresEmail();
break;
case webClient.protobuf.controller.Response.ResponseCode.RespEmailBlackListed:
SessionPersistence.registrationEmailError('This email provider has been blocked');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespTooManyRequests:
SessionPersistence.registrationEmailError('Max accounts reached for this email');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled:
SessionPersistence.registrationFailed('Registration is currently disabled');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
SessionPersistence.registrationFailed(raw.reasonStr, raw.endTime);
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
default:
SessionPersistence.registrationFailed('Registration failed due to a server issue');
break;
}
const onRegistrationError = (action: () => void) => {
action();
updateStatus(StatusEnum.DISCONNECTED, 'Registration failed');
disconnect(); disconnect();
};
BackendService.sendSessionCommand('Command_Register', params, {
onResponseCode: {
[ResponseCode.RespRegistrationAccepted]: () => {
login(options, passwordSalt);
SessionPersistence.registrationSuccess();
},
[ResponseCode.RespRegistrationAcceptedNeedsActivation]: () => {
updateStatus(StatusEnum.DISCONNECTED, 'Registration accepted, awaiting activation');
SessionPersistence.accountAwaitingActivation(options);
disconnect();
},
[ResponseCode.RespUserAlreadyExists]: () => onRegistrationError(
() => SessionPersistence.registrationUserNameError('Username is taken')
),
[ResponseCode.RespUsernameInvalid]: () => onRegistrationError(
() => SessionPersistence.registrationUserNameError('Invalid username')
),
[ResponseCode.RespPasswordTooShort]: () => onRegistrationError(
() => SessionPersistence.registrationPasswordError('Your password was too short')
),
[ResponseCode.RespEmailRequiredToRegister]: () => onRegistrationError(
() => SessionPersistence.registrationRequiresEmail()
),
[ResponseCode.RespEmailBlackListed]: () => onRegistrationError(
() => SessionPersistence.registrationEmailError('This email provider has been blocked')
),
[ResponseCode.RespTooManyRequests]: () => onRegistrationError(
() => SessionPersistence.registrationEmailError('Max accounts reached for this email')
),
[ResponseCode.RespRegistrationDisabled]: () => onRegistrationError(
() => SessionPersistence.registrationFailed('Registration is currently disabled')
),
[ResponseCode.RespUserIsBanned]: (raw) => onRegistrationError(
() => SessionPersistence.registrationFailed(raw.reasonStr, raw.endTime)
),
},
onError: () => onRegistrationError(
() => SessionPersistence.registrationFailed('Registration failed due to a server issue')
),
}); });
} }

View file

@ -1,4 +1,4 @@
import webClient from '../../WebClient'; import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
export function removeFromBuddyList(userName: string): void { export function removeFromBuddyList(userName: string): void {
@ -10,16 +10,9 @@ export function removeFromIgnoreList(userName: string): void {
} }
export function removeFromList(list: string, userName: string): void { export function removeFromList(list: string, userName: string): void {
const command = webClient.protobuf.controller.Command_RemoveFromList.create({ list, userName }); BackendService.sendSessionCommand('Command_RemoveFromList', { list, userName }, {
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_RemoveFromList.ext': command }); onSuccess: () => {
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
SessionPersistence.removeFromList(list, userName); SessionPersistence.removeFromList(list, userName);
break; },
default:
console.error('Failed to remove from list', responseCode);
}
}); });
} }

View file

@ -0,0 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence';
export function replayDeleteMatch(gameId: number): void {
BackendService.sendSessionCommand('Command_ReplayDeleteMatch', { gameId }, {
onSuccess: () => {
SessionPersistence.replayDeleteMatch(gameId);
},
});
}

View file

@ -0,0 +1,11 @@
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence';
export function replayList(): void {
BackendService.sendSessionCommand('Command_ReplayList', {}, {
responseName: 'Response_ReplayList',
onSuccess: (response) => {
SessionPersistence.replayList(response.matchList);
},
});
}

View file

@ -0,0 +1,10 @@
import { BackendService } from '../../services/BackendService';
import { SessionPersistence } from '../../persistence';
export function replayModifyMatch(gameId: number, doNotHide: boolean): void {
BackendService.sendSessionCommand('Command_ReplayModifyMatch', { gameId, doNotHide }, {
onSuccess: () => {
SessionPersistence.replayModifyMatch(gameId, doNotHide);
},
});
}

View file

@ -2,6 +2,8 @@ import { RequestPasswordSaltParams } from 'store';
import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types'; import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { BackendService } from '../../services/BackendService';
import { ProtoController } from '../../services/ProtoController';
import { SessionPersistence } from '../../persistence'; import { SessionPersistence } from '../../persistence';
import { import {
@ -15,64 +17,48 @@ import {
export function requestPasswordSalt(options: WebSocketConnectOptions): void { export function requestPasswordSalt(options: WebSocketConnectOptions): void {
const { userName } = options as RequestPasswordSaltParams; const { userName } = options as RequestPasswordSaltParams;
const registerConfig = { const onFailure = () => {
...webClient.clientConfig,
userName,
};
const command = webClient.protobuf.controller.Command_RequestPasswordSalt.create(registerConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_RequestPasswordSalt.ext': command });
webClient.protobuf.sendSessionCommand(sc, raw => {
switch (raw.responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk: {
const passwordSalt = raw['.Response_PasswordSalt.ext']?.passwordSalt;
switch (options.reason) { switch (options.reason) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT: { case WebSocketConnectReason.ACTIVATE_ACCOUNT:
activate(options, passwordSalt);
break;
}
case WebSocketConnectReason.PASSWORD_RESET: {
forgotPasswordReset(options, passwordSalt);
break;
}
case WebSocketConnectReason.LOGIN:
default: {
login(options, passwordSalt);
}
}
return;
}
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired: {
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required');
break;
}
default: {
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: Unknown Reason');
}
}
switch (options.reason) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT: {
SessionPersistence.accountActivationFailed(); SessionPersistence.accountActivationFailed();
break; break;
} case WebSocketConnectReason.PASSWORD_RESET:
case WebSocketConnectReason.PASSWORD_RESET: {
SessionPersistence.resetPasswordFailed(); SessionPersistence.resetPasswordFailed();
break; break;
} default:
case WebSocketConnectReason.LOGIN:
default: {
SessionPersistence.loginFailed(); SessionPersistence.loginFailed();
} }
}
disconnect(); disconnect();
};
BackendService.sendSessionCommand('Command_RequestPasswordSalt', {
...webClient.clientConfig,
userName,
}, {
responseName: 'Response_PasswordSalt',
onSuccess: (resp) => {
const passwordSalt = resp?.passwordSalt;
switch (options.reason) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
activate(options, passwordSalt);
break;
case WebSocketConnectReason.PASSWORD_RESET:
forgotPasswordReset(options, passwordSalt);
break;
default:
login(options, passwordSalt);
}
},
onResponseCode: {
[ProtoController.root.Response.ResponseCode.RespRegistrationRequired]: () => {
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required');
onFailure();
},
},
onError: () => {
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: Unknown Reason');
onFailure();
},
}); });
} }

View file

@ -4,8 +4,8 @@ import { leaveGame } from './leaveGame';
export const GameEvents: ProtobufEvents = { export const GameEvents: ProtobufEvents = {
'.Event_Join.ext': () => joinGame, '.Event_Join.ext': joinGame,
'.Event_Leave.ext': () => leaveGame, '.Event_Leave.ext': leaveGame,
'.Event_GameClosed.ext': () => console.log('Event_GameClosed.ext'), '.Event_GameClosed.ext': () => console.log('Event_GameClosed.ext'),
'.Event_GameHostChanged.ext': () => console.log('Event_GameHostChanged.ext'), '.Event_GameHostChanged.ext': () => console.log('Event_GameHostChanged.ext'),
'.Event_Kicked.ext': () => console.log('Event_Kicked.ext'), '.Event_Kicked.ext': () => console.log('Event_Kicked.ext'),

View file

@ -1,5 +1,5 @@
import { StatusEnum } from 'types'; import { StatusEnum } from 'types';
import webClient from '../../WebClient'; import { ProtoController } from '../../services/ProtoController';
import { updateStatus } from '../../commands/session'; import { updateStatus } from '../../commands/session';
import { ConnectionClosedData } from './interfaces'; import { ConnectionClosedData } from './interfaces';
@ -10,29 +10,30 @@ export function connectionClosed({ reason, reasonStr }: ConnectionClosedData): v
if (reasonStr) { if (reasonStr) {
message = reasonStr; message = reasonStr;
} else { } else {
const { CloseReason } = ProtoController.root.Event_ConnectionClosed;
switch (reason) { switch (reason) {
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.USER_LIMIT_REACHED: case CloseReason.USER_LIMIT_REACHED:
message = 'The server has reached its maximum user capacity'; message = 'The server has reached its maximum user capacity';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.TOO_MANY_CONNECTIONS: case CloseReason.TOO_MANY_CONNECTIONS:
message = 'There are too many concurrent connections from your address'; message = 'There are too many concurrent connections from your address';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.BANNED: case CloseReason.BANNED:
message = 'You are banned'; message = 'You are banned';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.DEMOTED: case CloseReason.DEMOTED:
message = 'You were demoted'; message = 'You were demoted';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.SERVER_SHUTDOWN: case CloseReason.SERVER_SHUTDOWN:
message = 'Scheduled server shutdown'; message = 'Scheduled server shutdown';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.USERNAMEINVALID: case CloseReason.USERNAMEINVALID:
message = 'Invalid username'; message = 'Invalid username';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.LOGGEDINELSEWERE: case CloseReason.LOGGEDINELSEWERE:
message = 'You have been logged out due to logging in at another location'; message = 'You have been logged out due to logging in at another location';
break; break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.OTHER: case CloseReason.OTHER:
default: default:
message = 'Unknown reason'; message = 'Unknown reason';
break; break;

View file

@ -3,8 +3,9 @@ import { addToList } from './addToList';
import { connectionClosed } from './connectionClosed'; import { connectionClosed } from './connectionClosed';
import { listRooms } from './listRooms'; import { listRooms } from './listRooms';
import { notifyUser } from './notifyUser'; import { notifyUser } from './notifyUser';
import { playerPropertiesChanged } from '../common/playerPropertiesChanged';
import { removeFromList } from './removeFromList'; import { removeFromList } from './removeFromList';
import { replayAdded } from './replayAdded';
import { serverCompleteList } from './serverCompleteList';
import { serverIdentification } from './serverIdentification'; import { serverIdentification } from './serverIdentification';
import { serverMessage } from './serverMessage'; import { serverMessage } from './serverMessage';
import { serverShutdown } from './serverShutdown'; import { serverShutdown } from './serverShutdown';
@ -20,8 +21,8 @@ export const SessionEvents: ProtobufEvents = {
'.Event_ListRooms.ext': listRooms, '.Event_ListRooms.ext': listRooms,
'.Event_NotifyUser.ext': notifyUser, '.Event_NotifyUser.ext': notifyUser,
'.Event_RemoveFromList.ext': removeFromList, '.Event_RemoveFromList.ext': removeFromList,
'.Event_ReplayAdded.ext': () => console.log('Event_ReplayAdded'), '.Event_ReplayAdded.ext': replayAdded,
'.Event_ServerCompleteList.ext': () => console.log('Event_ServerCompleteList'), '.Event_ServerCompleteList.ext': serverCompleteList,
'.Event_ServerIdentification.ext': serverIdentification, '.Event_ServerIdentification.ext': serverIdentification,
'.Event_ServerMessage.ext': serverMessage, '.Event_ServerMessage.ext': serverMessage,
'.Event_ServerShutdown.ext': serverShutdown, '.Event_ServerShutdown.ext': serverShutdown,

View file

@ -1,4 +1,4 @@
import { Game, NotificationType, Room, User } from 'types'; import { Game, NotificationType, ReplayMatch, Room, User } from 'types';
export interface AddToListData { export interface AddToListData {
listName: string; listName: string;
@ -13,6 +13,8 @@ export interface ConnectionClosedData {
export interface GameJoinedData { export interface GameJoinedData {
gameInfo: Game; gameInfo: Game;
gameTypes: any[];
hostId: number;
playerId: number; playerId: number;
spectator: boolean; spectator: boolean;
resuming: boolean; resuming: boolean;
@ -76,3 +78,13 @@ export interface UserMessageData {
receiverName: string; receiverName: string;
message: string; message: string;
} }
export interface ReplayAddedData {
matchInfo: ReplayMatch;
}
export interface ServerCompleteListData {
serverId: number;
userList: User[];
roomList: Room[];
}

View file

@ -0,0 +1,6 @@
import { SessionPersistence } from '../../persistence';
import { ReplayAddedData } from './interfaces';
export function replayAdded({ matchInfo }: ReplayAddedData): void {
SessionPersistence.replayAdded(matchInfo);
}

View file

@ -0,0 +1,7 @@
import { RoomPersistence, SessionPersistence } from '../../persistence';
import { ServerCompleteListData } from './interfaces';
export function serverCompleteList({ userList, roomList }: ServerCompleteListData): void {
SessionPersistence.updateUsers(userList);
RoomPersistence.updateRooms(roomList);
}

View file

@ -1,4 +1,4 @@
import { StatusEnum, WebSocketConnectReason } from 'types'; import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient'; import webClient from '../../WebClient';
import { import {
@ -24,48 +24,48 @@ export function serverIdentification(info: ServerIdentificationData): void {
return; return;
} }
const getPasswordSalt = passwordSaltSupported(serverOptions, webClient); const getPasswordSalt = passwordSaltSupported(serverOptions);
const { options } = webClient; const connectOptions = { ...webClient.options };
switch (options.reason) { switch (connectOptions.reason) {
case WebSocketConnectReason.LOGIN: case WebSocketConnectReason.LOGIN:
updateStatus(StatusEnum.LOGGING_IN, 'Logging In...'); updateStatus(StatusEnum.LOGGING_IN, 'Logging In...');
if (getPasswordSalt) { if (getPasswordSalt) {
requestPasswordSalt(options); requestPasswordSalt(connectOptions);
} else { } else {
login(options); login(connectOptions);
} }
break; break;
case WebSocketConnectReason.REGISTER: case WebSocketConnectReason.REGISTER:
const passwordSalt = getPasswordSalt ? generateSalt() : null; const passwordSalt = getPasswordSalt ? generateSalt() : null;
register(options, passwordSalt); register(connectOptions, passwordSalt);
break; break;
case WebSocketConnectReason.ACTIVATE_ACCOUNT: case WebSocketConnectReason.ACTIVATE_ACCOUNT:
if (getPasswordSalt) { if (getPasswordSalt) {
requestPasswordSalt(options); requestPasswordSalt(connectOptions);
} else { } else {
activate(options); activate(connectOptions);
} }
break; break;
case WebSocketConnectReason.PASSWORD_RESET_REQUEST: case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
forgotPasswordRequest(options); forgotPasswordRequest(connectOptions);
break; break;
case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE: case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE:
forgotPasswordChallenge(options); forgotPasswordChallenge(connectOptions);
break; break;
case WebSocketConnectReason.PASSWORD_RESET: case WebSocketConnectReason.PASSWORD_RESET:
if (getPasswordSalt) { if (getPasswordSalt) {
requestPasswordSalt(options); requestPasswordSalt(connectOptions);
} else { } else {
forgotPasswordReset(options); forgotPasswordReset(connectOptions);
} }
break; break;
default: default:
updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + options.reason); updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + connectOptions.reason);
disconnect(); disconnect();
break; break;
} }
webClient.options = {}; webClient.options = {} as WebSocketConnectOptions;
SessionPersistence.updateInfo(serverName, serverVersion); SessionPersistence.updateInfo(serverName, serverVersion);
} }

View file

@ -27,4 +27,20 @@ export class ModeratorPersistence {
static warnUser(userName: string): void { static warnUser(userName: string): void {
ServerDispatch.warnUser(userName); ServerDispatch.warnUser(userName);
} }
static grantReplayAccess(replayId: number, moderatorName: string): void {
ServerDispatch.grantReplayAccess(replayId, moderatorName);
}
static forceActivateUser(usernameToActivate: string, moderatorName: string): void {
ServerDispatch.forceActivateUser(usernameToActivate, moderatorName);
}
static getAdminNotes(userName: string, notes: string): void {
ServerDispatch.getAdminNotes(userName, notes);
}
static updateAdminNotes(userName: string, notes: string): void {
ServerDispatch.updateAdminNotes(userName, notes);
}
} }

View file

@ -1,5 +1,5 @@
import { ServerDispatch } from 'store'; import { ServerDispatch } from 'store';
import { DeckStorageTreeItem, StatusEnum, User, WebSocketConnectOptions } from 'types'; import { DeckList, DeckStorageTreeItem, ReplayMatch, StatusEnum, User, WebSocketConnectOptions } from 'types';
import { sanitizeHtml } from 'websocket/utils'; import { sanitizeHtml } from 'websocket/utils';
import { import {
@ -10,9 +10,6 @@ import {
UserMessageData UserMessageData
} from '../events/session/interfaces'; } from '../events/session/interfaces';
import NormalizeService from '../utils/NormalizeService'; import NormalizeService from '../utils/NormalizeService';
import { DeckList } from 'types';
import { common } from 'protobufjs';
import IBytesValue = common.IBytesValue;
export class SessionPersistence { export class SessionPersistence {
static initialized() { static initialized() {
@ -165,7 +162,7 @@ export class SessionPersistence {
ServerDispatch.accountEditChanged({ realName, email, country }); ServerDispatch.accountEditChanged({ realName, email, country });
} }
static accountImageChanged(avatarBmp: IBytesValue): void { static accountImageChanged(avatarBmp: Uint8Array): void {
ServerDispatch.accountImageChanged({ avatarBmp }); ServerDispatch.accountImageChanged({ avatarBmp });
} }
@ -178,7 +175,8 @@ export class SessionPersistence {
} }
static getGamesOfUser(userName: string, response: any): void { static getGamesOfUser(userName: string, response: any): void {
console.log('getGamesOfUser'); // Response_GetGamesOfUser contains a gameList field — log for now until game layer is complete
console.log('getGamesOfUser', userName, response);
} }
static gameJoined(gameJoinedData: GameJoinedData): void { static gameJoined(gameJoinedData: GameJoinedData): void {
@ -209,28 +207,40 @@ export class SessionPersistence {
ServerDispatch.removeFromList(list, userName); ServerDispatch.removeFromList(list, userName);
} }
static deckDelete(deckId: number): void { static deleteServerDeck(deckId: number): void {
console.log('deckDelete', deckId); ServerDispatch.deckDelete(deckId);
} }
static deckDeleteDir(path: string): void { static updateServerDecks(deckList: DeckList): void {
console.log('deckDeleteDir', path); ServerDispatch.backendDecks(deckList);
} }
static deckDownload(deckId: number): void { static uploadServerDeck(path: string, treeItem: DeckStorageTreeItem): void {
console.log('deckDownload', deckId); ServerDispatch.deckUpload(path, treeItem);
} }
static deckList(deckList: DeckList): void { static createServerDeckDir(path: string, dirName: string): void {
console.log('deckList', deckList); ServerDispatch.deckNewDir(path, dirName);
} }
static deckNewDir(path: string, dirName: string): void { static deleteServerDeckDir(path: string): void {
console.log('deckNewDir', path, dirName); ServerDispatch.deckDelDir(path);
} }
static deckUpload(treeItem: DeckStorageTreeItem): void { static replayList(matchList: ReplayMatch[]): void {
console.log('deckUpload', treeItem); ServerDispatch.replayList(matchList);
}
static replayAdded(matchInfo: ReplayMatch): void {
ServerDispatch.replayAdded(matchInfo);
}
static replayModifyMatch(gameId: number, doNotHide: boolean): void {
ServerDispatch.replayModifyMatch(gameId, doNotHide);
}
static replayDeleteMatch(gameId: number): void {
ServerDispatch.replayDeleteMatch(gameId);
} }
} }

View file

@ -1,5 +1,5 @@
export { AdminPersistence } from './AdminPresistence'; export { AdminPersistence } from './AdminPersistence';
export { RoomPersistence } from './RoomPersistence'; export { RoomPersistence } from './RoomPersistence';
export { SessionPersistence } from './SessionPersistence'; export { SessionPersistence } from './SessionPersistence';
export { ModeratorPersistence } from './ModeratorPresistence'; export { ModeratorPersistence } from './ModeratorPersistence';
export { GamePersistence } from './GamePersistence'; export { GamePersistence } from './GamePersistence';

View file

@ -0,0 +1,82 @@
import webClient from '../WebClient';
import { ProtoController } from './ProtoController';
export interface CommandOptions {
responseName?: string;
onSuccess?: (response: any, raw: any) => void;
onError?: (responseCode: number, raw: any) => void;
onResponseCode?: { [code: number]: (raw: any) => void };
onResponse?: (raw: any) => void;
}
export class BackendService {
static sendSessionCommand(commandName: string, params: any, options: CommandOptions): void {
const command = ProtoController.root[commandName].create(params || {});
const sc = ProtoController.root.SessionCommand.create({
[`.${commandName}.ext`]: command,
});
webClient.protobuf.sendSessionCommand(sc, raw => {
BackendService.handleResponse(commandName, raw, options);
});
}
static sendRoomCommand(roomId: number, commandName: string, params: any, options: CommandOptions): void {
const command = ProtoController.root[commandName].create(params || {});
const rc = ProtoController.root.RoomCommand.create({
[`.${commandName}.ext`]: command,
});
webClient.protobuf.sendRoomCommand(roomId, rc, raw => {
BackendService.handleResponse(commandName, raw, options);
});
}
static sendModeratorCommand(commandName: string, params: any, options: CommandOptions): void {
const command = ProtoController.root[commandName].create(params || {});
const mc = ProtoController.root.ModeratorCommand.create({
[`.${commandName}.ext`]: command,
});
webClient.protobuf.sendModeratorCommand(mc, raw => {
BackendService.handleResponse(commandName, raw, options);
});
}
static sendAdminCommand(commandName: string, params: any, options: CommandOptions): void {
const command = ProtoController.root[commandName].create(params || {});
const ac = ProtoController.root.AdminCommand.create({
[`.${commandName}.ext`]: command,
});
webClient.protobuf.sendAdminCommand(ac, raw => {
BackendService.handleResponse(commandName, raw, options);
});
}
private static handleResponse(commandName: string, raw: any, options: CommandOptions): void {
if (options.onResponse) {
options.onResponse(raw);
return;
}
const { responseCode } = raw;
if (responseCode === ProtoController.root.Response.ResponseCode.RespOk) {
if (options.onSuccess) {
const response = options.responseName
? raw[`.${options.responseName}.ext`]
: raw;
options.onSuccess(response, raw);
}
return;
}
if (options.onResponseCode?.[responseCode]) {
options.onResponseCode[responseCode](raw);
return;
}
if (options.onError) {
options.onError(responseCode, raw);
} else {
console.error(`${commandName} failed with response code: ${responseCode}`);
}
}
}

View file

@ -0,0 +1,24 @@
import protobuf from 'protobufjs';
import { SessionPersistence } from '../persistence';
import ProtoFiles from '../../proto-files.json';
const PB_FILE_DIR = `${process.env.PUBLIC_URL}/pb`;
// Leaf module — no imports from the websocket layer other than persistence.
// Both BackendService and ProtobufService import this; neither should import
// the other for controller access, avoiding circular dependency cycles.
export const ProtoController = {
root: null as any,
load(): void {
const files = ProtoFiles.map(file => `${PB_FILE_DIR}/${file}`);
ProtoController.root = new protobuf.Root();
ProtoController.root.load(files, { keepCase: false }, (err: Error) => {
if (err) {
throw err;
}
SessionPersistence.initialized();
});
},
};

View file

@ -1,19 +1,13 @@
import protobuf from 'protobufjs';
import { CommonEvents, GameEvents, RoomEvents, SessionEvents } from '../events'; import { CommonEvents, GameEvents, RoomEvents, SessionEvents } from '../events';
import { SessionPersistence } from '../persistence';
import { WebClient } from '../WebClient'; import { WebClient } from '../WebClient';
import { SessionCommands } from 'websocket'; import { SessionCommands } from 'websocket';
import ProtoFiles from '../../proto-files.json'; import { ProtoController } from './ProtoController';
export interface ProtobufEvents { export interface ProtobufEvents {
[event: string]: Function; [event: string]: Function;
} }
export class ProtobufService { export class ProtobufService {
static PB_FILE_DIR = `${process.env.PUBLIC_URL}/pb`;
public controller;
private cmdId = 0; private cmdId = 0;
private pendingCommands: { [cmdId: string]: Function } = {}; private pendingCommands: { [cmdId: string]: Function } = {};
@ -21,8 +15,7 @@ export class ProtobufService {
constructor(webClient: WebClient) { constructor(webClient: WebClient) {
this.webClient = webClient; this.webClient = webClient;
ProtoController.load();
this.loadProtobufFiles();
} }
public resetCommands() { public resetCommands() {
@ -30,8 +23,8 @@ export class ProtobufService {
this.pendingCommands = {}; this.pendingCommands = {};
} }
public sendRoomCommand(roomId: number, roomCmd: number, callback?: Function) { public sendRoomCommand(roomId: number, roomCmd: any, callback?: Function) {
const cmd = this.controller.CommandContainer.create({ const cmd = ProtoController.root.CommandContainer.create({
'roomId': roomId, 'roomId': roomId,
'roomCommand': [roomCmd] 'roomCommand': [roomCmd]
}); });
@ -39,38 +32,38 @@ export class ProtobufService {
this.sendCommand(cmd, raw => callback && callback(raw)); this.sendCommand(cmd, raw => callback && callback(raw));
} }
public sendSessionCommand(sesCmd: number, callback?: Function) { public sendSessionCommand(sesCmd: any, callback?: Function) {
const cmd = this.controller.CommandContainer.create({ const cmd = ProtoController.root.CommandContainer.create({
'sessionCommand': [sesCmd] 'sessionCommand': [sesCmd]
}); });
this.sendCommand(cmd, (raw) => callback && callback(raw)); this.sendCommand(cmd, (raw) => callback && callback(raw));
} }
public sendModeratorCommand(modCmd: number, callback?: Function) { public sendModeratorCommand(modCmd: any, callback?: Function) {
const cmd = this.controller.CommandContainer.create({ const cmd = ProtoController.root.CommandContainer.create({
'moderatorCommand': [modCmd] 'moderatorCommand': [modCmd]
}); });
this.sendCommand(cmd, (raw) => callback && callback(raw)); this.sendCommand(cmd, (raw) => callback && callback(raw));
} }
public sendAdminCommand(adminCmd: number, callback?: Function) { public sendAdminCommand(adminCmd: any, callback?: Function) {
const cmd = this.controller.CommandContainer.create({ const cmd = ProtoController.root.CommandContainer.create({
'adminCommand': [adminCmd] 'adminCommand': [adminCmd]
}); });
this.sendCommand(cmd, (raw) => callback && callback(raw)); this.sendCommand(cmd, (raw) => callback && callback(raw));
} }
public sendCommand(cmd: number, callback: Function) { public sendCommand(cmd: any, callback: Function) {
this.cmdId++; this.cmdId++;
cmd['cmdId'] = this.cmdId; cmd['cmdId'] = this.cmdId;
this.pendingCommands[this.cmdId] = callback; this.pendingCommands[this.cmdId] = callback;
if (this.webClient.socket.checkReadyState(WebSocket.OPEN)) { if (this.webClient.socket.checkReadyState(WebSocket.OPEN)) {
this.webClient.socket.send(this.controller.CommandContainer.encode(cmd).finish()); this.webClient.socket.send(ProtoController.root.CommandContainer.encode(cmd).finish());
} }
} }
@ -81,20 +74,20 @@ export class ProtobufService {
public handleMessageEvent({ data }: MessageEvent): void { public handleMessageEvent({ data }: MessageEvent): void {
try { try {
const uint8msg = new Uint8Array(data); const uint8msg = new Uint8Array(data);
const msg = this.controller.ServerMessage.decode(uint8msg); const msg = ProtoController.root.ServerMessage.decode(uint8msg);
if (msg) { if (msg) {
switch (msg.messageType) { switch (msg.messageType) {
case this.controller.ServerMessage.MessageType.RESPONSE: case ProtoController.root.ServerMessage.MessageType.RESPONSE:
this.processServerResponse(msg.response); this.processServerResponse(msg.response);
break; break;
case this.controller.ServerMessage.MessageType.ROOM_EVENT: case ProtoController.root.ServerMessage.MessageType.ROOM_EVENT:
this.processRoomEvent(msg.roomEvent, msg); this.processRoomEvent(msg.roomEvent, msg);
break; break;
case this.controller.ServerMessage.MessageType.SESSION_EVENT: case ProtoController.root.ServerMessage.MessageType.SESSION_EVENT:
this.processSessionEvent(msg.sessionEvent, msg); this.processSessionEvent(msg.sessionEvent, msg);
break; break;
case this.controller.ServerMessage.MessageType.GAME_EVENT_CONTAINER: case ProtoController.root.ServerMessage.MessageType.GAME_EVENT_CONTAINER:
this.processGameEvent(msg.gameEvent, msg); this.processGameEvent(msg.gameEvent, msg);
break; break;
default: default:
@ -142,17 +135,4 @@ export class ProtobufService {
} }
} }
} }
private loadProtobufFiles() {
const files = ProtoFiles.map(file => `${ProtobufService.PB_FILE_DIR}/${file}`);
this.controller = new protobuf.Root();
this.controller.load(files, { keepCase: false }, (err, root) => {
if (err) {
throw err;
}
SessionPersistence.initialized();
});
}
} }

View file

@ -1,5 +1,6 @@
import sha512 from 'crypto-js/sha512'; import sha512 from 'crypto-js/sha512';
import Base64 from 'crypto-js/enc-base64'; import Base64 from 'crypto-js/enc-base64';
import { ProtoController } from '../services/ProtoController';
const HASH_ROUNDS = 1_000; const HASH_ROUNDS = 1_000;
const SALT_LENGTH = 16; const SALT_LENGTH = 16;
@ -25,7 +26,7 @@ export const generateSalt = (): string => {
return salt; return salt;
} }
export const passwordSaltSupported = (serverOptions, webClient): number => { export const passwordSaltSupported = (serverOptions: number): number => {
// Intentional use of Bitwise operator b/c of how Servatrice Enums work // Intentional use of Bitwise operator b/c of how Servatrice Enums work
return serverOptions & webClient.protobuf.controller.Event_ServerIdentification.ServerOptions.SupportsPasswordHash; return serverOptions & ProtoController.root.Event_ServerIdentification.ServerOptions.SupportsPasswordHash;
} }