Skip to content

Commit

Permalink
Merge pull request #2 from hyper63/tillathehun0/return-hyper-esque-1
Browse files Browse the repository at this point in the history
fix!: resolve hyper error and bubble rejected non-handled exceptions #1
  • Loading branch information
TillaTheHun0 committed Mar 2, 2022
2 parents af8c77e + f054a16 commit 0f556fe
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 127 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: Test

on:
push:
branches: '*'
tags-ignore: '*'
branches: "**"
tags-ignore: "*"

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
deno-version: [1.11.x]
deno-version: [1.x]
steps:
- uses: actions/checkout@v2
- name: Use Deno ${{ matrix.deno-version }}
Expand Down
156 changes: 68 additions & 88 deletions adapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { crocks, path, R } from "./deps.js";
import { handleHyperErr, HyperErr } from "./utils.js";

const { Async } = crocks;
const { always, identity } = R;
Expand All @@ -10,7 +11,6 @@ const { always, identity } = R;
* as the implementation details for
* the storage port.
*
*
* @typedef {Object} StorageInfo
* @property {string} bucket
* @property {string} object
Expand All @@ -34,22 +34,31 @@ export default function (root) {
"STORAGE: FS_Adapter: root directory required for this service!",
);
}

const open = Async.fromPromise(Deno.open.bind(Deno));
const mkdir = Async.fromPromise(Deno.mkdir.bind(Deno));
const rm = Async.fromPromise(Deno.remove.bind(Deno));
const rmdir = Async.fromPromise(Deno.remove.bind(Deno));
const create = Async.fromPromise(Deno.create.bind(Deno));
const copy = Async.fromPromise(Deno.copy.bind(Deno));

const resolvePath = (...pieces) => path.resolve(path.join(root, ...pieces));

/**
* @param {string} name
* @returns {Promise<Response>}
*/
function makeBucket(name) {
if (!name) {
return Promise.reject({ ok: false, msg: "name for bucket is required!" });
}

const mkdir = Async.fromPromise(Deno.mkdir.bind(Deno));

return mkdir(path.resolve(path.join(root, name)))
return Async.of(resolvePath(name))
.chain(mkdir)
.bimap(
(err) => ({ ok: false, error: err.message }),
(err) => HyperErr({ msg: err.message }),
always({ ok: true }),
)
.bichain(
handleHyperErr,
Async.Resolved,
)
.toPromise();
}

Expand All @@ -58,130 +67,101 @@ export default function (root) {
* @returns {Promise<Response>}
*/
function removeBucket(name) {
if (!name) {
return Promise.reject({ ok: false, msg: "name for bucket is required!" });
}

const rmdir = Async.fromPromise(Deno.remove.bind(Deno));

// TODO: Tyler. Do we want to do a recursive remove here?
return rmdir(path.resolve(path.join(root, name)))
return Async.of(resolvePath(name))
// deletes all contents of directory, then directory
.chain((bucket) => rmdir(bucket, { recursive: true }))
.bimap(
(err) => ({ ok: false, error: err.message }),
(err) => HyperErr({ msg: err.message }),
always({ ok: true }),
)
.bichain(
handleHyperErr,
Async.Resolved,
)
.toPromise();
}

/**
* @param {StorageObject}
* @returns {Promise<Response>}
*/
async function putObject({ bucket, object, stream }) {
if (!bucket) {
return Promise.reject({ ok: false, msg: "bucket name required" });
}
if (!object) {
return Promise.reject({ ok: false, msg: "object name required" });
}
if (!stream) {
return Promise.reject({ ok: false, msg: "stream is required" });
}

let file;
try {
// Create Writer
file = await Deno.create(
path.join(
path.resolve(path.join(root, bucket)),
object,
),
);

function putObject({ bucket, object, stream }) {
// Create Writer
return Async.of(resolvePath(bucket, object))
.chain(create)
// Copy Reader into Writer
await Deno.copy(stream, file);

return { ok: true };
} catch (err) {
return { ok: false, msg: err.message };
} finally {
file && await file.close();
}
.chain((file) => {
const close = Async.fromPromise(() => Promise.resolve(file.close()));

return copy(stream, file)
.bichain(
(err) => close().map(always(err)),
(res) => close().map(always(res)),
);
})
.bimap(
(err) => HyperErr({ msg: err.message }),
always({ ok: true }),
)
.bichain(
handleHyperErr,
Async.Resolved,
).toPromise();
}

/**
* @param {StorageInfo}
* @returns {Promise<Response>}
*/
function removeObject({ bucket, object }) {
if (!bucket) {
return Promise.reject({ ok: false, msg: "bucket name required" });
}
if (!object) {
return Promise.reject({ ok: false, msg: "object name required" });
}

const rm = Async.fromPromise(Deno.remove.bind(Deno));

return rm(
path.resolve(path.join(root, bucket, object)),
).bimap(
(err) => ({ ok: false, error: err.message }),
always({ ok: true }),
).toPromise();
return Async.of(resolvePath(bucket, object))
.chain(rm)
.bimap(
(err) => HyperErr({ msg: err.message }),
always({ ok: true }),
).bichain(
handleHyperErr,
Async.Resolved,
).toPromise();
}

/**
* @param {StorageInfo}
* @returns {Promise<stream>}
*/
function getObject({ bucket, object }) {
if (!bucket) {
return Promise.reject({ ok: false, msg: "bucket name required" });
}
if (!object) {
return Promise.reject({ ok: false, msg: "object name required" });
}

const open = Async.fromPromise(Deno.open.bind(Deno));

return open(
path.resolve(path.join(root, bucket, object)),
{
read: true,
write: false,
},
).bimap(
(err) => ({ ok: false, msg: err.message }),
identity,
).toPromise();
return Async.of(resolvePath(bucket, object))
.chain((p) => open(p, { read: true, write: false }))
.bimap(
(err) => HyperErr({ msg: err.message }),
identity,
).bichain(
handleHyperErr,
Async.Resolved,
).toPromise();
}

async function listObjects({ bucket, prefix = "" }) {
if (!bucket) {
return Promise.reject({ ok: false, msg: "bucket name required" });
}

const files = [];
try {
for await (
const dirEntry of Deno.readDir(
path.resolve(path.join(root, bucket, prefix)),
resolvePath(bucket, prefix),
)
) {
files.push(dirEntry.name);
}

return files;
} catch (err) {
return { ok: false, error: err.message };
return Promise.resolve(HyperErr({ msg: err.message }));
}
}

return Object.freeze({
makeBucket,
removeBucket,
listBuckets: () => null,
listBuckets: () => Promise.resolve(null),
putObject,
removeObject,
getObject,
Expand Down
9 changes: 8 additions & 1 deletion adapter_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import createAdapter from "./adapter.js";

const v4 = v4Generator.generate.bind(v4Generator);

const adapter = createAdapter("./");
const adapter = createAdapter("./tmp");

function emptyReader() {
return {
Expand Down Expand Up @@ -59,6 +59,13 @@ function textReader(text = "") {
return { read };
}

for await (const dirEntry of Deno.readDir("./tmp")) {
if (dirEntry.isDirectory) {
console.log("deleting test bucket: ", dirEntry);
await Deno.remove(`./tmp/${dirEntry.name}`, { recursive: true });
}
}

Deno.test("fs adapter make bucket", async () => {
const bucket = v4();
const result = await adapter.makeBucket(bucket);
Expand Down
6 changes: 3 additions & 3 deletions deps.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * as R from "https://cdn.skypack.dev/ramda@^0.27.1";
export { default as crocks } from "https://cdn.skypack.dev/crocks@^0.12.4";
export * as R from "https://cdn.skypack.dev/ramda@0.28.0";
export { default as crocks } from "https://cdn.skypack.dev/[email protected]";

export * as path from "https://deno.land/std@0.98.0/path/mod.ts";
export * as path from "https://deno.land/std@0.127.0/path/mod.ts";
Loading

0 comments on commit 0f556fe

Please sign in to comment.