mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
Merge branch 'master' into tooomm-qt5
This commit is contained in:
commit
14618bc2ce
114 changed files with 4069 additions and 3286 deletions
|
|
@ -9,20 +9,18 @@ RUN apt-get update && \
|
|||
file \
|
||||
g++ \
|
||||
git \
|
||||
libgl-dev \
|
||||
liblzma-dev \
|
||||
libmariadb-dev-compat \
|
||||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
libqt6svg6-dev \
|
||||
libqt6websockets6-dev \
|
||||
libqt5multimedia5-plugins \
|
||||
libqt5sql5-mysql \
|
||||
libqt5svg5-dev \
|
||||
libqt5websockets5-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
qt6-l10n-tools \
|
||||
qt6-multimedia-dev \
|
||||
qt6-tools-dev \
|
||||
qt6-tools-dev-tools \
|
||||
qt5-image-formats-plugins \
|
||||
qtmultimedia5-dev \
|
||||
qttools5-dev \
|
||||
qttools5-dev-tools \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
29
.ci/Ubuntu26.04/Dockerfile
Normal file
29
.ci/Ubuntu26.04/Dockerfile
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
FROM ubuntu:26.04
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
ccache \
|
||||
clang-format \
|
||||
cmake \
|
||||
file \
|
||||
g++ \
|
||||
git \
|
||||
libgl-dev \
|
||||
liblzma-dev \
|
||||
libmariadb-dev-compat \
|
||||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
qt6-l10n-tools \
|
||||
qt6-multimedia-dev \
|
||||
qt6-svg-dev \
|
||||
qt6-tools-dev \
|
||||
qt6-tools-dev-tools \
|
||||
qt6-websockets-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
|
@ -10,9 +10,11 @@
|
|||
# --test runs tests
|
||||
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
||||
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
||||
# --evict-ccache <age> runs ccache eviction based on given age after build
|
||||
# --dir <dir> sets the name of the build dir, default is "build"
|
||||
# --cmake-generator <generator> sets CMAKE_GENERATOR as used by cmake
|
||||
# --target-macos-version <version> sets the min os version - only used for macOS builds
|
||||
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION
|
||||
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION
|
||||
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
||||
# exitcode: 1 for failure, 3 for invalid arguments
|
||||
|
||||
|
|
@ -71,6 +73,15 @@ while [[ $# != 0 ]]; do
|
|||
shift
|
||||
fi
|
||||
;;
|
||||
'--evict-ccache')
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "::error file=$0::--evict-ccache expects an argument"
|
||||
exit 3
|
||||
fi
|
||||
CCACHE_EVICTION_AGE=$1
|
||||
shift
|
||||
;;
|
||||
'--vcpkg')
|
||||
USE_VCPKG=1
|
||||
shift
|
||||
|
|
@ -84,6 +95,15 @@ while [[ $# != 0 ]]; do
|
|||
BUILD_DIR="$1"
|
||||
shift
|
||||
;;
|
||||
'--cmake-generator')
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "::error file=$0::--cmake-generator expects an argument"
|
||||
exit 3
|
||||
fi
|
||||
export CMAKE_GENERATOR=$1
|
||||
shift
|
||||
;;
|
||||
'--target-macos-version')
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
|
|
@ -253,9 +273,16 @@ cmake --build . "${buildflags[@]}"
|
|||
echo "::endgroup::"
|
||||
|
||||
if [[ $USE_CCACHE ]]; then
|
||||
if [[ $CCACHE_EVICTION_AGE ]]; then
|
||||
echo "::group::evict ccache files older than $CCACHE_EVICTION_AGE"
|
||||
ccache --evict-older-than "$CCACHE_EVICTION_AGE"
|
||||
echo "::endgroup::"
|
||||
fi
|
||||
echo "::group::Show ccache stats again"
|
||||
ccachestatsverbose
|
||||
echo "::endgroup::"
|
||||
elif [[ $CCACHE_EVICTION_AGE ]]; then
|
||||
echo "::error file=$0::ccache eviction is enabled while ccache is disabled!"
|
||||
fi
|
||||
|
||||
if [[ $RUNNER_OS == macOS ]]; then
|
||||
|
|
|
|||
|
|
@ -3,17 +3,28 @@
|
|||
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
|
||||
|
||||
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
|
||||
# <arg> sets the name of the docker image, these correspond to directories in .ci
|
||||
#
|
||||
# usage: source <script> <name> [--get] [--build] [--save] [--interactive] [--set-cache <location>]
|
||||
# <name> sets the name of the docker image, these correspond to directories in .ci
|
||||
# --get loads the image from a previously saved image cache, will build if no image is found
|
||||
# --build builds the image from the Dockerfile in .ci/$NAME
|
||||
# --save stores the image, if an image was loaded it will not be stored
|
||||
# --interactive immediately starts the image interactively for debugging
|
||||
# --set-cache <location> sets the location to cache the image or for ccache
|
||||
#
|
||||
# requires: docker
|
||||
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE
|
||||
# (correspond to args: <name> --set-cache <cache> --build --get --save --interactive)
|
||||
# sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
|
||||
# exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments
|
||||
#
|
||||
# exported RUN function will run the BUILD_SCRIPT inside of the docker container.
|
||||
# note that the docker container will not inherit any environment variables!
|
||||
#
|
||||
# usage: RUN [arguments for build script]
|
||||
# roughly equivalent to `docker run $IMAGE_NAME bash $BUILD_SCRIPT $@`
|
||||
# uses env: CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
|
||||
# exitcode: 3 for invalid arguments, returns the returncode of docker run
|
||||
export BUILD_SCRIPT=".ci/compile.sh"
|
||||
|
||||
project_name="cockatrice"
|
||||
|
|
@ -41,12 +52,17 @@ while [[ $# != 0 ]]; do
|
|||
shift
|
||||
;;
|
||||
'--set-cache')
|
||||
CACHE=$2
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "--set-cache expects an argument" >&2
|
||||
exit 3
|
||||
fi
|
||||
CACHE=$1
|
||||
shift
|
||||
if ! [[ -d $CACHE ]]; then
|
||||
echo "could not find cache path: $CACHE" >&2
|
||||
return 3
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
if [[ ${1:0:1} == - ]]; then
|
||||
|
|
@ -149,8 +165,9 @@ function RUN ()
|
|||
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
|
||||
args+=(--env "CCACHE_DIR=/.ccache")
|
||||
fi
|
||||
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
||||
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
||||
if [[ $GITHUB_OUTPUT ]]; then
|
||||
args+=(--mount "type=bind,source=$GITHUB_OUTPUT,target=/gh_output")
|
||||
args+=(--env "GITHUB_OUTPUT=/gh_output")
|
||||
fi
|
||||
# shellcheck disable=2086
|
||||
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Available pre-compiled binaries for installation:
|
|||
• <kbd>macOS 13+</kbd> <sub><i>Ventura</i></sub> <sub>Intel</sub>
|
||||
|
||||
<b>Linux</b>
|
||||
• <kbd>Ubuntu 26.04 LTS</kbd> <sub><i>Resolute Racoon</i></sub>
|
||||
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
||||
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
||||
• <kbd>Debian 13</kbd> <sub><i>Trixie</i></sub>
|
||||
|
|
|
|||
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
|
|
@ -9,6 +9,9 @@ updates:
|
|||
- package-ecosystem: "gitsubmodule"
|
||||
# Look for `.gitmodules` in the `root` directory
|
||||
directory: "/"
|
||||
ignore:
|
||||
# Ignore updates for vcpkg (Bump to latest tag not working (no SemVer used) & macOS Intel triplet broken with newer releases)
|
||||
- dependency-name: "vcpkg"
|
||||
# Check for updates once a month
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
|
|
|
|||
68
.github/workflows/desktop-build.yml
vendored
68
.github/workflows/desktop-build.yml
vendored
|
|
@ -38,10 +38,10 @@ on:
|
|||
- 'vcpkg.json'
|
||||
- 'vcpkg'
|
||||
|
||||
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on master)
|
||||
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
|
||||
concurrency:
|
||||
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
|
||||
cancel-in-progress: ${{ github.ref_name != 'master' }}
|
||||
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
||||
|
||||
jobs:
|
||||
configure:
|
||||
|
|
@ -142,21 +142,28 @@ jobs:
|
|||
- distro: Ubuntu
|
||||
version: 22.04
|
||||
package: DEB
|
||||
test: skip # Running tests on all distros is superfluous
|
||||
|
||||
- distro: Ubuntu
|
||||
version: 24.04
|
||||
package: DEB
|
||||
|
||||
- distro: Ubuntu
|
||||
version: 26.04
|
||||
package: DEB
|
||||
|
||||
name: ${{matrix.distro}} ${{matrix.version}}
|
||||
needs: configure
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
||||
timeout-minutes: 70
|
||||
env:
|
||||
NAME: ${{matrix.distro}}${{matrix.version}}
|
||||
CACHE: ${{github.workspace}}/.cache/${{matrix.distro}}${{matrix.version}} # directory for caching docker image and ccache
|
||||
# Cache size over the entire repo is 10Gi:
|
||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||
CCACHE_SIZE: 550M
|
||||
CCACHE_EVICTION_AGE: 7d
|
||||
CMAKE_GENERATOR: 'Ninja'
|
||||
|
||||
steps:
|
||||
|
|
@ -180,34 +187,43 @@ jobs:
|
|||
- name: Build debug and test
|
||||
if: matrix.test != 'skip'
|
||||
shell: bash
|
||||
env:
|
||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||
run: |
|
||||
source .ci/docker.sh
|
||||
RUN --server --debug --test --ccache "$CCACHE_SIZE"
|
||||
RUN --server --debug --test --ccache "$CCACHE_SIZE" \
|
||||
--cmake-generator "$CMAKE_GENERATOR"
|
||||
|
||||
- name: Build release package
|
||||
id: build
|
||||
if: matrix.package != 'skip'
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
||||
package: '${{matrix.package}}'
|
||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
||||
NO_CLIENT: ${{matrix.server_only == 'yes' && '--no-client' || '' }}
|
||||
server_only: '${{matrix.server_only}}'
|
||||
run: |
|
||||
source .ci/docker.sh
|
||||
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
||||
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
||||
.ci/name_build.sh
|
||||
args=()
|
||||
if [[ $server_only == yes ]]; then
|
||||
args+=(--no-client)
|
||||
fi
|
||||
if [[ $GITHUB_REF == "refs/heads/master" ]]; then
|
||||
args+=(--evict-ccache "$CCACHE_EVICTION_AGE")
|
||||
fi
|
||||
args+=(--ccache "$CCACHE_SIZE")
|
||||
args+=(--cmake-generator "$CMAKE_GENERATOR")
|
||||
args+=(--suffix "$SUFFIX")
|
||||
RUN --server --release --package "$package" "${args[@]}"
|
||||
|
||||
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342.
|
||||
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||
- name: Delete remote compiler cache (ccache)
|
||||
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||
run: |
|
||||
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
|
||||
echo "Cache deleted successfully"
|
||||
fi
|
||||
|
||||
- name: Save updated compiler cache (ccache)
|
||||
if: github.ref == 'refs/heads/master'
|
||||
|
|
@ -265,11 +281,12 @@ jobs:
|
|||
override_target: 13
|
||||
make_package: 1
|
||||
package_suffix: "-macOS13_Intel"
|
||||
qt_version: 6.10.*
|
||||
qt_version: 6.11.*
|
||||
qt_arch: clang_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cmake_generator: Ninja
|
||||
use_ccache: 1
|
||||
ccache_eviction_age: 7d
|
||||
|
||||
- os: macOS
|
||||
target: 14
|
||||
|
|
@ -279,11 +296,12 @@ jobs:
|
|||
type: Release
|
||||
make_package: 1
|
||||
package_suffix: "-macOS14"
|
||||
qt_version: 6.10.*
|
||||
qt_version: 6.11.*
|
||||
qt_arch: clang_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cmake_generator: Ninja
|
||||
use_ccache: 1
|
||||
ccache_eviction_age: 7d
|
||||
|
||||
- os: macOS
|
||||
target: 15
|
||||
|
|
@ -293,11 +311,12 @@ jobs:
|
|||
type: Release
|
||||
make_package: 1
|
||||
package_suffix: "-macOS15"
|
||||
qt_version: 6.10.*
|
||||
qt_version: 6.11.*
|
||||
qt_arch: clang_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cmake_generator: Ninja
|
||||
use_ccache: 1
|
||||
ccache_eviction_age: 7d
|
||||
|
||||
- os: macOS
|
||||
target: 15
|
||||
|
|
@ -305,11 +324,12 @@ jobs:
|
|||
soc: Apple
|
||||
xcode: "16.4"
|
||||
type: Debug
|
||||
qt_version: 6.10.*
|
||||
qt_version: 6.11.*
|
||||
qt_arch: clang_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cmake_generator: Ninja
|
||||
use_ccache: 1
|
||||
ccache_eviction_age: 7d
|
||||
|
||||
- os: Windows
|
||||
target: 10
|
||||
|
|
@ -317,7 +337,7 @@ jobs:
|
|||
type: Release
|
||||
make_package: 1
|
||||
package_suffix: "-Win10"
|
||||
qt_version: 6.10.*
|
||||
qt_version: 6.11.*
|
||||
qt_arch: win64_msvc2022_64
|
||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||
cmake_generator: "Visual Studio 17 2022"
|
||||
|
|
@ -326,6 +346,7 @@ jobs:
|
|||
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||
needs: configure
|
||||
runs-on: ${{matrix.runner}}
|
||||
timeout-minutes: 100
|
||||
env:
|
||||
CCACHE_DIR: ${{github.workspace}}/.cache/
|
||||
# Cache size over the entire repo is 10Gi:
|
||||
|
|
@ -404,6 +425,8 @@ jobs:
|
|||
if: matrix.os == 'Windows'
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
# qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
|
||||
aqtsource: git+https://github.com/miurahr/aqtinstall.git
|
||||
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||
arch: ${{matrix.qt_arch}}
|
||||
modules: ${{matrix.qt_modules}}
|
||||
|
|
@ -440,14 +463,19 @@ jobs:
|
|||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||
DEVELOPER_DIR: '/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer'
|
||||
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
|
||||
run: .ci/compile.sh --server --test --vcpkg
|
||||
|
||||
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342.
|
||||
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||
- name: Delete remote compiler cache (ccache)
|
||||
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1 && steps.ccache_restore.outputs.cache-hit
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||
run: |
|
||||
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
|
||||
echo "Cache deleted successfully"
|
||||
fi
|
||||
|
||||
- name: Save updated compiler cache (ccache)
|
||||
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
||||
|
|
|
|||
5
.github/workflows/docker-release.yml
vendored
5
.github/workflows/docker-release.yml
vendored
|
|
@ -13,6 +13,11 @@ on:
|
|||
- '.github/workflows/docker-release.yml'
|
||||
- 'Dockerfile'
|
||||
|
||||
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
|
||||
concurrency:
|
||||
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
|
||||
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
name: amd64 & arm64
|
||||
|
|
|
|||
|
|
@ -520,6 +520,9 @@ if(WIN32)
|
|||
PATTERN "styles/qopensslbackend.dll"
|
||||
PATTERN "styles/qschannelbackend.dll"
|
||||
PATTERN "styles/qwindowsvistastyle.dll"
|
||||
PATTERN "styles/qwindows11style.dll"
|
||||
PATTERN "styles/qmodernwindowsstyle.dll"
|
||||
PATTERN "styles/qmodernwindowsstyled.dll"
|
||||
PATTERN "tls/qcertonlybackend.dll"
|
||||
PATTERN "tls/qopensslbackend.dll"
|
||||
PATTERN "tls/qschannelbackend.dll"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,9 @@
|
|||
#include "abstract_game.h"
|
||||
|
||||
#include "../interface/widgets/tabs/tab_game.h"
|
||||
#include "player/player.h"
|
||||
|
||||
AbstractGame::AbstractGame(TabGame *_tab) : tab(_tab)
|
||||
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
|
||||
{
|
||||
gameMetaInfo = new GameMetaInfo(this);
|
||||
gameEventHandler = new GameEventHandler(this);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
|
||||
|
||||
PlayerMenu::PlayerMenu(Player *_player) : player(_player)
|
||||
PlayerMenu::PlayerMenu(Player *_player) : QObject(_player), player(_player)
|
||||
{
|
||||
playerMenu = new TearOffMenu();
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ private slots:
|
|||
void refreshShortcuts();
|
||||
|
||||
public:
|
||||
PlayerMenu(Player *player);
|
||||
explicit PlayerMenu(Player *player);
|
||||
/// Lifecycle methods: delegate to all managedComponents, plus counters separately via player->getCounters().
|
||||
void retranslateUi();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../interface/widgets/utility/get_text_with_max.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../client/settings/card_counter_settings.h"
|
||||
#include "../dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../dialogs/dlg_roll_dice.h"
|
||||
#include "../zones/hand_zone.h"
|
||||
|
|
@ -27,13 +28,15 @@
|
|||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/utility/expression.h>
|
||||
#include <libcockatrice/utility/trice_limits.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
// milliseconds in between triggers of the move top cards until action
|
||||
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
||||
|
||||
PlayerActions::PlayerActions(Player *_player) : player(_player), lastTokenTableRow(0), movingCardsUntil(false)
|
||||
PlayerActions::PlayerActions(Player *_player)
|
||||
: QObject(_player), player(_player), lastTokenTableRow(0), movingCardsUntil(false)
|
||||
{
|
||||
moveTopCardTimer = new QTimer(this);
|
||||
moveTopCardTimer->setInterval(MOVE_TOP_CARD_UNTIL_INTERVAL);
|
||||
|
|
@ -1568,23 +1571,34 @@ void PlayerActions::actCardCounterTrigger()
|
|||
break;
|
||||
}
|
||||
case 11: { // set counter with dialog
|
||||
bool ok;
|
||||
player->setDialogSemaphore(true);
|
||||
|
||||
int oldValue = 0;
|
||||
if (player->getGameScene()->selectedItems().size() == 1) {
|
||||
auto *card = static_cast<CardItem *>(player->getGameScene()->selectedItems().first());
|
||||
oldValue = card->getCounters().value(counterId, 0);
|
||||
// If a single card is selected, we show the old value in the dialog. Otherwise, we show "x"
|
||||
QList<QGraphicsItem *> sel = player->getGameScene()->selectedItems();
|
||||
QString oldValueForDlg = "x";
|
||||
if (sel.size() == 1) {
|
||||
auto *card = dynamic_cast<CardItem *>(sel.first());
|
||||
oldValueForDlg = QString::number(card->getCounters().value(counterId, 0));
|
||||
}
|
||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Set counters"), tr("Number:"), oldValue,
|
||||
0, MAX_COUNTERS_ON_CARD, 1, &ok);
|
||||
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
QString counterName = cardCounterSettings.displayName(counterId);
|
||||
|
||||
AbstractCounterDialog dialog(counterName, oldValueForDlg, player->getGame()->getTab());
|
||||
int ok = dialog.exec();
|
||||
|
||||
player->setDialogSemaphore(false);
|
||||
if (player->clearCardsToDelete() || !ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &item : player->getGameScene()->selectedItems()) {
|
||||
auto *card = static_cast<CardItem *>(item);
|
||||
for (const auto &item : sel) {
|
||||
auto *card = dynamic_cast<CardItem *>(item);
|
||||
|
||||
int oldValue = card->getCounters().value(counterId, 0);
|
||||
Expression exp(oldValue);
|
||||
int number = static_cast<int>(exp.parse(dialog.textValue()));
|
||||
|
||||
auto *cmd = new Command_SetCardCounter;
|
||||
cmd->set_zone(card->getZone()->getName().toStdString());
|
||||
cmd->set_card_id(card->getId());
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player)
|
||||
PlayerEventHandler::PlayerEventHandler(Player *_player) : QObject(_player), player(_player)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,6 @@ void PlayerEventHandler::eventShuffle(const Event_Shuffle &event)
|
|||
// we want to close empty views as well
|
||||
if (length == 0 || length > absStart) { // note this assumes views always start at the top of the library
|
||||
view->close();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
qWarning() << zone->getName() << "of" << player->getPlayerInfo()->getName() << "holds empty zoneview!";
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ CardPictureLoader::CardPictureLoader() : QObject(nullptr)
|
|||
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this,
|
||||
&CardPictureLoader::picDownloadChanged);
|
||||
|
||||
qRegisterMetaType<ExactCard>();
|
||||
connect(worker, &CardPictureLoaderWorker::imageLoaded, this, &CardPictureLoader::imageLoaded);
|
||||
|
||||
statusBar = new CardPictureLoaderStatusBar(nullptr);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <QPrinter>
|
||||
#include <QTextCursor>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <optional>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader");
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
#include <libcockatrice/network/server/remote/user_level.h>
|
||||
#include <optional>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(PixelMapGeneratorLog, "pixel_map_generator");
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ struct PaletteColorInfo
|
|||
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||
{
|
||||
defaultStyleName = qApp->style()->objectName();
|
||||
// FIXME workaround for windows11 style being broken
|
||||
if (defaultStyleName == "windows11") {
|
||||
defaultStyleName = "windowsvista";
|
||||
}
|
||||
ensureThemeDirectoryExists();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot);
|
||||
|
|
@ -179,7 +183,7 @@ QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
|
|||
|
||||
static inline QPalette createDarkGreenFusionPalette()
|
||||
{
|
||||
QPalette p;
|
||||
QPalette p = QStyleFactory::create("Fusion")->standardPalette();
|
||||
|
||||
// ---------- Core backgrounds ----------
|
||||
p.setColor(QPalette::Window, QColor(30, 30, 30)); // #ff1e1e1e
|
||||
|
|
@ -248,7 +252,7 @@ static inline QPalette createDarkGreenFusionPalette()
|
|||
|
||||
static inline QPalette createLightGreenFusionPalette()
|
||||
{
|
||||
QPalette p;
|
||||
QPalette p = QStyleFactory::create("Fusion")->standardPalette();
|
||||
|
||||
// ---------- Core backgrounds ----------
|
||||
p.setColor(QPalette::Window, QColor(240, 240, 240)); // #fff0f0f0
|
||||
|
|
@ -332,13 +336,15 @@ void ThemeManager::themeChangedSlot()
|
|||
}
|
||||
|
||||
if (themeName == FUSION_THEME_NAME) {
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
QStyle *fusionStyle = QStyleFactory::create("Fusion");
|
||||
qApp->setStyle(fusionStyle);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||
QPalette palette;
|
||||
// Start from Fusion's own palette so dark mode is handled correctly,
|
||||
// then apply any tweaks on top of it.
|
||||
QPalette palette = fusionStyle->standardPalette();
|
||||
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
|
||||
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
||||
}
|
||||
|
||||
qApp->setPalette(palette);
|
||||
#endif
|
||||
} else if (themeName == FUSION_THEME_NAME_LIGHT) {
|
||||
|
|
@ -348,7 +354,7 @@ void ThemeManager::themeChangedSlot()
|
|||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
qApp->setPalette(createDarkGreenFusionPalette());
|
||||
} else {
|
||||
qApp->setStyle(defaultStyleName); // setting the style also sets the palette
|
||||
qApp->setStyle(QStyleFactory::create(defaultStyleName)); // setting the style also sets the palette
|
||||
}
|
||||
|
||||
if (dirPath.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -339,11 +339,9 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
|
|||
QWidget::mousePressEvent(event);
|
||||
if (event->button() == Qt::RightButton) {
|
||||
createRightClickMenu()->popup(QCursor::pos());
|
||||
} else {
|
||||
emit cardClicked();
|
||||
}
|
||||
|
||||
emit cardClicked();
|
||||
emit cardClicked(event);
|
||||
}
|
||||
|
||||
void CardInfoPictureWidget::hideEvent(QHideEvent *event)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ signals:
|
|||
void hoveredOnCard(const ExactCard &hoveredCard);
|
||||
void cardScaleFactorChanged(int _scale);
|
||||
void cardChanged(const ExactCard &card);
|
||||
void cardClicked();
|
||||
void cardClicked(QMouseEvent *event);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
|
|||
frame = new QFrame(this);
|
||||
frame->setFrameShape(QFrame::Box);
|
||||
frame->setLineWidth(2);
|
||||
frame->setStyleSheet("border: none;");
|
||||
|
||||
auto *frameLayout = new QVBoxLayout(frame);
|
||||
frameLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
|
@ -30,13 +29,11 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
|
|||
frameLayout->addWidget(analyticsPanel);
|
||||
|
||||
dropIndicator = new QFrame(frame);
|
||||
dropIndicator->setStyleSheet("background-color: #3daee9;");
|
||||
dropIndicator->setFixedHeight(3);
|
||||
dropIndicator->hide(); // hidden by default
|
||||
dropIndicator->raise(); // make sure it's above children
|
||||
|
||||
selectionOverlay = new QFrame(frame);
|
||||
selectionOverlay->setStyleSheet("background-color: rgba(61,174,233,50);"); // semi-transparent blue
|
||||
selectionOverlay->hide(); // hidden by default
|
||||
selectionOverlay->raise(); // make sure it is above children
|
||||
selectionOverlay->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
|
@ -51,24 +48,41 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
|
|||
dragButton = new QPushButton("☰", bottomBar);
|
||||
dragButton->setFixedSize(40, 8);
|
||||
dragButton->setCursor(Qt::OpenHandCursor);
|
||||
dragButton->setStyleSheet("QPushButton { "
|
||||
"background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #4a4a4a, stop:1 #3a3a3a); "
|
||||
"border: none; color: #888; font-size: 10px; }"
|
||||
"QPushButton:hover { background: #5a5a5a; }");
|
||||
bottomLayout->addWidget(dragButton);
|
||||
|
||||
// Resize handle fills the rest
|
||||
resizeHandle = new QWidget(bottomBar);
|
||||
resizeHandle->setFixedHeight(8);
|
||||
resizeHandle->setCursor(Qt::SizeVerCursor);
|
||||
resizeHandle->setStyleSheet("background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
|
||||
"stop:0 #3a3a3a, stop:1 #2a2a2a);");
|
||||
bottomLayout->addWidget(resizeHandle, 1);
|
||||
|
||||
frameLayout->addWidget(bottomBar);
|
||||
|
||||
mainLayout->addWidget(frame);
|
||||
|
||||
const QPalette &pal = QApplication::palette();
|
||||
QColor mid = pal.color(QPalette::Mid);
|
||||
QColor dark = pal.color(QPalette::Dark);
|
||||
QColor midLight = pal.color(QPalette::Midlight);
|
||||
QColor shadow = pal.color(QPalette::Shadow);
|
||||
QColor placeholderText = pal.color(QPalette::PlaceholderText);
|
||||
|
||||
frame->setStyleSheet("QFrame { border: none; }");
|
||||
|
||||
dropIndicator->setStyleSheet("QFrame { background-color: #3daee9; }");
|
||||
|
||||
selectionOverlay->setStyleSheet("QFrame { background-color: rgba(61,174,233,50); }");
|
||||
|
||||
dragButton->setStyleSheet(QString("QPushButton { "
|
||||
"background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:1 %2); "
|
||||
"border: none; color: %3; font-size: 10px; }"
|
||||
"QPushButton:hover { background: %4; }")
|
||||
.arg(mid.name(), dark.name(), placeholderText.name(), midLight.name()));
|
||||
|
||||
resizeHandle->setStyleSheet(QString("QWidget { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
|
||||
"stop:0 %1, stop:1 %2); }")
|
||||
.arg(dark.name(), shadow.name()));
|
||||
|
||||
// Set size policy
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
|
||||
|
|
|
|||
|
|
@ -1775,7 +1775,7 @@ DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent)
|
|||
contentsWidget->setSpacing(5);
|
||||
|
||||
pagesWidget = new QStackedWidget;
|
||||
pagesWidget->addWidget(new GeneralSettingsPage);
|
||||
pagesWidget->addWidget(makeScrollable(new GeneralSettingsPage));
|
||||
pagesWidget->addWidget(makeScrollable(new AppearanceSettingsPage));
|
||||
pagesWidget->addWidget(makeScrollable(new UserInterfaceSettingsPage));
|
||||
pagesWidget->addWidget(new DeckEditorSettingsPage);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../../../../general/display/background_plate_widget.h"
|
||||
#include "../../tab_edhrec_main.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWidget(
|
||||
|
|
@ -48,7 +49,7 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
|
|||
if (parentTab) {
|
||||
cardPictureWidget->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value());
|
||||
connect(cardPictureWidget, &CardInfoPictureWidget::cardClicked, this,
|
||||
&EdhrecApiResponseCardDetailsDisplayWidget::actRequestPageNavigation);
|
||||
&EdhrecApiResponseCardDetailsDisplayWidget::mousePressEvent);
|
||||
connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, cardPictureWidget,
|
||||
&CardInfoPictureWidget::setScaleFactor);
|
||||
connect(this, &EdhrecApiResponseCardDetailsDisplayWidget::requestUrl, parentTab,
|
||||
|
|
@ -59,8 +60,10 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
|
|||
void EdhrecApiResponseCardDetailsDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mousePressEvent(event);
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
actRequestPageNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
void EdhrecApiResponseCardDetailsDisplayWidget::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include <libcockatrice/protocol/pb/response_replay_get_code.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(TabReplaysLog, "replays_tab");
|
||||
|
||||
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo)
|
||||
: Tab(_tabSupervisor), client(_client)
|
||||
{
|
||||
|
|
@ -265,9 +267,11 @@ void TabReplays::actOpenLocalReplay()
|
|||
f.close();
|
||||
|
||||
GameReplay *replay = new GameReplay;
|
||||
replay->ParseFromArray(_data.data(), _data.size());
|
||||
|
||||
if (replay->ParseFromArray(_data.data(), _data.size())) {
|
||||
emit openReplay(replay);
|
||||
} else {
|
||||
qCWarning(TabReplaysLog) << "could not parse replay!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -379,9 +383,12 @@ void TabReplays::openRemoteReplayFinished(const Response &r)
|
|||
|
||||
const Response_ReplayDownload &resp = r.GetExtension(Response_ReplayDownload::ext);
|
||||
GameReplay *replay = new GameReplay;
|
||||
replay->ParseFromString(resp.replay_data());
|
||||
if (replay->ParseFromString(resp.replay_data())) {
|
||||
|
||||
emit openReplay(replay);
|
||||
} else {
|
||||
qCWarning(TabReplaysLog) << "could not parse remote replay!";
|
||||
}
|
||||
}
|
||||
|
||||
void TabReplays::actDownload()
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
const QString MainWindow::appName = "Cockatrice";
|
||||
const QStringList MainWindow::fileNameFilters = QStringList() << QObject::tr("Cockatrice card database (*.xml)")
|
||||
<< QObject::tr("All files (*.*)");
|
||||
inline Q_LOGGING_CATEGORY(MainWindowLog, "main_window");
|
||||
|
||||
/**
|
||||
* Replaces the tab-specific menus that are shown in the menuBar.
|
||||
|
|
@ -277,9 +278,11 @@ void MainWindow::actWatchReplay()
|
|||
file.close();
|
||||
|
||||
replay = new GameReplay;
|
||||
replay->ParseFromArray(buf.data(), buf.size());
|
||||
|
||||
if (replay->ParseFromArray(buf.data(), buf.size())) {
|
||||
tabSupervisor->openReplay(replay);
|
||||
} else {
|
||||
qCWarning(MainWindowLog) << "failed to parse replay!";
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::localGameEnded()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -114,5 +114,6 @@ public:
|
|||
*/
|
||||
void emitPixmapUpdated() const;
|
||||
};
|
||||
Q_DECLARE_METATYPE(ExactCard)
|
||||
|
||||
#endif // EXACT_CARD_H
|
||||
|
|
|
|||
|
|
@ -390,14 +390,18 @@ void RemoteClient::readData()
|
|||
return;
|
||||
|
||||
ServerMessage newServerMessage;
|
||||
newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
|
||||
qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
|
||||
bool ok = newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
|
||||
inputBuffer.remove(0, messageLength);
|
||||
messageInProgress = false;
|
||||
|
||||
if (ok) {
|
||||
qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
|
||||
|
||||
processProtocolItem(newServerMessage);
|
||||
} else {
|
||||
qCDebug(RemoteClientLog) << "parsing error!";
|
||||
}
|
||||
|
||||
if (getStatus() == StatusDisconnecting) // use thread-safe getter
|
||||
doDisconnectFromServer();
|
||||
|
|
@ -408,11 +412,13 @@ void RemoteClient::websocketMessageReceived(const QByteArray &message)
|
|||
{
|
||||
lastDataReceived = timeRunning;
|
||||
ServerMessage newServerMessage;
|
||||
newServerMessage.ParseFromArray(message.data(), message.length());
|
||||
|
||||
if (newServerMessage.ParseFromArray(message.data(), message.length())) {
|
||||
qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
|
||||
|
||||
processProtocolItem(newServerMessage);
|
||||
} else {
|
||||
qCDebug(RemoteClientLog) << "parsing error!";
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
||||
|
|
@ -426,13 +432,17 @@ void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
|||
qCDebug(RemoteClientLog).noquote() << "OUT" << getSafeDebugString(cont);
|
||||
|
||||
QByteArray buf;
|
||||
bool ok;
|
||||
if (usingWebSocket) {
|
||||
buf.resize(size);
|
||||
cont.SerializeToArray(buf.data(), size);
|
||||
ok = cont.SerializeToArray(buf.data(), size);
|
||||
if (ok) {
|
||||
websocket->sendBinaryMessage(buf);
|
||||
}
|
||||
} else {
|
||||
buf.resize(size + 4);
|
||||
cont.SerializeToArray(buf.data() + 4, size);
|
||||
ok = cont.SerializeToArray(buf.data() + 4, size);
|
||||
if (ok) {
|
||||
buf.data()[3] = (unsigned char)size;
|
||||
buf.data()[2] = (unsigned char)(size >> 8);
|
||||
buf.data()[1] = (unsigned char)(size >> 16);
|
||||
|
|
@ -441,6 +451,10 @@ void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
|||
socket->write(buf);
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
qCDebug(RemoteClientLog) << "transmit error!";
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::connectToHost(const QString &hostname, unsigned int port)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,6 +101,10 @@ QString getSafeDebugString(const ::google::protobuf::Message &message)
|
|||
#endif // GOOGLE_PROTOBUF_VERSION > 3004000
|
||||
|
||||
std::string debug_string;
|
||||
printer.PrintToString(message, &debug_string);
|
||||
bool ok = printer.PrintToString(message, &debug_string);
|
||||
if (ok) {
|
||||
return QString::number(size) + " bytes " + QString::fromStdString(debug_string);
|
||||
} else {
|
||||
return "[could not convert message to string]";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ peg::parser math(R"(
|
|||
|
||||
NUMBER <- < '-'? [0-9]+ >
|
||||
NAME <- < [a-z][a-z0-9]* >
|
||||
VARIABLE <- < [x] >
|
||||
VARIABLE <- < [xX] >
|
||||
FUNCTION <- NAME '(' EXPRESSION ( [,\n] EXPRESSION )* ')'
|
||||
|
||||
%whitespace <- [ \t\r]*
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@
|
|||
<context>
|
||||
<name>OracleImporter</name>
|
||||
<message>
|
||||
<location filename="src/oracleimporter.cpp" line="541"/>
|
||||
<location filename="src/oracleimporter.cpp" line="540"/>
|
||||
<source>Dummy set containing tokens</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
@ -286,7 +286,7 @@
|
|||
<context>
|
||||
<name>OracleWizard</name>
|
||||
<message>
|
||||
<location filename="src/oraclewizard.cpp" line="70"/>
|
||||
<location filename="src/oraclewizard.cpp" line="97"/>
|
||||
<source>Oracle Importer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
|
|||
|
|
@ -360,13 +360,13 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
|||
}
|
||||
|
||||
// split cards are considered a single card, enqueue for later merging
|
||||
if (layout == "split" || layout == "aftermath" || layout == "adventure") {
|
||||
if (layout == "split" || layout == "aftermath" || layout == "adventure" || layout == "prepare") {
|
||||
auto _faceName = getStringPropertyFromMap(card, "faceName");
|
||||
SplitCardPart split(_faceName, text, properties, printingInfo);
|
||||
auto found_iter = splitCards.find(name + numProperty);
|
||||
if (found_iter == splitCards.end()) {
|
||||
splitCards.insert(name + numProperty, {{split}, name});
|
||||
} else if (layout == "adventure") {
|
||||
} else if (layout == "adventure" || layout == "prepare") {
|
||||
found_iter->first.insert(0, split);
|
||||
} else {
|
||||
found_iter->first.append(split);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const QMap<QString, CardSet::Priority> setTypePriorities{
|
|||
{"archenemy", CardSet::PriorityReprint},
|
||||
{"arsenal", CardSet::PriorityReprint},
|
||||
{"box", CardSet::PriorityReprint},
|
||||
{"eternal", CardSet::PriorityReprint},
|
||||
{"from_the_vault", CardSet::PriorityReprint},
|
||||
{"masterpiece", CardSet::PriorityReprint},
|
||||
{"masters", CardSet::PriorityReprint},
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
|
|||
// define a dummy context that will be used where needed
|
||||
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
setWizardStyle(QWizard::ModernStyle);
|
||||
#endif
|
||||
|
||||
QString oracleSettingsFile = SettingsCache::instance().getSettingsPath() + "oracle.ini";
|
||||
settings = new QSettings(oracleSettingsFile, QSettings::IniFormat, this);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "main.h"
|
||||
#include "server_logger.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QSslSocket>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <libcockatrice/protocol/debug_pb_message.h>
|
||||
|
|
@ -21,6 +22,8 @@
|
|||
#include <server_protocolhandler.h>
|
||||
#include <server_room.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(IslInterfaceLog, "isl_interface");
|
||||
|
||||
void IslInterface::sharedCtor(const QSslCertificate &cert, const QSslKey &privateKey)
|
||||
{
|
||||
socket = new QSslSocket(this);
|
||||
|
|
@ -113,10 +116,11 @@ void IslInterface::initServer()
|
|||
socket->startServerEncryption();
|
||||
if (!socket->waitForEncrypted(5000)) {
|
||||
QList<QSslError> sslErrors(socket->sslHandshakeErrors());
|
||||
if (sslErrors.isEmpty())
|
||||
qDebug() << "[ISL] SSL handshake timeout, terminating connection";
|
||||
else
|
||||
qDebug() << "[ISL] SSL errors:" << sslErrors;
|
||||
if (sslErrors.isEmpty()) {
|
||||
qCDebug(IslInterfaceLog) << "SSL handshake timeout, terminating connection";
|
||||
} else {
|
||||
qCWarning(IslInterfaceLog) << "SSL errors:" << sslErrors;
|
||||
}
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
|
|
@ -157,7 +161,7 @@ void IslInterface::initServer()
|
|||
|
||||
server->islLock.lockForWrite();
|
||||
if (server->islConnectionExists(serverId)) {
|
||||
qDebug() << "[ISL] Duplicate connection to #" << serverId << "terminating connection";
|
||||
qCDebug(IslInterfaceLog) << "Duplicate connection to #" << serverId << "terminating connection";
|
||||
deleteLater();
|
||||
} else {
|
||||
transmitMessage(message);
|
||||
|
|
@ -180,27 +184,28 @@ void IslInterface::initClient()
|
|||
expectedErrors.append(QSslError(QSslError::SelfSignedCertificate, peerCert));
|
||||
socket->ignoreSslErrors(expectedErrors);
|
||||
|
||||
qDebug() << "[ISL] Connecting to #" << serverId << ":" << peerAddress << ":" << peerPort;
|
||||
qCDebug(IslInterfaceLog) << "Connecting to #" << serverId << ":" << peerAddress << ":" << peerPort;
|
||||
|
||||
socket->connectToHostEncrypted(peerAddress, peerPort, peerHostName);
|
||||
if (!socket->waitForConnected(5000)) {
|
||||
qDebug() << "[ISL] Socket error:" << socket->errorString();
|
||||
qCDebug(IslInterfaceLog) << "Socket error:" << socket->errorString();
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
if (!socket->waitForEncrypted(5000)) {
|
||||
QList<QSslError> sslErrors(socket->sslHandshakeErrors());
|
||||
if (sslErrors.isEmpty())
|
||||
qDebug() << "[ISL] SSL handshake timeout, terminating connection";
|
||||
else
|
||||
qDebug() << "[ISL] SSL errors:" << sslErrors;
|
||||
if (sslErrors.isEmpty()) {
|
||||
qCDebug(IslInterfaceLog) << "SSL handshake timeout, terminating connection";
|
||||
} else {
|
||||
qCWarning(IslInterfaceLog) << "SSL errors:" << sslErrors;
|
||||
}
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
server->islLock.lockForWrite();
|
||||
if (server->islConnectionExists(serverId)) {
|
||||
qDebug() << "[ISL] Duplicate connection to #" << serverId << "terminating connection";
|
||||
qCDebug(IslInterfaceLog) << "Duplicate connection to #" << serverId << "terminating connection";
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
|
|
@ -242,17 +247,21 @@ void IslInterface::readClient()
|
|||
return;
|
||||
|
||||
IslMessage newMessage;
|
||||
newMessage.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
bool ok = newMessage.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
inputBuffer.remove(0, messageLength);
|
||||
messageInProgress = false;
|
||||
|
||||
if (ok) {
|
||||
processMessage(newMessage);
|
||||
} else {
|
||||
qCWarning(IslInterfaceLog) << "parsing error!";
|
||||
}
|
||||
} while (!inputBuffer.isEmpty());
|
||||
}
|
||||
|
||||
void IslInterface::catchSocketError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
qDebug() << "[ISL] Socket error:" << socketError;
|
||||
qCWarning(IslInterfaceLog) << "Socket error:" << socketError;
|
||||
|
||||
server->islLock.lockForWrite();
|
||||
server->removeIslInterface(serverId);
|
||||
|
|
@ -270,7 +279,10 @@ void IslInterface::transmitMessage(const IslMessage &item)
|
|||
unsigned int size = static_cast<unsigned int>(item.ByteSize());
|
||||
#endif
|
||||
buf.resize(size + 4);
|
||||
item.SerializeToArray(buf.data() + 4, size);
|
||||
if (!item.SerializeToArray(buf.data() + 4, size)) {
|
||||
qCWarning(IslInterfaceLog) << "transmit error!";
|
||||
return;
|
||||
}
|
||||
buf.data()[3] = (unsigned char)size;
|
||||
buf.data()[2] = (unsigned char)(size >> 8);
|
||||
buf.data()[1] = (unsigned char)(size >> 16);
|
||||
|
|
@ -368,7 +380,7 @@ void IslInterface::processSessionEvent(const SessionEvent &event, qint64 session
|
|||
QReadLocker clientsLocker(&server->clientsLock);
|
||||
Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId);
|
||||
if (!client) {
|
||||
qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
|
||||
qCDebug(IslInterfaceLog) << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
|
||||
break;
|
||||
}
|
||||
const Event_GameJoined &gameJoined = event.GetExtension(Event_GameJoined::ext);
|
||||
|
|
@ -382,7 +394,8 @@ void IslInterface::processSessionEvent(const SessionEvent &event, qint64 session
|
|||
QReadLocker clientsLocker(&server->clientsLock);
|
||||
Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId);
|
||||
if (!client) {
|
||||
qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
|
||||
qCWarning(IslInterfaceLog)
|
||||
<< "IslInterface::processSessionEvent: session id" << sessionId << "not found";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +443,7 @@ void IslInterface::processRoomCommand(const CommandContainer &cont, qint64 sessi
|
|||
|
||||
void IslInterface::processMessage(const IslMessage &item)
|
||||
{
|
||||
qDebug() << getSafeDebugString(item);
|
||||
qCDebug(IslInterfaceLog) << getSafeDebugString(item);
|
||||
|
||||
switch (item.message_type()) {
|
||||
case IslMessage::ROOM_COMMAND_CONTAINER: {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,15 @@
|
|||
#include <QChar>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QLoggingCategory>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/protocol/pb/game_replay.pb.h>
|
||||
#include <libcockatrice/utility/passwordhasher.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(DatabaseInterfaceLog, "database_interface");
|
||||
|
||||
Servatrice_DatabaseInterface::Servatrice_DatabaseInterface(int _instanceId, Servatrice *_server)
|
||||
: instanceId(_instanceId), sqlDatabase(QSqlDatabase()), server(_server)
|
||||
{
|
||||
|
|
@ -56,17 +59,16 @@ bool Servatrice_DatabaseInterface::openDatabase()
|
|||
sqlDatabase.close();
|
||||
|
||||
const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
|
||||
qDebug().noquote() << QString("[%1] Opening database...").arg(poolStr);
|
||||
qCDebug(DatabaseInterfaceLog).noquote() << poolStr << "Opening database...";
|
||||
if (!sqlDatabase.open()) {
|
||||
qCritical() << QString("[%1] Error opening database: %2").arg(poolStr).arg(sqlDatabase.lastError().text());
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database:" << sqlDatabase.lastError().text();
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlQuery *versionQuery = prepareQuery("select version from {prefix}_schema_version limit 1");
|
||||
if (!execSqlQuery(versionQuery)) {
|
||||
qCritical() << QString("[%1] Error opening database: unable to load database schema version (hint: ensure the "
|
||||
"cockatrice_schema_version exists)")
|
||||
.arg(poolStr);
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database: unable to load database schema version"
|
||||
<< "(hint: ensure the cockatrice_schema_version exists)";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -74,24 +76,21 @@ bool Servatrice_DatabaseInterface::openDatabase()
|
|||
const int dbversion = versionQuery->value(0).toInt();
|
||||
const int expectedversion = DATABASE_SCHEMA_VERSION;
|
||||
if (dbversion < expectedversion) {
|
||||
qCritical() << QString("[%1] Error opening database: the database schema version is too old, you need to "
|
||||
"run the migrations to update it from version %2 to version %3")
|
||||
.arg(poolStr)
|
||||
.arg(dbversion)
|
||||
.arg(expectedversion);
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr
|
||||
<< "Error opening database: the database schema version is too old, you "
|
||||
"need to run the migrations to update it from version"
|
||||
<< dbversion << "to version" << expectedversion;
|
||||
return false;
|
||||
} else if (dbversion > expectedversion) {
|
||||
qCritical() << QString("[%1] Error opening database: the database schema version %2 is too new, you need "
|
||||
"to update servatrice (this servatrice actually uses version %3)")
|
||||
.arg(poolStr)
|
||||
.arg(dbversion)
|
||||
.arg(expectedversion);
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database: the database schema version"
|
||||
<< dbversion << "is too new, you need to update servatrice"
|
||||
<< "(this servatrice actually uses version" << expectedversion << ")";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qCritical() << QString("[%1] Error opening database: unable to load database schema version (hint: ensure the "
|
||||
"cockatrice_schema_version contains a single record)")
|
||||
.arg(poolStr);
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr
|
||||
<< "Error opening database: unable to load database schema version (hint: "
|
||||
"ensure the cockatrice_schema_version contains a single record)";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -114,9 +113,7 @@ bool Servatrice_DatabaseInterface::checkSql()
|
|||
|
||||
if (query.lastError().isValid()) {
|
||||
const auto &poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
|
||||
qCritical() << QString("[%1] Error executing query: %2, resetting connection")
|
||||
.arg(poolStr)
|
||||
.arg(query.lastError().text());
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr << "Error executing query:" << query.lastError().text();
|
||||
|
||||
sqlDatabase.close();
|
||||
return openDatabase();
|
||||
|
|
@ -145,7 +142,7 @@ bool Servatrice_DatabaseInterface::execSqlQuery(QSqlQuery *query)
|
|||
if (query->exec())
|
||||
return true;
|
||||
const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
|
||||
qCritical() << QString("[%1] Error executing query: %2").arg(poolStr).arg(query->lastError().text());
|
||||
qCCritical(DatabaseInterfaceLog) << poolStr << "Error executing query:" << query->lastError().text();
|
||||
sqlDatabase.close();
|
||||
openDatabase();
|
||||
return false;
|
||||
|
|
@ -252,7 +249,8 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName,
|
|||
query->bindValue(":token", token);
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug() << "Failed to insert user: " << query->lastError() << " sql: " << query->lastQuery();
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to insert user: " << query->lastError()
|
||||
<< " sql: " << query->lastQuery();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -270,7 +268,7 @@ bool Servatrice_DatabaseInterface::activateUser(const QString &userName, const Q
|
|||
activateQuery->bindValue(":username", userName);
|
||||
activateQuery->bindValue(":token", token);
|
||||
if (!execSqlQuery(activateQuery)) {
|
||||
qDebug() << "Account activation failed: SQL error." << activateQuery->lastError()
|
||||
qCWarning(DatabaseInterfaceLog) << "Account activation failed: SQL error." << activateQuery->lastError()
|
||||
<< " sql: " << activateQuery->lastQuery();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -284,7 +282,8 @@ bool Servatrice_DatabaseInterface::activateUser(const QString &userName, const Q
|
|||
query->bindValue(":userName", userName);
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug() << "Failed to activate user: " << query->lastError() << " sql: " << query->lastQuery();
|
||||
qCWarning(DatabaseInterfaceLog)
|
||||
<< "Failed to activate user: " << query->lastError() << " sql: " << query->lastQuery();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +325,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
|
|||
prepareQuery("select password_sha512, active from {prefix}_users where name = :name");
|
||||
passwordQuery->bindValue(":name", user);
|
||||
if (!execSqlQuery(passwordQuery)) {
|
||||
qDebug("Login denied: SQL error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Login denied: SQL error";
|
||||
return NotLoggedIn;
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +333,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
|
|||
const QString correctPasswordSha512 = passwordQuery->value(0).toString();
|
||||
const bool userIsActive = passwordQuery->value(1).toBool();
|
||||
if (!userIsActive) {
|
||||
qDebug("Login denied: user not active");
|
||||
qCWarning(DatabaseInterfaceLog) << "Login denied: user not active";
|
||||
return UserIsInactive;
|
||||
}
|
||||
QString hashedPassword;
|
||||
|
|
@ -344,14 +343,14 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
|
|||
hashedPassword = password;
|
||||
}
|
||||
if (correctPasswordSha512 == hashedPassword) {
|
||||
qDebug("Login accepted: password right");
|
||||
qCDebug(DatabaseInterfaceLog) << "Login accepted: password right";
|
||||
return PasswordRight;
|
||||
} else {
|
||||
qDebug("Login denied: password wrong");
|
||||
qCDebug(DatabaseInterfaceLog) << "Login denied: password wrong";
|
||||
return NotLoggedIn;
|
||||
}
|
||||
} else {
|
||||
qDebug("Login accepted: unknown user");
|
||||
qCDebug(DatabaseInterfaceLog) << "Login accepted: unknown user";
|
||||
return UnknownUser;
|
||||
}
|
||||
}
|
||||
|
|
@ -369,7 +368,7 @@ bool Servatrice_DatabaseInterface::checkUserIsBanned(const QString &ipAddress,
|
|||
return false;
|
||||
|
||||
if (!checkSql()) {
|
||||
qDebug("Failed to check if user is banned. Database invalid.");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to check if user is banned. Database invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +399,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIdBanned(const QString &clientId,
|
|||
idBanQuery->bindValue(":id", clientId);
|
||||
idBanQuery->bindValue(":id2", clientId);
|
||||
if (!execSqlQuery(idBanQuery)) {
|
||||
qDebug() << "Id ban check failed: SQL error." << idBanQuery->lastError();
|
||||
qCWarning(DatabaseInterfaceLog) << "Id ban check failed: SQL error." << idBanQuery->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -410,7 +409,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIdBanned(const QString &clientId,
|
|||
if ((secondsLeft > 0) || permanentBan) {
|
||||
banReason = idBanQuery->value(2).toString();
|
||||
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
|
||||
qDebug() << "User is banned by client id" << clientId;
|
||||
qCDebug(DatabaseInterfaceLog) << "User is banned by client id" << clientId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -428,7 +427,7 @@ bool Servatrice_DatabaseInterface::checkUserIsNameBanned(const QString &userName
|
|||
nameBanQuery->bindValue(":name1", userName);
|
||||
nameBanQuery->bindValue(":name2", userName);
|
||||
if (!execSqlQuery(nameBanQuery)) {
|
||||
qDebug() << "Name ban check failed: SQL error" << nameBanQuery->lastError();
|
||||
qCWarning(DatabaseInterfaceLog) << "Name ban check failed: SQL error" << nameBanQuery->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +437,7 @@ bool Servatrice_DatabaseInterface::checkUserIsNameBanned(const QString &userName
|
|||
if ((secondsLeft > 0) || permanentBan) {
|
||||
banReason = nameBanQuery->value(2).toString();
|
||||
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
|
||||
qDebug() << "Username" << userName << "is banned by name";
|
||||
qCDebug(DatabaseInterfaceLog) << "Username" << userName << "is banned by name";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -464,7 +463,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIpBanned(const QString &ipAddress,
|
|||
ipBanQuery->bindValue(":address", ipAddress);
|
||||
ipBanQuery->bindValue(":address2", ipAddress);
|
||||
if (!execSqlQuery(ipBanQuery)) {
|
||||
qDebug() << "IP ban check failed: SQL error." << ipBanQuery->lastError();
|
||||
qCWarning(DatabaseInterfaceLog) << "IP ban check failed: SQL error." << ipBanQuery->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -474,7 +473,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIpBanned(const QString &ipAddress,
|
|||
if ((secondsLeft > 0) || permanentBan) {
|
||||
banReason = ipBanQuery->value(2).toString();
|
||||
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
|
||||
qDebug() << "User is banned by address" << ipAddress;
|
||||
qCDebug(DatabaseInterfaceLog) << "User is banned by address" << ipAddress;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -865,12 +864,17 @@ void Servatrice_DatabaseInterface::storeGameInformation(const QString &roomName,
|
|||
const unsigned int size = static_cast<unsigned int>(replayList[i]->ByteSize());
|
||||
#endif
|
||||
blob.resize(size);
|
||||
replayList[i]->SerializeToArray(blob.data(), size);
|
||||
qulonglong replayId = replayList[i]->replay_id();
|
||||
if (replayList[i]->SerializeToArray(blob.data(), size)) {
|
||||
|
||||
replayIds.append(QVariant((qulonglong)replayList[i]->replay_id()));
|
||||
replayIds.append(QVariant(replayId));
|
||||
replayGameIds.append(gameInfo.game_id());
|
||||
replayDurations.append(replayList[i]->duration_seconds());
|
||||
replayBlobs.append(blob);
|
||||
} else {
|
||||
qCWarning(DatabaseInterfaceLog)
|
||||
<< "failed to serialise replay, id:" << replayId << "game:" << gameInfo.game_id();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -1017,7 +1021,7 @@ bool Servatrice_DatabaseInterface::changeUserPassword(const QString &user,
|
|||
passwordQuery->bindValue(":name", user);
|
||||
|
||||
if (!execSqlQuery(passwordQuery)) {
|
||||
qDebug("Change password denied: SQL error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Change password denied: SQL error";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1084,7 +1088,7 @@ void Servatrice_DatabaseInterface::updateUsersLastLoginData(const QString &userN
|
|||
QSqlQuery *query = prepareQuery("select id from {prefix}_users where name = :user_name");
|
||||
query->bindValue(":user_name", userName);
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to locate user id when updating users last login data: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to locate user id when updating users last login data: SQL Error";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1133,7 +1137,7 @@ QList<ServerInfo_Ban> Servatrice_DatabaseInterface::getUserBanHistory(const QStr
|
|||
query->bindValue(":user_name", userName);
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to collect ban history information: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to collect ban history information: SQL Error";
|
||||
return results;
|
||||
}
|
||||
|
||||
|
|
@ -1168,7 +1172,7 @@ bool Servatrice_DatabaseInterface::addWarning(const QString userName,
|
|||
query->bindValue(":warn_reason", warningReason);
|
||||
query->bindValue(":client_id", clientID);
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to collect create warning history information: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to collect create warning history information: SQL Error";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1189,7 +1193,7 @@ QList<ServerInfo_Warning> Servatrice_DatabaseInterface::getUserWarnHistory(const
|
|||
query->bindValue(":user_id", userID);
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to collect warning history information: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to collect warning history information: SQL Error";
|
||||
return results;
|
||||
}
|
||||
|
||||
|
|
@ -1296,7 +1300,7 @@ QList<ServerInfo_ChatMessage> Servatrice_DatabaseInterface::getMessageLogHistory
|
|||
}
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to collect log history information: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog) << "Failed to collect log history information: SQL Error";
|
||||
return results;
|
||||
}
|
||||
|
||||
|
|
@ -1324,7 +1328,8 @@ int Servatrice_DatabaseInterface::checkNumberOfUserAccounts(const QString &email
|
|||
query->bindValue(":user_email", email);
|
||||
|
||||
if (!execSqlQuery(query)) {
|
||||
qDebug("Failed to identify the number of users accounts for users email address: SQL Error");
|
||||
qCWarning(DatabaseInterfaceLog)
|
||||
<< "Failed to identify the number of users accounts for users email address: SQL Error";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
#include <QLoggingCategory>
|
||||
#include <QRegularExpression>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
|
|
@ -83,6 +84,10 @@
|
|||
#include <server_room.h>
|
||||
#include <string>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(AbstractServerSocketInterfaceLog, "abstract_server_socket_interface");
|
||||
inline Q_LOGGING_CATEGORY(TcpServerSocketInterfaceLog, "tcp_server_socket_interface");
|
||||
inline Q_LOGGING_CATEGORY(WebsocketServerSocketInterfaceLog, "websocket_server_socket_interface");
|
||||
|
||||
static const int protocolVersion = 14;
|
||||
|
||||
AbstractServerSocketInterface::AbstractServerSocketInterface(Servatrice *_server,
|
||||
|
|
@ -130,7 +135,7 @@ bool AbstractServerSocketInterface::initSession()
|
|||
|
||||
void AbstractServerSocketInterface::catchSocketError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
qDebug() << "Socket error:" << socketError;
|
||||
qCWarning(AbstractServerSocketInterfaceLog) << "Socket error:" << socketError;
|
||||
|
||||
prepareDestroy();
|
||||
}
|
||||
|
|
@ -1100,7 +1105,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdBanFromServer(const Com
|
|||
clientIdQuery->bindValue(":client_id", nameFromStdString(cmd.clientid()));
|
||||
sqlInterface->execSqlQuery(clientIdQuery);
|
||||
if (!sqlInterface->execSqlQuery(clientIdQuery)) {
|
||||
qDebug("ClientID username ban lookup failed: SQL Error");
|
||||
qCWarning(AbstractServerSocketInterfaceLog) << "ClientID username ban lookup failed: SQL Error";
|
||||
} else {
|
||||
while (clientIdQuery->next()) {
|
||||
userName = clientIdQuery->value(0).toString();
|
||||
|
|
@ -1152,7 +1157,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
|
|||
{
|
||||
QString userName = nameFromStdString(cmd.user_name());
|
||||
QString clientId = nameFromStdString(cmd.clientid());
|
||||
qDebug() << "Got register command for user:" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Got register command for user:" << userName;
|
||||
|
||||
bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
|
||||
if (!registrationEnabled) {
|
||||
|
|
@ -1289,7 +1294,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
|
|||
country, !requireEmailActivation);
|
||||
|
||||
if (regSucceeded) {
|
||||
qDebug() << "Accepted register command for user:" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Accepted register command for user:" << userName;
|
||||
if (requireEmailActivation) {
|
||||
QSqlQuery *query =
|
||||
sqlInterface->prepareQuery("insert into {prefix}_activation_emails (name) values(:name)");
|
||||
|
|
@ -1337,7 +1342,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdActivateAccount(const C
|
|||
clientId = "UNKNOWN";
|
||||
|
||||
if (sqlInterface->activateUser(userName, token)) {
|
||||
qDebug() << "Accepted activation for user" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Accepted activation for user" << userName;
|
||||
|
||||
if (servatrice->getEnableRegistrationAudit())
|
||||
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
||||
|
|
@ -1345,7 +1350,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdActivateAccount(const C
|
|||
|
||||
return Response::RespActivationAccepted;
|
||||
} else {
|
||||
qDebug() << "Failed activation for user" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Failed activation for user" << userName;
|
||||
|
||||
if (servatrice->getEnableRegistrationAudit())
|
||||
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
||||
|
|
@ -1493,7 +1498,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c
|
|||
const QString userName = nameFromStdString(cmd.user_name());
|
||||
const QString clientId = nameFromStdString(cmd.clientid());
|
||||
|
||||
qDebug() << "Received reset password request from user:" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password request from user:" << userName;
|
||||
|
||||
if (!servatrice->getEnableForgotPassword()) {
|
||||
if (servatrice->getEnableForgotPasswordAudit())
|
||||
|
|
@ -1575,7 +1580,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordReset(con
|
|||
Q_UNUSED(rc);
|
||||
QString userName = nameFromStdString(cmd.user_name());
|
||||
QString clientId = nameFromStdString(cmd.clientid());
|
||||
qDebug() << "Received reset password reset from user:" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password reset from user:" << userName;
|
||||
|
||||
if (!sqlInterface->doesForgotPasswordExist(userName)) {
|
||||
if (servatrice->getEnableForgotPasswordAudit())
|
||||
|
|
@ -1626,7 +1631,7 @@ AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPa
|
|||
const QString userName = nameFromStdString(cmd.user_name());
|
||||
const QString clientId = nameFromStdString(cmd.clientid());
|
||||
|
||||
qDebug() << "Received reset password challenge from user:" << userName;
|
||||
qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password challenge from user:" << userName;
|
||||
|
||||
if (!servatrice->getEnableForgotPasswordChallenge()) {
|
||||
if (servatrice->getEnableForgotPasswordAudit()) {
|
||||
|
|
@ -1971,13 +1976,16 @@ void TcpServerSocketInterface::flushOutputQueue()
|
|||
unsigned int size = static_cast<unsigned int>(item.ByteSize());
|
||||
#endif
|
||||
buf.resize(size + 4);
|
||||
item.SerializeToArray(buf.data() + 4, size);
|
||||
if (item.SerializeToArray(buf.data() + 4, size)) {
|
||||
buf.data()[3] = (unsigned char)size;
|
||||
buf.data()[2] = (unsigned char)(size >> 8);
|
||||
buf.data()[1] = (unsigned char)(size >> 16);
|
||||
buf.data()[0] = (unsigned char)(size >> 24);
|
||||
// In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
|
||||
writeToSocket(buf);
|
||||
} else {
|
||||
qCWarning(TcpServerSocketInterfaceLog) << "serialisation error!";
|
||||
}
|
||||
|
||||
totalBytes += size + 4;
|
||||
locker.relock();
|
||||
|
|
@ -2010,32 +2018,35 @@ void TcpServerSocketInterface::readClient()
|
|||
return;
|
||||
|
||||
CommandContainer newCommandContainer;
|
||||
bool ok;
|
||||
try {
|
||||
newCommandContainer.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
ok = newCommandContainer.ParseFromArray(inputBuffer.data(), messageLength);
|
||||
} catch (std::exception &e) {
|
||||
qDebug() << "Caught std::exception in" << __FILE__ << __LINE__ <<
|
||||
qCWarning(TcpServerSocketInterfaceLog) << "Caught std::exception in" << __FILE__ << __LINE__ <<
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
__FUNCTION__;
|
||||
__FUNCTION__
|
||||
#else
|
||||
__PRETTY_FUNCTION__;
|
||||
__PRETTY_FUNCTION__
|
||||
#endif
|
||||
qDebug() << "Exception:" << e.what();
|
||||
qDebug() << "Message coming from:" << getAddress();
|
||||
qDebug() << "Message length:" << messageLength;
|
||||
qDebug() << "Message content:" << inputBuffer.toHex();
|
||||
<< Qt::endl
|
||||
<< "Exception:" << e.what() << Qt::endl
|
||||
<< "Message coming from:" << getAddress() << Qt::endl
|
||||
<< "Message length:" << messageLength << Qt::endl
|
||||
<< "Message content:" << inputBuffer.toHex();
|
||||
} catch (...) {
|
||||
qDebug() << "Unhandled exception in" << __FILE__ << __LINE__ <<
|
||||
qCWarning(TcpServerSocketInterfaceLog) << "Unhandled exception in" << __FILE__ << __LINE__ <<
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
__FUNCTION__;
|
||||
__FUNCTION__
|
||||
#else
|
||||
__PRETTY_FUNCTION__;
|
||||
__PRETTY_FUNCTION__
|
||||
#endif
|
||||
qDebug() << "Message coming from:" << getAddress();
|
||||
<< Qt::endl
|
||||
<< "Message coming from:" << getAddress();
|
||||
}
|
||||
|
||||
inputBuffer.remove(0, messageLength);
|
||||
messageInProgress = false;
|
||||
|
||||
if (ok) {
|
||||
// dirty hack to make v13 client display the correct error message
|
||||
if (handshakeStarted)
|
||||
processCommandContainer(newCommandContainer);
|
||||
|
|
@ -2045,6 +2056,10 @@ void TcpServerSocketInterface::readClient()
|
|||
prepareDestroy();
|
||||
}
|
||||
// end of hack
|
||||
} else {
|
||||
qCWarning(TcpServerSocketInterfaceLog) << "parsing error!";
|
||||
}
|
||||
|
||||
} while (!inputBuffer.isEmpty());
|
||||
}
|
||||
|
||||
|
|
@ -2172,9 +2187,12 @@ void WebsocketServerSocketInterface::flushOutputQueue()
|
|||
unsigned int size = static_cast<unsigned int>(item.ByteSize());
|
||||
#endif
|
||||
buf.resize(size);
|
||||
item.SerializeToArray(buf.data(), size);
|
||||
if (item.SerializeToArray(buf.data(), size)) {
|
||||
// In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
|
||||
writeToSocket(buf);
|
||||
} else {
|
||||
qCWarning(TcpServerSocketInterfaceLog) << "serialisation error!";
|
||||
}
|
||||
|
||||
totalBytes += size;
|
||||
locker.relock();
|
||||
|
|
@ -2190,30 +2208,37 @@ void WebsocketServerSocketInterface::binaryMessageReceived(const QByteArray &mes
|
|||
servatrice->incRxBytes(message.size());
|
||||
|
||||
CommandContainer newCommandContainer;
|
||||
bool ok;
|
||||
try {
|
||||
newCommandContainer.ParseFromArray(message.data(), message.size());
|
||||
ok = newCommandContainer.ParseFromArray(message.data(), message.size());
|
||||
} catch (std::exception &e) {
|
||||
qDebug() << "Caught std::exception in" << __FILE__ << __LINE__ <<
|
||||
qCWarning(WebsocketServerSocketInterfaceLog) << "Caught std::exception in" << __FILE__ << __LINE__ <<
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
__FUNCTION__;
|
||||
__FUNCTION__
|
||||
#else
|
||||
__PRETTY_FUNCTION__;
|
||||
__PRETTY_FUNCTION__
|
||||
#endif
|
||||
qDebug() << "Exception:" << e.what();
|
||||
qDebug() << "Message coming from:" << getAddress();
|
||||
qDebug() << "Message length:" << message.size();
|
||||
qDebug() << "Message content:" << message.toHex();
|
||||
<< Qt::endl
|
||||
<< "Exception:" << e.what() << Qt::endl
|
||||
<< "Message coming from:" << getAddress() << Qt::endl
|
||||
<< "Message length:" << message.size() << Qt::endl
|
||||
<< "Message content:" << message.toHex();
|
||||
} catch (...) {
|
||||
qDebug() << "Unhandled exception in" << __FILE__ << __LINE__ <<
|
||||
qCWarning(WebsocketServerSocketInterfaceLog) << "Unhandled exception in" << __FILE__ << __LINE__ <<
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
__FUNCTION__;
|
||||
__FUNCTION__
|
||||
#else
|
||||
__PRETTY_FUNCTION__;
|
||||
__PRETTY_FUNCTION__
|
||||
#endif
|
||||
qDebug() << "Message coming from:" << getAddress();
|
||||
<< Qt::endl
|
||||
<< "Message coming from:" << getAddress();
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
processCommandContainer(newCommandContainer);
|
||||
} else {
|
||||
qCWarning(WebsocketServerSocketInterfaceLog) << "parsing error!";
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractServerSocketInterface::isPasswordLongEnough(const int passwordLength)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { StatusEnum, User, WebSocketConnectReason, WebSocketConnectOptions } from 'types';
|
||||
import { SessionCommands, webClient } from 'websocket';
|
||||
import { ProtoController } from 'websocket/services/ProtoController';
|
||||
|
||||
export class AuthenticationService {
|
||||
static login(options: WebSocketConnectOptions): void {
|
||||
|
|
@ -39,7 +40,7 @@ export class AuthenticationService {
|
|||
}
|
||||
|
||||
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
|
||||
return (user.userLevel & moderatorLevel) === moderatorLevel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class ModeratorService {
|
|||
ModeratorCommands.viewLogHistory(filters);
|
||||
}
|
||||
|
||||
static warnUser(userName: string, reason: string, clientid?: string, removeMessage?: boolean): void {
|
||||
ModeratorCommands.warnUser(userName, reason, clientid, removeMessage);
|
||||
static warnUser(userName: string, reason: string, clientid?: string, removeMessages?: number): void {
|
||||
ModeratorCommands.warnUser(userName, reason, clientid, removeMessages);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { SessionCommands } from 'websocket';
|
||||
import { common } from 'protobufjs';
|
||||
import IBytesValue = common.IBytesValue;
|
||||
|
||||
export class SessionService {
|
||||
static addToBuddyList(userName: string) {
|
||||
|
|
@ -27,7 +25,7 @@ export class SessionService {
|
|||
SessionCommands.accountEdit(passwordCheck, realName, email, country);
|
||||
}
|
||||
|
||||
static changeAccountImage(image: IBytesValue): void {
|
||||
static changeAccountImage(image: Uint8Array): void {
|
||||
SessionCommands.accountImage(image);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { WebSocketConnectOptions } from 'types';
|
||||
import { DeckList, DeckStorageTreeItem, ReplayMatch, WebSocketConnectOptions } from 'types';
|
||||
import { Types } from './server.types';
|
||||
|
||||
export const Actions = {
|
||||
|
|
@ -210,4 +210,33 @@ export const Actions = {
|
|||
type: Types.WARN_USER,
|
||||
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 }),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { reset } from 'redux-form';
|
||||
import { Actions } from './server.actions';
|
||||
import { store } from 'store';
|
||||
import { WebSocketConnectOptions } from 'types';
|
||||
import { DeckList, DeckStorageTreeItem, ReplayMatch, WebSocketConnectOptions } from 'types';
|
||||
|
||||
export const Dispatch = {
|
||||
initialized: () => {
|
||||
|
|
@ -177,4 +177,43 @@ export const Dispatch = {
|
|||
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));
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
export interface ServerConnectParams {
|
||||
|
|
@ -67,6 +69,9 @@ export interface ServerState {
|
|||
};
|
||||
warnListOptions: WarnListItem[];
|
||||
warnUser: string;
|
||||
adminNotes: { [userName: string]: string };
|
||||
replays: ReplayMatch[];
|
||||
backendDecks: DeckList | null;
|
||||
}
|
||||
|
||||
export interface ServerStateStatus {
|
||||
|
|
|
|||
|
|
@ -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 { ServerState } from './server.interfaces'
|
||||
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 = {
|
||||
initialized: false,
|
||||
buddyList: [],
|
||||
|
|
@ -40,6 +90,9 @@ const initialState: ServerState = {
|
|||
warnHistory: {},
|
||||
warnListOptions: [],
|
||||
warnUser: '',
|
||||
adminNotes: {},
|
||||
replays: [],
|
||||
backendDecks: null,
|
||||
};
|
||||
|
||||
export const serverReducer = (state = initialState, action: any) => {
|
||||
|
|
@ -247,7 +300,7 @@ export const serverReducer = (state = initialState, action: any) => {
|
|||
messages: {
|
||||
...state.messages,
|
||||
[userName]: [
|
||||
...state.messages[userName],
|
||||
...(state.messages[userName] ?? []),
|
||||
action.messageData,
|
||||
],
|
||||
}
|
||||
|
|
@ -328,6 +381,17 @@ export const serverReducer = (state = initialState, action: any) => {
|
|||
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: {
|
||||
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:
|
||||
return state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,5 +16,7 @@ export const Selectors = {
|
|||
getUsers: ({ server }: State) => server.users,
|
||||
getLogs: ({ server }: State) => server.logs,
|
||||
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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,4 +54,19 @@ export const Types = {
|
|||
WARN_HISTORY: '[Server] Warn History',
|
||||
WARN_LIST_OPTIONS: '[Server] Warn List Options',
|
||||
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',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ export interface DeckStorageFile {
|
|||
export interface DeckStorageTreeItem {
|
||||
id: number;
|
||||
name: string;
|
||||
file: DeckStorageFile;
|
||||
folder: DeckStorageFolder;
|
||||
file: DeckStorageFile | null;
|
||||
folder: DeckStorageFolder | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,3 +16,4 @@ export * from './logs';
|
|||
export * from './session';
|
||||
export * from './deckList';
|
||||
export * from './moderator';
|
||||
export * from './replay';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
export interface LogFilters {
|
||||
userName: string;
|
||||
ipAddress: string;
|
||||
gameName: string;
|
||||
gameId: string;
|
||||
message: string;
|
||||
logLocation: string;
|
||||
userName?: string;
|
||||
ipAddress?: string;
|
||||
gameName?: string;
|
||||
gameId?: string;
|
||||
message?: string;
|
||||
logLocation?: string[];
|
||||
dateRange: number;
|
||||
maximumResults?: number;
|
||||
}
|
||||
|
|
|
|||
16
webclient/src/types/replay.ts
Normal file
16
webclient/src/types/replay.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -1,26 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { AdminPersistence } from '../../persistence';
|
||||
|
||||
export function adjustMod(userName: string, shouldBeMod?: boolean, shouldBeJudge?: boolean): void {
|
||||
const command = webClient.protobuf.controller.Command_AdjustMod.create({ userName, shouldBeMod, shouldBeJudge });
|
||||
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_AdjustMod.ext': command });
|
||||
|
||||
webClient.protobuf.sendAdminCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendAdminCommand('Command_AdjustMod', { userName, shouldBeMod, shouldBeJudge }, {
|
||||
onSuccess: () => {
|
||||
AdminPersistence.adjustMod(userName, shouldBeMod, shouldBeJudge);
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to reload config.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { AdminPersistence } from '../../persistence';
|
||||
|
||||
export function reloadConfig(): void {
|
||||
const command = webClient.protobuf.controller.Command_ReloadConfig.create();
|
||||
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_ReloadConfig.ext': command });
|
||||
|
||||
webClient.protobuf.sendAdminCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendAdminCommand('Command_ReloadConfig', {}, {
|
||||
onSuccess: () => {
|
||||
AdminPersistence.reloadConfig();
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to reload config.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { AdminPersistence } from '../../persistence';
|
||||
|
||||
export function shutdownServer(reason: string, minutes: number): void {
|
||||
const command = webClient.protobuf.controller.Command_ShutdownServer.create({ reason, minutes });
|
||||
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_ShutdownServer.ext': command });
|
||||
|
||||
webClient.protobuf.sendAdminCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendAdminCommand('Command_ShutdownServer', { reason, minutes }, {
|
||||
onSuccess: () => {
|
||||
AdminPersistence.shutdownServer();
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to update server message.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { AdminPersistence } from '../../persistence';
|
||||
|
||||
export function updateServerMessage(): void {
|
||||
const command = webClient.protobuf.controller.Command_UpdateServerMessage.create();
|
||||
const sc = webClient.protobuf.controller.AdminCommand.create({ '.Command_UpdateServerMessage.ext': command });
|
||||
|
||||
webClient.protobuf.sendAdminCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendAdminCommand('Command_UpdateServerMessage', {}, {
|
||||
onSuccess: () => {
|
||||
AdminPersistence.updateServerMessage();
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to update server message.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,13 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
|
||||
export function banFromServer(minutes: number, userName?: string, address?: string, reason?: string,
|
||||
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
|
||||
});
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_BanFromServer.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
ModeratorPersistence.banFromServer(userName);
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to ban user.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
11
webclient/src/websocket/commands/moderator/getAdminNotes.ts
Normal file
11
webclient/src/websocket/commands/moderator/getAdminNotes.ts
Normal 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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -1,27 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
|
||||
export function getBanHistory(userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_GetBanHistory.create({ userName });
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetBanHistory.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
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);
|
||||
}
|
||||
BackendService.sendModeratorCommand('Command_GetBanHistory', { userName }, {
|
||||
responseName: 'Response_BanHistory',
|
||||
onSuccess: (response) => {
|
||||
ModeratorPersistence.banHistory(userName, response.banList);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
|
||||
export function getWarnHistory(userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_GetWarnHistory.create({ userName });
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetWarnHistory.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
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);
|
||||
}
|
||||
BackendService.sendModeratorCommand('Command_GetWarnHistory', { userName }, {
|
||||
responseName: 'Response_WarnHistory',
|
||||
onSuccess: (response) => {
|
||||
ModeratorPersistence.warnHistory(userName, response.warnList);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
|
||||
export function getWarnList(modName: string, userName: string, userClientid: string): void {
|
||||
const command = webClient.protobuf.controller.Command_GetWarnList.create({ modName, userName, userClientid });
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_GetWarnList.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
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);
|
||||
}
|
||||
BackendService.sendModeratorCommand('Command_GetWarnList', { modName, userName, userClientid }, {
|
||||
responseName: 'Response_WarnList',
|
||||
onSuccess: (response) => {
|
||||
ModeratorPersistence.warnListOptions(response.warning);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
export * from './banFromServer';
|
||||
export * from './forceActivateUser';
|
||||
export * from './getAdminNotes';
|
||||
export * from './getBanHistory';
|
||||
export * from './getWarnHistory';
|
||||
export * from './getWarnList';
|
||||
export * from './grantReplayAccess';
|
||||
export * from './updateAdminNotes';
|
||||
export * from './viewLogHistory';
|
||||
export * from './warnUser';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -1,28 +1,12 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
import { LogFilters } from 'types';
|
||||
|
||||
export function viewLogHistory(filters: LogFilters): void {
|
||||
const command = webClient.protobuf.controller.Command_ViewLogHistory.create(filters);
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_ViewLogHistory.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
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);
|
||||
}
|
||||
BackendService.sendModeratorCommand('Command_ViewLogHistory', filters, {
|
||||
responseName: 'Response_ViewLogHistory',
|
||||
onSuccess: (response) => {
|
||||
ModeratorPersistence.viewLogs(response.logMessage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ModeratorPersistence } from '../../persistence';
|
||||
|
||||
export function warnUser(userName: string, reason: string, clientid?: string, removeMessage?: boolean): void {
|
||||
const command = webClient.protobuf.controller.Command_WarnUser.create({ userName, reason, clientid, removeMessage });
|
||||
const sc = webClient.protobuf.controller.ModeratorCommand.create({ '.Command_WarnUser.ext': command });
|
||||
|
||||
webClient.protobuf.sendModeratorCommand(sc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
let error: string;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
export function warnUser(userName: string, reason: string, clientid?: string, removeMessages?: number): void {
|
||||
BackendService.sendModeratorCommand('Command_WarnUser', { userName, reason, clientid, removeMessages }, {
|
||||
onSuccess: () => {
|
||||
ModeratorPersistence.warnUser(userName);
|
||||
return;
|
||||
default:
|
||||
error = 'Failed to warn user.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error(responseCode, error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
import { BackendService } from '../../services/BackendService';
|
||||
import { RoomPersistence } from '../../persistence';
|
||||
import webClient from '../../WebClient';
|
||||
import { GameConfig } from 'types';
|
||||
|
||||
export function createGame(roomId: number, gameConfig: GameConfig): void {
|
||||
const command = webClient.protobuf.controller.Command_CreateGame.create(gameConfig);
|
||||
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_CreateGame.ext': command });
|
||||
|
||||
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendRoomCommand(roomId, 'Command_CreateGame', gameConfig, {
|
||||
onSuccess: () => {
|
||||
RoomPersistence.gameCreated(roomId);
|
||||
break;
|
||||
default:
|
||||
console.log('Failed to do the thing');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
import { BackendService } from '../../services/BackendService';
|
||||
import { RoomPersistence } from '../../persistence';
|
||||
import webClient from '../../WebClient';
|
||||
import { GameConfig, JoinGameParams } from 'types';
|
||||
import { JoinGameParams } from 'types';
|
||||
|
||||
export function joinGame(roomId: number, joinGameParams: JoinGameParams): void {
|
||||
const command = webClient.protobuf.controller.Command_JoinGame.create(joinGameParams);
|
||||
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_JoinGame.ext': command });
|
||||
|
||||
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendRoomCommand(roomId, 'Command_JoinGame', joinGameParams, {
|
||||
onSuccess: () => {
|
||||
RoomPersistence.joinedGame(roomId, joinGameParams.gameId);
|
||||
break;
|
||||
default:
|
||||
console.log('Failed to do the thing');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
import { BackendService } from '../../services/BackendService';
|
||||
import { RoomPersistence } from '../../persistence';
|
||||
import webClient from '../../WebClient';
|
||||
|
||||
export function leaveRoom(roomId: number): void {
|
||||
const command = webClient.protobuf.controller.Command_LeaveRoom.create();
|
||||
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_LeaveRoom.ext': command });
|
||||
|
||||
webClient.protobuf.sendRoomCommand(roomId, rc, (raw) => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendRoomCommand(roomId, 'Command_LeaveRoom', {}, {
|
||||
onSuccess: () => {
|
||||
RoomPersistence.leaveRoom(roomId);
|
||||
break;
|
||||
default:
|
||||
console.log(`Failed to leave Room ${roomId} [${responseCode}] : `, raw);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
|
||||
export function roomSay(roomId: number, message: string): void {
|
||||
const trimmed = message.trim();
|
||||
|
|
@ -7,8 +7,5 @@ export function roomSay(roomId: number, message: string): void {
|
|||
return;
|
||||
}
|
||||
|
||||
const command = webClient.protobuf.controller.Command_RoomSay.create({ 'message': trimmed });
|
||||
const rc = webClient.protobuf.controller.RoomCommand.create({ '.Command_RoomSay.ext': command });
|
||||
|
||||
webClient.protobuf.sendRoomCommand(roomId, rc);
|
||||
BackendService.sendRoomCommand(roomId, 'Command_RoomSay', { message: trimmed }, {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function accountEdit(passwordCheck: string, realName?: string, email?: string, country?: string): void {
|
||||
const command = webClient.protobuf.controller.Command_AccountEdit.create({ passwordCheck, realName, email, country });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountEdit.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_AccountEdit', { passwordCheck, realName, email, country }, {
|
||||
onSuccess: () => {
|
||||
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');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
import { common } from 'protobufjs';
|
||||
import IBytesValue = common.IBytesValue;
|
||||
|
||||
export function accountImage(image: IBytesValue): void {
|
||||
const command = webClient.protobuf.controller.Command_AccountImage.create({ image });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountImage.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
export function accountImage(image: Uint8Array): void {
|
||||
BackendService.sendSessionCommand('Command_AccountImage', { image }, {
|
||||
onSuccess: () => {
|
||||
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');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function accountPassword(oldPassword: string, newPassword: string, hashedNewPassword: string): void {
|
||||
const command = webClient.protobuf.controller.Command_AccountPassword.create({ oldPassword, newPassword, hashedNewPassword });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AccountPassword.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_AccountPassword', { oldPassword, newPassword, hashedNewPassword }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.accountPasswordChange();
|
||||
break;
|
||||
default:
|
||||
console.log('Failed to change password');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { AccountActivationParams } from 'store';
|
|||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ProtoController } from '../../services/ProtoController';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
import { disconnect, login, updateStatus } from './';
|
||||
|
|
@ -9,23 +11,21 @@ import { disconnect, login, updateStatus } from './';
|
|||
export function activate(options: WebSocketConnectOptions, passwordSalt?: string): void {
|
||||
const { userName, token } = options as unknown as AccountActivationParams;
|
||||
|
||||
const accountActivationConfig = {
|
||||
BackendService.sendSessionCommand('Command_Activate', {
|
||||
...webClient.clientConfig,
|
||||
userName,
|
||||
token,
|
||||
};
|
||||
|
||||
const command = webClient.protobuf.controller.Command_Activate.create(accountActivationConfig);
|
||||
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) {
|
||||
}, {
|
||||
onResponseCode: {
|
||||
[ProtoController.root.Response.ResponseCode.RespActivationAccepted]: () => {
|
||||
SessionPersistence.accountActivationSuccess();
|
||||
login(options, passwordSalt);
|
||||
} else {
|
||||
},
|
||||
},
|
||||
onError: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
|
||||
disconnect();
|
||||
SessionPersistence.accountActivationFailed();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function addToBuddyList(userName: string): void {
|
||||
|
|
@ -10,16 +10,9 @@ export function addToIgnoreList(userName: string): void {
|
|||
}
|
||||
|
||||
export function addToList(list: string, userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_AddToList.create({ list, userName });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_AddToList.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_AddToList', { list, userName }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.addToList(list, userName);
|
||||
break;
|
||||
default:
|
||||
console.error('Failed to add to list', responseCode);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function deckDel(deckId: number): void {
|
||||
const command = webClient.protobuf.controller.Command_DeckDel.create({ deckId });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckDel.ext': command });
|
||||
|
||||
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');
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_DeckDel', { deckId }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.deleteServerDeck(deckId);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function deckDelDir(path: string): void {
|
||||
const command = webClient.protobuf.controller.Command_DeckDelDir.create({ path });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckDelDir.ext': command });
|
||||
|
||||
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');
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_DeckDelDir', { path }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.deleteServerDeckDir(path);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,22 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function deckList(): void {
|
||||
const command = webClient.protobuf.controller.Command_DeckList.create();
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckList.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
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');
|
||||
}
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_DeckList', {}, {
|
||||
responseName: 'Response_DeckList',
|
||||
onSuccess: (response) => {
|
||||
SessionPersistence.updateServerDecks(response);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function deckNewDir(path: string, dirName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_DeckNewDir.create({ path, dirName });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckNewDir.ext': command });
|
||||
|
||||
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');
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_DeckNewDir', { path, dirName }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.createServerDeckDir(path, dirName);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function deckUpload(path: string, deckId: number, deckList: string): void {
|
||||
const command = webClient.protobuf.controller.Command_DeckUpload.create({ path, deckId, deckList });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_DeckUpload.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
BackendService.sendSessionCommand('Command_DeckUpload', { path, deckId, deckList }, {
|
||||
responseName: 'Response_DeckUpload',
|
||||
onSuccess: (response) => {
|
||||
SessionPersistence.uploadServerDeck(path, response.newFile);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,30 +2,27 @@ import { ForgotPasswordChallengeParams } from 'store';
|
|||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
import { disconnect, updateStatus } from './';
|
||||
|
||||
export function forgotPasswordChallenge(options: WebSocketConnectOptions): void {
|
||||
const { userName, email } = options as unknown as ForgotPasswordChallengeParams;
|
||||
|
||||
const forgotPasswordChallengeConfig = {
|
||||
BackendService.sendSessionCommand('Command_ForgotPasswordChallenge', {
|
||||
...webClient.clientConfig,
|
||||
userName,
|
||||
email,
|
||||
};
|
||||
|
||||
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) {
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPassword();
|
||||
} else {
|
||||
disconnect();
|
||||
},
|
||||
onError: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPasswordFailed();
|
||||
}
|
||||
|
||||
disconnect();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { ForgotPasswordParams } from 'store';
|
|||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
import { disconnect, updateStatus } from './';
|
||||
|
|
@ -9,30 +10,25 @@ import { disconnect, updateStatus } from './';
|
|||
export function forgotPasswordRequest(options: WebSocketConnectOptions): void {
|
||||
const { userName } = options as unknown as ForgotPasswordParams;
|
||||
|
||||
const forgotPasswordConfig = {
|
||||
BackendService.sendSessionCommand('Command_ForgotPasswordRequest', {
|
||||
...webClient.clientConfig,
|
||||
userName,
|
||||
};
|
||||
|
||||
const command = webClient.protobuf.controller.Command_ForgotPasswordRequest.create(forgotPasswordConfig);
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ForgotPasswordRequest.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
||||
const resp = raw['.Response_ForgotPasswordRequest.ext'];
|
||||
|
||||
if (resp.challengeEmail) {
|
||||
}, {
|
||||
responseName: 'Response_ForgotPasswordRequest',
|
||||
onSuccess: (resp) => {
|
||||
if (resp?.challengeEmail) {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPasswordChallenge();
|
||||
} else {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPassword();
|
||||
}
|
||||
} else {
|
||||
disconnect();
|
||||
},
|
||||
onError: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPasswordFailed();
|
||||
}
|
||||
|
||||
disconnect();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { ForgotPasswordResetParams } from 'store';
|
|||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
import { hashPassword } from '../../utils';
|
||||
|
||||
|
|
@ -10,30 +11,28 @@ import { disconnect, updateStatus } from '.';
|
|||
export function forgotPasswordReset(options: WebSocketConnectOptions, passwordSalt?: string): void {
|
||||
const { userName, token, newPassword } = options as unknown as ForgotPasswordResetParams;
|
||||
|
||||
const forgotPasswordResetConfig: any = {
|
||||
const params: any = {
|
||||
...webClient.clientConfig,
|
||||
userName,
|
||||
token,
|
||||
};
|
||||
|
||||
if (passwordSalt) {
|
||||
forgotPasswordResetConfig.hashedNewPassword = hashPassword(passwordSalt, newPassword);
|
||||
params.hashedNewPassword = hashPassword(passwordSalt, newPassword);
|
||||
} else {
|
||||
forgotPasswordResetConfig.newPassword = newPassword;
|
||||
params.newPassword = newPassword;
|
||||
}
|
||||
|
||||
const command = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig);
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ForgotPasswordReset.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
||||
BackendService.sendSessionCommand('Command_ForgotPasswordReset', params, {
|
||||
onSuccess: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPasswordSuccess();
|
||||
} else {
|
||||
disconnect();
|
||||
},
|
||||
onError: () => {
|
||||
updateStatus(StatusEnum.DISCONNECTED, null);
|
||||
SessionPersistence.resetPasswordFailed();
|
||||
}
|
||||
|
||||
disconnect();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function getGamesOfUser(userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_GetGamesOfUser.create({ userName });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_GetGamesOfUser.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const { responseCode } = raw;
|
||||
const response = raw['.Response_GetGamesOfUser.ext'];
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_GetGamesOfUser', { userName }, {
|
||||
responseName: 'Response_GetGamesOfUser',
|
||||
onSuccess: (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');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function getUserInfo(userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_GetUserInfo.create({ userName });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_GetUserInfo.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
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');
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_GetUserInfo', { userName }, {
|
||||
responseName: 'Response_GetUserInfo',
|
||||
onSuccess: (response) => {
|
||||
SessionPersistence.getUserInfo(response.userInfo);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@ export * from './addToList';
|
|||
export * from './connect';
|
||||
export * from './deckDel';
|
||||
export * from './deckDelDir';
|
||||
export * from './deckDownload';
|
||||
export * from './deckList';
|
||||
export * from './deckNewDir';
|
||||
export * from './deckUpload';
|
||||
export * from './disconnect';
|
||||
export * from './forgotPasswordChallenge'
|
||||
export * from './forgotPasswordChallenge';
|
||||
export * from './forgotPasswordRequest';
|
||||
export * from './forgotPasswordReset';
|
||||
export * from './getGamesOfUser';
|
||||
|
|
@ -24,12 +23,8 @@ export * from './message';
|
|||
export * from './ping';
|
||||
export * from './register';
|
||||
export * from './removeFromList';
|
||||
export * from './replayDeleteMatch';
|
||||
export * from './replayList';
|
||||
export * from './replayModifyMatch';
|
||||
export * from './requestPasswordSalt';
|
||||
export * from './updateStatus';
|
||||
|
||||
/** TODO
|
||||
* REPLAY_DELETE_MATCH
|
||||
* REPLAY_DOWNLOAD
|
||||
* REPLAY_LIST
|
||||
* REPLAY_MODIFY_MATCH
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,37 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { RoomPersistence } from '../../persistence';
|
||||
|
||||
export function joinRoom(roomId: number): void {
|
||||
const command = webClient.protobuf.controller.Command_JoinRoom.create({ roomId });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_JoinRoom.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, (raw) => {
|
||||
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);
|
||||
}
|
||||
BackendService.sendSessionCommand('Command_JoinRoom', { roomId }, {
|
||||
responseName: 'Response_JoinRoom',
|
||||
onSuccess: (response) => {
|
||||
RoomPersistence.joinRoom(response.roomInfo);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
|
||||
export function listRooms(): void {
|
||||
const command = webClient.protobuf.controller.Command_ListRooms.create();
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ListRooms.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc);
|
||||
BackendService.sendSessionCommand('Command_ListRooms', {}, {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,11 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function listUsers(): void {
|
||||
const command = webClient.protobuf.controller.Command_ListUsers.create();
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_ListUsers.ext': command });
|
||||
|
||||
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:
|
||||
BackendService.sendSessionCommand('Command_ListUsers', {}, {
|
||||
responseName: 'Response_ListUsers',
|
||||
onSuccess: (response) => {
|
||||
SessionPersistence.updateUsers(response.userList);
|
||||
break;
|
||||
default:
|
||||
console.log(`Failed to fetch Server Rooms [${responseCode}] : `, raw);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ProtoController } from '../../services/ProtoController';
|
||||
import { hashPassword } from '../../utils';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
|
|
@ -25,13 +27,18 @@ export function login(options: WebSocketConnectOptions, passwordSalt?: string):
|
|||
loginConfig.password = password;
|
||||
}
|
||||
|
||||
const command = webClient.protobuf.controller.Command_Login.create(loginConfig);
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Login.ext': command });
|
||||
const { ResponseCode } = ProtoController.root.Response;
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const resp = raw['.Response_Login.ext'];
|
||||
const onLoginError = (message: string, extra?: () => void) => {
|
||||
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;
|
||||
|
||||
SessionPersistence.updateBuddyList(buddyList);
|
||||
|
|
@ -43,50 +50,30 @@ export function login(options: WebSocketConnectOptions, passwordSalt?: string):
|
|||
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();
|
||||
},
|
||||
onResponseCode: {
|
||||
[ResponseCode.RespClientUpdateRequired]: () =>
|
||||
onLoginError('Login failed: missing features'),
|
||||
[ResponseCode.RespWrongPassword]: () =>
|
||||
onLoginError('Login failed: incorrect username or password'),
|
||||
[ResponseCode.RespUsernameInvalid]: () =>
|
||||
onLoginError('Login failed: incorrect username or password'),
|
||||
[ResponseCode.RespWouldOverwriteOldSession]: () =>
|
||||
onLoginError('Login failed: duplicated user session'),
|
||||
[ResponseCode.RespUserIsBanned]: () =>
|
||||
onLoginError('Login failed: banned user'),
|
||||
[ResponseCode.RespRegistrationRequired]: () =>
|
||||
onLoginError('Login failed: registration required'),
|
||||
[ResponseCode.RespClientIdRequired]: () =>
|
||||
onLoginError('Login failed: missing client ID'),
|
||||
[ResponseCode.RespContextError]: () =>
|
||||
onLoginError('Login failed: server error'),
|
||||
[ResponseCode.RespAccountNotActivated]: () =>
|
||||
onLoginError('Login failed: account not activated',
|
||||
() => SessionPersistence.accountAwaitingActivation(options)
|
||||
),
|
||||
},
|
||||
onError: (responseCode) =>
|
||||
onLoginError(`Login failed: unknown error: ${responseCode}`),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,10 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function message(userName: string, message: string): void {
|
||||
const command = webClient.protobuf.controller.Command_Message.create({ userName, message });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Message.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
const { responseCode } = raw;
|
||||
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_Message', { userName, message }, {
|
||||
onSuccess: () => {
|
||||
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');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
|
||||
export function ping(pingReceived: Function): void {
|
||||
const command = webClient.protobuf.controller.Command_Ping.create();
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_Ping.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, pingReceived);
|
||||
BackendService.sendSessionCommand('Command_Ping', {}, {
|
||||
onResponse: (raw) => pingReceived(raw),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import { ServerRegisterParams } from 'store';
|
||||
import { WebSocketConnectOptions } from 'types';
|
||||
import { StatusEnum, WebSocketConnectOptions } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ProtoController } from '../../services/ProtoController';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
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 {
|
||||
const { userName, password, email, country, realName } = options as ServerRegisterParams;
|
||||
|
||||
const registerConfig: any = {
|
||||
const params: any = {
|
||||
...webClient.clientConfig,
|
||||
userName,
|
||||
email,
|
||||
|
|
@ -20,55 +21,57 @@ export function register(options: WebSocketConnectOptions, passwordSalt?: string
|
|||
};
|
||||
|
||||
if (passwordSalt) {
|
||||
registerConfig.hashedPassword = hashPassword(passwordSalt, password);
|
||||
params.hashedPassword = hashPassword(passwordSalt, password);
|
||||
} else {
|
||||
registerConfig.password = password;
|
||||
params.password = password;
|
||||
}
|
||||
|
||||
const command = webClient.protobuf.controller.Command_Register.create(registerConfig);
|
||||
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 { ResponseCode } = ProtoController.root.Response;
|
||||
|
||||
const onRegistrationError = (action: () => void) => {
|
||||
action();
|
||||
updateStatus(StatusEnum.DISCONNECTED, 'Registration failed');
|
||||
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')
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
export function removeFromBuddyList(userName: string): void {
|
||||
|
|
@ -10,16 +10,9 @@ export function removeFromIgnoreList(userName: string): void {
|
|||
}
|
||||
|
||||
export function removeFromList(list: string, userName: string): void {
|
||||
const command = webClient.protobuf.controller.Command_RemoveFromList.create({ list, userName });
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({ '.Command_RemoveFromList.ext': command });
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, ({ responseCode }) => {
|
||||
switch (responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk:
|
||||
BackendService.sendSessionCommand('Command_RemoveFromList', { list, userName }, {
|
||||
onSuccess: () => {
|
||||
SessionPersistence.removeFromList(list, userName);
|
||||
break;
|
||||
default:
|
||||
console.error('Failed to remove from list', responseCode);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
11
webclient/src/websocket/commands/session/replayList.ts
Normal file
11
webclient/src/websocket/commands/session/replayList.ts
Normal 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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ import { RequestPasswordSaltParams } from 'store';
|
|||
import { StatusEnum, WebSocketConnectOptions, WebSocketConnectReason } from 'types';
|
||||
|
||||
import webClient from '../../WebClient';
|
||||
import { BackendService } from '../../services/BackendService';
|
||||
import { ProtoController } from '../../services/ProtoController';
|
||||
import { SessionPersistence } from '../../persistence';
|
||||
|
||||
import {
|
||||
|
|
@ -15,64 +17,48 @@ import {
|
|||
export function requestPasswordSalt(options: WebSocketConnectOptions): void {
|
||||
const { userName } = options as RequestPasswordSaltParams;
|
||||
|
||||
const registerConfig = {
|
||||
...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;
|
||||
|
||||
const onFailure = () => {
|
||||
switch (options.reason) {
|
||||
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: {
|
||||
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
|
||||
SessionPersistence.accountActivationFailed();
|
||||
break;
|
||||
}
|
||||
|
||||
case WebSocketConnectReason.PASSWORD_RESET: {
|
||||
case WebSocketConnectReason.PASSWORD_RESET:
|
||||
SessionPersistence.resetPasswordFailed();
|
||||
break;
|
||||
}
|
||||
|
||||
case WebSocketConnectReason.LOGIN:
|
||||
default: {
|
||||
default:
|
||||
SessionPersistence.loginFailed();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import { leaveGame } from './leaveGame';
|
|||
|
||||
|
||||
export const GameEvents: ProtobufEvents = {
|
||||
'.Event_Join.ext': () => joinGame,
|
||||
'.Event_Leave.ext': () => leaveGame,
|
||||
'.Event_Join.ext': joinGame,
|
||||
'.Event_Leave.ext': leaveGame,
|
||||
'.Event_GameClosed.ext': () => console.log('Event_GameClosed.ext'),
|
||||
'.Event_GameHostChanged.ext': () => console.log('Event_GameHostChanged.ext'),
|
||||
'.Event_Kicked.ext': () => console.log('Event_Kicked.ext'),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue