diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index 624f42155..c48ce22c2 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -53,7 +53,7 @@ jobs: run: | $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" $env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}" - $env:DISCORD_BLITZ_DB = "${{ secrets.DISCORD_BLITZ_DB }}" + $env:DATABASE_URL = "${{ secrets.DATABASE_URL }}" $env:WOTB_DLC_CDN = "${{ secrets.WOTB_DLC_CDN }}" yarn setup:patches --depot @@ -61,5 +61,5 @@ jobs: run: | $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" $env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}" - $env:DISCORD_BLITZ_DB = "${{ secrets.DISCORD_BLITZ_DB }}" + $env:DATABASE_URL = "${{ secrets.DATABASE_URL }}" yarn build:assets --all-targets --depot ${{ github.ref == 'refs/heads/main' && '--production' || '' }} diff --git a/.github/workflows/cd-host.yml b/.github/workflows/cd-host.yml index b75d31c4a..bf9ac84cd 100644 --- a/.github/workflows/cd-host.yml +++ b/.github/workflows/cd-host.yml @@ -33,4 +33,4 @@ jobs: unzip bot.zip - name: Run bot - run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} node --enable-source-maps index.cjs + run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} node --enable-source-maps index.cjs diff --git a/.github/workflows/cd-rating-asia.yml b/.github/workflows/cd-rating-asia.yml index a25ce9887..e0cfd345a 100644 --- a/.github/workflows/cd-rating-asia.yml +++ b/.github/workflows/cd-rating-asia.yml @@ -31,4 +31,4 @@ jobs: run: yarn - name: Generate leaderboard - run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingleaderboard --region=asia --target=midnight --production + run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} yarn publish:ratingleaderboard --region=asia --target=midnight --production diff --git a/.github/workflows/cd-rating-eu.yml b/.github/workflows/cd-rating-eu.yml index 42092a58c..77f383fc5 100644 --- a/.github/workflows/cd-rating-eu.yml +++ b/.github/workflows/cd-rating-eu.yml @@ -31,4 +31,4 @@ jobs: run: yarn - name: Generate leaderboard - run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingleaderboard --region=eu --target=midnight --production + run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} yarn publish:ratingleaderboard --region=eu --target=midnight --production diff --git a/.github/workflows/cd-rating-latest.yml b/.github/workflows/cd-rating-latest.yml index 8bcbeb029..880c3ab35 100644 --- a/.github/workflows/cd-rating-latest.yml +++ b/.github/workflows/cd-rating-latest.yml @@ -31,4 +31,4 @@ jobs: run: yarn - name: Generate all leaderboards - run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingleaderboard --region=na,asia,eu --target=latest --production + run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} yarn publish:ratingleaderboard --region=na,asia,eu --target=latest --production diff --git a/.github/workflows/cd-rating-na.yml b/.github/workflows/cd-rating-na.yml index d554998c4..7677c1da9 100644 --- a/.github/workflows/cd-rating-na.yml +++ b/.github/workflows/cd-rating-na.yml @@ -31,4 +31,4 @@ jobs: run: yarn - name: Generate leaderboard - run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingleaderboard --region=na --target=midnight --production + run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} yarn publish:ratingleaderboard --region=na --target=midnight --production diff --git a/package.json b/package.json index 8b05832cd..cd7c34829 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,13 @@ "main": "src/server.ts", "type": "module", "scripts": { - "build:bot": "vite-node --script scripts/build", + "build:bot": "vite-node --script scripts/build --production", "build:website": "next build && next-sitemap --config next-sitemap.config.cjs", "build:docs": "vitepress build docs", "build:ratingleaderboard": "vite-node --script scripts/buildRatingLeaderboard", "build:assets": "vite-node --max_old_space_size=16384 --script scripts/buildAssets/index", "build:test": "vite-node --script scripts/buildTest", - "dev:bot": "vite-node --script scripts/build --production && yarn start:bot", + "dev:bot": "vite-node --script scripts/build && yarn start:bot", "dev:docs": "vitepress dev docs", "dev:website": "next dev", "start:bot": "node --enable-source-maps dist/bot/index.cjs", diff --git a/prisma/migrations/20231009152251_use_big_int/migration.sql b/prisma/migrations/20231009152251_use_big_int/migration.sql deleted file mode 100644 index 2fdbde59a..000000000 --- a/prisma/migrations/20231009152251_use_big_int/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ --- CreateTable -CREATE TABLE "discord_blitz" ( - "discord" INT8 NOT NULL, - "region" STRING NOT NULL, - "blitz" INT4 NOT NULL, - - CONSTRAINT "discord_blitz_pkey" PRIMARY KEY ("discord") -); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index 7106c8a84..000000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "cockroachdb" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 20719dbc2..e648508ac 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -4,11 +4,15 @@ generator client { datasource db { provider = "cockroachdb" - url = env("DISCORD_BLITZ_DB") + url = env("DATABASE_URL") } -model discord_blitz { +model Users { + blitz Int @id + last_used DateTime? @default(now()) +} + +model DiscordUsers { discord BigInt @id - region String blitz Int } diff --git a/src/commands/link.tsx b/src/commands/link.tsx index f56686286..591ddb13c 100644 --- a/src/commands/link.tsx +++ b/src/commands/link.tsx @@ -6,7 +6,7 @@ import { Glow } from '../components/AllStatsOverview/components/HeroStat/compone import CommandWrapper from '../components/CommandWrapper'; import { getAccountInfo } from '../core/blitz/getAccountInfo'; import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo'; -import { linkBlitzAndDiscord } from '../core/blitzkrieg/discordBlitz'; +import { linkBlitzAndDiscord } from '../core/blitzkrieg/discordBlitzLink'; import addUsernameChoices from '../core/discord/addUsernameChoices'; import autocompleteUsername from '../core/discord/autocompleteUsername'; import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; @@ -29,11 +29,11 @@ export const verifyCommand = new Promise((resolve) => { async handler(interaction) { const { t, translate } = translator(interaction.locale); const { id, region } = await resolvePlayerFromCommand(interaction); - const discordId = parseInt(interaction.user.id); + const discordId = BigInt(interaction.user.id); const accountInfo = await getAccountInfo(region, id); const clanAccountInfo = await getClanAccountInfo(region, id, ['clan']); - await linkBlitzAndDiscord(discordId, region, id); + await linkBlitzAndDiscord(discordId, id); if (interaction.guildId === discord.sklld_guild_id) { if (!interaction.guild?.members.me?.permissions.has('ManageRoles')) { diff --git a/src/core/blitz/idToRegion.ts b/src/core/blitz/idToRegion.ts new file mode 100644 index 000000000..2c95af2a1 --- /dev/null +++ b/src/core/blitz/idToRegion.ts @@ -0,0 +1,19 @@ +import { Region } from '../../constants/regions'; + +export function idToRange(id: number): Region { + if (id >= 42e8) { + throw new Error('bot id'); + } else if (id >= 31e8) { + throw new Error('china id'); + } else if (id >= 20e8) { + return 'asia'; + } else if (id >= 10e8) { + return 'com'; + } else if (id >= 5e8) { + return 'eu'; + } else if (id >= 0) { + throw new Error('ru id'); + } else { + throw new Error(`id ${id} is out of range`); + } +} diff --git a/src/core/blitzkrieg/discordBlitz.ts b/src/core/blitzkrieg/discordBlitz.ts deleted file mode 100644 index 6af53d2c0..000000000 --- a/src/core/blitzkrieg/discordBlitz.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Region } from '../../constants/regions'; -import { discordBlitzDB } from './discordBlitzDB'; - -export function linkBlitzAndDiscord( - discord: number, - region: Region, - blitz: number, -) { - return discordBlitzDB.discord_blitz.upsert({ - where: { discord }, - update: { region, blitz }, - create: { discord, region, blitz }, - }); -} - -export function getBlitzFromDiscord(discord: number) { - return discordBlitzDB.discord_blitz.findUnique({ - where: { discord }, - select: { region: true, blitz: true }, - }) as Promise; -} diff --git a/src/core/blitzkrieg/discordBlitzDB.ts b/src/core/blitzkrieg/discordBlitzDB.ts deleted file mode 100644 index cfabf3e73..000000000 --- a/src/core/blitzkrieg/discordBlitzDB.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PrismaClient } from '@prisma/client'; - -export const discordBlitzDB = new PrismaClient(); diff --git a/src/core/blitzkrieg/discordBlitzLink.ts b/src/core/blitzkrieg/discordBlitzLink.ts new file mode 100644 index 000000000..987c95d14 --- /dev/null +++ b/src/core/blitzkrieg/discordBlitzLink.ts @@ -0,0 +1,30 @@ +import { usersDatabase } from '../../databases/users'; +import { idToRange } from '../blitz/idToRegion'; + +export async function flagUserActivity(blitz: number) { + await usersDatabase.users.upsert({ + where: { blitz }, + update: {}, + create: { blitz }, + }); +} + +export async function linkBlitzAndDiscord(discord: bigint, blitz: number) { + await usersDatabase.discordUsers.upsert({ + where: { discord }, + update: { blitz }, + create: { discord, blitz }, + }); + await flagUserActivity(blitz); +} + +export async function getBlitzFromDiscord(discord: bigint) { + const unique = await usersDatabase.discordUsers.findUnique({ + where: { discord }, + }); + + if (unique === null) return null; + + await flagUserActivity(unique.blitz); + return { id: unique.blitz, region: idToRange(unique.blitz) }; +} diff --git a/src/core/blitzkrieg/processes.ts b/src/core/blitzkrieg/processes.ts index dd579c3de..ffbf7816f 100644 --- a/src/core/blitzkrieg/processes.ts +++ b/src/core/blitzkrieg/processes.ts @@ -1,5 +1,5 @@ +import { usersDatabase } from '../../databases/users'; import { client } from '../discord/client'; -import { discordBlitzDB } from './discordBlitzDB'; const EXIT_EVENTS = [ 'beforeExit', @@ -13,7 +13,7 @@ const EXIT_EVENTS = [ async function cleanup() { console.log('Cleaning up...'); - await Promise.all([discordBlitzDB.$disconnect(), client.destroy()]); + await Promise.all([usersDatabase.$disconnect(), client.destroy()]); console.log('Gracefully exiting...'); diff --git a/src/core/blitzkrieg/secrets.ts b/src/core/blitzkrieg/secrets.ts index 35d968746..de08e3377 100644 --- a/src/core/blitzkrieg/secrets.ts +++ b/src/core/blitzkrieg/secrets.ts @@ -5,7 +5,7 @@ config(); const SECRET_KEYS = [ 'DISCORD_TOKEN', 'GH_TOKEN', - 'DISCORD_BLITZ_DB', + 'DATABASE_URL', 'WOTB_DLC_CDN', ] as const; diff --git a/src/core/discord/resolvePlayerFromCommand/index.ts b/src/core/discord/resolvePlayerFromCommand/index.ts index 0dd292756..d658624e1 100644 --- a/src/core/discord/resolvePlayerFromCommand/index.ts +++ b/src/core/discord/resolvePlayerFromCommand/index.ts @@ -3,7 +3,7 @@ import markdownEscape from 'markdown-escape'; import { Region } from '../../../constants/regions'; import { UserError } from '../../../hooks/userError'; import searchPlayersAcrossRegions from '../../blitz/searchPlayersAcrossRegions'; -import { getBlitzFromDiscord } from '../../blitzkrieg/discordBlitz'; +import { getBlitzFromDiscord } from '../../blitzkrieg/discordBlitzLink'; import { translator } from '../../localization/translator'; import { serverAndIdPattern } from './constants'; @@ -43,12 +43,10 @@ export default async function resolvePlayerFromCommand( } } } else { - const account = await getBlitzFromDiscord(parseInt(interaction.user.id)); + const account = await getBlitzFromDiscord(BigInt(interaction.user.id)); - if (account) { - return { region: account.region, id: account.blitz }; - } else { - throw new UserError(t`bot.common.errors.player_not_linked`); - } + if (account) return account; + + throw new UserError(t`bot.common.errors.player_not_linked`); } } diff --git a/src/databases/users.ts b/src/databases/users.ts new file mode 100644 index 000000000..06490a7ca --- /dev/null +++ b/src/databases/users.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from '@prisma/client'; + +export const usersDatabase = new PrismaClient();