Skip to content

Commit

Permalink
Merge pull request #12 from GravityTwoG/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
GravityTwoG authored Mar 27, 2024
2 parents 3fa1328 + 19d6f32 commit cc0130c
Show file tree
Hide file tree
Showing 91 changed files with 2,765 additions and 834 deletions.
362 changes: 311 additions & 51 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"react-hook-form": "^7.49.3",
"react-hot-toast": "^2.4.1",
"react-i18next": "^14.1.0",
"react-select": "^5.8.0",
"wouter": "^3.0.0"
},
"volta": {
Expand Down
7 changes: 5 additions & 2 deletions src/@types/electron-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ interface Window {
) => Promise<
ElectronApiResponse<{
buffer: Buffer;
gameStateValues: import("../types").GameStateValues;
gameStateValues: {
gameStateParameterId: string;
value: string;
}[];
}>
>;

Expand All @@ -57,7 +60,7 @@ interface Window {
onGetSyncedSaves: (callback: () => void) => void;

sendSyncedSaves: (
args: import("../types").GameSave[]
args: import("../types").GameState[]
) => Promise<ElectronApiResponse<void>>;
};
}
7 changes: 4 additions & 3 deletions src/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { setupIPC } from "./backend/electron-api";
import { SyncManager } from "./backend/SyncManager";
import { syncManager } from "./backend";

const clientProtocol = "cloud-saves://";
const protocolName = "cloud-saves";
const clientProtocol = `${protocolName}://`;

export class Application {
private mainWindow: BrowserWindow | null = null;
Expand Down Expand Up @@ -95,12 +96,12 @@ export class Application {
private registerProtocolClient() {
if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient("cloud-saves", process.execPath, [
app.setAsDefaultProtocolClient(protocolName, process.execPath, [
path.resolve(process.argv[1]),
]);
}
} else {
app.setAsDefaultProtocolClient("cloud-saves");
app.setAsDefaultProtocolClient(protocolName);
}
}

Expand Down
26 changes: 13 additions & 13 deletions src/backend/GameSaveAPI.ts → src/backend/GameStateAPI.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { session } from "electron";
import { Game, GameSave } from "@/types";
import { SavesManager } from "./SavesManager";
import { Game, GameState } from "@/types";
import { StatesManager } from "./StatesManager";

export class GameSaveAPI {
private savesManager: SavesManager;
export class GameStateAPI {
private statesManager: StatesManager;

constructor(savesManager: SavesManager) {
this.savesManager = savesManager;
constructor(statesManager: StatesManager) {
this.statesManager = statesManager;
}

uploadSave = async (gameSave: GameSave) => {
const game = gameSave.gameId
? await this.getGame(gameSave.gameId)
uploadState = async (gameState: GameState) => {
const game = gameState.gameId
? await this.getGame(gameState.gameId)
: undefined;

const response = await this.savesManager.uploadSave(
{ name: gameSave.name, path: gameSave.path },
const response = await this.statesManager.uploadSave(
{ name: gameState.name, path: gameState.localPath },
game
);

Expand All @@ -34,8 +34,8 @@ export class GameSaveAPI {
return response;
};

downloadSave = async (gameSave: GameSave) => {
await this.savesManager.downloadSave(gameSave.path);
downloadState = async (gameState: GameState) => {
await this.statesManager.downloadState(gameState.localPath);
};

private async getGame(gameId: string): Promise<Game> {
Expand Down
12 changes: 6 additions & 6 deletions src/backend/SavesManager.ts → src/backend/StatesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from "fs/promises";
import { Game } from "@/types";
import { ValueExtractor } from "./game-state-parameters/ValueExtractor";

export class SavesManager {
export class StatesManager {
private readonly valueExtractor: ValueExtractor;

constructor(valueExtractor: ValueExtractor) {
Expand Down Expand Up @@ -33,21 +33,21 @@ export class SavesManager {
};
}

async downloadSave(archiveURL: string) {
async downloadState(archiveURL: string) {
// TODO
console.log("Downloading save", archiveURL);
console.log("Downloading state", archiveURL);
return { path: "" };
}

async downloadAndExtractSave(archiveURL: string, path: string) {
// TODO
const save = await this.downloadSave(archiveURL);
const state = await this.downloadState(archiveURL);
// TODO
this.extractZIP(save.path);
this.extractZIP(state.path);

console.log("Extracted to", path);

return save;
return state;
}

private extractZIP(filePath: string) {
Expand Down
77 changes: 39 additions & 38 deletions src/backend/SyncManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GameSave, GameSaveSync } from "@/types";
import { GameState, GameStateSync } from "@/types";
import { ipcMain } from "electron";
import { getModifiedAtMs } from "./fs/getModifiedAtMs";
import { GameSaveAPI } from "./GameSaveAPI";
import { GameStateAPI } from "./GameStateAPI";

const SECOND = 1000;
const MINUTE = 60 * SECOND;
Expand All @@ -11,26 +11,26 @@ const MIN_SYNC_PERIOD_MS = 1000 * 60;

export class SyncManager {
private intervalId: NodeJS.Timeout | null = null;
private gameSaveAPI: GameSaveAPI;
private gameStateAPI: GameStateAPI;

constructor(gameSaveAPI: GameSaveAPI) {
this.gameSaveAPI = gameSaveAPI;
constructor(gameStateAPI: GameStateAPI) {
this.gameStateAPI = gameStateAPI;
}

init(onGetSyncedSaves: () => void) {
init(onGetSyncedStates: () => void) {
this.intervalId = setInterval(() => {
onGetSyncedSaves();
onGetSyncedStates();
}, MIN_SYNC_PERIOD_MS);

let isSyncing = false;
ipcMain.handle("sendSyncedSaves", async (_, gameSaves: GameSave[]) => {
ipcMain.handle("sendSyncedSaves", async (_, gameStates: GameState[]) => {
if (isSyncing) {
return;
}

isSyncing = true;
await this.uploadSynced(gameSaves);
await this.downloadSynced(gameSaves);
await this.uploadSynced(gameStates);
await this.downloadSynced(gameStates);
isSyncing = false;
});
}
Expand All @@ -44,60 +44,61 @@ export class SyncManager {
ipcMain.removeAllListeners("sendSyncedSaves");
}

private async uploadSynced(gameSaves: GameSave[]) {
for (const gameSave of gameSaves) {
private async uploadSynced(gameStates: GameState[]) {
for (const gameState of gameStates) {
try {
const lastUploadMs = new Date(gameSave.uploadedAt).getTime();
const lastUploadMs = new Date(gameState.uploadedAt).getTime();
const currentTimeMs = new Date().getTime();
const periodMs = this.getPeriodInMs(gameSave.sync);
const periodMs = this.getPeriodInMs(gameState.sync);

console.log(
"lastUpload",
lastUploadMs,
"currentTime",
currentTimeMs,
"period",
periodMs
);
console.log("lastUpload", lastUploadMs, "currentTime", currentTimeMs);

if (currentTimeMs - lastUploadMs > periodMs && periodMs > 0) {
console.log("Uploading save", gameSave.path);
console.log("Uploading state", gameState.localPath);

await this.gameSaveAPI.uploadSave(gameSave);
await this.gameStateAPI.uploadState(gameState);
}
} catch (error) {
console.error(error);
if (error instanceof Error) {
console.error(error.message);
} else {
console.error(error);
}
}
}
}

private async downloadSynced(gameSaves: GameSave[]) {
for (const gameSave of gameSaves) {
const lastUploadMs = new Date(gameSave.uploadedAt).getTime();
const modifiedAtMs = await getModifiedAtMs(gameSave.path);
private async downloadSynced(gameStates: GameState[]) {
for (const gameState of gameStates) {
const lastUploadMs = new Date(gameState.uploadedAt).getTime();
const modifiedAtMs = await getModifiedAtMs(gameState.localPath);

try {
if (lastUploadMs > modifiedAtMs) {
console.log("Downloading save", gameSave.path);
await this.gameSaveAPI.downloadSave(gameSave);
console.log("Downloading state", gameState.localPath);
await this.gameStateAPI.downloadState(gameState);
}
} catch (error) {
console.error(error);
if (error instanceof Error) {
console.error(error.message);
} else {
console.error(error);
}
}
}
}

private getPeriodInMs(sync: GameSaveSync) {
private getPeriodInMs(sync: GameStateSync) {
switch (sync) {
case GameSaveSync.NO:
case GameStateSync.NO:
return -1;
case GameSaveSync.EVERY_HOUR:
case GameStateSync.EVERY_HOUR:
return HOUR;
case GameSaveSync.EVERY_DAY:
case GameStateSync.EVERY_DAY:
return 24 * HOUR;
case GameSaveSync.EVERY_WEEK:
case GameStateSync.EVERY_WEEK:
return 24 * 7 * HOUR;
case GameSaveSync.EVERY_MONTH:
case GameStateSync.EVERY_MONTH:
return 24 * 30 * HOUR;
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/backend/electron-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { dialog, ipcMain } from "electron";
import { Game, GamePath } from "@/types";

import { getFolderInfo } from "./fs/getFolderInfo";
import { getSavePaths } from "./fs/getSavePaths";
import { savesManager } from ".";
import { getStatePaths } from "./fs/getStatePaths";
import { statesManager } from ".";

export function setupIPC() {
ipcMain.handle("showFolderDialog", async () => {
Expand All @@ -24,7 +24,7 @@ export function setupIPC() {

ipcMain.handle("getSavePaths", async (_, paths: GamePath[]) => {
try {
const filteredPaths = await getSavePaths(paths);
const filteredPaths = await getStatePaths(paths);
return { data: filteredPaths };
} catch (error) {
return { data: null, error: (error as Error).toString() };
Expand All @@ -49,7 +49,7 @@ export function setupIPC() {
game: Game
) => {
try {
const data = await savesManager.uploadSave(folder, game);
const data = await statesManager.uploadSave(folder, game);
return { data };
} catch (error) {
return { data: null, error: (error as Error)?.toString() };
Expand All @@ -59,7 +59,7 @@ export function setupIPC() {

ipcMain.handle("downloadSave", async (_, archiveURL: string) => {
try {
await savesManager.downloadSave(archiveURL);
await statesManager.downloadState(archiveURL);
return { data: null };
} catch (error) {
return { data: null, error: (error as Error).toString() };
Expand All @@ -70,7 +70,7 @@ export function setupIPC() {
"downloadAndExtractSave",
async (_, archiveURL: string, path: string) => {
try {
await savesManager.downloadAndExtractSave(archiveURL, path);
await statesManager.downloadAndExtractSave(archiveURL, path);
return { data: null };
} catch (error) {
return { data: null, error: (error as Error).toString() };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function replaceShorthands(path: string) {
return path;
}

export async function getSavePaths(paths: GamePath[]): Promise<GamePath[]> {
export async function getStatePaths(paths: GamePath[]): Promise<GamePath[]> {
const validPaths: GamePath[] = [];

for (const gamePath of paths) {
Expand Down
Loading

0 comments on commit cc0130c

Please sign in to comment.