Commit 7016800d authored by nanahira's avatar nanahira

limited support for sqlite

parent 8788b9f1
......@@ -11,6 +11,8 @@ const typedefs_json_1 = __importDefault(require("./data/typedefs.json"));
const proto_structs_json_1 = __importDefault(require("./data/proto_structs.json"));
const constants_json_1 = __importDefault(require("./data/constants.json"));
class Handler {
handler;
synchronous;
constructor(handler, synchronous) {
this.handler = handler;
this.synchronous = synchronous || false;
......@@ -28,6 +30,13 @@ class Handler {
}
}
class YGOProMessagesHelper {
handlers;
structs;
structs_declaration;
typedefs;
proto_structs;
constants;
singleHandleLimit;
constructor(singleHandleLimit) {
this.handlers = {
STOC: [new Map(),
......
......@@ -8,6 +8,9 @@ const axios_1 = __importDefault(require("axios"));
const querystring_1 = __importDefault(require("querystring"));
const moment_1 = __importDefault(require("moment"));
class AthleticChecker {
config;
athleticDeckCache;
lastAthleticDeckFetchTime;
constructor(config) {
this.config = config;
}
......
......@@ -38,35 +38,40 @@ const jszip_1 = __importDefault(require("jszip"));
const fs = __importStar(require("fs"));
require("reflect-metadata");
class DataManager {
config;
log;
ready;
db;
constructor(config, log) {
this.config = config;
this.ready = false;
this.log = log;
this.ready = false;
}
async transaction(fun) {
const runner = this.db.createQueryRunner();
await runner.connect();
await runner.startTransaction();
let result = false;
try {
result = await fun(runner.manager);
// @ts-ignore
if (this.config.type !== 'sqlite') {
this.db.transaction(async (mdb) => {
const result = await fun(mdb);
if (!result) {
throw new Error('Rollback requested.');
}
});
}
else {
await fun(this.db.manager);
}
}
catch (e) {
result = false;
this.log.warn(`Failed running transaction: ${e.toString()}`);
}
if (result) {
await runner.commitTransaction();
this.log.warn(`Transaction failed: ${e.toString()}`);
}
else {
await runner.rollbackTransaction();
}
await runner.release();
}
async init() {
this.db = await typeorm_1.createConnection({
type: "mysql",
synchronize: true,
supportBigNumbers: true,
bigNumberStrings: false,
entities: ["./data-manager/entities/*.js"],
...this.config
});
......@@ -74,8 +79,13 @@ class DataManager {
}
async getCloudReplaysFromKey(key) {
try {
const replays = await this.db.createQueryBuilder(CloudReplay_1.CloudReplay, "replay")
.where("exists (select id from cloud_replay_player where cloud_replay_player.cloudReplayId = replay.id and cloud_replay_player.key = :key)", { key })
const replaysQuery = this.db.createQueryBuilder(CloudReplay_1.CloudReplay, "replay");
const sqb = replaysQuery.subQuery()
.select('splayer.id')
.from(CloudReplayPlayer_1.CloudReplayPlayer, 'splayer')
.where('splayer.cloudReplayId = replay.id')
.andWhere('splayer.key = :key');
const replays = await replaysQuery.where(`exists ${sqb.getQuery()}`, { key })
.orderBy("replay.date", "DESC")
.limit(10)
.leftJoinAndSelect("replay.players", "player")
......@@ -273,18 +283,24 @@ class DataManager {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
}
if (playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const sqb = queryBuilder.subQuery()
.select('splayer.id')
.from(DuelLogPlayer_1.DuelLogPlayer, 'splayer')
.where('splayer.duelLogId = duelLog.id');
//let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams = {};
if (playerName != null && playerName.length) {
//const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName";
sqb.andWhere('splayer.realName = :playerName');
//innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName;
}
if (playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore";
//innerQuery += " and duel_log_player.score = :playerScore";
sqb.andWhere('splayer.score = :playerScore');
innerQueryParams.playerScore = playerScore;
}
queryBuilder.andWhere(`exists (${innerQuery})`, innerQueryParams);
queryBuilder.andWhere(`exists ${sqb.getQuery()}`, innerQueryParams);
}
queryBuilder.orderBy("duelLog.id", "DESC")
.leftJoinAndSelect("duelLog.players", "player");
......@@ -311,8 +327,16 @@ class DataManager {
async getDuelLogFromRecoverSearch(realName) {
const repo = this.db.getRepository(DuelLog_1.DuelLog);
try {
const duelLogs = await repo.createQueryBuilder("duelLog")
.where("startDeckBuffer is not null and currentDeckBuffer is not null and roomMode != 2 and exists (select id from duel_log_player where duel_log_player.duelLogId = duelLog.id and duel_log_player.realName = :realName)", { realName })
const duelLogsQuery = repo.createQueryBuilder("duelLog")
.where('startDeckBuffer is not null')
.andWhere('currentDeckBuffer is not null')
.andWhere('roomMode != 2');
const sqb = duelLogsQuery.subQuery()
.select('splayer.id')
.from(DuelLogPlayer_1.DuelLogPlayer, 'splayer')
.andWhere('splayer.duelLogId = duelLog.id')
.andWhere('splayer.realName = :realName');
const duelLogs = await duelLogsQuery.andWhere(`exists ${sqb.getQuery()}`, { realName })
.orderBy("duelLog.id", "DESC")
.limit(10)
.leftJoinAndSelect("duelLog.players", "player")
......
import moment from "moment";
import bunyan from "bunyan";
import {Connection, ConnectionOptions, createConnection, EntityManager} from "typeorm";
import {Connection, createConnection, EntityManager} from "typeorm";
import {CloudReplay} from "./entities/CloudReplay";
import {CloudReplayPlayer} from "./entities/CloudReplayPlayer";
import {Ban} from "./entities/Ban";
......@@ -14,6 +14,7 @@ import {RandomDuelScore} from "./entities/RandomDuelScore";
import JSZip from "jszip";
import * as fs from "fs";
import "reflect-metadata";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions";
interface BasePlayerInfo {
name: string;
......@@ -40,37 +41,34 @@ export interface DuelLogQuery {roomName: string, duelCount: number, playerName:
export class DataManager {
config: ConnectionOptions;
ready: boolean;
db: Connection;
log: bunyan;
constructor(config: ConnectionOptions, log: bunyan) {
this.config = config;
private db: Connection;
constructor(private config: MysqlConnectionOptions, private log: bunyan) {
this.ready = false;
this.log = log;
}
private async transaction(fun: (mdb: EntityManager) => Promise<boolean>) {
const runner = this.db.createQueryRunner();
await runner.connect();
await runner.startTransaction();
let result = false;
try {
result = await fun(runner.manager);
} catch(e) {
result = false;
this.log.warn(`Failed running transaction: ${e.toString()}`)
}
if(result) {
await runner.commitTransaction();
} else {
await runner.rollbackTransaction();
// @ts-ignore
if (this.config.type !== 'sqlite') {
this.db.transaction(async (mdb) => {
const result = await fun(mdb);
if (!result) {
throw new Error('Rollback requested.');
}
});
} else {
await fun(this.db.manager);
}
} catch (e) {
this.log.warn(`Transaction failed: ${e.toString()}`);
}
await runner.release();
}
async init() {
this.db = await createConnection({
type: "mysql",
synchronize: true,
supportBigNumbers: true,
bigNumberStrings: false,
entities: ["./data-manager/entities/*.js"],
...this.config
});
......@@ -78,8 +76,13 @@ export class DataManager {
}
async getCloudReplaysFromKey(key: string) {
try {
const replays = await this.db.createQueryBuilder(CloudReplay, "replay")
.where("exists (select id from cloud_replay_player where cloud_replay_player.cloudReplayId = replay.id and cloud_replay_player.key = :key)", { key })
const replaysQuery = this.db.createQueryBuilder(CloudReplay, "replay");
const sqb = replaysQuery.subQuery()
.select('splayer.id')
.from(CloudReplayPlayer, 'splayer')
.where('splayer.cloudReplayId = replay.id')
.andWhere('splayer.key = :key');
const replays = await replaysQuery.where(`exists ${sqb.getQuery()}`, { key })
.orderBy("replay.date", "DESC")
.limit(10)
.leftJoinAndSelect("replay.players", "player")
......@@ -280,19 +283,25 @@ export class DataManager {
if(duelCount != null && !isNaN(duelCount)) {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
}
if(playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
if (playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) {
const sqb = queryBuilder.subQuery()
.select('splayer.id')
.from(DuelLogPlayer, 'splayer')
.where('splayer.duelLogId = duelLog.id');
//let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams: any = {};
if(playerName != null && playerName.length) {
//const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName";
sqb.andWhere('splayer.realName = :playerName');
//innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName;
}
if(playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore";
//innerQuery += " and duel_log_player.score = :playerScore";
sqb.andWhere('splayer.score = :playerScore');
innerQueryParams.playerScore = playerScore;
}
queryBuilder.andWhere(`exists (${innerQuery})`, innerQueryParams);
queryBuilder.andWhere(`exists ${sqb.getQuery()}`, innerQueryParams);
}
queryBuilder.orderBy("duelLog.id", "DESC")
.leftJoinAndSelect("duelLog.players", "player");
......@@ -320,8 +329,16 @@ export class DataManager {
async getDuelLogFromRecoverSearch(realName: string) {
const repo = this.db.getRepository(DuelLog);
try {
const duelLogs = await repo.createQueryBuilder("duelLog")
.where("startDeckBuffer is not null and currentDeckBuffer is not null and roomMode != 2 and exists (select id from duel_log_player where duel_log_player.duelLogId = duelLog.id and duel_log_player.realName = :realName)", { realName })
const duelLogsQuery = repo.createQueryBuilder("duelLog")
.where('startDeckBuffer is not null')
.andWhere('currentDeckBuffer is not null')
.andWhere('roomMode != 2');
const sqb = duelLogsQuery.subQuery()
.select('splayer.id')
.from(DuelLogPlayer, 'splayer')
.andWhere('splayer.duelLogId = duelLog.id')
.andWhere('splayer.realName = :realName');
const duelLogs = await duelLogsQuery.andWhere(`exists ${sqb.getQuery()}`, { realName })
.orderBy("duelLog.id", "DESC")
.limit(10)
.leftJoinAndSelect("duelLog.players", "player")
......
......@@ -13,9 +13,12 @@ exports.Ban = void 0;
const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let Ban = class Ban extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
ip;
name;
};
__decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }),
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number)
], Ban.prototype, "id", void 0);
__decorate([
......
......@@ -4,7 +4,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
@Entity()
@Unique(["ip", "name"])
export class Ban extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({ unsigned: true, type: "bigint" })
@PrimaryGeneratedColumn({ unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint' })
id: number;
@Index()
......
......@@ -13,9 +13,12 @@ exports.BasePlayer = void 0;
const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
class BasePlayer extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
name;
pos;
}
__decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }),
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number)
], BasePlayer.prototype, "id", void 0);
__decorate([
......
import {Column, PrimaryGeneratedColumn} from "typeorm";
import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
export abstract class BasePlayer extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({unsigned: true, type: "bigint"})
@PrimaryGeneratedColumn({unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint'})
id: number;
@Column({ type: "varchar", length: 20 })
......@@ -10,4 +9,4 @@ export abstract class BasePlayer extends CreateAndUpdateTimeBase {
@Column({ type: "tinyint" })
pos: number;
}
\ No newline at end of file
}
......@@ -19,15 +19,19 @@ const underscore_1 = __importDefault(require("underscore"));
const moment_1 = __importDefault(require("moment"));
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
data;
fromBuffer(buffer) {
this.data = buffer.toString("base64");
}
toBuffer() {
return Buffer.from(this.data, "base64");
}
date;
getDateString() {
return moment_1.default(this.date).format('YYYY-MM-DD HH:mm:ss');
}
players;
getPlayerNamesString() {
const playerInfos = underscore_1.default.clone(this.players);
playerInfos.sort((p1, p2) => p1.pos - p2.pos);
......@@ -38,7 +42,7 @@ let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndU
}
};
__decorate([
typeorm_1.PrimaryColumn({ unsigned: true, type: "bigint" }),
typeorm_1.PrimaryColumn({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number)
], CloudReplay.prototype, "id", void 0);
__decorate([
......
......@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
}
})
export class CloudReplay extends CreateAndUpdateTimeBase {
@PrimaryColumn({ unsigned: true, type: "bigint" })
@PrimaryColumn({ unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint' })
id: number;
@Column({ type: "text" })
......
......@@ -15,6 +15,8 @@ const typeorm_1 = require("typeorm");
const CloudReplay_1 = require("./CloudReplay");
const BasePlayer_1 = require("./BasePlayer");
let CloudReplayPlayer = CloudReplayPlayer_1 = class CloudReplayPlayer extends BasePlayer_1.BasePlayer {
key;
cloudReplay;
static fromPlayerInfo(info) {
const p = new CloudReplayPlayer_1();
p.key = info.key;
......
......@@ -12,6 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateAndUpdateTimeBase = void 0;
const typeorm_1 = require("typeorm");
class CreateAndUpdateTimeBase {
createTime;
updateTime;
}
__decorate([
typeorm_1.CreateDateColumn(),
......
......@@ -19,6 +19,15 @@ const moment_1 = __importDefault(require("moment"));
const underscore_1 = __importDefault(require("underscore"));
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
time;
name;
roomId;
cloudReplayId; // not very needed to become a relation
replayFileName;
roomMode;
duelCount;
players;
getViewString() {
const viewPlayers = underscore_1.default.clone(this.players);
viewPlayers.sort((p1, p2) => p1.pos - p2.pos);
......@@ -47,7 +56,7 @@ let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTim
}
};
__decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }),
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number)
], DuelLog.prototype, "id", void 0);
__decorate([
......@@ -65,7 +74,7 @@ __decorate([
__metadata("design:type", Number)
], DuelLog.prototype, "roomId", void 0);
__decorate([
typeorm_1.Column("bigint"),
typeorm_1.Column(global.PrimaryKeyType || 'bigint'),
__metadata("design:type", Number)
], DuelLog.prototype, "cloudReplayId", void 0);
__decorate([
......
......@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
}
})
export class DuelLog extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({unsigned: true, type: "bigint"})
@PrimaryGeneratedColumn({unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint'})
id: number;
@Index()
......@@ -24,7 +24,7 @@ export class DuelLog extends CreateAndUpdateTimeBase {
@Column("int")
roomId: number;
@Column("bigint")
@Column((global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint')
cloudReplayId: number; // not very needed to become a relation
@Column({type: "varchar", length: 256})
......@@ -67,4 +67,4 @@ export class DuelLog extends CreateAndUpdateTimeBase {
}
return data;
}
}
\ No newline at end of file
}
......@@ -16,6 +16,15 @@ const BasePlayer_1 = require("./BasePlayer");
const DuelLog_1 = require("./DuelLog");
const DeckEncoder_1 = require("../DeckEncoder");
let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.BasePlayer {
realName;
ip;
isFirst;
score;
lp;
cardCount;
startDeckBuffer;
currentDeckBuffer;
winner;
setStartDeck(deck) {
if (deck === null) {
this.startDeckBuffer = null;
......@@ -36,6 +45,7 @@ let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.B
getCurrentDeck() {
return DeckEncoder_1.decodeDeck(Buffer.from(this.currentDeckBuffer, "base64"));
}
duelLog;
static fromDuelLogPlayerInfo(info) {
const p = new DuelLogPlayer_1();
p.name = info.name;
......
......@@ -13,6 +13,11 @@ exports.RandomDuelBan = void 0;
const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let RandomDuelBan = class RandomDuelBan extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
ip;
time;
count;
reasons;
needTip;
setNeedTip(need) {
this.needTip = need ? 1 : 0;
}
......
......@@ -13,6 +13,11 @@ exports.RandomDuelScore = void 0;
const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let RandomDuelScore = class RandomDuelScore extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
name;
winCount;
loseCount;
fleeCount;
winCombo;
getDisplayName() {
return this.name.split("$")[0];
}
......
......@@ -13,6 +13,8 @@ exports.User = void 0;
const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let User = class User extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
key;
chatColor;
};
__decorate([
typeorm_1.PrimaryColumn({ type: "varchar", length: 128 }),
......
......@@ -323,6 +323,7 @@ init = () ->
log.info('Saving migrated settings.')
await setting_save(settings)
if settings.modules.mysql.enabled
global.PrimaryKeyType = if settings.modules.mysql.db.type == 'sqlite' then 'integer' else 'bigint'
DataManager = require('./data-manager/DataManager.js').DataManager
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log)
log.info('Connecting to database.')
......
......@@ -424,6 +424,7 @@
await setting_save(settings);
}
if (settings.modules.mysql.enabled) {
global.PrimaryKeyType = settings.modules.mysql.db.type === 'sqlite' ? 'integer' : 'bigint';
DataManager = require('./data-manager/DataManager.js').DataManager;
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log);
log.info('Connecting to database.');
......
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