Compare commits

..

No commits in common. "2303880b8727870abdba8e021ae7d821ee783498" and "b0d8a33d5f7e13f3d7df495e648b09f2742e517e" have entirely different histories.

79 changed files with 4375 additions and 1084 deletions

View file

@ -1,4 +1,4 @@
FROM fedora:40
FROM fedora:38
RUN dnf install -y \
ccache \

View file

@ -1,4 +1,4 @@
FROM ubuntu:noble
FROM ubuntu:lunar
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \

View file

@ -15,11 +15,11 @@ include different targets -->
- <kbd>Ubuntu 18.04 LTS</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04 LTS</kbd> ("Focal Fossa")
- <kbd>Ubuntu 22.04 LTS</kbd> ("Jammy Jellyfish")
- <kbd>Ubuntu 24.04 LTS</kbd> ("Noble Numbat")
- <kbd>Ubuntu 23.04</kbd> ("Lunar Lobster")
- <kbd>Debian 11</kbd> ("Bullseye")
- <kbd>Debian 12</kbd> ("Bookworm")
- <kbd>Fedora 38</kbd>
- <kbd>Fedora 39</kbd>
- <kbd>Fedora 40</kbd>
<kbd>We are also packaged in Arch Linux's official community repository, courtesy of @FFY00</kbd></i>
<kbd>General Linux support is available via a flatpak package (Flathub)</kbd></i>
</pre>

View file

@ -97,10 +97,10 @@ jobs:
- distro: Debian12
package: DEB
- distro: Fedora39
- distro: Fedora38
package: RPM
- distro: Fedora40
- distro: Fedora39
package: RPM
- distro: UbuntuBionic
@ -114,7 +114,7 @@ jobs:
package: DEB
test: skip # running tests on all distros is superfluous
- distro: UbuntuNoble
- distro: UbuntuLunar
package: DEB
name: ${{matrix.distro}}

View file

@ -32,7 +32,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v5
with:
add-paths: |
cockatrice/translations/*.ts

View file

@ -56,7 +56,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v5
with:
add-paths: |
cockatrice/cockatrice_en@source.ts

View file

@ -74,7 +74,7 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
project("Cockatrice" VERSION 2.9.1)
project("Cockatrice" VERSION 2.9.0)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)

View file

@ -32,7 +32,6 @@ RemoteClient::RemoteClient(QObject *parent)
{
clearNewClientFeatures();
maxTimeout = SettingsCache::instance().getTimeOut();
int keepalive = SettingsCache::instance().getKeepAlive();
timer = new QTimer(this);
timer->setInterval(keepalive * 1000);

View file

@ -89,7 +89,7 @@ private slots:
void submitForgotPasswordChallengeResponse(const Response &response);
private:
int maxTimeout;
static const int maxTimeout = 5;
int timeRunning, lastDataReceived;
QByteArray inputBuffer;
bool messageInProgress;

View file

@ -195,7 +195,6 @@ SettingsCache::SettingsCache()
lang = settings->value("personal/lang").toString();
keepalive = settings->value("personal/keepalive", 3).toInt();
timeout = settings->value("personal/timeout", 5).toInt();
// tip of the day settings
showTipsOnStartup = settings->value("tipOfDay/showTips", true).toBool();

View file

@ -134,7 +134,6 @@ private:
bool spectatorsCanSeeEverything;
bool createGameAsSpectator;
int keepalive;
int timeout;
void translateLegacySettings();
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
@ -435,10 +434,6 @@ public:
{
return keepalive;
}
int getTimeOut() const
{
return timeout;
}
int getMaxFontSize() const
{
return maxFontSize;

View file

@ -21,10 +21,6 @@ public:
{
return id;
}
void setId(int _id)
{
id = _id;
}
Server_Card *getStartCard() const
{
return startCard;

View file

@ -296,12 +296,6 @@ void Server_Player::addArrow(Server_Arrow *arrow)
arrows.insert(arrow->getId(), arrow);
}
void Server_Player::updateArrowId(int id)
{
auto *arrow = arrows.take(id);
arrows.insert(arrow->getId(), arrow);
}
bool Server_Player::deleteArrow(int arrowId)
{
Server_Arrow *arrow = arrows.value(arrowId, 0);
@ -503,7 +497,9 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
const QList<Server_Player *> &players = game->getPlayers().values();
for (auto player : players) {
QList<int> arrowsToDelete;
for (Server_Arrow *arrow : player->getArrows()) {
QMapIterator<int, Server_Arrow *> arrowIterator(player->getArrows());
while (arrowIterator.hasNext()) {
Server_Arrow *arrow = arrowIterator.next().value();
if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card))
arrowsToDelete.append(arrow->getId());
}
@ -1482,8 +1478,9 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
// Copy Arrows
const QList<Server_Player *> &players = game->getPlayers().values();
for (auto player : players) {
QList<int> changedArrowIds;
for (Server_Arrow *arrow : player->getArrows()) {
QMapIterator<int, Server_Arrow *> arrowIterator(player->getArrows());
while (arrowIterator.hasNext()) {
Server_Arrow *arrow = arrowIterator.next().value();
bool sendGameEvent = false;
const auto *startCard = arrow->getStartCard();
if (startCard == targetCard) {
@ -1500,10 +1497,7 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
if (sendGameEvent) {
Event_CreateArrow _event;
ServerInfo_Arrow *arrowInfo = _event.mutable_arrow_info();
changedArrowIds.append(arrow->getId());
int id = player->newArrowId();
arrow->setId(id);
arrowInfo->set_id(id);
arrowInfo->set_id(arrow->getId());
arrowInfo->set_start_player_id(player->getPlayerId());
arrowInfo->set_start_zone(startCard->getZone()->getName().toStdString());
arrowInfo->set_start_card_id(startCard->getId());
@ -1520,9 +1514,6 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
ges.enqueueGameEvent(_event, player->getPlayerId());
}
}
for (int id : changedArrowIds) {
player->updateArrowId(id);
}
}
targetCard->resetState();
@ -1588,7 +1579,9 @@ Server_Player::cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer
return Response::RespNameNotFound;
}
for (Server_Arrow *temp : arrows) {
QMapIterator<int, Server_Arrow *> arrowIterator(arrows);
while (arrowIterator.hasNext()) {
Server_Arrow *temp = arrowIterator.next().value();
if ((temp->getStartCard() == startCard) && (temp->getTargetItem() == targetItem)) {
return Response::RespContextError;
}

View file

@ -164,7 +164,6 @@ public:
void addZone(Server_CardZone *zone);
void addArrow(Server_Arrow *arrow);
void updateArrowId(int id);
bool deleteArrow(int arrowId);
void addCounter(Server_Counter *counter);

View file

@ -7828,9 +7828,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
"integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==",
"dependencies": {
"jake": "^10.8.5"
},
@ -25550,9 +25550,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
"integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==",
"requires": {
"jake": "^10.8.5"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -20,7 +20,7 @@ import './Account.css';
const Account = (props: AccountProps) => {
const { buddyList, ignoreList, serverName, serverVersion, user } = props;
const { country, realName, name, userLevel, accountageSecs, avatarBmp } = user || {};
const { country, realName, name, userLevel, accountageSecs, avatarBmp } = user;
let url = URL.createObjectURL(new Blob([avatarBmp], { 'type': 'image/png' }));
const { t } = useTranslation();

View file

@ -35,14 +35,13 @@ const LoginForm = ({ onSubmit, disableSubmitButton, onResetPassword }: LoginForm
return errors;
}
const useStoredPassword = (remember, password) => remember && host?.hashedPassword && !password;
const useStoredPassword = (remember, password) => remember && host.hashedPassword && !password;
const togglePasswordLabel = (useStoredLabel) => {
setUseStoredPasswordLabel(useStoredLabel);
};
const handleOnSubmit = ({ userName, ...values }) => {
userName = userName?.trim();
console.log(userName, values);
onSubmit({ userName, ...values });
}
@ -85,7 +84,7 @@ const LoginForm = ({ onSubmit, disableSubmitButton, onResetPassword }: LoginForm
}, [host]);
const onUserNameChange = (userName) => {
const fieldChanged = host?.userName?.toLowerCase() !== values.userName?.toLowerCase();
const fieldChanged = host.userName?.toLowerCase() !== values.userName?.toLowerCase();
if (useStoredPassword(values.remember, values.password) && fieldChanged) {
setHost(({ hashedPassword, ...s }) => ({ ...s, userName }));
}

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
import { StatusEnum, WebSocketConnectOptions } from 'types';
import { ServerStatus, StatusEnum, WebSocketConnectOptions } from 'types';
import { ProtobufService } from './services/ProtobufService';
import { WebSocketService } from './services/WebSocketService';
@ -37,7 +37,6 @@ export class WebClient {
};
public options: WebSocketConnectOptions;
public status: StatusEnum;
public connectionAttemptMade = false;
@ -46,6 +45,10 @@ export class WebClient {
this.protobuf.handleMessageEvent(message);
});
this.socket.statusChange$.subscribe((status: ServerStatus) => {
this.handleStatusChange(status);
});
if (process.env.NODE_ENV !== 'test') {
console.log(this);
}
@ -65,8 +68,12 @@ export class WebClient {
this.socket.disconnect();
}
public updateStatus(status: StatusEnum) {
this.status = status;
public updateStatus(status: StatusEnum, description: string) {
this.socket.updateStatus(status, description);
}
public handleStatusChange({ status, description }: ServerStatus) {
SessionPersistence.updateStatus(status, description);
if (status === StatusEnum.DISCONNECTED) {
this.protobuf.resetCommands();

View file

@ -1,9 +1,9 @@
import { RoomPersistence } from '../../persistence';
import webClient from '../../WebClient';
import { RoomCommands } from './RoomCommands';
import { leaveRoom, roomSay } from './';
import { RoomPersistence } from '../persistence';
import webClient from '../WebClient';
describe.skip('RoomCommands', () => {
describe('RoomCommands', () => {
const roomId = 1;
let sendRoomCommandSpy;
@ -25,7 +25,7 @@ describe.skip('RoomCommands', () => {
it('should call protobuf controller methods and sendCommand', () => {
const message = ' message ';
roomSay(roomId, message);
RoomCommands.roomSay(roomId, message);
expect(webClient.protobuf.sendRoomCommand).toHaveBeenCalled();
expect(webClient.protobuf.sendRoomCommand).toHaveBeenCalledWith(roomId, {
@ -36,7 +36,7 @@ describe.skip('RoomCommands', () => {
it('should not call sendRoomCommand if trimmed message is empty', () => {
const message = ' ';
roomSay(roomId, message);
RoomCommands.roomSay(roomId, message);
expect(webClient.protobuf.sendRoomCommand).not.toHaveBeenCalled();
});
@ -48,7 +48,7 @@ describe.skip('RoomCommands', () => {
});
it('should call protobuf controller methods and sendCommand', () => {
leaveRoom(roomId);
RoomCommands.leaveRoom(roomId);
expect(webClient.protobuf.sendRoomCommand).toHaveBeenCalled();
expect(webClient.protobuf.sendRoomCommand).toHaveBeenCalledWith(
@ -67,7 +67,7 @@ describe.skip('RoomCommands', () => {
jest.spyOn(RoomPersistence, 'leaveRoom').mockImplementation(() => {});
leaveRoom(roomId);
RoomCommands.leaveRoom(roomId);
expect(RoomPersistence.leaveRoom).toHaveBeenCalledWith(roomId);
});

View file

@ -0,0 +1,42 @@
import { RoomPersistence } from '../persistence';
import webClient from '../WebClient';
export class RoomCommands {
static roomSay(roomId: number, message: string): void {
const trimmed = message.trim();
if (!trimmed) {
return;
}
const CmdRoomSay = webClient.protobuf.controller.Command_RoomSay.create({
'message': trimmed
});
const rc = webClient.protobuf.controller.RoomCommand.create({
'.Command_RoomSay.ext': CmdRoomSay
});
webClient.protobuf.sendRoomCommand(roomId, rc);
}
static leaveRoom(roomId: number): void {
const CmdLeaveRoom = webClient.protobuf.controller.Command_LeaveRoom.create();
const rc = webClient.protobuf.controller.RoomCommand.create({
'.Command_LeaveRoom.ext': CmdLeaveRoom
});
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
const { responseCode } = raw;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
RoomPersistence.leaveRoom(roomId);
break;
default:
console.log(`Failed to leave Room ${roomId} [${responseCode}] : `, raw);
}
});
}
}

View file

@ -1,12 +1,12 @@
import { AccountActivationParams, ServerRegisterParams } from 'store';
import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient';
import { RoomPersistence, SessionPersistence } from '../../persistence';
import { SessionCommands } from './SessionCommands';
import * as SessionCommands from './';
import { RoomPersistence, SessionPersistence } from '../persistence';
import webClient from '../WebClient';
import { AccountActivationParams, ServerRegisterParams } from '../../store';
describe.skip('SessionCommands', () => {
describe('SessionCommands', () => {
const roomId = 1;
let sendModeratorCommandSpy;
let sendSessionCommandSpy;

View file

@ -0,0 +1,530 @@
import { HostDTO } from 'services';
import { StatusEnum, WebSocketConnectReason, WebSocketConnectOptions } from 'types';
import { RoomPersistence, SessionPersistence } from '../persistence';
import webClient from '../WebClient';
import { guid, hashPassword } from '../utils';
import {
AccountActivationParams,
ForgotPasswordChallengeParams,
ForgotPasswordParams,
ForgotPasswordResetParams,
RequestPasswordSaltParams,
ServerRegisterParams
} from '../../store';
import NormalizeService from '../utils/NormalizeService';
export class SessionCommands {
static connect(options: WebSocketConnectOptions, reason: WebSocketConnectReason): void {
switch (reason) {
case WebSocketConnectReason.LOGIN:
case WebSocketConnectReason.REGISTER:
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE:
case WebSocketConnectReason.PASSWORD_RESET:
SessionCommands.updateStatus(StatusEnum.CONNECTING, 'Connecting...');
break;
case WebSocketConnectReason.TEST_CONNECTION:
webClient.testConnect({ ...options });
return;
default:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Attempt: ' + reason);
return;
}
webClient.connect({ ...options, reason });
}
static disconnect(): void {
webClient.disconnect();
}
static login(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, password, hashedPassword } = options;
const loginConfig: any = {
...webClient.clientConfig,
clientid: 'webatrice',
userName,
};
if (passwordSalt) {
loginConfig.hashedPassword = hashedPassword || hashPassword(passwordSalt, password);
} else {
loginConfig.password = password;
}
const CmdLogin = webClient.protobuf.controller.Command_Login.create(loginConfig);
const command = webClient.protobuf.controller.SessionCommand.create({
'.Command_Login.ext': CmdLogin
});
webClient.protobuf.sendSessionCommand(command, raw => {
const resp = raw['.Response_Login.ext'];
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
const { buddyList, ignoreList, userInfo } = resp;
SessionPersistence.updateBuddyList(buddyList);
SessionPersistence.updateIgnoreList(ignoreList);
SessionPersistence.updateUser(userInfo);
SessionPersistence.loginSuccessful(loginConfig);
SessionCommands.listUsers();
SessionCommands.listRooms();
SessionCommands.updateStatus(StatusEnum.LOGGED_IN, 'Logged in.');
return;
}
switch (raw.responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespClientUpdateRequired:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: missing features');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: incorrect username or password');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWouldOverwriteOldSession:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: duplicated user session');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: banned user');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespClientIdRequired:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: missing client ID');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespContextError:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: server error');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespAccountNotActivated:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: account not activated');
SessionPersistence.accountAwaitingActivation(options);
break;
default:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Login failed: unknown error: ${raw.responseCode}`);
}
SessionPersistence.loginFailed();
SessionCommands.disconnect();
});
}
static requestPasswordSalt(options: WebSocketConnectOptions): void {
const { userName } = options as RequestPasswordSaltParams;
const registerConfig = {
...webClient.clientConfig,
userName,
};
const CmdRequestPasswordSalt = webClient.protobuf.controller.Command_RequestPasswordSalt.create(registerConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_RequestPasswordSalt.ext': CmdRequestPasswordSalt
});
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) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT: {
SessionCommands.activateAccount(options, passwordSalt);
break;
}
case WebSocketConnectReason.PASSWORD_RESET: {
SessionCommands.resetPassword(options, passwordSalt);
break;
}
case WebSocketConnectReason.LOGIN:
default: {
SessionCommands.login(options, passwordSalt);
}
}
return;
}
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired: {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required');
break;
}
default: {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: Unknown Reason');
}
}
switch (options.reason) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT: {
SessionPersistence.accountActivationFailed();
break;
}
case WebSocketConnectReason.PASSWORD_RESET: {
SessionPersistence.resetPasswordFailed();
break;
}
case WebSocketConnectReason.LOGIN:
default: {
SessionPersistence.loginFailed();
}
}
SessionCommands.disconnect();
});
}
static register(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, password, email, country, realName } = options as ServerRegisterParams;
const registerConfig: any = {
...webClient.clientConfig,
userName,
email,
country,
realName,
};
if (passwordSalt) {
registerConfig.hashedPassword = hashPassword(passwordSalt, password);
} else {
registerConfig.password = password;
}
const CmdRegister = webClient.protobuf.controller.Command_Register.create(registerConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_Register.ext': CmdRegister
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAccepted) {
SessionCommands.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:
console.error('ResponseCode.RespUsernameInvalid', raw.reasonStr);
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(NormalizeService.normalizeBannedUserError(raw.reasonStr, raw.endTime));
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
default:
SessionPersistence.registrationFailed('Registration failed due to a server issue');
break;
}
SessionCommands.disconnect();
});
};
static activateAccount(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token } = options as unknown as AccountActivationParams;
const accountActivationConfig = {
...webClient.clientConfig,
userName,
token,
};
const CmdActivate = webClient.protobuf.controller.Command_Activate.create(accountActivationConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_Activate.ext': CmdActivate
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
SessionPersistence.accountActivationSuccess();
SessionCommands.login(options, passwordSalt);
} else {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
SessionCommands.disconnect();
SessionPersistence.accountActivationFailed();
}
});
}
static resetPasswordRequest(options: WebSocketConnectOptions): void {
const { userName } = options as unknown as ForgotPasswordParams;
const forgotPasswordConfig = {
...webClient.clientConfig,
userName,
};
const CmdForgotPasswordRequest = webClient.protobuf.controller.Command_ForgotPasswordRequest.create(forgotPasswordConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ForgotPasswordRequest.ext': CmdForgotPasswordRequest
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
const resp = raw['.Response_ForgotPasswordRequest.ext'];
if (resp.challengeEmail) {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordChallenge();
} else {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPassword();
}
} else {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed();
}
SessionCommands.disconnect();
});
}
static resetPasswordChallenge(options: WebSocketConnectOptions): void {
const { userName, email } = options as unknown as ForgotPasswordChallengeParams;
const forgotPasswordChallengeConfig = {
...webClient.clientConfig,
userName,
email,
};
const CmdForgotPasswordChallenge = webClient.protobuf.controller.Command_ForgotPasswordChallenge.create(forgotPasswordChallengeConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ForgotPasswordChallenge.ext': CmdForgotPasswordChallenge
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPassword();
} else {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed();
}
SessionCommands.disconnect();
});
}
static resetPassword(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token, newPassword } = options as unknown as ForgotPasswordResetParams;
const forgotPasswordResetConfig: any = {
...webClient.clientConfig,
userName,
token,
};
if (passwordSalt) {
forgotPasswordResetConfig.hashedNewPassword = hashPassword(passwordSalt, newPassword);
} else {
forgotPasswordResetConfig.newPassword = newPassword;
}
const CmdForgotPasswordReset = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ForgotPasswordReset.ext': CmdForgotPasswordReset
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordSuccess();
} else {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed();
}
SessionCommands.disconnect();
});
}
static listUsers(): void {
const CmdListUsers = webClient.protobuf.controller.Command_ListUsers.create();
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ListUsers.ext': CmdListUsers
});
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);
break;
default:
console.log(`Failed to fetch Server Rooms [${responseCode}] : `, raw);
}
}
});
}
static listRooms(): void {
const CmdListRooms = webClient.protobuf.controller.Command_ListRooms.create();
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ListRooms.ext': CmdListRooms
});
webClient.protobuf.sendSessionCommand(sc);
}
static joinRoom(roomId: number): void {
const CmdJoinRoom = webClient.protobuf.controller.Command_JoinRoom.create({ roomId });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_JoinRoom.ext': CmdJoinRoom
});
webClient.protobuf.sendSessionCommand(sc, (raw) => {
const { responseCode } = raw;
let error;
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);
}
});
}
static addToBuddyList(userName: string): void {
this.addToList('buddy', userName);
}
static removeFromBuddyList(userName: string): void {
this.removeFromList('buddy', userName);
}
static addToIgnoreList(userName: string): void {
this.addToList('ignore', userName);
}
static removeFromIgnoreList(userName: string): void {
this.removeFromList('ignore', userName);
}
static addToList(list: string, userName: string): void {
const CmdAddToList = webClient.protobuf.controller.Command_AddToList.create({ list, userName });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_AddToList.ext': CmdAddToList
});
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
// @TODO: filter responseCode, pop snackbar for error
});
}
static removeFromList(list: string, userName: string): void {
const CmdRemoveFromList = webClient.protobuf.controller.Command_RemoveFromList.create({ list, userName });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_RemoveFromList.ext': CmdRemoveFromList
});
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
// @TODO: filter responseCode, pop snackbar for error
});
}
static viewLogHistory(filters): void {
const CmdViewLogHistory = webClient.protobuf.controller.Command_ViewLogHistory.create(filters);
const sc = webClient.protobuf.controller.ModeratorCommand.create({
'.Command_ViewLogHistory.ext': CmdViewLogHistory
});
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
const { responseCode } = raw;
let error;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { logMessage } = raw['.Response_ViewLogHistory.ext'];
SessionPersistence.viewLogs(logMessage)
return;
default:
error = 'Failed to retrieve log history.';
break;
}
if (error) {
console.error(responseCode, error);
}
});
}
static updateStatus(status: StatusEnum, description: string): void {
webClient.updateStatus(status, description);
}
}

View file

@ -1,2 +1,2 @@
export * as RoomCommands from './room';
export * as SessionCommands from './session';
export { RoomCommands } from './RoomCommands';
export { SessionCommands } from './SessionCommands';

View file

@ -1,2 +0,0 @@
export * from './leaveRoom';
export * from './roomSay';

View file

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

View file

@ -1,19 +0,0 @@
import webClient from '../../WebClient';
export function roomSay(roomId: number, message: string): void {
const trimmed = message.trim();
if (!trimmed) {
return;
}
const CmdRoomSay = webClient.protobuf.controller.Command_RoomSay.create({
'message': trimmed
});
const rc = webClient.protobuf.controller.RoomCommand.create({
'.Command_RoomSay.ext': CmdRoomSay
});
webClient.protobuf.sendRoomCommand(roomId, rc);
}

View file

@ -1,34 +0,0 @@
import { AccountActivationParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
import { disconnect, login, updateStatus } from './';
export function activateAccount(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token } = options as unknown as AccountActivationParams;
const accountActivationConfig = {
...webClient.clientConfig,
userName,
token,
};
const CmdActivate = webClient.protobuf.controller.Command_Activate.create(accountActivationConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_Activate.ext': CmdActivate
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
SessionPersistence.accountActivationSuccess();
login(options, passwordSalt);
} else {
updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
disconnect();
SessionPersistence.accountActivationFailed();
}
});
}

View file

@ -1,21 +0,0 @@
import webClient from '../../WebClient';
export function addToBuddyList(userName: string): void {
addToList('buddy', userName);
}
export function addToIgnoreList(userName: string): void {
addToList('ignore', userName);
}
export function addToList(list: string, userName: string): void {
const CmdAddToList = webClient.protobuf.controller.Command_AddToList.create({ list, userName });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_AddToList.ext': CmdAddToList
});
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
// @TODO: filter responseCode, pop snackbar for error
});
}

View file

@ -1,24 +0,0 @@
import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient';
import { updateStatus } from './';
export function connect(options: WebSocketConnectOptions, reason: WebSocketConnectReason): void {
switch (reason) {
case WebSocketConnectReason.LOGIN:
case WebSocketConnectReason.REGISTER:
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE:
case WebSocketConnectReason.PASSWORD_RESET:
updateStatus(StatusEnum.CONNECTING, 'Connecting...');
break;
case WebSocketConnectReason.TEST_CONNECTION:
webClient.testConnect({ ...options });
return;
default:
updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Attempt: ' + reason);
return;
}
webClient.connect({ ...options, reason });
}

View file

@ -1,5 +0,0 @@
import webClient from '../../WebClient';
export function disconnect(): void {
webClient.disconnect();
}

View file

@ -1,16 +0,0 @@
export * from './activateAccount';
export * from './addToList';
export * from './connect';
export * from './disconnect';
export * from './joinRoom';
export * from './listRooms';
export * from './listUsers';
export * from './login';
export * from './register';
export * from './removeFromList';
export * from './requestPasswordSalt';
export * from './resetPassword';
export * from './resetPasswordChallenge'
export * from './resetPasswordRequest';
export * from './updateStatus';
export * from './viewLogHistory';

View file

@ -1,40 +0,0 @@
import webClient from '../../WebClient';
import { RoomPersistence } from '../../persistence';
export function joinRoom(roomId: number): void {
const CmdJoinRoom = webClient.protobuf.controller.Command_JoinRoom.create({ roomId });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_JoinRoom.ext': CmdJoinRoom
});
webClient.protobuf.sendSessionCommand(sc, (raw) => {
const { responseCode } = raw;
let error;
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,11 +0,0 @@
import webClient from '../../WebClient';
export function listRooms(): void {
const CmdListRooms = webClient.protobuf.controller.Command_ListRooms.create();
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ListRooms.ext': CmdListRooms
});
webClient.protobuf.sendSessionCommand(sc);
}

View file

@ -1,26 +0,0 @@
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
export function listUsers(): void {
const CmdListUsers = webClient.protobuf.controller.Command_ListUsers.create();
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ListUsers.ext': CmdListUsers
});
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);
break;
default:
console.log(`Failed to fetch Server Rooms [${responseCode}] : `, raw);
}
}
});
}

View file

@ -1,95 +0,0 @@
import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient';
import { hashPassword } from '../../utils';
import { SessionPersistence } from '../../persistence';
import {
disconnect,
listUsers,
listRooms,
updateStatus,
} from './';
export function login(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, password, hashedPassword } = options;
const loginConfig: any = {
...webClient.clientConfig,
clientid: 'webatrice',
userName,
};
if (passwordSalt) {
loginConfig.hashedPassword = hashedPassword || hashPassword(passwordSalt, password);
} else {
loginConfig.password = password;
}
const CmdLogin = webClient.protobuf.controller.Command_Login.create(loginConfig);
const command = webClient.protobuf.controller.SessionCommand.create({
'.Command_Login.ext': CmdLogin
});
webClient.protobuf.sendSessionCommand(command, raw => {
const resp = raw['.Response_Login.ext'];
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
const { buddyList, ignoreList, userInfo } = resp;
SessionPersistence.updateBuddyList(buddyList);
SessionPersistence.updateIgnoreList(ignoreList);
SessionPersistence.updateUser(userInfo);
SessionPersistence.loginSuccessful(loginConfig);
listUsers();
listRooms();
updateStatus(StatusEnum.LOGGED_IN, 'Logged in.');
return;
}
switch (raw.responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespClientUpdateRequired:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: missing features');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWrongPassword:
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: incorrect username or password');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespWouldOverwriteOldSession:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: duplicated user session');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: banned user');
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired:
updateStatus(StatusEnum.DISCONNECTED, 'Login failed: registration required');
break;
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,78 +0,0 @@
import { ServerRegisterParams } from 'store';
import { WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
import { hashPassword } from '../../utils';
import NormalizeService from '../../utils/NormalizeService';
import { login, disconnect } from './';
export function register(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, password, email, country, realName } = options as ServerRegisterParams;
const registerConfig: any = {
...webClient.clientConfig,
userName,
email,
country,
realName,
};
if (passwordSalt) {
registerConfig.hashedPassword = hashPassword(passwordSalt, password);
} else {
registerConfig.password = password;
}
const CmdRegister = webClient.protobuf.controller.Command_Register.create(registerConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_Register.ext': CmdRegister
});
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:
console.error('ResponseCode.RespUsernameInvalid', raw.reasonStr);
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(NormalizeService.normalizeBannedUserError(raw.reasonStr, raw.endTime));
break;
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
default:
SessionPersistence.registrationFailed('Registration failed due to a server issue');
break;
}
disconnect();
});
}

View file

@ -1,21 +0,0 @@
import webClient from '../../WebClient';
export function removeFromBuddyList(userName: string): void {
removeFromList('buddy', userName);
}
export function removeFromIgnoreList(userName: string): void {
removeFromList('ignore', userName);
}
export function removeFromList(list: string, userName: string): void {
const CmdRemoveFromList = webClient.protobuf.controller.Command_RemoveFromList.create({ list, userName });
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_RemoveFromList.ext': CmdRemoveFromList
});
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
// @TODO: filter responseCode, pop snackbar for error
});
}

View file

@ -1,81 +0,0 @@
import { RequestPasswordSaltParams } from 'store';
import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
import {
activateAccount,
disconnect,
login,
resetPassword,
updateStatus
} from './';
export function requestPasswordSalt(options: WebSocketConnectOptions): void {
const { userName } = options as RequestPasswordSaltParams;
const registerConfig = {
...webClient.clientConfig,
userName,
};
const CmdRequestPasswordSalt = webClient.protobuf.controller.Command_RequestPasswordSalt.create(registerConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_RequestPasswordSalt.ext': CmdRequestPasswordSalt
});
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) {
case WebSocketConnectReason.ACTIVATE_ACCOUNT: {
activateAccount(options, passwordSalt);
break;
}
case WebSocketConnectReason.PASSWORD_RESET: {
resetPassword(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();
break;
}
case WebSocketConnectReason.PASSWORD_RESET: {
SessionPersistence.resetPasswordFailed();
break;
}
case WebSocketConnectReason.LOGIN:
default: {
SessionPersistence.loginFailed();
}
}
disconnect();
});
}

View file

@ -1,42 +0,0 @@
import { ForgotPasswordResetParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
import { hashPassword } from '../../utils';
import { disconnect, updateStatus } from '.';
export function resetPassword(options: WebSocketConnectOptions, passwordSalt?: string): void {
const { userName, token, newPassword } = options as unknown as ForgotPasswordResetParams;
const forgotPasswordResetConfig: any = {
...webClient.clientConfig,
userName,
token,
};
if (passwordSalt) {
forgotPasswordResetConfig.hashedNewPassword = hashPassword(passwordSalt, newPassword);
} else {
forgotPasswordResetConfig.newPassword = newPassword;
}
const CmdForgotPasswordReset = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ForgotPasswordReset.ext': CmdForgotPasswordReset
});
webClient.protobuf.sendSessionCommand(sc, raw => {
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordSuccess();
} else {
updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed();
}
disconnect();
});
}

View file

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

View file

@ -1,41 +0,0 @@
import { ForgotPasswordParams } from 'store';
import { StatusEnum, WebSocketConnectOptions } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
import { disconnect, updateStatus } from './';
export function resetPasswordRequest(options: WebSocketConnectOptions): void {
const { userName } = options as unknown as ForgotPasswordParams;
const forgotPasswordConfig = {
...webClient.clientConfig,
userName,
};
const CmdForgotPasswordRequest = webClient.protobuf.controller.Command_ForgotPasswordRequest.create(forgotPasswordConfig);
const sc = webClient.protobuf.controller.SessionCommand.create({
'.Command_ForgotPasswordRequest.ext': CmdForgotPasswordRequest
});
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);
SessionPersistence.resetPasswordChallenge();
} else {
updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPassword();
}
} else {
updateStatus(StatusEnum.DISCONNECTED, null);
SessionPersistence.resetPasswordFailed();
}
disconnect();
});
}

View file

@ -1,9 +0,0 @@
import { StatusEnum } from 'types';
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
export function updateStatus(status: StatusEnum, description: string): void {
SessionPersistence.updateStatus(status, description);
webClient.updateStatus(status);
}

View file

@ -1,30 +0,0 @@
import webClient from '../../WebClient';
import { SessionPersistence } from '../../persistence';
export function viewLogHistory(filters): void {
const CmdViewLogHistory = webClient.protobuf.controller.Command_ViewLogHistory.create(filters);
const sc = webClient.protobuf.controller.ModeratorCommand.create({
'.Command_ViewLogHistory.ext': CmdViewLogHistory
});
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
const { responseCode } = raw;
let error;
switch (responseCode) {
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
const { logMessage } = raw['.Response_ViewLogHistory.ext'];
SessionPersistence.viewLogs(logMessage)
return;
default:
error = 'Failed to retrieve log history.';
break;
}
if (error) {
console.error(responseCode, error);
}
});
}

View file

@ -1,17 +1,15 @@
import { Message } from 'types';
import { RoomPersistence } from '../../persistence';
import {
RoomEvents,
RoomEvent,
JoinRoomData,
LeaveRoomData,
ListGamesData,
} from './interfaces';
} from './RoomEvents';
import { RoomPersistence } from '../persistence/RoomPersistence';
import { RoomEvents } from '.';
describe.skip('RoomEvents', () => {
describe('RoomEvents', () => {
it('.Event_JoinRoom.ext should call RoomPersistence.userJoined', () => {
jest.spyOn(RoomPersistence, 'userJoined').mockImplementation(() => {});
const data: JoinRoomData = { userInfo: {} as any };

View file

@ -0,0 +1,49 @@
import { Game, Message, User } from 'types';
import { RoomPersistence } from '../persistence/RoomPersistence';
import { ProtobufEvents } from '../services/ProtobufService';
export const RoomEvents: ProtobufEvents = {
'.Event_JoinRoom.ext': joinRoom,
'.Event_LeaveRoom.ext': leaveRoom,
'.Event_ListGames.ext': listGames,
'.Event_RoomSay.ext': roomSay,
};
function joinRoom({ userInfo }: JoinRoomData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.userJoined(roomId, userInfo);
}
function leaveRoom({ name }: LeaveRoomData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.userLeft(roomId, name);
}
function listGames({ gameList }: ListGamesData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.updateGames(roomId, gameList);
}
function roomSay(message: Message, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.addMessage(roomId, message);
}
export interface RoomEvent {
roomEvent: {
roomId: number;
}
}
export interface JoinRoomData {
userInfo: User;
}
export interface LeaveRoomData {
name: string;
}
export interface ListGamesData {
gameList: Game[];
}

View file

@ -1,9 +1,5 @@
import { StatusEnum, WebSocketConnectReason } from 'types';
import { SessionCommands } from '../../commands';
import { RoomPersistence, SessionPersistence } from '../../persistence';
import webClient from '../../WebClient';
import {
AddToListData,
ConnectionClosedData,
@ -11,13 +7,16 @@ import {
RemoveFromListData,
ServerIdentificationData,
ServerMessageData,
SessionEvents,
UserJoinedData,
UserLeftData,
} from './interfaces';
} from './SessionEvents';
import { SessionEvents } from '.';
import { SessionCommands } from '../commands';
import { RoomPersistence, SessionPersistence } from '../persistence';
import webClient from '../WebClient';
describe.skip('SessionEvents', () => {
describe('SessionEvents', () => {
const roomId = 1;
beforeEach(() => {

View file

@ -0,0 +1,230 @@
import { Room, StatusEnum, User, WebSocketConnectReason } from 'types';
import { SessionCommands } from '../commands';
import { RoomPersistence, SessionPersistence } from '../persistence';
import { ProtobufEvents } from '../services/ProtobufService';
import { generateSalt, passwordSaltSupported } from '../utils';
import webClient from '../WebClient';
export const SessionEvents: ProtobufEvents = {
'.Event_AddToList.ext': addToList,
'.Event_ConnectionClosed.ext': connectionClosed,
'.Event_ListRooms.ext': listRooms,
'.Event_NotifyUser.ext': notifyUser,
'.Event_PlayerPropertiesChanges.ext': playerPropertiesChanges,
'.Event_RemoveFromList.ext': removeFromList,
'.Event_ServerIdentification.ext': serverIdentification,
'.Event_ServerMessage.ext': serverMessage,
'.Event_ServerShutdown.ext': serverShutdown,
'.Event_UserJoined.ext': userJoined,
'.Event_UserLeft.ext': userLeft,
'.Event_UserMessage.ext': userMessage,
}
function addToList({ listName, userInfo }: AddToListData) {
switch (listName) {
case 'buddy': {
SessionPersistence.addToBuddyList(userInfo);
break;
}
case 'ignore': {
SessionPersistence.addToIgnoreList(userInfo);
break;
}
default: {
console.log(`Attempted to add to unknown list: ${listName}`);
}
}
}
function connectionClosed({ reason, reasonStr }: ConnectionClosedData) {
let message;
// @TODO (5)
if (reasonStr) {
message = reasonStr;
} else {
switch (reason) {
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.USER_LIMIT_REACHED:
message = 'The server has reached its maximum user capacity';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.TOO_MANY_CONNECTIONS:
message = 'There are too many concurrent connections from your address';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.BANNED:
message = 'You are banned';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.DEMOTED:
message = 'You were demoted';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.SERVER_SHUTDOWN:
message = 'Scheduled server shutdown';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.USERNAMEINVALID:
message = 'Invalid username';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.LOGGEDINELSEWERE:
message = 'You have been logged out due to logging in at another location';
break;
case webClient.protobuf.controller.Event_ConnectionClosed.CloseReason.OTHER:
default:
message = 'Unknown reason';
break;
}
}
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, message);
}
function listRooms({ roomList }: ListRoomsData) {
RoomPersistence.updateRooms(roomList);
if (webClient.clientOptions.autojoinrooms) {
roomList.forEach(({ autoJoin, roomId }) => {
if (autoJoin) {
SessionCommands.joinRoom(roomId);
}
});
}
}
function notifyUser(payload) {
// console.info('Event_NotifyUser', payload);
}
function playerPropertiesChanges(payload) {
// console.info('Event_PlayerPropertiesChanges', payload);
}
function removeFromList({ listName, userName }: RemoveFromListData) {
switch (listName) {
case 'buddy': {
SessionPersistence.removeFromBuddyList(userName);
break;
}
case 'ignore': {
SessionPersistence.removeFromIgnoreList(userName);
break;
}
default: {
console.log(`Attempted to remove from unknown list: ${listName}`);
}
}
}
function serverIdentification(info: ServerIdentificationData) {
const { serverName, serverVersion, protocolVersion, serverOptions } = info;
if (protocolVersion !== webClient.protocolVersion) {
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Protocol version mismatch: ${protocolVersion}`);
SessionCommands.disconnect();
return;
}
const getPasswordSalt = passwordSaltSupported(serverOptions, webClient);
const { options } = webClient;
switch (options.reason) {
case WebSocketConnectReason.LOGIN:
SessionCommands.updateStatus(StatusEnum.LOGGING_IN, 'Logging In...');
if (getPasswordSalt) {
SessionCommands.requestPasswordSalt(options);
} else {
SessionCommands.login(options);
}
break;
case WebSocketConnectReason.REGISTER:
const passwordSalt = getPasswordSalt ? generateSalt() : null;
SessionCommands.register(options, passwordSalt);
break;
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
if (getPasswordSalt) {
SessionCommands.requestPasswordSalt(options);
} else {
SessionCommands.activateAccount(options);
}
break;
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
SessionCommands.resetPasswordRequest(options);
break;
case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE:
SessionCommands.resetPasswordChallenge(options);
break;
case WebSocketConnectReason.PASSWORD_RESET:
if (getPasswordSalt) {
SessionCommands.requestPasswordSalt(options);
} else {
SessionCommands.resetPassword(options);
}
break;
default:
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + options.reason);
SessionCommands.disconnect();
break;
}
webClient.options = {};
SessionPersistence.updateInfo(serverName, serverVersion);
}
function serverMessage({ message }: ServerMessageData) {
SessionPersistence.serverMessage(message);
}
function serverShutdown(payload) {
// console.info('Event_ServerShutdown', payload);
}
function userJoined({ userInfo }: UserJoinedData) {
SessionPersistence.userJoined(userInfo);
}
function userLeft({ name }: UserLeftData) {
SessionPersistence.userLeft(name);
}
function userMessage(payload) {
// console.info('Event_UserMessage', payload);
}
export interface SessionEvent {
sessionEvent: {}
}
export interface AddToListData {
listName: string;
userInfo: User;
}
export interface ConnectionClosedData {
endTime: number;
reason: number;
reasonStr: string;
}
export interface ListRoomsData {
roomList: Room[];
}
export interface RemoveFromListData {
listName: string;
userName: string;
}
export interface ServerIdentificationData {
protocolVersion: number;
serverName: string;
serverVersion: string;
serverOptions: number;
}
export interface ServerMessageData {
message: string;
}
export interface UserJoinedData {
userInfo: User;
}
export interface UserLeftData {
name: string;
}

View file

@ -1,2 +1,2 @@
export * from './room';
export * from './session';
export * from './RoomEvents';
export * from './SessionEvents';

View file

@ -1,13 +0,0 @@
import { ProtobufEvents } from '../../services/ProtobufService';
import { joinRoom } from './joinRoom';
import { leaveRoom } from './leaveRoom';
import { listGames } from './listGames';
import { roomSay } from './roomSay';
export const RoomEvents: ProtobufEvents = {
'.Event_JoinRoom.ext': joinRoom,
'.Event_LeaveRoom.ext': leaveRoom,
'.Event_ListGames.ext': listGames,
'.Event_RoomSay.ext': roomSay,
};

View file

@ -1,19 +0,0 @@
import { Game, User } from 'types';
export interface RoomEvent {
roomEvent: {
roomId: number;
}
}
export interface JoinRoomData {
userInfo: User;
}
export interface LeaveRoomData {
name: string;
}
export interface ListGamesData {
gameList: Game[];
}

View file

@ -1,8 +0,0 @@
import { RoomPersistence } from '../../persistence';
import { JoinRoomData, RoomEvent } from './interfaces';
export function joinRoom({ userInfo }: JoinRoomData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.userJoined(roomId, userInfo);
}

View file

@ -1,7 +0,0 @@
import { RoomPersistence } from '../../persistence';
import { LeaveRoomData, RoomEvent } from './interfaces';
export function leaveRoom({ name }: LeaveRoomData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.userLeft(roomId, name);
}

View file

@ -1,7 +0,0 @@
import { RoomPersistence } from '../../persistence';
import { ListGamesData, RoomEvent } from './interfaces';
export function listGames({ gameList }: ListGamesData, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.updateGames(roomId, gameList);
}

View file

@ -1,9 +0,0 @@
import { Message } from 'types';
import { RoomPersistence } from '../../persistence';
import { RoomEvent } from './interfaces';
export function roomSay(message: Message, { roomEvent }: RoomEvent) {
const { roomId } = roomEvent;
RoomPersistence.addMessage(roomId, message);
}

View file

@ -1,18 +0,0 @@
import { SessionPersistence } from '../../persistence';
import { AddToListData } from './interfaces';
export function addToList({ listName, userInfo }: AddToListData) {
switch (listName) {
case 'buddy': {
SessionPersistence.addToBuddyList(userInfo);
break;
}
case 'ignore': {
SessionPersistence.addToIgnoreList(userInfo);
break;
}
default: {
console.log(`Attempted to add to unknown list: ${listName}`);
}
}
}

View file

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

View file

@ -1,28 +0,0 @@
import { ProtobufEvents } from '../../services/ProtobufService';
import { addToList } from './addToList';
import { connectionClosed } from './connectionClosed';
import { listRooms } from './listRooms';
import { notifyUser } from './notifyUser';
import { playerPropertiesChanges } from './playerPropertiesChanges';
import { removeFromList } from './removeFromList';
import { serverIdentification } from './serverIdentification';
import { serverMessage } from './serverMessage';
import { serverShutdown } from './serverShutdown';
import { userJoined } from './userJoined';
import { userLeft } from './userLeft';
import { userMessage } from './userMessage';
export const SessionEvents: ProtobufEvents = {
'.Event_AddToList.ext': addToList,
'.Event_ConnectionClosed.ext': connectionClosed,
'.Event_ListRooms.ext': listRooms,
'.Event_NotifyUser.ext': notifyUser,
'.Event_PlayerPropertiesChanges.ext': playerPropertiesChanges,
'.Event_RemoveFromList.ext': removeFromList,
'.Event_ServerIdentification.ext': serverIdentification,
'.Event_ServerMessage.ext': serverMessage,
'.Event_ServerShutdown.ext': serverShutdown,
'.Event_UserJoined.ext': userJoined,
'.Event_UserLeft.ext': userLeft,
'.Event_UserMessage.ext': userMessage,
}

View file

@ -1,44 +0,0 @@
import { Room, User } from 'types';
export interface SessionEvent {
sessionEvent: {}
}
export interface AddToListData {
listName: string;
userInfo: User;
}
export interface ConnectionClosedData {
endTime: number;
reason: number;
reasonStr: string;
}
export interface ListRoomsData {
roomList: Room[];
}
export interface RemoveFromListData {
listName: string;
userName: string;
}
export interface ServerIdentificationData {
protocolVersion: number;
serverName: string;
serverVersion: string;
serverOptions: number;
}
export interface ServerMessageData {
message: string;
}
export interface UserJoinedData {
userInfo: User;
}
export interface UserLeftData {
name: string;
}

View file

@ -1,16 +0,0 @@
import webClient from '../../WebClient';
import { joinRoom } from '../../commands/session';
import { RoomPersistence } from '../../persistence';
import { ListRoomsData } from './interfaces';
export function listRooms({ roomList }: ListRoomsData) {
RoomPersistence.updateRooms(roomList);
if (webClient.clientOptions.autojoinrooms) {
roomList.forEach(({ autoJoin, roomId }) => {
if (autoJoin) {
joinRoom(roomId);
}
});
}
}

View file

@ -1,3 +0,0 @@
export function notifyUser(payload) {
console.info('Event_NotifyUser', payload);
}

View file

@ -1,3 +0,0 @@
export function playerPropertiesChanges(payload) {
console.info('Event_PlayerPropertiesChanges', payload);
}

View file

@ -1,18 +0,0 @@
import { SessionPersistence } from '../../persistence';
import { RemoveFromListData } from './interfaces';
export function removeFromList({ listName, userName }: RemoveFromListData) {
switch (listName) {
case 'buddy': {
SessionPersistence.removeFromBuddyList(userName);
break;
}
case 'ignore': {
SessionPersistence.removeFromIgnoreList(userName);
break;
}
default: {
console.log(`Attempted to remove from unknown list: ${listName}`);
}
}
}

View file

@ -1,71 +0,0 @@
import { StatusEnum, WebSocketConnectReason } from 'types';
import webClient from '../../WebClient';
import {
activateAccount,
disconnect,
login,
register,
requestPasswordSalt,
resetPassword,
resetPasswordChallenge,
resetPasswordRequest,
updateStatus,
} from '../../commands/session';
import { generateSalt, passwordSaltSupported } from '../../utils';
import { ServerIdentificationData } from './interfaces';
import { SessionPersistence } from '../../persistence';
export function serverIdentification(info: ServerIdentificationData) {
const { serverName, serverVersion, protocolVersion, serverOptions } = info;
if (protocolVersion !== webClient.protocolVersion) {
updateStatus(StatusEnum.DISCONNECTED, `Protocol version mismatch: ${protocolVersion}`);
disconnect();
return;
}
const getPasswordSalt = passwordSaltSupported(serverOptions, webClient);
const { options } = webClient;
switch (options.reason) {
case WebSocketConnectReason.LOGIN:
updateStatus(StatusEnum.LOGGING_IN, 'Logging In...');
if (getPasswordSalt) {
requestPasswordSalt(options);
} else {
login(options);
}
break;
case WebSocketConnectReason.REGISTER:
const passwordSalt = getPasswordSalt ? generateSalt() : null;
register(options, passwordSalt);
break;
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
if (getPasswordSalt) {
requestPasswordSalt(options);
} else {
activateAccount(options);
}
break;
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
resetPasswordRequest(options);
break;
case WebSocketConnectReason.PASSWORD_RESET_CHALLENGE:
resetPasswordChallenge(options);
break;
case WebSocketConnectReason.PASSWORD_RESET:
if (getPasswordSalt) {
requestPasswordSalt(options);
} else {
resetPassword(options);
}
break;
default:
updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + options.reason);
disconnect();
break;
}
webClient.options = {};
SessionPersistence.updateInfo(serverName, serverVersion);
}

View file

@ -1,6 +0,0 @@
import { SessionPersistence } from '../../persistence';
import { ServerMessageData } from './interfaces';
export function serverMessage({ message }: ServerMessageData) {
SessionPersistence.serverMessage(message);
}

View file

@ -1,3 +0,0 @@
export function serverShutdown(payload) {
console.info('Event_ServerShutdown', payload);
}

View file

@ -1,6 +0,0 @@
import { SessionPersistence } from '../../persistence';
import { UserJoinedData } from './interfaces';
export function userJoined({ userInfo }: UserJoinedData) {
SessionPersistence.userJoined(userInfo);
}

View file

@ -1,6 +0,0 @@
import { SessionPersistence } from '../../persistence';
import { UserLeftData } from './interfaces';
export function userLeft({ name }: UserLeftData) {
SessionPersistence.userLeft(name);
}

View file

@ -1,3 +0,0 @@
export function userMessage(payload) {
console.info('Event_UserMessage', payload);
}

View file

@ -1,14 +1,17 @@
import { KeepAliveService } from './KeepAliveService';
import { WebSocketService } from './WebSocketService';
import webClient from '../WebClient';
describe('KeepAliveService', () => {
let service: KeepAliveService;
let socket: WebSocketService;
beforeEach(() => {
jest.useFakeTimers();
service = new KeepAliveService(webClient.socket);
socket = new WebSocketService(webClient);
service = new KeepAliveService(socket);
});
it('should create', () => {
@ -27,7 +30,7 @@ describe('KeepAliveService', () => {
promise = new Promise(resolve => resolvePing = resolve);
ping = (done) => promise.then(done);
checkReadyStateSpy = jest.spyOn(webClient.socket, 'checkReadyState');
checkReadyStateSpy = jest.spyOn(socket, 'checkReadyState');
checkReadyStateSpy.mockImplementation(() => true);
service.startPingLoop(interval, ping);

View file

@ -1,11 +1,10 @@
import { Subject } from 'rxjs';
import { StatusEnum, WebSocketConnectOptions } from 'types';
import { ServerStatus, StatusEnum, WebSocketConnectOptions } from 'types';
import { KeepAliveService } from './KeepAliveService';
import { WebClient } from '../WebClient';
import { SessionPersistence } from '../persistence';
import { updateStatus } from '../commands/session';
export class WebSocketService {
private socket: WebSocket;
@ -15,7 +14,9 @@ export class WebSocketService {
private keepAliveService: KeepAliveService;
public message$: Subject<MessageEvent> = new Subject();
public statusChange$: Subject<ServerStatus> = new Subject();
private status: StatusEnum = StatusEnum.DISCONNECTED;
private keepalive: number;
constructor(webClient: WebClient) {
@ -24,7 +25,7 @@ export class WebSocketService {
this.keepAliveService = new KeepAliveService(this);
this.keepAliveService.disconnected$.subscribe(() => {
this.disconnect();
updateStatus(StatusEnum.DISCONNECTED, 'Connection timeout');
this.updateStatus(StatusEnum.DISCONNECTED, 'Connection timeout');
});
}
@ -63,6 +64,11 @@ export class WebSocketService {
this.socket.send(message);
}
public updateStatus(status: StatusEnum, description: string): void {
this.status = status;
this.statusChange$.next({ status, description });
}
private createWebSocket(url: string): WebSocket {
const socket = new WebSocket(url);
socket.binaryType = 'arraybuffer';
@ -71,7 +77,7 @@ export class WebSocketService {
socket.onopen = () => {
clearTimeout(connectionTimer);
updateStatus(StatusEnum.CONNECTED, 'Connected');
this.updateStatus(StatusEnum.CONNECTED, 'Connected');
this.keepAliveService.startPingLoop(this.keepalive, (pingReceived: Function) => {
this.webClient.keepAlive(pingReceived);
@ -80,15 +86,15 @@ export class WebSocketService {
socket.onclose = () => {
// dont overwrite failure messages
if (this.webClient.status !== StatusEnum.DISCONNECTED) {
updateStatus(StatusEnum.DISCONNECTED, 'Connection Closed');
if (this.status !== StatusEnum.DISCONNECTED) {
this.updateStatus(StatusEnum.DISCONNECTED, 'Connection Closed');
}
this.keepAliveService.endPingLoop();
};
socket.onerror = () => {
updateStatus(StatusEnum.DISCONNECTED, 'Connection Failed');
this.updateStatus(StatusEnum.DISCONNECTED, 'Connection Failed');
SessionPersistence.connectionFailed();
};