mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-30 14:21:04 +00:00
feat: refactor watcher for sync friend request
This commit is contained in:
@@ -31,3 +31,5 @@ export const achievementSoundPath = app.isPackaged
|
|||||||
export const backupsPath = path.join(app.getPath("userData"), "Backups");
|
export const backupsPath = path.join(app.getPath("userData"), "Backups");
|
||||||
|
|
||||||
export const appVersion = app.getVersion() + (isStaging ? "-staging" : "");
|
export const appVersion = app.getVersion() + (isStaging ? "-staging" : "");
|
||||||
|
|
||||||
|
export const MAIN_LOOP_INTERVAL = 1500;
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
|
import { MAIN_LOOP_INTERVAL } from "@main/constants";
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { HydraApi } from "@main/services";
|
import { HydraApi, WindowManager } from "@main/services";
|
||||||
import { publishNewFriendRequestNotification } from "@main/services/notifications";
|
import { publishNewFriendRequestNotification } from "@main/services/notifications";
|
||||||
import { UserNotLoggedInError } from "@shared";
|
import { UserNotLoggedInError } from "@shared";
|
||||||
import type { FriendRequestSync } from "@types";
|
import type { FriendRequestSync } from "@types";
|
||||||
|
|
||||||
interface SyncState {
|
interface SyncState {
|
||||||
friendRequestCount: number | null;
|
friendRequestCount: number | null;
|
||||||
|
tick: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ticksToUpdate = (2 * 60 * 1000) / MAIN_LOOP_INTERVAL; // 2 minutes
|
||||||
|
|
||||||
const syncState: SyncState = {
|
const syncState: SyncState = {
|
||||||
friendRequestCount: null,
|
friendRequestCount: null,
|
||||||
|
tick: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncFriendRequests = async (_event: Electron.IpcMainInvokeEvent) => {
|
const syncFriendRequests = async () => {
|
||||||
return HydraApi.get<FriendRequestSync>(`/profile/friend-requests/sync`)
|
return HydraApi.get<FriendRequestSync>(`/profile/friend-requests/sync`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (
|
if (
|
||||||
@@ -24,6 +29,11 @@ const syncFriendRequests = async (_event: Electron.IpcMainInvokeEvent) => {
|
|||||||
|
|
||||||
syncState.friendRequestCount = res.friendRequestCount;
|
syncState.friendRequestCount = res.friendRequestCount;
|
||||||
|
|
||||||
|
WindowManager.mainWindow?.webContents.send(
|
||||||
|
"on-sync-friend-requests",
|
||||||
|
res
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -34,4 +44,16 @@ const syncFriendRequests = async (_event: Electron.IpcMainInvokeEvent) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
registerEvent("syncFriendRequests", syncFriendRequests);
|
const syncFriendRequestsEvent = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||||
|
return syncFriendRequests();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const watchFriendRequests = async () => {
|
||||||
|
if (syncState.tick % ticksToUpdate === 0) {
|
||||||
|
await syncFriendRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
syncState.tick++;
|
||||||
|
};
|
||||||
|
|
||||||
|
registerEvent("syncFriendRequests", syncFriendRequestsEvent);
|
||||||
|
|||||||
@@ -3,18 +3,21 @@ import { DownloadManager } from "./download";
|
|||||||
import { watchProcesses } from "./process-watcher";
|
import { watchProcesses } from "./process-watcher";
|
||||||
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
||||||
import { UpdateManager } from "./update-manager";
|
import { UpdateManager } from "./update-manager";
|
||||||
|
import { watchFriendRequests } from "@main/events/profile/sync-friend-requests";
|
||||||
|
import { MAIN_LOOP_INTERVAL } from "@main/constants";
|
||||||
|
|
||||||
export const startMainLoop = async () => {
|
export const startMainLoop = async () => {
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
watchProcesses(),
|
watchProcesses(),
|
||||||
|
watchFriendRequests(),
|
||||||
DownloadManager.watchDownloads(),
|
DownloadManager.watchDownloads(),
|
||||||
AchievementWatcherManager.watchAchievements(),
|
AchievementWatcherManager.watchAchievements(),
|
||||||
DownloadManager.getSeedStatus(),
|
DownloadManager.getSeedStatus(),
|
||||||
UpdateManager.checkForUpdatePeriodically(),
|
UpdateManager.checkForUpdatePeriodically(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await sleep(1500);
|
await sleep(MAIN_LOOP_INTERVAL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { AppUpdaterEvent, UserPreferences } from "@types";
|
|||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications";
|
import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications";
|
||||||
import { db, levelKeys } from "@main/level";
|
import { db, levelKeys } from "@main/level";
|
||||||
|
import { MAIN_LOOP_INTERVAL } from "@main/constants";
|
||||||
|
|
||||||
const { autoUpdater } = updater;
|
const { autoUpdater } = updater;
|
||||||
const sendEventsForDebug = false;
|
const sendEventsForDebug = false;
|
||||||
|
const ticksToUpdate = (50 * 60 * 1000) / MAIN_LOOP_INTERVAL; // 50 minutes
|
||||||
|
|
||||||
export class UpdateManager {
|
export class UpdateManager {
|
||||||
private static hasNotified = false;
|
private static hasNotified = false;
|
||||||
@@ -72,7 +74,7 @@ export class UpdateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static checkForUpdatePeriodically() {
|
public static checkForUpdatePeriodically() {
|
||||||
if (this.checkTick % 2000 == 0) {
|
if (this.checkTick % ticksToUpdate == 0) {
|
||||||
this.checkForUpdates();
|
this.checkForUpdates();
|
||||||
}
|
}
|
||||||
this.checkTick++;
|
this.checkTick++;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import type {
|
|||||||
SeedingStatus,
|
SeedingStatus,
|
||||||
GameAchievement,
|
GameAchievement,
|
||||||
Theme,
|
Theme,
|
||||||
|
FriendRequestSync,
|
||||||
} from "@types";
|
} from "@types";
|
||||||
import type { AuthPage, CatalogueCategory } from "@shared";
|
import type { AuthPage, CatalogueCategory } from "@shared";
|
||||||
import type { AxiosProgressEvent } from "axios";
|
import type { AxiosProgressEvent } from "axios";
|
||||||
@@ -306,6 +307,15 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
ipcRenderer.invoke("processProfileImage", imagePath),
|
ipcRenderer.invoke("processProfileImage", imagePath),
|
||||||
getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"),
|
getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"),
|
||||||
syncFriendRequests: () => ipcRenderer.invoke("syncFriendRequests"),
|
syncFriendRequests: () => ipcRenderer.invoke("syncFriendRequests"),
|
||||||
|
onSyncFriendRequests: (cb: (friendRequests: FriendRequestSync) => void) => {
|
||||||
|
const listener = (
|
||||||
|
_event: Electron.IpcRendererEvent,
|
||||||
|
friendRequests: FriendRequestSync
|
||||||
|
) => cb(friendRequests);
|
||||||
|
ipcRenderer.on("on-sync-friend-requests", listener);
|
||||||
|
return () =>
|
||||||
|
ipcRenderer.removeListener("on-sync-friend-requests", listener);
|
||||||
|
},
|
||||||
updateFriendRequest: (userId: string, action: FriendRequestAction) =>
|
updateFriendRequest: (userId: string, action: FriendRequestAction) =>
|
||||||
ipcRenderer.invoke("updateFriendRequest", userId, action),
|
ipcRenderer.invoke("updateFriendRequest", userId, action),
|
||||||
sendFriendRequest: (userId: string) =>
|
sendFriendRequest: (userId: string) =>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
setUserDetails,
|
setUserDetails,
|
||||||
setProfileBackground,
|
setProfileBackground,
|
||||||
setGameRunning,
|
setGameRunning,
|
||||||
|
setFriendRequestCount,
|
||||||
} from "@renderer/features";
|
} from "@renderer/features";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UserFriendModal } from "./pages/shared-modals/user-friend-modal";
|
import { UserFriendModal } from "./pages/shared-modals/user-friend-modal";
|
||||||
@@ -51,7 +52,6 @@ export function App() {
|
|||||||
isFriendsModalVisible,
|
isFriendsModalVisible,
|
||||||
friendRequetsModalTab,
|
friendRequetsModalTab,
|
||||||
friendModalUserId,
|
friendModalUserId,
|
||||||
syncFriendRequests,
|
|
||||||
hideFriendsModal,
|
hideFriendsModal,
|
||||||
fetchUserDetails,
|
fetchUserDetails,
|
||||||
updateUserDetails,
|
updateUserDetails,
|
||||||
@@ -123,7 +123,7 @@ export function App() {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
updateUserDetails(response);
|
updateUserDetails(response);
|
||||||
syncFriendRequests();
|
window.electron.syncFriendRequests();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -134,23 +134,27 @@ export function App() {
|
|||||||
$script.src = `${import.meta.env.RENDERER_VITE_EXTERNAL_RESOURCES_URL}/bundle.js?t=${Date.now()}`;
|
$script.src = `${import.meta.env.RENDERER_VITE_EXTERNAL_RESOURCES_URL}/bundle.js?t=${Date.now()}`;
|
||||||
document.head.appendChild($script);
|
document.head.appendChild($script);
|
||||||
});
|
});
|
||||||
}, [fetchUserDetails, syncFriendRequests, updateUserDetails, dispatch]);
|
}, [fetchUserDetails, updateUserDetails, dispatch]);
|
||||||
|
|
||||||
const onSignIn = useCallback(() => {
|
const onSignIn = useCallback(() => {
|
||||||
fetchUserDetails().then((response) => {
|
fetchUserDetails().then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
updateUserDetails(response);
|
updateUserDetails(response);
|
||||||
syncFriendRequests();
|
window.electron.syncFriendRequests();
|
||||||
showSuccessToast(t("successfully_signed_in"));
|
showSuccessToast(t("successfully_signed_in"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [
|
}, [fetchUserDetails, t, showSuccessToast, updateUserDetails]);
|
||||||
fetchUserDetails,
|
|
||||||
syncFriendRequests,
|
useEffect(() => {
|
||||||
t,
|
const unsubscribe = window.electron.onSyncFriendRequests((result) => {
|
||||||
showSuccessToast,
|
dispatch(setFriendRequestCount(result.friendRequestCount));
|
||||||
updateUserDetails,
|
});
|
||||||
]);
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = window.electron.onGamesRunning((gamesRunning) => {
|
const unsubscribe = window.electron.onGamesRunning((gamesRunning) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { PeopleIcon } from "@primer/octicons-react";
|
import { PeopleIcon } from "@primer/octicons-react";
|
||||||
import { useAppSelector, useUserDetails } from "@renderer/hooks";
|
import { useAppSelector, useUserDetails } from "@renderer/hooks";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal";
|
import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal";
|
||||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||||
@@ -9,19 +9,13 @@ import { Avatar } from "../avatar/avatar";
|
|||||||
import { AuthPage } from "@shared";
|
import { AuthPage } from "@shared";
|
||||||
import "./sidebar-profile.scss";
|
import "./sidebar-profile.scss";
|
||||||
|
|
||||||
const LONG_POLLING_INTERVAL = 120_000;
|
|
||||||
|
|
||||||
export function SidebarProfile() {
|
export function SidebarProfile() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { t } = useTranslation("sidebar");
|
const { t } = useTranslation("sidebar");
|
||||||
|
|
||||||
const {
|
const { userDetails, friendRequestCount, showFriendsModal } =
|
||||||
userDetails,
|
useUserDetails();
|
||||||
friendRequestCount,
|
|
||||||
showFriendsModal,
|
|
||||||
syncFriendRequests,
|
|
||||||
} = useUserDetails();
|
|
||||||
|
|
||||||
const { gameRunning } = useAppSelector((state) => state.gameRunning);
|
const { gameRunning } = useAppSelector((state) => state.gameRunning);
|
||||||
|
|
||||||
@@ -34,16 +28,6 @@ export function SidebarProfile() {
|
|||||||
navigate(`/profile/${userDetails.id}`);
|
navigate(`/profile/${userDetails.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const pollingInterval = setInterval(() => {
|
|
||||||
syncFriendRequests();
|
|
||||||
}, LONG_POLLING_INTERVAL);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(pollingInterval);
|
|
||||||
};
|
|
||||||
}, [syncFriendRequests]);
|
|
||||||
|
|
||||||
const friendsButton = useMemo(() => {
|
const friendsButton = useMemo(() => {
|
||||||
if (!userDetails) return null;
|
if (!userDetails) return null;
|
||||||
|
|
||||||
|
|||||||
5
src/renderer/src/declaration.d.ts
vendored
5
src/renderer/src/declaration.d.ts
vendored
@@ -280,7 +280,10 @@ declare global {
|
|||||||
path: string
|
path: string
|
||||||
) => Promise<{ imagePath: string; mimeType: string }>;
|
) => Promise<{ imagePath: string; mimeType: string }>;
|
||||||
getFriendRequests: () => Promise<FriendRequest[]>;
|
getFriendRequests: () => Promise<FriendRequest[]>;
|
||||||
syncFriendRequests: () => Promise<FriendRequestSync>;
|
syncFriendRequests: () => Promise<void>;
|
||||||
|
onSyncFriendRequests: (
|
||||||
|
cb: (friendRequests: FriendRequestSync) => void
|
||||||
|
) => () => Electron.IpcRenderer;
|
||||||
updateFriendRequest: (
|
updateFriendRequest: (
|
||||||
userId: string,
|
userId: string,
|
||||||
action: FriendRequestAction
|
action: FriendRequestAction
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
setFriendRequests,
|
setFriendRequests,
|
||||||
setFriendsModalVisible,
|
setFriendsModalVisible,
|
||||||
setFriendsModalHidden,
|
setFriendsModalHidden,
|
||||||
setFriendRequestCount,
|
|
||||||
} from "@renderer/features";
|
} from "@renderer/features";
|
||||||
import type {
|
import type {
|
||||||
FriendRequestAction,
|
FriendRequestAction,
|
||||||
@@ -88,24 +87,15 @@ export function useUserDetails() {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const syncFriendRequests = useCallback(async () => {
|
|
||||||
return window.electron
|
|
||||||
.syncFriendRequests()
|
|
||||||
.then((sync) => {
|
|
||||||
dispatch(setFriendRequestCount(sync.friendRequestCount));
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const fetchFriendRequests = useCallback(async () => {
|
const fetchFriendRequests = useCallback(async () => {
|
||||||
return window.electron
|
return window.electron
|
||||||
.getFriendRequests()
|
.getFriendRequests()
|
||||||
.then((friendRequests) => {
|
.then((friendRequests) => {
|
||||||
syncFriendRequests();
|
window.electron.syncFriendRequests();
|
||||||
dispatch(setFriendRequests(friendRequests));
|
dispatch(setFriendRequests(friendRequests));
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}, [dispatch, syncFriendRequests]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const showFriendsModal = useCallback(
|
const showFriendsModal = useCallback(
|
||||||
(initialTab: UserFriendModalTab, userId: string) => {
|
(initialTab: UserFriendModalTab, userId: string) => {
|
||||||
@@ -167,7 +157,6 @@ export function useUserDetails() {
|
|||||||
patchUser,
|
patchUser,
|
||||||
sendFriendRequest,
|
sendFriendRequest,
|
||||||
fetchFriendRequests,
|
fetchFriendRequests,
|
||||||
syncFriendRequests,
|
|
||||||
updateFriendRequestState,
|
updateFriendRequestState,
|
||||||
blockUser,
|
blockUser,
|
||||||
unblockUser,
|
unblockUser,
|
||||||
|
|||||||
Reference in New Issue
Block a user