diff --git a/.eslintrc.js b/.eslintrc.js index 60a441e8..5c7a1609 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,12 +5,12 @@ module.exports = { browser: true, }, globals: { - "NodeJS": true + NodeJS: true, }, - ignorePatterns: ["typed-router.d.ts"], + ignorePatterns: ["dist", "build", "node_modules", "working-files", "**/*.js", "typed-router.d.ts"], rules: { // Rules should only be added here for testing temporarily and should eventually be moved into jaz-ts-utils to ensure consistency across projects "func-style": ["error", "declaration"], - "lines-between-class-members": ['error', 'always', { 'exceptAfterSingleLine': true }] + "lines-between-class-members": ["error", "always", { exceptAfterSingleLine: true }], }, }; diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 9175102f..d2824732 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -48,7 +48,7 @@ export default defineConfig({ esbuildOptions: { target: "esnext", }, - include: ["tachyon-protocol"], + exclude: ["tachyon-protocol"], // only when using npm link? }, css: { modules: false, diff --git a/package.json b/package.json index 53beef81..a3f1e4df 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "sdfz-demo-parser": "^5.9.1", "spring-map-parser": "^6.1.1", "steamworks.js": "^0.3.1", - "tachyon-client": "^10.4.1", "tachyon-protocol": "^1.4.0", "vue-i18n": "^9.2.2", "vue3-markdown-it": "^1.0.9", @@ -134,4 +133,4 @@ "@typescript-eslint/eslint-plugin": "$@typescript-eslint/eslint-plugin", "eslint-plugin-unused-imports": "$eslint-plugin-unused-imports" } -} +} \ No newline at end of file diff --git a/src/renderer/api/api.ts b/src/renderer/api/api.ts index 749f472d..946a6080 100644 --- a/src/renderer/api/api.ts +++ b/src/renderer/api/api.ts @@ -15,6 +15,7 @@ import { prompt } from "@/api/prompt"; import { SessionAPI } from "@/api/session"; import { StoreAPI } from "@/api/store"; import { UtilsAPI } from "@/api/utils"; +import { serverConfig } from "@/config/server"; import { accountSchema } from "@/model/account"; import type { Info } from "$/model/info"; import { settingsSchema } from "$/model/settings"; @@ -90,11 +91,10 @@ export async function apiInit() { api.game = new GameAPI(); api.comms = new CommsAPI({ - host: "127.0.0.1", // TODO: temporary host for local testing - port: 3005, + host: serverConfig.host, + port: serverConfig.port, logging: true, }); - await api.comms.init(); api.content = await new ContentAPI().init(); diff --git a/src/renderer/api/comms.ts b/src/renderer/api/comms.ts index 3818cbf7..4d1b4d61 100644 --- a/src/renderer/api/comms.ts +++ b/src/renderer/api/comms.ts @@ -7,7 +7,9 @@ * this includes matchmaking, chat, direct messages, and other lobby related functions. */ +import { GenericResponseCommand } from "tachyon-protocol"; import { ref } from "vue"; + import { TachyonClient } from "@/utils/tachyon-client"; //import { TachyonClient } from "tachyon-client"; @@ -18,6 +20,16 @@ import { TachyonClient } from "@/utils/tachyon-client"; export class CommsAPI extends TachyonClient { public readonly isConnectedRef = ref(false); + constructor(...args: ConstructorParameters) { + super(...args); + + this.onResponse.add((responseCommand: GenericResponseCommand) => { + if (responseCommand.status === "failed") { + console.error(`Failed response: ${responseCommand.commandId}`, responseCommand.reason); + } + }); + } + public override async connect(token: string): ReturnType { const userResponse = await super.connect(token); diff --git a/src/renderer/api/response-handlers/system/serverStats.ts b/src/renderer/api/response-handlers/system/serverStats.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/renderer/api/session.ts b/src/renderer/api/session.ts index d84cab71..f3ca96db 100644 --- a/src/renderer/api/session.ts +++ b/src/renderer/api/session.ts @@ -1,5 +1,6 @@ import { assign } from "jaz-ts-utils"; -import { TachyonPrivateUser, TachyonUser } from "tachyon-client/node_modules/tachyon-protocol"; +import { TachyonPrivateUser, TachyonUser } from "tachyon-protocol"; +import { SuccessResponseData } from "tachyon-protocol"; import { computed, ComputedRef, reactive, Ref, ref, shallowReactive, shallowRef } from "vue"; import { MatchmakingBattle } from "@/model/battle/matchmaking-battle"; @@ -17,7 +18,7 @@ export class SessionAPI { public readonly onlineUser: TachyonPrivateUser; public readonly customBattles: Map = shallowReactive(new Map()); public readonly battleMessages: Message[] = reactive([]); - //public readonly serverStats: Ref | null> = shallowRef(null); + public readonly serverStats: Ref | null> = shallowRef(null); // public readonly outgoingFriendRequests: ComputedRef; // public readonly incomingFriendRequests: ComputedRef; public readonly friends: ComputedRef; @@ -31,7 +32,7 @@ export class SessionAPI { this.users.clear(); this.customBattles.clear(); this.battleMessages.length = 0; - //this.serverStats.value = null; + this.serverStats.value = null; this.directMessages.clear(); const user: TachyonPrivateUser = { diff --git a/src/renderer/components/navbar/Exit.vue b/src/renderer/components/navbar/Exit.vue index 155180e8..4265034e 100644 --- a/src/renderer/components/navbar/Exit.vue +++ b/src/renderer/components/navbar/Exit.vue @@ -21,11 +21,12 @@ async function logout() { api.account.model.token = ""; try { if (!api.session.offlineMode.value) { - await api.comms.request("c.auth.disconnect"); // TODO: replace with logout https://github.com/beyond-all-reason/teiserver/issues/56 + await api.comms.request("system", "disconnect"); } } catch (err) { console.error(err); } + api.settings.model.loginAutomatically = false; await router.push("/login"); modal.value?.close(); } diff --git a/src/renderer/components/navbar/NavBar.vue b/src/renderer/components/navbar/NavBar.vue index 7ae3dcc5..feab1f7a 100644 --- a/src/renderer/components/navbar/NavBar.vue +++ b/src/renderer/components/navbar/NavBar.vue @@ -56,7 +56,7 @@ diff --git a/src/renderer/config/server.ts b/src/renderer/config/server.ts index abe5e545..800482ee 100644 --- a/src/renderer/config/server.ts +++ b/src/renderer/config/server.ts @@ -1,4 +1,7 @@ +// TODO: make this configurable at runtime export const serverConfig = { - host: "server4.beyondallreason.info", - port: 8202, + // host: "server4.beyondallreason.info", + // port: 8202, + host: "127.0.0.1", + port: 3005, }; diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 73a51b55..081d34cc 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -53,7 +53,7 @@ async function setupVue() { app.use(api.router); app.use(PrimeVue, { - ripple: true, + ripple: false, // disabled for now because it's creating weird displacement issues when triggered, maybe fixed in latest primevue }); app.use(await setupI18n()); diff --git a/src/renderer/model/battle/abstract-battle.ts b/src/renderer/model/battle/abstract-battle.ts index 9a8c6ca7..e984c616 100644 --- a/src/renderer/model/battle/abstract-battle.ts +++ b/src/renderer/model/battle/abstract-battle.ts @@ -1,7 +1,7 @@ import { useNow } from "@vueuse/core"; import { formatDuration } from "date-fns"; import { groupBy } from "jaz-ts-utils"; -import { TachyonUser } from "tachyon-client/node_modules/tachyon-protocol"; +import { TachyonUser } from "tachyon-protocol"; import { computed, ComputedRef, reactive, shallowReactive, WatchStopHandle } from "vue"; import { BattleOptions, BattlePlayer, BattleSpectator, BattleUser, Bot } from "@/model/battle/battle-types"; diff --git a/src/renderer/model/battle/battle-types.ts b/src/renderer/model/battle/battle-types.ts index 14a08377..5ad9d6c5 100644 --- a/src/renderer/model/battle/battle-types.ts +++ b/src/renderer/model/battle/battle-types.ts @@ -1,4 +1,4 @@ -import { TachyonUser } from "tachyon-client/node_modules/tachyon-protocol"; +import { TachyonUser } from "tachyon-protocol"; export type BattleUser = BattlePlayer | BattleSpectator; export type BattlePlayer = TachyonUser & { battleStatus: { isSpectator: false } }; diff --git a/src/renderer/shims.d.ts b/src/renderer/shims.d.ts index 6495baa5..454a5502 100644 --- a/src/renderer/shims.d.ts +++ b/src/renderer/shims.d.ts @@ -1,20 +1,19 @@ import "@total-typescript/ts-reset"; +/// +/// + declare const __static: string; -/* eslint-disable */ declare module "*.vue" { import type { Component } from "vue"; + // eslint-disable-next-line const component: Component<{}, {}, any>; export default component; } declare module "vue3-markdown-it"; declare module "vue3-popper"; -declare module "tachyon-protocol/validators" { - const validators: any; - export = validators; -} declare module "*.png"; declare module "*.mp3"; diff --git a/src/renderer/utils/tachyon-client.ts b/src/renderer/utils/tachyon-client.ts index 54a20c7a..140b0a55 100644 --- a/src/renderer/utils/tachyon-client.ts +++ b/src/renderer/utils/tachyon-client.ts @@ -3,8 +3,7 @@ import { Signal } from "jaz-ts-utils"; import { randomUUID } from "node:crypto"; import http from "node:http"; import { AddressInfo } from "node:net"; -import { EndpointId, GenericRequestCommand, RequestData, ResponseCommand, ServiceId, SuccessResponseData, tachyonMeta } from "tachyon-protocol"; -// @ts-ignore +import { EndpointId, GenericRequestCommand, GenericResponseCommand, RequestData, ResponseCommand, ServiceId, SuccessResponseData, tachyonMeta } from "tachyon-protocol"; import * as validators from "tachyon-protocol/validators"; import { SetOptional } from "type-fest"; import { ClientOptions, WebSocket } from "ws"; @@ -38,6 +37,8 @@ const defaultTachyonClientOptions = { export class TachyonClient { public socket?: WebSocket; public config: TachyonClientOptions; + public onRequest: Signal = new Signal(); + public onResponse: Signal = new Signal(); protected responseSignals: Map = new Map(); protected oauthClient: OAuth2Client; @@ -53,11 +54,6 @@ export class TachyonClient { }); } - public async init() { - // @ts-ignore - //this.validators = await import("tachyon-protocol/validators"); - } - public async connect(token: string): Promise> { return new Promise((resolve, reject) => { if (this.socket && this.socket.readyState === this.socket.OPEN) { @@ -94,16 +90,13 @@ export class TachyonClient { const isValid = validator(response); if (!isValid) { console.error(`Command validation failed for ${commandId}`); - if (validator.errors) { - for (const error of validator.errors) { - console.error(error); - } - } + console.error(validator.errors); } const signal = this.responseSignals.get(response.commandId); if (signal) { signal.dispatch(response); + this.onResponse.dispatch(response as GenericResponseCommand); } }); @@ -167,20 +160,17 @@ export class TachyonClient { const validator = validators[`${serviceId as string}_${endpointId as string}_request`]; if (data) { - Object.assign(request, data); + request.data = data; } const isValid = validator(request); if (!isValid) { console.error(`Command validation failed for ${commandId}`); - if (validator.errors) { - for (const error of validator.errors) { - console.error(error); - } - } + console.error(validator.errors); } this.socket?.send(JSON.stringify(request)); + this.onRequest.dispatch(request); this.log("REQUEST", request); diff --git a/src/renderer/utils/tachyon-log.ts b/src/renderer/utils/tachyon-log.ts deleted file mode 100644 index 993c3dcf..00000000 --- a/src/renderer/utils/tachyon-log.ts +++ /dev/null @@ -1,12 +0,0 @@ -const hideCmds = ["c.system.ping", "s.system.pong", "s.system.server_stats"]; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function tachyonLog(...data: any[]) { - for (const part of data) { - if (typeof part === "object") { - if (part.cmd && !hideCmds.includes(part.cmd)) { - console.debug(...data); - } - } - } -} diff --git a/src/renderer/utils/type-checkers.ts b/src/renderer/utils/type-checkers.ts index 19278fb0..7cda8bc6 100644 --- a/src/renderer/utils/type-checkers.ts +++ b/src/renderer/utils/type-checkers.ts @@ -1,4 +1,4 @@ -import { TachyonUser } from "tachyon-client/node_modules/tachyon-protocol"; +import { TachyonUser } from "tachyon-protocol"; import { BattlePlayer, BattleSpectator, Bot } from "@/model/battle/battle-types"; import { Replay } from "@/model/cache/replay"; diff --git a/src/renderer/views/login.vue b/src/renderer/views/login.vue index 4ec039af..555e93b5 100644 --- a/src/renderer/views/login.vue +++ b/src/renderer/views/login.vue @@ -66,6 +66,8 @@ async function connect() { await api.comms.connect(oauthToken.accessToken); state.value = "connected"; + + await api.router.push("/home"); } catch (err) { state.value = "error"; if (err instanceof Error) { @@ -115,7 +117,9 @@ async function promptUsername(): Promise { return "bob"; } -await connect(); +if (api.settings.model.loginAutomatically) { + await connect(); +} + diff --git a/tsconfig.web.json b/tsconfig.web.json index cde527e3..1a342fc0 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -11,6 +11,7 @@ "$/*": ["src/common/*"], "jaz-ts-utils": ["node_modules/jaz-ts-utils"] }, + "moduleResolution": "Bundler", "noEmit": true, "downlevelIteration": true, "noUnusedParameters": false,