Commit 4793da0a authored by nanahira's avatar nanahira

Merge branch 'koishi' into enter-room-log

parents 1e0613cb f1ea8a1b
Pipeline #16038 passed with stages
in 8 minutes and 39 seconds
stages:
- build
- build2
- combine
- deploy
variables:
GIT_DEPTH: "1"
CONTAINER_TEST_IMAGE_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-full
CONTAINER_TEST_IMAGE_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-lite
CONTAINER_TEST_IMAGE_X86_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-full
CONTAINER_TEST_IMAGE_X86_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-lite
CONTAINER_TEST_IMAGE_ARM_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-full
CONTAINER_TEST_IMAGE_ARM_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-lite
CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
CONTAINER_RELEASE_IMAGE_FULL: $CI_REGISTRY_IMAGE:full
CONTAINER_RELEASE_IMAGE_LITE: $CI_REGISTRY_IMAGE:lite
build_lite_x86:
stage: build
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_X86_LITE
.docker-op:
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull --no-cache -f ./Dockerfile.lite -t $TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_lite_arm:
stage: build
tags:
- docker-arm
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_ARM_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull --no-cache -f ./Dockerfile.lite -t $TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_full_x86:
stage: build2
.docker-x86:
extends: .docker-op
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_X86_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_X86_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --build-arg BASE_IMAGE=$SOURCE_IMAGE --pull --no-cache -t
$TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_full_arm:
stage: build2
variables:
ARCH: x86
.docker-arm:
extends: .docker-op
tags:
- docker-arm
variables:
ARCH: arm
.build_lite:
stage: build
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_ARM_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_ARM_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --build-arg BASE_IMAGE=$SOURCE_IMAGE --pull --no-cache -t
$TARGET_IMAGE .
- docker push $TARGET_IMAGE
combine_lite:
- docker build --pull --no-cache -f ./Dockerfile.lite -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$ARCH-lite .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$ARCH-lite
build_lite_x86:
extends:
- .docker-x86
- .build_lite
build_lite_arm:
extends:
- .docker-arm
- .build_lite
.build_full:
stage: build2
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- SOURCE_IMAGE_2=$CONTAINER_TEST_IMAGE_ARM_LITE
- SOURCE_IMAGE_1=$CONTAINER_TEST_IMAGE_X86_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE_1
- docker pull $SOURCE_IMAGE_2
- docker manifest create $TARGET_IMAGE --amend $SOURCE_IMAGE_1 --amend
$SOURCE_IMAGE_2
- docker manifest push $TARGET_IMAGE
combine_full:
stage: combine
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- SOURCE_IMAGE_2=$CONTAINER_TEST_IMAGE_ARM_FULL
- SOURCE_IMAGE_1=$CONTAINER_TEST_IMAGE_X86_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE_1
- docker pull $SOURCE_IMAGE_2
- docker manifest create $TARGET_IMAGE --amend $SOURCE_IMAGE_1 --amend
$SOURCE_IMAGE_2
- docker manifest push $TARGET_IMAGE
#upload_stuff_to_minio:
# stage: deploy
# tags:
# - linux
# image: $CONTAINER_TEST_IMAGE_FULL
# script:
# - apt update ; apt -y install python3-pip
# - pip3 install -U -i https://mirrors.aliyun.com/pypi/simple/ awscli
# - cd /ygopro-server
# - mkdir /dist
# - tar zcfv /dist/ygopro-server.tar.gz ./*
# - aws s3 --endpoint=https://minio.mycard.moe:9000 cp /dist/ygopro-server.tar.gz s3://mycard/srvpro/ygopro-server.tar.gz
# only:
# - master
- docker build --build-arg BASE_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$ARCH-lite --pull --no-cache -t
$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$ARCH-full .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$ARCH-full
deploy_latest_full:
build_full_x86:
extends:
- .docker-x86
- .build_full
build_full_arm:
extends:
- .docker-arm
- .build_full
.deploy_image:
stage: deploy
tags:
- docker
extends: .docker-x86
script:
- TARGET_IMAGE_2=$CONTAINER_RELEASE_IMAGE
- TARGET_IMAGE=$CONTAINER_RELEASE_IMAGE_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE_2
- docker push $TARGET_IMAGE_2
only:
- master
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-$DEPLOY_TYPE
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-$DEPLOY_TYPE
- docker manifest create $CI_REGISTRY_IMAGE:$DEPLOY_TAG $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-$DEPLOY_TYPE $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-$DEPLOY_TYPE
- docker manifest push $CI_REGISTRY_IMAGE:$DEPLOY_TAG
deploy_lite:
extends: .deploy_image
variables:
DEPLOY_TYPE: lite
DEPLOY_TAG: $CI_COMMIT_REF_SLUG-lite
deploy_full:
extends: .deploy_image
variables:
DEPLOY_TYPE: full
DEPLOY_TAG: $CI_COMMIT_REF_SLUG-full
deploy_branch:
extends: .deploy_image
variables:
DEPLOY_TYPE: full
DEPLOY_TAG: $CI_COMMIT_REF_SLUG
deploy_latest_lite:
stage: deploy
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_RELEASE_IMAGE_LITE
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
extends: .deploy_image
variables:
DEPLOY_TYPE: lite
DEPLOY_TAG: lite
only:
- master
deploy_tag_full:
stage: deploy
tags:
- docker
script:
- TARGET_IMAGE_2=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
- TARGET_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG-full
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE_2
- docker push $TARGET_IMAGE_2
deploy_latest_full:
extends: .deploy_image
variables:
DEPLOY_TYPE: full
DEPLOY_TAG: full
only:
- tags
deploy_tag_lite:
stage: deploy
tags:
- docker
script:
- TARGET_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG-lite
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
- master
deploy_latest:
extends: .deploy_image
variables:
DEPLOY_TYPE: full
DEPLOY_TAG: latest
only:
- tags
- master
......@@ -5,7 +5,7 @@ LABEL Author="Nanahira <nanahira@momobako.com>"
RUN apt update && \
apt -y install mono-complete && \
npm install -g pm2 && \
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/*
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/log/*
# windbot
RUN git clone --depth=1 https://code.mycard.moe/nanahira/windbot /tmp/windbot && \
......
......@@ -3,13 +3,13 @@ FROM debian:bullseye as premake-builder
RUN apt update && \
env DEBIAN_FRONTEND=noninteractive apt install -y wget build-essential p7zip-full && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/log/*
WORKDIR /usr/src
RUN wget -O premake.zip https://github.com/premake/premake-core/releases/download/v5.0.0-alpha14/premake-5.0.0-alpha14-src.zip && \
RUN wget -O premake.zip https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-src.zip && \
7z x -y premake.zip && \
mv premake-5.0.0-alpha14 premake && \
cd premake/build/gmake.unix && \
mv premake-5.0.0-beta1-src premake && \
cd premake/build/gmake2.unix && \
make -j$(nproc)
FROM node:16-bullseye-slim
......@@ -31,7 +31,7 @@ COPY --from=premake-builder /usr/src/premake/bin/release/premake5 /usr/bin/prema
RUN git clone --branch=server --recursive --depth=1 https://code.mycard.moe/nanahira/ygopro && \
cd ygopro && \
git submodule foreach git checkout master && \
premake5 gmake && \
premake5 gmake --lua-deb && \
cd build && \
make config=release -j$(nproc) && \
cd .. && \
......
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Challonge = void 0;
const axios_1 = __importDefault(require("axios"));
const bunyan_1 = require("bunyan");
const moment_1 = __importDefault(require("moment"));
const p_queue_1 = __importDefault(require("p-queue"));
class Challonge {
config;
constructor(config) {
this.config = config;
}
queue = new p_queue_1.default({ concurrency: 1 });
log = (0, bunyan_1.createLogger)({ name: 'challonge' });
previous;
previousTime;
async getTournamentProcess(noCache = false) {
if (!noCache && this.previous && this.previousTime.isAfter((0, moment_1.default)().subtract(this.config.cache_ttl, 'ms'))) {
return this.previous;
}
try {
const { data: { tournament } } = await axios_1.default.get(`https://api.challonge.com/v1/tournaments/${this.config.tournament_id}.json`, {
params: {
api_key: this.config.api_key,
include_participants: 1,
include_matches: 1,
},
timeout: 5000,
});
this.previous = tournament;
this.previousTime = (0, moment_1.default)();
return tournament;
}
catch (e) {
this.log.error(`Failed to get tournament ${this.config.tournament_id}`, e);
return;
}
}
async getTournament(noCache = false) {
if (noCache) {
return this.getTournamentProcess(noCache);
}
return this.queue.add(() => this.getTournamentProcess());
}
async putScore(matchId, match, retried = 0) {
try {
await axios_1.default.put(`https://api.challonge.com/v1/tournaments/${this.config.tournament_id}/matches/${matchId}.json`, {
api_key: this.config.api_key,
match: match,
});
this.previous = undefined;
this.previousTime = undefined;
return true;
}
catch (e) {
this.log.error(`Failed to put score for match ${matchId}`, e);
if (retried < 5) {
this.log.info(`Retrying match ${matchId}`);
return this.putScore(matchId, match, retried + 1);
}
else {
this.log.error(`Failed to put score for match ${matchId} after 5 retries`);
return false;
}
}
}
}
exports.Challonge = Challonge;
//# sourceMappingURL=challonge.js.map
\ No newline at end of file
import axios from 'axios';
import { createLogger } from 'bunyan';
import moment, { Moment } from 'moment';
import PQueue from 'p-queue';
export interface Match {
attachment_count?: any;
created_at: string;
group_id?: any;
has_attachment: boolean;
id: number;
identifier: string;
location?: any;
loser_id?: any;
player1_id: number;
player1_is_prereq_match_loser: boolean;
player1_prereq_match_id?: any;
player1_votes?: any;
player2_id: number;
player2_is_prereq_match_loser: boolean;
player2_prereq_match_id?: any;
player2_votes?: any;
round: number;
scheduled_time?: any;
started_at: string;
state: string;
tournament_id: number;
underway_at?: any;
updated_at: string;
winner_id?: any;
prerequisite_match_ids_csv: string;
scores_csv: string;
}
export interface MatchWrapper {
match: Match;
}
export interface Participant {
active: boolean;
checked_in_at?: any;
created_at: string;
final_rank?: any;
group_id?: any;
icon?: any;
id: number;
invitation_id?: any;
invite_email?: any;
misc?: any;
name: string;
on_waiting_list: boolean;
seed: number;
tournament_id: number;
updated_at: string;
challonge_username?: any;
challonge_email_address_verified?: any;
removable: boolean;
participatable_or_invitation_attached: boolean;
confirm_remove: boolean;
invitation_pending: boolean;
display_name_with_invitation_email_address: string;
email_hash?: any;
username?: any;
attached_participatable_portrait_url?: any;
can_check_in: boolean;
checked_in: boolean;
reactivatable: boolean;
}
export interface ParticipantWrapper {
participant: Participant;
}
export interface Tournament {
accept_attachments: boolean;
allow_participant_match_reporting: boolean;
anonymous_voting: boolean;
category?: any;
check_in_duration?: any;
completed_at?: any;
created_at: string;
created_by_api: boolean;
credit_capped: boolean;
description: string;
game_id: number;
group_stages_enabled: boolean;
hide_forum: boolean;
hide_seeds: boolean;
hold_third_place_match: boolean;
id: number;
max_predictions_per_user: number;
name: string;
notify_users_when_matches_open: boolean;
notify_users_when_the_tournament_ends: boolean;
open_signup: boolean;
participants_count: number;
prediction_method: number;
predictions_opened_at?: any;
private: boolean;
progress_meter: number;
pts_for_bye: string;
pts_for_game_tie: string;
pts_for_game_win: string;
pts_for_match_tie: string;
pts_for_match_win: string;
quick_advance: boolean;
ranked_by: string;
require_score_agreement: boolean;
rr_pts_for_game_tie: string;
rr_pts_for_game_win: string;
rr_pts_for_match_tie: string;
rr_pts_for_match_win: string;
sequential_pairings: boolean;
show_rounds: boolean;
signup_cap?: any;
start_at?: any;
started_at: string;
started_checking_in_at?: any;
state: string;
swiss_rounds: number;
teams: boolean;
tie_breaks: string[];
tournament_type: string;
updated_at: string;
url: string;
description_source: string;
subdomain?: any;
full_challonge_url: string;
live_image_url: string;
sign_up_url?: any;
review_before_finalizing: boolean;
accepting_predictions: boolean;
participants_locked: boolean;
game_name: string;
participants_swappable: boolean;
team_convertable: boolean;
group_stages_were_started: boolean;
participants: ParticipantWrapper[];
matches: MatchWrapper[];
}
export interface TournamentWrapper {
tournament: Tournament;
}
export interface MatchPost {
scores_csv: string;
winner_id: number;
}
export interface ChallongeConfig {
api_key: string;
tournament_id: string;
cache_ttl: number;
}
export class Challonge {
constructor(private config: ChallongeConfig) { }
private queue = new PQueue({ concurrency: 1 })
private log = createLogger({ name: 'challonge' });
private previous: Tournament;
private previousTime: Moment;
private async getTournamentProcess(noCache = false) {
if(!noCache && this.previous && this.previousTime.isAfter(moment().subtract(this.config.cache_ttl, 'ms'))) {
return this.previous;
}
try {
const { data: { tournament } } = await axios.get<TournamentWrapper>(
`https://api.challonge.com/v1/tournaments/${this.config.tournament_id}.json`,
{
params: {
api_key: this.config.api_key,
include_participants: 1,
include_matches: 1,
},
timeout: 5000,
},
);
this.previous = tournament;
this.previousTime = moment();
return tournament;
} catch (e) {
this.log.error(`Failed to get tournament ${this.config.tournament_id}`, e);
return;
}
}
async getTournament(noCache = false) {
if (noCache) {
return this.getTournamentProcess(noCache);
}
return this.queue.add(() => this.getTournamentProcess())
}
async putScore(matchId: number, match: MatchPost, retried = 0) {
try {
await axios.put(
`https://api.challonge.com/v1/tournaments/${this.config.tournament_id}/matches/${matchId}.json`,
{
api_key: this.config.api_key,
match: match,
},
);
this.previous = undefined;
this.previousTime = undefined;
return true;
} catch (e) {
this.log.error(`Failed to put score for match ${matchId}`, e);
if (retried < 5) {
this.log.info(`Retrying match ${matchId}`);
return this.putScore(matchId, match, retried + 1);
} else {
this.log.error(`Failed to put score for match ${matchId} after 5 retries`);
return false;
}
}
}
}
......@@ -53,7 +53,7 @@ class DataManager {
try {
// @ts-ignore
if (this.config.type !== 'sqlite') {
this.db.transaction(async (mdb) => {
await this.db.transaction(async (mdb) => {
const result = await fun(mdb);
if (!result) {
throw new Error('Rollback requested.');
......@@ -614,11 +614,12 @@ class DataManager {
}
async useVipKey(userKey, vipKeyText) {
let user = await this.getOrCreateUser(userKey);
let result = 0;
let result = 3;
await this.transaction(async (mdb) => {
try {
const vipKey = await mdb.findOne(VipKey_1.VipKey, { key: vipKeyText, isUsed: 0 });
if (!vipKey) {
result = 0;
return false;
}
const keyType = vipKey.type;
......
......@@ -52,7 +52,7 @@ export class DataManager {
try {
// @ts-ignore
if (this.config.type !== 'sqlite') {
this.db.transaction(async (mdb) => {
await this.db.transaction(async (mdb) => {
const result = await fun(mdb);
if (!result) {
throw new Error('Rollback requested.');
......@@ -615,11 +615,12 @@ export class DataManager {
async useVipKey(userKey: string, vipKeyText: string) {
let user = await this.getOrCreateUser(userKey);
let result = 0;
let result = 3;
await this.transaction(async (mdb) => {
try {
const vipKey = await mdb.findOne(VipKey, {key: vipKeyText, isUsed: 0});
if(!vipKey) {
if (!vipKey) {
result = 0;
return false;
}
const keyType = vipKey.type;
......
......@@ -163,11 +163,8 @@
"post_score_midduel": true,
"cache_ttl": 60000,
"no_match_mode": false,
"options": {
"apiKey": "123"
},
"tournament_id": "456",
"use_custom_module": false
"api_key": "123",
"tournament_id": "456"
},
"deck_log": {
"enabled": false,
......
This diff is collapsed.
......@@ -14,9 +14,8 @@
"async": "^3.2.0",
"axios": "^0.19.2",
"bunyan": "^1.8.14",
"challonge": "^2.2.0",
"deepmerge": "^4.2.2",
"formidable": "^2.0.1",
"formidable": "^1.2.6",
"geoip-country-lite": "^1.0.0",
"jszip": "^3.5.0",
"load-json-file": "^6.2.0",
......@@ -24,6 +23,7 @@
"moment": "^2.29.1",
"mysql": "^2.18.1",
"node-os-utils": "^1.3.2",
"p-queue": "6.6.2",
"pg": "^6.4.2",
"q": "^1.5.1",
"querystring": "^0.2.0",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment