feat: adding image processing

This commit is contained in:
Chubby Granny Chaser
2024-09-14 00:09:34 +01:00
18 changed files with 165 additions and 77 deletions

View File

@@ -3,11 +3,8 @@ import path from "node:path";
export const defaultDownloadsPath = app.getPath("downloads");
export const databasePath = path.join(
app.getPath("appData"),
"hydra",
"hydra.db"
);
export const databaseDirectory = path.join(app.getPath("appData"), "hydra");
export const databasePath = path.join(databaseDirectory, "hydra.db");
export const logsPath = path.join(app.getPath("appData"), "hydra", "logs");

View File

@@ -54,6 +54,7 @@ import "./profile/get-me";
import "./profile/undo-friendship";
import "./profile/update-friend-request";
import "./profile/update-profile";
import "./profile/process-profile-image";
import "./profile/send-friend-request";
import { isPortableVersion } from "@main/helpers";

View File

@@ -0,0 +1,11 @@
import { registerEvent } from "../register-event";
import { PythonInstance } from "@main/services";
const processProfileImage = async (
_event: Electron.IpcMainInvokeEvent,
path: string
) => {
return PythonInstance.processProfileImage(path);
};
registerEvent("processProfileImage", processProfileImage);

View File

@@ -1,50 +1,54 @@
import { registerEvent } from "../register-event";
import { HydraApi, logger } from "@main/services";
import axios from "axios";
import { HydraApi, PythonInstance } from "@main/services";
import fs from "node:fs";
import path from "node:path";
import { fileTypeFromFile } from "file-type";
import type { UpdateProfileRequest, UserProfile } from "@types";
import { omit } from "lodash-es";
import axios from "axios";
interface PresignedResponse {
presignedUrl: string;
profileImageUrl: string;
}
const patchUserProfile = async (updateProfile: UpdateProfileRequest) => {
return HydraApi.patch("/profile", updateProfile);
return HydraApi.patch<UserProfile>("/profile", updateProfile);
};
const getNewProfileImageUrl = async (localImageUrl: string) => {
const { imagePath, mimeType } =
await PythonInstance.processProfileImage(localImageUrl);
const stats = fs.statSync(imagePath);
const fileBuffer = fs.readFileSync(imagePath);
const fileSizeInBytes = stats.size;
const { presignedUrl, profileImageUrl } =
await HydraApi.post<PresignedResponse>(`/presigned-urls/profile-image`, {
imageExt: path.extname(imagePath).slice(1),
imageLength: fileSizeInBytes,
});
await axios.put(presignedUrl, fileBuffer, {
headers: {
"Content-Type": mimeType,
},
});
return profileImageUrl;
};
const updateProfile = async (
_event: Electron.IpcMainInvokeEvent,
updateProfile: UpdateProfileRequest
): Promise<UserProfile> => {
) => {
if (!updateProfile.profileImageUrl) {
return patchUserProfile(updateProfile);
return patchUserProfile(omit(updateProfile, "profileImageUrl"));
}
const newProfileImagePath = updateProfile.profileImageUrl;
const stats = fs.statSync(newProfileImagePath);
const fileBuffer = fs.readFileSync(newProfileImagePath);
const fileSizeInBytes = stats.size;
const profileImageUrl = await HydraApi.post(`/presigned-urls/profile-image`, {
imageExt: path.extname(newProfileImagePath).slice(1),
imageLength: fileSizeInBytes,
})
.then(async (preSignedResponse) => {
const { presignedUrl, profileImageUrl } = preSignedResponse;
const mimeType = await fileTypeFromFile(newProfileImagePath);
await axios.put(presignedUrl, fileBuffer, {
headers: {
"Content-Type": mimeType?.mime,
},
});
return profileImageUrl as string;
})
.catch((err) => {
logger.error("Error uploading profile image", err);
return undefined;
});
const profileImageUrl = await getNewProfileImageUrl(
updateProfile.profileImageUrl
).catch(() => undefined);
return patchUserProfile({ ...updateProfile, profileImageUrl });
};

View File

@@ -4,12 +4,14 @@ import updater from "electron-updater";
import i18n from "i18next";
import path from "node:path";
import url from "node:url";
import fs from "node:fs";
import { electronApp, optimizer } from "@electron-toolkit/utils";
import { logger, PythonInstance, WindowManager } from "@main/services";
import { dataSource } from "@main/data-source";
import resources from "@locales";
import { userPreferencesRepository } from "@main/repository";
import { knexClient, migrationConfig } from "./knex-client";
import { databaseDirectory } from "./constants";
const { autoUpdater } = updater;
@@ -54,6 +56,10 @@ if (process.defaultApp) {
}
const runMigrations = async () => {
if (!fs.existsSync(databaseDirectory)) {
fs.mkdirSync(databaseDirectory, { recursive: true });
}
await knexClient.migrate.list(migrationConfig).then((result) => {
logger.log(
"Migrations to run:",

View File

@@ -166,6 +166,14 @@ export class PythonInstance {
this.downloadingGameId = -1;
}
static async processProfileImage(imagePath: string) {
return this.rpc
.post<{ imagePath: string; mimeType: string }>("/profile-image", {
image_path: imagePath,
})
.then((response) => response.data);
}
private static async handleRpcError(_error: unknown) {
await this.rpc.get("/healthcheck").catch(() => {
logger.error(