diff --git a/src/app/tools/session/page.tsx b/src/app/tools/session/page.tsx index 740e728db..66c0d9c78 100644 --- a/src/app/tools/session/page.tsx +++ b/src/app/tools/session/page.tsx @@ -14,7 +14,7 @@ import { debounce } from 'lodash'; import { useEffect, useRef, useState } from 'react'; import PageWrapper from '../../../components/PageWrapper'; import { UNLOCALIZED_REGION_NAMES_SHORT } from '../../../constants/regions'; -import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID'; +import { authURL } from '../../../core/blitz/authURL'; import { getAccountInfo } from '../../../core/blitz/getAccountInfo'; import getTankStats from '../../../core/blitz/getTankStats'; import { idToRegion } from '../../../core/blitz/idToRegion'; @@ -117,11 +117,10 @@ export default function Page() { diff --git a/src/components/Navbar/components/LoggedIn.tsx b/src/components/Navbar/components/LoggedIn.tsx new file mode 100644 index 000000000..b6deaf1e4 --- /dev/null +++ b/src/components/Navbar/components/LoggedIn.tsx @@ -0,0 +1,22 @@ +import { ExitIcon } from '@radix-ui/react-icons'; +import { Flex, IconButton, Text } from '@radix-ui/themes'; +import { use } from 'react'; +import { getAccountInfo } from '../../../core/blitz/getAccountInfo'; +import { idToRegion } from '../../../core/blitz/idToRegion'; +import { logout } from '../../../core/blitz/logout'; +import { useApp } from '../../../stores/app'; + +export function LoggedIn() { + const login = useApp((state) => state.login!); + const accountInfo = use(getAccountInfo(idToRegion(login.id), login.id)); + + return ( + + Hello, {accountInfo.nickname} + + + + + + ); +} diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 19ecd2dd0..ab5600efd 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -2,25 +2,50 @@ import { DiscordLogoIcon, GearIcon, HamburgerMenuIcon, + PersonIcon, } from '@radix-ui/react-icons'; import { + Button, Flex, Heading, IconButton, Link as LinkRadix, Popover, + Select, + Spinner, + Text, } from '@radix-ui/themes'; import Link from 'next/link'; +import { Suspense, useEffect, useState } from 'react'; +import { Region } from '../../constants/regions'; import { TOOLS } from '../../constants/tools'; +import { authURL } from '../../core/blitz/authURL'; +import { extendAuth } from '../../core/blitz/extendAuth'; +import { logout } from '../../core/blitz/logout'; import { useFullScreen } from '../../hooks/useFullScreen'; -import { useWideFormat } from '../../hooks/useWideFormat'; import { BlitzkitWide } from '../../icons/BlitzkitWide'; import { PatreonIcon } from '../../icons/Patreon'; import { theme } from '../../stitches.config'; +import { useApp } from '../../stores/app'; +import { LoggedIn } from './components/LoggedIn'; export default function Navbar() { const isFullScreen = useFullScreen(); - const wideFormat = useWideFormat(600); + const login = useApp((state) => state.login); + const [region, setRegion] = useState('com'); + + useEffect(() => { + if (!login) return; + + const expiresIn = login.expiresAt - Date.now() / 1000; + const expiresInDays = expiresIn / 60 / 60 / 24; + + if (expiresInDays < 0) { + logout(); + } else if (expiresInDays < 7) { + extendAuth(); + } + }); if (isFullScreen) return null; @@ -89,6 +114,7 @@ export default function Navbar() { > +
@@ -153,6 +179,54 @@ export default function Navbar() { + + + + + + + + + + + {login && ( + }> + + + )} + + {!login && ( + <> + Currently signed out + + + setRegion(value as Region)} + > + + + + North America + + + Europe + + + Asia + + + + + + + + + + )} + + +
diff --git a/src/core/blitz/authURL.ts b/src/core/blitz/authURL.ts new file mode 100644 index 000000000..19d3a14b6 --- /dev/null +++ b/src/core/blitz/authURL.ts @@ -0,0 +1,8 @@ +import { Region } from '../../constants/regions'; +import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; + +export function authURL(region: Region, callback?: string) { + return `https://api.worldoftanks.${region}/wot/auth/login/?application_id=${WARGAMING_APPLICATION_ID}&redirect_uri=${encodeURIComponent( + `${location.origin}/callback/wargaming/${callback ? `?return=${location.href}` : ''}`, + )}`; +} diff --git a/src/core/blitz/extendAuth.ts b/src/core/blitz/extendAuth.ts new file mode 100644 index 000000000..578e7da38 --- /dev/null +++ b/src/core/blitz/extendAuth.ts @@ -0,0 +1,59 @@ +import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; +import { mutateApp, useApp } from '../../stores/app'; +import { idToRegion } from './idToRegion'; + +interface Extension { + data: { + access_token: string; + account_id: number; + expires_at: number; + }; +} + +export async function extendAuth() { + const { login } = useApp.getState(); + + if (!login) return; + + // error handling? what's that? + /* + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠛⠛⠿⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⡀⠠⠤⠒⢂⣉⣉⣉⣑⣒⣒⠒⠒⠒⠒⠒⠒⠒⠀⠀⠐⠒⠚⠻⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⡠⠔⠉⣀⠔⠒⠉⣀⣀⠀⠀⠀⣀⡀⠈⠉⠑⠒⠒⠒⠒⠒⠈⠉⠉⠉⠁⠂⠀⠈⠙⢿⣿⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠔⠁⠠⠖⠡⠔⠊⠀⠀⠀⠀⠀⠀⠀⠐⡄⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠉⠲⢄⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠊⠀⢀⣀⣤⣤⣤⣤⣀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠜⠀⠀⠀⠀⣀⡀⠀⠈⠃⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⡿⠥⠐⠂⠀⠀⠀⠀⡄⠀⠰⢺⣿⣿⣿⣿⣿⣟⠀⠈⠐⢤⠀⠀⠀⠀⠀⠀⢀⣠⣶⣾⣯⠀⠀⠉⠂⠀⠠⠤⢄⣀⠙⢿⣿⣿⣿⣿ + ⣿⡿⠋⠡⠐⠈⣉⠭⠤⠤⢄⡀⠈⠀⠈⠁⠉⠁⡠⠀⠀⠀⠉⠐⠠⠔⠀⠀⠀⠀⠀⠲⣿⠿⠛⠛⠓⠒⠂⠀⠀⠀⠀⠀⠀⠠⡉⢢⠙⣿⣿⣿ + ⣿⠀⢀⠁⠀⠊⠀⠀⠀⠀⠀⠈⠁⠒⠂⠀⠒⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢀⣀⡠⠔⠒⠒⠂⠀⠈⠀⡇⣿⣿⣿⣿⣿ + ⣿⠀⢸⠀⠀⠀⢀⣀⡠⠋⠓⠤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠈⠢⠤⡀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⡠⠀⡇⣿⣿⣿⣿⣿ + ⣿⡀⠘⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠈⠑⡦⢄⣀⠀⠀⠐⠒⠁⢸⠀⠀⠠⠒⠄⠀⠀⠀⠀⠀⢀⠇⠀⣀⡀⠀⠀⢀⢾⡆⠀⠈⡀⠎⣸⣿⣿⣿ + ⣿⣿⣄⡈⠢⠀⠀⠀⠀⠘⣶⣄⡀⠀⠀⡇⠀⠀⠈⠉⠒⠢⡤⣀⡀⠀⠀⠀⠀⠀⠐⠦⠤⠒⠁⠀⠀⠀⠀⣀⢴⠁⠀⢷⠀⠀⠀⢰⣿⣿⣿⣿ + ⣿⣿⣿⣿⣇⠂⠀⠀⠀⠀⠈⢂⠀⠈⠹⡧⣀⠀⠀⠀⠀⠀⡇⠀⠀⠉⠉⠉⢱⠒⠒⠒⠒⢖⠒⠒⠂⠙⠏⠀⠘⡀⠀⢸⠀⠀⠀⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠑⠄⠰⠀⠀⠁⠐⠲⣤⣴⣄⡀⠀⠀⠀⠀⢸⠀⠀⠀⠀⢸⠀⠀⠀⠀⢠⠀⣠⣷⣶⣿⠀⠀⢰⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠁⢀⠀⠀⠀⠀⠀⡙⠋⠙⠓⠲⢤⣤⣷⣤⣤⣤⣤⣾⣦⣤⣤⣶⣿⣿⣿⣿⡟⢹⠀⠀⢸⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠑⠀⢄⠀⡰⠁⠀⠀⠀⠀⠀⠈⠉⠁⠈⠉⠻⠋⠉⠛⢛⠉⠉⢹⠁⢀⢇⠎⠀⠀⢸⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣀⠈⠢⢄⡉⠂⠄⡀⠀⠈⠒⠢⠄⠀⢀⣀⣀⣰⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⢀⣎⠀⠼⠊⠀⠀⠀⠘⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⡀⠉⠢⢄⡈⠑⠢⢄⡀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⢀⠀⠀⠀⠀⠀⢻⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣀⡈⠑⠢⢄⡀⠈⠑⠒⠤⠄⣀⣀⠀⠉⠉⠉⠉⠀⠀⠀⣀⡀⠤⠂⠁⠀⢀⠆⠀⠀⢸⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⡀⠁⠉⠒⠂⠤⠤⣀⣀⣉⡉⠉⠉⠉⠉⢀⣀⣀⡠⠤⠒⠈⠀⠀⠀⠀⣸⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿ + ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣤⣤⣤⣤⣀⣀⣤⣤⣤⣶⣾⣿⣿⣿⣿⣿ + */ + + const response = await fetch( + `https://api.worldoftanks.${idToRegion( + login.id, + )}/wot/auth/prolongate/?application_id=${WARGAMING_APPLICATION_ID}&access_token=${ + login.token + }`, + ); + const json = (await response.json()) as Extension; + + mutateApp((draft) => { + draft.login = { + id: login.id, + token: json.data.access_token, + expiresAt: json.data.expires_at, + }; + }); +} diff --git a/src/core/blitz/logout.ts b/src/core/blitz/logout.ts new file mode 100644 index 000000000..290aa4774 --- /dev/null +++ b/src/core/blitz/logout.ts @@ -0,0 +1,7 @@ +import { mutateApp } from '../../stores/app'; + +export function logout() { + mutateApp((draft) => { + draft.login = undefined; + }); +} diff --git a/src/core/streams/wotbreplay.ts b/src/core/streams/wotbreplay.ts index ab37f46ff..0d996ad86 100644 --- a/src/core/streams/wotbreplay.ts +++ b/src/core/streams/wotbreplay.ts @@ -1,5 +1,5 @@ import AdmZip from 'adm-zip'; -import { readFile } from 'fs/promises'; +import { readFile, writeFile } from 'fs/promises'; import { Parser } from 'pickleparser'; import protobuf from 'protobufjs'; import { ReadStream } from './buffer'; @@ -42,10 +42,14 @@ export class WotbReplayReadStream extends ReadStream { 'BattleResultsGenerated.BattleResultsClient', ); - const decodedBattleResults = BattleResults.decode( - Buffer.from(battleResultsString, 'binary'), - ); - console.log(decodedBattleResults.toJSON()); + writeFile('test.dat', Buffer.from(battleResultsString)); + + const reader = protobuf.Reader.create(Buffer.from(battleResultsString)); + + // const decodedBattleResults = BattleResults.decodeDelimited( + // Buffer.from(battleResultsString), + // ); + // console.log(decodedBattleResults.toJSON()); } }