Merge pull request #596 from hydralauncher/feature/integrate-hydra-api
Some checks failed
Release / build (ubuntu-latest) (push) Has been cancelled
Release / build (windows-latest) (push) Has been cancelled

feat: create HydraApi
This commit is contained in:
Zamitto 2024-06-13 23:38:23 -03:00 committed by GitHub
commit 8fad9b05e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 122 additions and 4 deletions

View file

@ -1,4 +1,3 @@
MAIN_VITE_STEAMGRIDDB_API_KEY=YOUR_API_KEY
MAIN_VITE_ONLINEFIX_USERNAME=YOUR_USERNAME
MAIN_VITE_ONLINEFIX_PASSWORD=YOUR_PASSWORD
MAIN_VITE_API_URL=API_URL

View file

@ -11,6 +11,7 @@ import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlit
import { databasePath } from "./constants";
import migrations from "./migrations";
import { UserAuth } from "./entity/user-auth";
export const createDataSource = (
options: Partial<BetterSqlite3ConnectionOptions>
@ -24,6 +25,7 @@ export const createDataSource = (
GameShopCache,
DownloadSource,
DownloadQueue,
UserAuth,
],
synchronize: true,
database: databasePath,

View file

@ -0,0 +1,28 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from "typeorm";
@Entity("user_auth")
export class UserAuth {
@PrimaryGeneratedColumn()
id: number;
@Column("text", { default: "" })
accessToken: string;
@Column("text", { default: "" })
refreshToken: string;
@Column("int", { default: 0 })
tokenExpirationTimestamp: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}

View file

@ -9,6 +9,7 @@ import { RealDebridClient } from "./services/real-debrid";
import { fetchDownloadSourcesAndUpdate } from "./helpers";
import { publishNewRepacksNotifications } from "./services/notifications";
import { MoreThan } from "typeorm";
import { HydraApi } from "./services/hydra-api";
startMainLoop();
@ -20,6 +21,8 @@ const loadState = async (userPreferences: UserPreferences | null) => {
if (userPreferences?.realDebridApiToken)
RealDebridClient.authorize(userPreferences?.realDebridApiToken);
HydraApi.setupApi();
const [nextQueueItem] = await downloadQueueRepository.find({
order: {
id: "DESC",

View file

@ -7,6 +7,7 @@ import {
Repack,
UserPreferences,
} from "@main/entity";
import { UserAuth } from "./entity/user-auth";
export const gameRepository = dataSource.getRepository(Game);
@ -21,3 +22,5 @@ export const downloadSourceRepository =
dataSource.getRepository(DownloadSource);
export const downloadQueueRepository = dataSource.getRepository(DownloadQueue);
export const userAuthRepository = dataSource.getRepository(UserAuth);

View file

@ -0,0 +1,84 @@
import { userAuthRepository } from "@main/repository";
import axios, { AxiosInstance } from "axios";
export class HydraApi {
private static instance: AxiosInstance;
private static readonly EXPIRATION_OFFSET_IN_MS = 1000 * 60 * 5;
private static userAuth = {
authToken: "",
refreshToken: "",
expirationTimestamp: 0,
};
static async setupApi() {
this.instance = axios.create({
baseURL: import.meta.env.MAIN_VITE_API_URL,
});
const userAuth = await userAuthRepository.findOne({
where: { id: 1 },
});
this.userAuth = {
authToken: userAuth?.accessToken ?? "",
refreshToken: userAuth?.refreshToken ?? "",
expirationTimestamp: userAuth?.tokenExpirationTimestamp ?? 0,
};
}
private static async revalidateAccessTokenIfExpired() {
const now = new Date();
if (this.userAuth.expirationTimestamp < now.getTime()) {
const response = await this.instance.post(`/auth/refresh`, {
refreshToken: this.userAuth.refreshToken,
});
const { accessToken, expiresIn } = response.data;
const tokenExpirationTimestamp =
now.getTime() + expiresIn - this.EXPIRATION_OFFSET_IN_MS;
this.userAuth.authToken = accessToken;
this.userAuth.expirationTimestamp = tokenExpirationTimestamp;
userAuthRepository.upsert(
{
id: 1,
accessToken,
tokenExpirationTimestamp,
},
["id"]
);
}
}
private static getAxiosConfig() {
return {
headers: {
Authorization: `Bearer ${this.userAuth.authToken}`,
},
};
}
static async get(url: string) {
await this.revalidateAccessTokenIfExpired();
return this.instance.get(url, this.getAxiosConfig());
}
static async post(url: string, data?: any) {
await this.revalidateAccessTokenIfExpired();
return this.instance.post(url, data, this.getAxiosConfig());
}
static async put(url, data?: any) {
await this.revalidateAccessTokenIfExpired();
return this.instance.put(url, data, this.getAxiosConfig());
}
static async patch(url, data?: any) {
await this.revalidateAccessTokenIfExpired();
return this.instance.patch(url, data, this.getAxiosConfig());
}
}

View file

@ -2,8 +2,7 @@
interface ImportMetaEnv {
readonly MAIN_VITE_STEAMGRIDDB_API_KEY: string;
readonly MAIN_VITE_ONLINEFIX_USERNAME: string;
readonly MAIN_VITE_ONLINEFIX_PASSWORD: string;
readonly MAIN_VITE_API_URL: string;
}
interface ImportMeta {