mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
refactor: 🚨 Make more class methods static
This commit is contained in:
parent
5ec19f037a
commit
2537e3cd48
|
|
@ -15,13 +15,13 @@ import {
|
||||||
import { rm } from "node:fs/promises";
|
import { rm } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import type { Config } from "~/packages/config-manager/config.type";
|
import type { Config } from "~/packages/config-manager/config.type";
|
||||||
import type { MediaHasher } from "../media-hasher";
|
import type { getMediaHash } from "../media-hasher";
|
||||||
import { DiskMediaDriver } from "./disk";
|
import { DiskMediaDriver } from "./disk";
|
||||||
|
|
||||||
describe("DiskMediaDriver", () => {
|
describe("DiskMediaDriver", () => {
|
||||||
let diskDriver: DiskMediaDriver;
|
let diskDriver: DiskMediaDriver;
|
||||||
let mockConfig: Config;
|
let mockConfig: Config;
|
||||||
let mockMediaHasher: MediaHasher;
|
let mockMediaHasher: Mock<typeof getMediaHash>;
|
||||||
let bunWriteSpy: Mock<typeof Bun.write>;
|
let bunWriteSpy: Mock<typeof Bun.write>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
@ -31,9 +31,11 @@ describe("DiskMediaDriver", () => {
|
||||||
},
|
},
|
||||||
} as Config;
|
} as Config;
|
||||||
|
|
||||||
mockMediaHasher = mock(() => ({
|
mockMediaHasher = mock(() => Promise.resolve("testhash"));
|
||||||
getMediaHash: mock(() => Promise.resolve("testhash")),
|
|
||||||
}))();
|
mock.module("../media-hasher", () => ({
|
||||||
|
getMediaHash: mockMediaHasher,
|
||||||
|
}));
|
||||||
|
|
||||||
diskDriver = new DiskMediaDriver(mockConfig);
|
diskDriver = new DiskMediaDriver(mockConfig);
|
||||||
// @ts-expect-error: Replacing private property for testing
|
// @ts-expect-error: Replacing private property for testing
|
||||||
|
|
@ -65,7 +67,7 @@ describe("DiskMediaDriver", () => {
|
||||||
const file = new File(["test"], "test.webp", { type: "image/webp" });
|
const file = new File(["test"], "test.webp", { type: "image/webp" });
|
||||||
const result = await diskDriver.addFile(file);
|
const result = await diskDriver.addFile(file);
|
||||||
|
|
||||||
expect(mockMediaHasher.getMediaHash).toHaveBeenCalledWith(file);
|
expect(mockMediaHasher).toHaveBeenCalledWith(file);
|
||||||
expect(bunWriteSpy).toHaveBeenCalledWith(
|
expect(bunWriteSpy).toHaveBeenCalledWith(
|
||||||
join("/test/uploads", "testhash", "test.webp"),
|
join("/test/uploads", "testhash", "test.webp"),
|
||||||
expect.any(ArrayBuffer),
|
expect.any(ArrayBuffer),
|
||||||
|
|
@ -81,7 +83,7 @@ describe("DiskMediaDriver", () => {
|
||||||
const file = new Blob(["test"], { type: "image/webp" });
|
const file = new Blob(["test"], { type: "image/webp" });
|
||||||
const result = await diskDriver.addFile(file as File);
|
const result = await diskDriver.addFile(file as File);
|
||||||
|
|
||||||
expect(mockMediaHasher.getMediaHash).toHaveBeenCalledWith(file);
|
expect(mockMediaHasher).toHaveBeenCalledWith(file);
|
||||||
expect(bunWriteSpy).toHaveBeenCalledWith(
|
expect(bunWriteSpy).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("testhash"),
|
expect.stringContaining("testhash"),
|
||||||
expect.any(ArrayBuffer),
|
expect.any(ArrayBuffer),
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
import { rm } from "node:fs/promises";
|
import { rm } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import type { Config } from "~/packages/config-manager/config.type";
|
import type { Config } from "~/packages/config-manager/config.type";
|
||||||
import { MediaHasher } from "../media-hasher";
|
import { getMediaHash } from "../media-hasher";
|
||||||
import type { UploadedFileMetadata } from "../media-manager";
|
import type { UploadedFileMetadata } from "../media-manager";
|
||||||
import type { MediaDriver } from "./media-driver";
|
import type { MediaDriver } from "./media-driver";
|
||||||
|
|
||||||
|
|
@ -14,15 +14,11 @@ import type { MediaDriver } from "./media-driver";
|
||||||
* Implements the MediaDriver interface for disk storage.
|
* Implements the MediaDriver interface for disk storage.
|
||||||
*/
|
*/
|
||||||
export class DiskMediaDriver implements MediaDriver {
|
export class DiskMediaDriver implements MediaDriver {
|
||||||
private mediaHasher: MediaHasher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new DiskMediaDriver instance.
|
* Creates a new DiskMediaDriver instance.
|
||||||
* @param config - The configuration object.
|
* @param config - The configuration object.
|
||||||
*/
|
*/
|
||||||
constructor(private config: Config) {
|
constructor(private config: Config) {}
|
||||||
this.mediaHasher = new MediaHasher();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
|
|
@ -33,7 +29,7 @@ export class DiskMediaDriver implements MediaDriver {
|
||||||
// Sometimes the file name is not available, so we generate a random name
|
// Sometimes the file name is not available, so we generate a random name
|
||||||
const fileName = file.name ?? crypto.randomUUID();
|
const fileName = file.name ?? crypto.randomUUID();
|
||||||
|
|
||||||
const hash = await this.mediaHasher.getMediaHash(file);
|
const hash = await getMediaHash(file);
|
||||||
const path = join(hash, fileName);
|
const path = join(hash, fileName);
|
||||||
const fullPath = join(this.config.media.local_uploads_folder, path);
|
const fullPath = join(this.config.media.local_uploads_folder, path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@
|
||||||
* @module Tests/S3MediaDriver
|
* @module Tests/S3MediaDriver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { beforeEach, describe, expect, it, mock } from "bun:test";
|
import { type Mock, beforeEach, describe, expect, it, mock } from "bun:test";
|
||||||
import type { S3Client } from "@bradenmacdonald/s3-lite-client";
|
import type { S3Client } from "@bradenmacdonald/s3-lite-client";
|
||||||
import type { Config } from "~/packages/config-manager/config.type";
|
import type { Config } from "~/packages/config-manager/config.type";
|
||||||
import type { MediaHasher } from "../media-hasher";
|
import type { getMediaHash } from "../media-hasher";
|
||||||
import { S3MediaDriver } from "./s3";
|
import { S3MediaDriver } from "./s3";
|
||||||
|
|
||||||
describe("S3MediaDriver", () => {
|
describe("S3MediaDriver", () => {
|
||||||
let s3Driver: S3MediaDriver;
|
let s3Driver: S3MediaDriver;
|
||||||
let mockConfig: Config;
|
let mockConfig: Config;
|
||||||
let mockS3Client: S3Client;
|
let mockS3Client: S3Client;
|
||||||
let mockMediaHasher: MediaHasher;
|
let mockMediaHasher: Mock<typeof getMediaHash>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
|
|
@ -38,9 +38,11 @@ describe("S3MediaDriver", () => {
|
||||||
deleteObject: mock(() => Promise.resolve()),
|
deleteObject: mock(() => Promise.resolve()),
|
||||||
}))() as unknown as S3Client;
|
}))() as unknown as S3Client;
|
||||||
|
|
||||||
mockMediaHasher = mock(() => ({
|
mockMediaHasher = mock(() => Promise.resolve("testhash"));
|
||||||
getMediaHash: mock(() => Promise.resolve("testhash")),
|
|
||||||
}))();
|
mock.module("../media-hasher", () => ({
|
||||||
|
getMediaHash: mockMediaHasher,
|
||||||
|
}));
|
||||||
|
|
||||||
s3Driver = new S3MediaDriver(mockConfig);
|
s3Driver = new S3MediaDriver(mockConfig);
|
||||||
// @ts-expect-error: Replacing private property for testing
|
// @ts-expect-error: Replacing private property for testing
|
||||||
|
|
@ -53,7 +55,7 @@ describe("S3MediaDriver", () => {
|
||||||
const file = new File(["test"], "test.webp", { type: "image/webp" });
|
const file = new File(["test"], "test.webp", { type: "image/webp" });
|
||||||
const result = await s3Driver.addFile(file);
|
const result = await s3Driver.addFile(file);
|
||||||
|
|
||||||
expect(mockMediaHasher.getMediaHash).toHaveBeenCalledWith(file);
|
expect(mockMediaHasher).toHaveBeenCalledWith(file);
|
||||||
expect(mockS3Client.putObject).toHaveBeenCalledWith(
|
expect(mockS3Client.putObject).toHaveBeenCalledWith(
|
||||||
"testhash/test.webp",
|
"testhash/test.webp",
|
||||||
expect.any(ReadableStream),
|
expect.any(ReadableStream),
|
||||||
|
|
@ -70,7 +72,7 @@ describe("S3MediaDriver", () => {
|
||||||
const file = new Blob(["test"], { type: "image/webp" });
|
const file = new Blob(["test"], { type: "image/webp" });
|
||||||
const result = await s3Driver.addFile(file as File);
|
const result = await s3Driver.addFile(file as File);
|
||||||
|
|
||||||
expect(mockMediaHasher.getMediaHash).toHaveBeenCalledWith(file);
|
expect(mockMediaHasher).toHaveBeenCalledWith(file);
|
||||||
expect(mockS3Client.putObject).toHaveBeenCalledWith(
|
expect(mockS3Client.putObject).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("testhash"),
|
expect.stringContaining("testhash"),
|
||||||
expect.any(ReadableStream),
|
expect.any(ReadableStream),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import { S3Client } from "@bradenmacdonald/s3-lite-client";
|
import { S3Client } from "@bradenmacdonald/s3-lite-client";
|
||||||
import type { Config } from "~/packages/config-manager/config.type";
|
import type { Config } from "~/packages/config-manager/config.type";
|
||||||
import { MediaHasher } from "../media-hasher";
|
import { getMediaHash } from "../media-hasher";
|
||||||
import type { UploadedFileMetadata } from "../media-manager";
|
import type { UploadedFileMetadata } from "../media-manager";
|
||||||
import type { MediaDriver } from "./media-driver";
|
import type { MediaDriver } from "./media-driver";
|
||||||
|
|
||||||
|
|
@ -14,7 +14,6 @@ import type { MediaDriver } from "./media-driver";
|
||||||
*/
|
*/
|
||||||
export class S3MediaDriver implements MediaDriver {
|
export class S3MediaDriver implements MediaDriver {
|
||||||
private s3Client: S3Client;
|
private s3Client: S3Client;
|
||||||
private mediaHasher: MediaHasher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new S3MediaDriver instance.
|
* Creates a new S3MediaDriver instance.
|
||||||
|
|
@ -29,7 +28,6 @@ export class S3MediaDriver implements MediaDriver {
|
||||||
accessKey: config.s3.access_key,
|
accessKey: config.s3.access_key,
|
||||||
secretKey: config.s3.secret_access_key,
|
secretKey: config.s3.secret_access_key,
|
||||||
});
|
});
|
||||||
this.mediaHasher = new MediaHasher();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,7 +39,7 @@ export class S3MediaDriver implements MediaDriver {
|
||||||
// Sometimes the file name is not available, so we generate a random name
|
// Sometimes the file name is not available, so we generate a random name
|
||||||
const fileName = file.name ?? crypto.randomUUID();
|
const fileName = file.name ?? crypto.randomUUID();
|
||||||
|
|
||||||
const hash = await this.mediaHasher.getMediaHash(file);
|
const hash = await getMediaHash(file);
|
||||||
const path = `${hash}/${fileName}`;
|
const path = `${hash}/${fileName}`;
|
||||||
|
|
||||||
await this.s3Client.putObject(path, file.stream(), {
|
await this.s3Client.putObject(path, file.stream(), {
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for hashing media files.
|
* Generates a SHA-256 hash for a given file.
|
||||||
|
* @param file - The file to hash.
|
||||||
|
* @returns A promise that resolves to the SHA-256 hash of the file in hex format.
|
||||||
*/
|
*/
|
||||||
export class MediaHasher {
|
export const getMediaHash = async (file: File): Promise<string> => {
|
||||||
/**
|
const arrayBuffer = await file.arrayBuffer();
|
||||||
* Generates a SHA-256 hash for a given file.
|
const hash = new Bun.SHA256().update(arrayBuffer).digest("hex");
|
||||||
* @param file - The file to hash.
|
return hash;
|
||||||
* @returns A promise that resolves to the SHA-256 hash of the file in hex format.
|
};
|
||||||
*/
|
|
||||||
public async getMediaHash(file: File): Promise<string> {
|
|
||||||
const arrayBuffer = await file.arrayBuffer();
|
|
||||||
const hash = new Bun.SHA256().update(arrayBuffer).digest("hex");
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,10 @@ export class ImageConversionPreprocessor implements MediaPreprocessor {
|
||||||
return {
|
return {
|
||||||
file: new File(
|
file: new File(
|
||||||
[convertedBuffer],
|
[convertedBuffer],
|
||||||
this.getReplacedFileName(file.name, commandName),
|
ImageConversionPreprocessor.getReplacedFileName(
|
||||||
|
file.name,
|
||||||
|
commandName,
|
||||||
|
),
|
||||||
{
|
{
|
||||||
type: targetFormat,
|
type: targetFormat,
|
||||||
lastModified: Date.now(),
|
lastModified: Date.now(),
|
||||||
|
|
@ -100,7 +103,7 @@ export class ImageConversionPreprocessor implements MediaPreprocessor {
|
||||||
* @param newExtension - The new extension.
|
* @param newExtension - The new extension.
|
||||||
* @returns The filename with the new extension.
|
* @returns The filename with the new extension.
|
||||||
*/
|
*/
|
||||||
private getReplacedFileName(
|
private static getReplacedFileName(
|
||||||
fileName: string,
|
fileName: string,
|
||||||
newExtension: string,
|
newExtension: string,
|
||||||
): string {
|
): string {
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ describe("PluginLoader", () => {
|
||||||
])
|
])
|
||||||
.mockResolvedValue(["manifest.json", "index.ts"]);
|
.mockResolvedValue(["manifest.json", "index.ts"]);
|
||||||
|
|
||||||
const plugins = await pluginLoader.findPlugins("/some/path");
|
const plugins = await PluginLoader.findPlugins("/some/path");
|
||||||
expect(plugins).toEqual(["plugin1", "plugin2"]);
|
expect(plugins).toEqual(["plugin1", "plugin2"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export class PluginLoader {
|
||||||
* @param {string} dir - The directory to search.
|
* @param {string} dir - The directory to search.
|
||||||
* @returns {Promise<string[]>} - An array of plugin directories.
|
* @returns {Promise<string[]>} - An array of plugin directories.
|
||||||
*/
|
*/
|
||||||
public async findPlugins(dir: string): Promise<string[]> {
|
public static async findPlugins(dir: string): Promise<string[]> {
|
||||||
const directories = await PluginLoader.getDirectories(dir);
|
const directories = await PluginLoader.getDirectories(dir);
|
||||||
const plugins: string[] = [];
|
const plugins: string[] = [];
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ export class PluginLoader {
|
||||||
public async loadPlugins(
|
public async loadPlugins(
|
||||||
dir: string,
|
dir: string,
|
||||||
): Promise<{ manifest: Manifest; plugin: Plugin<ZodTypeAny> }[]> {
|
): Promise<{ manifest: Manifest; plugin: Plugin<ZodTypeAny> }[]> {
|
||||||
const plugins = await this.findPlugins(dir);
|
const plugins = await PluginLoader.findPlugins(dir);
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
plugins.map(async (plugin) => {
|
plugins.map(async (plugin) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue