Skip to content

Commit

Permalink
fix(blob-storage-manager): add the following fixes to the file system…
Browse files Browse the repository at this point in the history
… storage:

- Do not throw error if the blob to removed doesn't exists
- Create blob directory and files with full permissions
  • Loading branch information
PJColombo committed May 8, 2024
1 parent 6310360 commit fad721d
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 45 deletions.
5 changes: 5 additions & 0 deletions .changeset/slimy-jars-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/blob-storage-manager": patch
---

Fixed file system storage issue where blob removal operation was throwing error if the blob path didn't exists
5 changes: 5 additions & 0 deletions .changeset/tough-parents-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/blob-storage-manager": patch
---

Fixed file system storage issue where files and directories were not being created with the correct full permissions
23 changes: 13 additions & 10 deletions packages/blob-storage-manager/src/storages/FileSystemStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import path from "path";
import { BlobStorage } from "../BlobStorage";
import type { BlobStorageConfig } from "../BlobStorage";
import { StorageCreationError } from "../errors";
import { BLOB_STORAGE_NAMES } from "../utils";
import {
BLOB_STORAGE_NAMES,
createFullPermissionDirectory,
createFullPermissionFile,
} from "../utils";

export interface FileSystemStorageConfig extends BlobStorageConfig {
blobDirPath: string;
Expand All @@ -18,9 +22,7 @@ export class FileSystemStorage extends BlobStorage {

this.blobDirPath = blobDirPath;

if (!fs.existsSync(this.blobDirPath)) {
fs.mkdirSync(this.blobDirPath);
}
createFullPermissionDirectory(this.blobDirPath);
}

protected async _healthCheck(): Promise<void> {
Expand All @@ -38,7 +40,11 @@ export class FileSystemStorage extends BlobStorage {
}

protected async _removeBlob(uri: string): Promise<void> {
await fs.promises.unlink(uri);
const fileExists = fs.existsSync(uri);

if (fileExists) {
return fs.promises.unlink(uri);
}
}

protected async _storeBlob(
Expand All @@ -48,11 +54,8 @@ export class FileSystemStorage extends BlobStorage {
const blobUri = this.getBlobUri(versionedHash);
const blobDirPath = blobUri.slice(0, blobUri.lastIndexOf("/"));

if (!fs.existsSync(blobDirPath)) {
fs.mkdirSync(blobDirPath, { recursive: true });
}

await fs.promises.writeFile(blobUri, data, { encoding: "utf-8" });
createFullPermissionDirectory(blobDirPath);
createFullPermissionFile(blobUri, data);

return blobUri;
}
Expand Down
3 changes: 3 additions & 0 deletions packages/blob-storage-manager/src/utils/blob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function calculateBlobBytes(blob: string): number {
return blob.slice(2).length / 2;
}
22 changes: 22 additions & 0 deletions packages/blob-storage-manager/src/utils/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import fs from "fs";

function performFullPermissionOp(operation: () => void) {
const oldUmask = process.umask(0);

try {
operation();
} finally {
process.umask(oldUmask);
}
}
export function createFullPermissionDirectory(dirPath: string) {
performFullPermissionOp(() => {
fs.mkdirSync(dirPath, { recursive: true, mode: 0o777 });
});
}

export function createFullPermissionFile(filePath: string, data: string) {
performFullPermissionOp(() => {
fs.writeFileSync(filePath, data, { encoding: "utf-8", mode: 0o777 });
});
}
3 changes: 3 additions & 0 deletions packages/blob-storage-manager/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./blob";
export * from "./file";
export * from "./storage";
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { $Enums, prisma } from "@blobscan/db";

import type { BlobStorage } from "./BlobStorage";
import { env } from "./env";
import type { BlobStorage } from "../BlobStorage";
import { env } from "../env";
import {
FileSystemStorage,
GoogleStorage,
PostgresStorage,
SwarmStorage,
} from "./storages";
import type { BlobStorageName } from "./types";
} from "../storages";
import type { BlobStorageName } from "../types";

export const BLOB_STORAGE_NAMES = $Enums.BlobStorage;

Expand All @@ -21,10 +21,6 @@ export function removeDuplicatedStorages(
);
}

export function calculateBlobBytes(blob: string): number {
return blob.slice(2).length / 2;
}

export async function createStorageFromEnv(
storageName: BlobStorageName
): Promise<BlobStorage> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,6 @@ describe("FileSystemStorage", () => {
"Blob file should not exist after removal"
).toBeFalsy();
});

testValidError(
"should throw a valid error if trying to remove a non-existent blob",
async () => {
await storage.removeBlob("missing-blob");
},
BlobStorageError,
{
checkCause: true,
}
);
});

describe("when storing a blob", () => {
Expand Down
12 changes: 0 additions & 12 deletions packages/blob-storage-manager/test/storages/SwarmStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { prisma } from "@blobscan/db";
import { fixtures, testValidError } from "@blobscan/test";

import { env } from "../../src/env";
import { BlobStorageError } from "../../src/errors";
import { SwarmStorage } from "../../src/storages/SwarmStorage";
import type { SwarmStorageConfig } from "../../src/storages/SwarmStorage";
import { NEW_BLOB_DATA, NEW_BLOB_HASH, SWARM_REFERENCE } from "../fixtures";
Expand Down Expand Up @@ -131,17 +130,6 @@ describe("SwarmStorage", () => {
await expect(storage.getBlob(ref)).rejects.toThrowError();
});

testValidError(
"should throw a valid error if trying to remove a non-existent blob",
async () => {
await storage.removeBlob("missing-blob");
},
BlobStorageError,
{
checkCause: true,
}
);

it("should store a blob", async () => {
const uploadReference = await storage.storeBlob(
NEW_BLOB_HASH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,3 @@
exports[`FileSystemStorage > when getting a blob > should throw a valid error when getting a non-existent blob 1`] = `"FileSystemStorageMock failed: Failed to get blob with uri \\"missing-blob\\""`;

exports[`FileSystemStorage > when getting a blob > should throw a valid error when getting a non-existent blob 2`] = `[Error: Blob file missing-blob missing: Error: ENOENT: no such file or directory, open 'missing-blob']`;

exports[`FileSystemStorage > when removing a blob > should throw a valid error if trying to remove a non-existent blob 1`] = `"FileSystemStorageMock failed: Failed to remove blob with uri \\"missing-blob\\""`;

exports[`FileSystemStorage > when removing a blob > should throw a valid error if trying to remove a non-existent blob 2`] = `[Error: ENOENT: no such file or directory, unlink 'missing-blob']`;

0 comments on commit fad721d

Please sign in to comment.