Skip to content

Commit

Permalink
Merge pull request #814 from hydralauncher/hyd-270-create-a-section-u…
Browse files Browse the repository at this point in the history
…nder-library-games-in-profile-page-for

feat: add friends
  • Loading branch information
zamitto authored Jul 20, 2024
2 parents 202f5b6 + 929be48 commit 3952f10
Show file tree
Hide file tree
Showing 32 changed files with 970 additions and 136 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@reduxjs/toolkit": "^2.2.3",
"@sentry/electron": "^5.1.0",
"@vanilla-extract/css": "^1.14.2",
"@vanilla-extract/dynamic": "^2.1.1",
"@vanilla-extract/recipes": "^0.5.2",
"aria2": "^4.1.2",
"auto-launch": "^5.0.6",
Expand Down
11 changes: 10 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@
"successfully_signed_out": "Successfully signed out",
"sign_out": "Sign out",
"playing_for": "Playing for {{amount}}",
"sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?"
"sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?",
"add_friends": "Add Friends",
"add": "Add",
"friend_code": "Friend code",
"see_profile": "See profile",
"sending": "Sending",
"friend_request_sent": "Friend request sent",
"friends": "Friends",
"friends_list": "Friends list",
"user_not_found": "User not found"
}
}
11 changes: 10 additions & 1 deletion src/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@
"sign_out": "Sair da conta",
"sign_out_modal_title": "Tem certeza?",
"playing_for": "Jogando por {{amount}}",
"sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?"
"sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?",
"add_friends": "Adicionar Amigos",
"friend_code": "Código de amigo",
"see_profile": "Ver perfil",
"friend_request_sent": "Pedido de amizade enviado",
"friends": "Amigos",
"add": "Adicionar",
"sending": "Enviando",
"friends_list": "Lista de amigos",
"user_not_found": "Usuário não encontrado"
}
}
3 changes: 3 additions & 0 deletions src/main/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ import "./auth/sign-out";
import "./auth/open-auth-window";
import "./auth/get-session-hash";
import "./user/get-user";
import "./profile/get-friend-requests";
import "./profile/get-me";
import "./profile/update-friend-request";
import "./profile/update-profile";
import "./profile/send-friend-request";

ipcMain.handle("ping", () => "pong");
ipcMain.handle("getVersion", () => app.getVersion());
Expand Down
11 changes: 11 additions & 0 deletions src/main/events/profile/get-friend-requests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { registerEvent } from "../register-event";
import { HydraApi } from "@main/services";
import { FriendRequest } from "@types";

const getFriendRequests = async (
_event: Electron.IpcMainInvokeEvent
): Promise<FriendRequest[]> => {
return HydraApi.get(`/profile/friend-requests`).catch(() => []);
};

registerEvent("getFriendRequests", getFriendRequests);
14 changes: 9 additions & 5 deletions src/main/events/profile/get-me.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ const getMe = async (
_event: Electron.IpcMainInvokeEvent
): Promise<UserProfile | null> => {
return HydraApi.get(`/profile/me`)
.then((response) => {
const me = response.data;

.then((me) => {
userAuthRepository.upsert(
{
id: 1,
Expand All @@ -26,12 +24,18 @@ const getMe = async (

return me;
})
.catch((err) => {
.catch(async (err) => {
if (err instanceof UserNotLoggedInError) {
return null;
}

return userAuthRepository.findOne({ where: { id: 1 } });
const loggedUser = await userAuthRepository.findOne({ where: { id: 1 } });

if (loggedUser) {
return { ...loggedUser, id: loggedUser.userId };
}

return null;
});
};

Expand Down
11 changes: 11 additions & 0 deletions src/main/events/profile/send-friend-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { registerEvent } from "../register-event";
import { HydraApi } from "@main/services";

const sendFriendRequest = async (
_event: Electron.IpcMainInvokeEvent,
userId: string
) => {
return HydraApi.post("/profile/friend-requests", { friendCode: userId });
};

registerEvent("sendFriendRequest", sendFriendRequest);
19 changes: 19 additions & 0 deletions src/main/events/profile/update-friend-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { registerEvent } from "../register-event";
import { HydraApi } from "@main/services";
import { FriendRequestAction } from "@types";

const updateFriendRequest = async (
_event: Electron.IpcMainInvokeEvent,
userId: string,
action: FriendRequestAction
) => {
if (action == "CANCEL") {
return HydraApi.delete(`/profile/friend-requests/${userId}`);
}

return HydraApi.patch(`/profile/friend-requests/${userId}`, {
requestState: action,
});
};

registerEvent("updateFriendRequest", updateFriendRequest);
14 changes: 5 additions & 9 deletions src/main/events/profile/update-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ const updateProfile = async (
_event: Electron.IpcMainInvokeEvent,
displayName: string,
newProfileImagePath: string | null
) => {
): Promise<UserProfile> => {
if (!newProfileImagePath) {
return patchUserProfile(displayName).then(
(response) => response.data as UserProfile
);
return patchUserProfile(displayName);
}

const stats = fs.statSync(newProfileImagePath);
Expand All @@ -42,7 +40,7 @@ const updateProfile = async (
imageLength: fileSizeInBytes,
})
.then(async (preSignedResponse) => {
const { presignedUrl, profileImageUrl } = preSignedResponse.data;
const { presignedUrl, profileImageUrl } = preSignedResponse;

const mimeType = await fileTypeFromFile(newProfileImagePath);

Expand All @@ -51,13 +49,11 @@ const updateProfile = async (
"Content-Type": mimeType?.mime,
},
});
return profileImageUrl;
return profileImageUrl as string;
})
.catch(() => undefined);

return patchUserProfile(displayName, profileImageUrl).then(
(response) => response.data as UserProfile
);
return patchUserProfile(displayName, profileImageUrl);
};

registerEvent("updateProfile", updateProfile);
3 changes: 1 addition & 2 deletions src/main/events/user/get-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ const getUser = async (
userId: string
): Promise<UserProfile | null> => {
try {
const response = await HydraApi.get(`/user/${userId}`);
const profile = response.data;
const profile = await HydraApi.get(`/user/${userId}`);

const recentGames = await Promise.all(
profile.recentGames.map(async (game) => {
Expand Down
3 changes: 3 additions & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ autoUpdater.setFeedURL({

autoUpdater.logger = logger;

logger.log("Init Hydra");

const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) app.quit();

Expand Down Expand Up @@ -121,6 +123,7 @@ app.on("window-all-closed", () => {
app.on("before-quit", () => {
/* Disconnects libtorrent */
PythonInstance.kill();
logger.log("Quit Hydra");
});

app.on("activate", () => {
Expand Down
27 changes: 22 additions & 5 deletions src/main/services/hydra-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { UserNotLoggedInError } from "@shared";
export class HydraApi {
private static instance: AxiosInstance;

private static readonly EXPIRATION_OFFSET_IN_MS = 1000 * 60 * 5;
private static readonly EXPIRATION_OFFSET_IN_MS = 1000 * 60 * 5; // 5 minutes

private static secondsToMilliseconds = (seconds: number) => seconds * 1000;

Expand Down Expand Up @@ -45,6 +45,8 @@ export class HydraApi {
expirationTimestamp: tokenExpirationTimestamp,
};

logger.log("Sign in received", this.userAuth);

await userAuthRepository.upsert(
{
id: 1,
Expand Down Expand Up @@ -74,7 +76,7 @@ export class HydraApi {
return request;
},
(error) => {
logger.log("request error", error);
logger.error("request error", error);
return Promise.reject(error);
}
);
Expand All @@ -95,12 +97,18 @@ export class HydraApi {

const { config } = error;

logger.error(config.method, config.baseURL, config.url, config.headers);
logger.error(
config.method,
config.baseURL,
config.url,
config.headers,
config.data
);

if (error.response) {
logger.error(error.response.status, error.response.data);
logger.error("Response", error.response.status, error.response.data);
} else if (error.request) {
logger.error(error.request);
logger.error("Request", error.request);
} else {
logger.error("Error", error.message);
}
Expand Down Expand Up @@ -146,6 +154,8 @@ export class HydraApi {
this.userAuth.authToken = accessToken;
this.userAuth.expirationTimestamp = tokenExpirationTimestamp;

logger.log("Token refreshed", this.userAuth);

userAuthRepository.upsert(
{
id: 1,
Expand All @@ -170,6 +180,8 @@ export class HydraApi {

private static handleUnauthorizedError = (err) => {
if (err instanceof AxiosError && err.response?.status === 401) {
logger.error("401 - Current credentials:", this.userAuth);

this.userAuth = {
authToken: "",
expirationTimestamp: 0,
Expand All @@ -190,6 +202,7 @@ export class HydraApi {
await this.revalidateAccessTokenIfExpired();
return this.instance
.get(url, this.getAxiosConfig())
.then((response) => response.data)
.catch(this.handleUnauthorizedError);
}

Expand All @@ -199,6 +212,7 @@ export class HydraApi {
await this.revalidateAccessTokenIfExpired();
return this.instance
.post(url, data, this.getAxiosConfig())
.then((response) => response.data)
.catch(this.handleUnauthorizedError);
}

Expand All @@ -208,6 +222,7 @@ export class HydraApi {
await this.revalidateAccessTokenIfExpired();
return this.instance
.put(url, data, this.getAxiosConfig())
.then((response) => response.data)
.catch(this.handleUnauthorizedError);
}

Expand All @@ -217,6 +232,7 @@ export class HydraApi {
await this.revalidateAccessTokenIfExpired();
return this.instance
.patch(url, data, this.getAxiosConfig())
.then((response) => response.data)
.catch(this.handleUnauthorizedError);
}

Expand All @@ -226,6 +242,7 @@ export class HydraApi {
await this.revalidateAccessTokenIfExpired();
return this.instance
.delete(url, this.getAxiosConfig())
.then((response) => response.data)
.catch(this.handleUnauthorizedError);
}
}
6 changes: 1 addition & 5 deletions src/main/services/library-sync/create-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ export const createGame = async (game: Game) => {
lastTimePlayed: game.lastTimePlayed,
})
.then((response) => {
const {
id: remoteId,
playTimeInMilliseconds,
lastTimePlayed,
} = response.data;
const { id: remoteId, playTimeInMilliseconds, lastTimePlayed } = response;

gameRepository.update(
{ objectID: game.objectID },
Expand Down
2 changes: 1 addition & 1 deletion src/main/services/library-sync/merge-with-remote-games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getSteamAppAsset } from "@main/helpers";
export const mergeWithRemoteGames = async () => {
return HydraApi.get("/games")
.then(async (response) => {
for (const game of response.data) {
for (const game of response) {
const localGame = await gameRepository.findOne({
where: {
objectID: game.objectId,
Expand Down
6 changes: 6 additions & 0 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
AppUpdaterEvent,
StartGameDownloadPayload,
GameRunning,
FriendRequestAction,
} from "@types";

contextBridge.exposeInMainWorld("electron", {
Expand Down Expand Up @@ -136,6 +137,11 @@ contextBridge.exposeInMainWorld("electron", {
getMe: () => ipcRenderer.invoke("getMe"),
updateProfile: (displayName: string, newProfileImagePath: string | null) =>
ipcRenderer.invoke("updateProfile", displayName, newProfileImagePath),
getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"),
updateFriendRequest: (userId: string, action: FriendRequestAction) =>
ipcRenderer.invoke("updateFriendRequest", userId, action),
sendFriendRequest: (userId: string) =>
ipcRenderer.invoke("sendFriendRequest", userId),

/* User */
getUser: (userId: string) => ipcRenderer.invoke("getUser", userId),
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<title>Hydra</title>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: local: https://*.cloudfront.net https://*.s3.amazonaws.com https://steamcdn-a.akamaihd.net https://shared.akamai.steamstatic.com https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' local: data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com https://shared.akamai.steamstatic.com;"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: local: https://cdn.discordapp.com https://*.cloudfront.net https://*.s3.amazonaws.com https://steamcdn-a.akamaihd.net https://shared.akamai.steamstatic.com https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' local: data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com https://shared.akamai.steamstatic.com;"
/>
</head>
<body style="background-color: #1c1c1c">
Expand Down
Loading

0 comments on commit 3952f10

Please sign in to comment.