Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
f3a0ff1f63 | |||
8bc939173a | |||
410c16a717 | |||
f809631451 | |||
226bf990b9 | |||
f3e2a8a4f2 | |||
0430a35873 | |||
a074a9558d | |||
e8cc232fa1 | |||
89f48cea21 | |||
784e54f021 | |||
95065de1b5 | |||
ea9d0f58e9 | |||
9592ab863a | |||
b60ece389c | |||
121c71102a | |||
ec8f320317 | |||
cca3ade103 | |||
caedf37288 | |||
9255875d83 | |||
346269d399 | |||
4bb6e2ef51 | |||
0ec7e1d6c6 | |||
bac986ac85 | |||
476ff5bbce | |||
178c360b89 | |||
191e0b8e05 | |||
7d6bbd289d | |||
3f5461dfe0 | |||
78ec895a39 | |||
0b14904027 | |||
a8ce2f75b7 | |||
c383b75336 | |||
d5d3105a98 | |||
6b69edb3ef | |||
77e69171e2 | |||
365eea59bd | |||
1a64835510 | |||
b61a86f029 | |||
b9d082f07f | |||
4819dd0bc5 | |||
7250793f95 | |||
8fb5e89714 | |||
9dbd19d1a9 | |||
43d29947c5 | |||
d715ed7bb8 | |||
9c2af1931b | |||
c58f465189 | |||
5506db9612 | |||
0fcfba2973 | |||
cba7c11eea | |||
51c6b29b58 | |||
1089c8f3ec | |||
789ff96cf0 | |||
1b49699663 | |||
aa209e87c1 | |||
9ad70a9942 | |||
bc41089925 | |||
ab39809c2a | |||
cede6c7539 | |||
547692ac62 | |||
5410df0011 | |||
5b8a55d6d2 | |||
61145d5e80 | |||
6596893ee5 | |||
514a8407f6 | |||
fcadbe0a44 | |||
e6398ebbe3 | |||
8a7824f2d9 | |||
b61118c950 | |||
905f7d189f | |||
6d856b3647 | |||
fea4645cdd | |||
5896791b14 | |||
27fb5f3291 | |||
34d7ef2686 | |||
fbac742db2 | |||
3456459456 | |||
c4374da42a | |||
7ba61904ee | |||
f5da38592e | |||
caf0566020 | |||
c333533c63 | |||
2317562e87 | |||
9f0b1dab55 | |||
9b84cf8bc0 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,8 +15,6 @@ node_modules/
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_web/
|
||||
dist_serve/
|
||||
dist_ts_web/
|
||||
dist_*/
|
||||
|
||||
# custom
|
106
.gitlab-ci.yml
106
.gitlab-ci.yml
@ -3,14 +3,17 @@ image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: "$CI_BUILD_STAGE"
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
before_script:
|
||||
- npm install -g @shipzone/npmci
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
@ -18,21 +21,37 @@ stages:
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
snyk:
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install -g snyk
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command snyk test
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
@ -41,37 +60,36 @@ snyk:
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- priv
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
@ -79,34 +97,38 @@ release:
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci command npm install -g typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- docker
|
||||
- priv
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci command npm install -g @git.zone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
@ -114,5 +136,5 @@ pages:
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
- public
|
||||
allow_failure: true
|
||||
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -3,12 +3,13 @@
|
||||
"npmGlobalTools": []
|
||||
},
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"gitscope": "push.rocks",
|
||||
"gitrepo": "smartbucket",
|
||||
"shortDescription": "simple cloud independent object storage",
|
||||
"npmPackagename": "@pushrocks/smartbucket",
|
||||
"description": "simple cloud independent object storage",
|
||||
"npmPackagename": "@push.rocks/smartbucket",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
12420
package-lock.json
generated
12420
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@ -1,38 +1,45 @@
|
||||
{
|
||||
"name": "@pushrocks/smartbucket",
|
||||
"version": "1.0.6",
|
||||
"name": "@push.rocks/smartbucket",
|
||||
"version": "2.0.3",
|
||||
"description": "simple cloud independent object storage",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
"author": "Lossless GmbH",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"test": "tstest test/",
|
||||
"format": "(gitzone format)",
|
||||
"build": "echo \"Not needed for now\""
|
||||
"test": "(tstest test/)",
|
||||
"build": "(tsbuild --web --allowimplicitany)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.1.17",
|
||||
"@gitzone/tstest": "^1.0.28",
|
||||
"@pushrocks/tapbundle": "^3.0.13",
|
||||
"tslint": "^5.20.0",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
"@git.zone/tsrun": "^1.2.46",
|
||||
"@git.zone/tsbuild": "^2.1.63",
|
||||
"@git.zone/tstest": "^1.0.71",
|
||||
"@push.rocks/qenv": "^6.0.4",
|
||||
"@push.rocks/tapbundle": "^5.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pushrocks/smartpromise": "^3.0.6",
|
||||
"@types/minio": "^7.0.3",
|
||||
"minio": "^7.0.12"
|
||||
"@push.rocks/smartpath": "^5.0.5",
|
||||
"@push.rocks/smartpromise": "^4.0.3",
|
||||
"@push.rocks/smartrx": "^3.0.7",
|
||||
"@push.rocks/smartstream": "^2.0.2",
|
||||
"@types/minio": "^7.0.13",
|
||||
"minio": "^7.0.28"
|
||||
},
|
||||
"private": true,
|
||||
"private": false,
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_web/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
}
|
||||
|
6113
pnpm-lock.yaml
generated
Normal file
6113
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
readme.md
31
readme.md
@ -1,23 +1,36 @@
|
||||
# @pushrocks/smartbucket
|
||||
# @push.rocks/smartbucket
|
||||
simple cloud independent object storage
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartbucket)
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@push.rocks/smartbucket)
|
||||
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartbucket)
|
||||
* [github.com (source mirror)](https://github.com/pushrocks/smartbucket)
|
||||
* [docs (typedoc)](https://pushrocks.gitlab.io/smartbucket/)
|
||||
|
||||
## Status for master
|
||||
[](https://gitlab.com/pushrocks/smartbucket/commits/master)
|
||||
[](https://gitlab.com/pushrocks/smartbucket/commits/master)
|
||||
[](https://www.npmjs.com/package/@pushrocks/smartbucket)
|
||||
[](https://snyk.io/test/npm/@pushrocks/smartbucket)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://prettier.io/)
|
||||
|
||||
Status Category | Status Badge
|
||||
-- | --
|
||||
GitLab Pipelines | [](https://lossless.cloud)
|
||||
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||
npm | [](https://lossless.cloud)
|
||||
Snyk | [](https://lossless.cloud)
|
||||
TypeScript Support | [](https://lossless.cloud)
|
||||
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
Code Style | [](https://lossless.cloud)
|
||||
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||
Platform support | [](https://lossless.cloud) [](https://lossless.cloud)
|
||||
|
||||
## Usage
|
||||
|
||||
Use TypeScript for best in class intellisense.
|
||||
|
||||
## Contribution
|
||||
|
||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
|
88
test/test.ts
88
test/test.ts
@ -1,8 +1,88 @@
|
||||
import { expect, tap } from '@pushrocks/tapbundle';
|
||||
import * as smartbucket from '../ts/index';
|
||||
import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
|
||||
import { Qenv } from '@push.rocks/qenv';
|
||||
|
||||
tap.test('first test', async () => {
|
||||
console.log('hi');
|
||||
import * as smartbucket from '../ts/index.js';
|
||||
|
||||
const testQenv = new Qenv('./', './.nogit/');
|
||||
|
||||
let testSmartbucket: smartbucket.SmartBucket;
|
||||
let myBucket: smartbucket.Bucket;
|
||||
let baseDirectory: smartbucket.Directory;
|
||||
|
||||
tap.test('should create a valid smartbucket', async () => {
|
||||
testSmartbucket = new smartbucket.SmartBucket({
|
||||
accessKey: await testQenv.getEnvVarOnDemand('S3_KEY'),
|
||||
accessSecret: await testQenv.getEnvVarOnDemand('S3_SECRET'),
|
||||
endpoint: 's3.eu-central-1.wasabisys.com',
|
||||
});
|
||||
});
|
||||
|
||||
tap.skip.test('should create testbucket', async () => {
|
||||
// await testSmartbucket.createBucket('testzone');
|
||||
});
|
||||
|
||||
tap.skip.test('should remove testbucket', async () => {
|
||||
// await testSmartbucket.removeBucket('testzone');
|
||||
});
|
||||
|
||||
tap.test('should get a bucket', async () => {
|
||||
myBucket = await testSmartbucket.getBucketByName('testzone');
|
||||
expect(myBucket).toBeInstanceOf(smartbucket.Bucket);
|
||||
expect(myBucket.name).toEqual('testzone');
|
||||
});
|
||||
|
||||
// Fast operations
|
||||
tap.test('should store data in bucket fast', async () => {
|
||||
await myBucket.fastStore('hithere/socool.txt', 'hi there!');
|
||||
});
|
||||
|
||||
tap.test('should get data in bucket', async () => {
|
||||
const fileString = await myBucket.fastGet('hithere/socool.txt');
|
||||
const fileStringStream = await myBucket.fastGetStream('hithere/socool.txt');
|
||||
console.log(fileString);
|
||||
});
|
||||
|
||||
tap.test('should delete data in bucket', async () => {
|
||||
await myBucket.fastRemove('hithere/socool.txt');
|
||||
});
|
||||
|
||||
// fs operations
|
||||
|
||||
tap.test('prepare for directory style tests', async () => {
|
||||
await myBucket.fastStore('dir1/file1.txt', 'dir1/file1.txt content');
|
||||
await myBucket.fastStore('dir1/file2.txt', 'dir1/file2.txt content');
|
||||
await myBucket.fastStore('dir2/file1.txt', 'dir2/file1.txt content');
|
||||
await myBucket.fastStore('dir3/file1.txt', 'dir3/file1.txt content');
|
||||
await myBucket.fastStore('dir3/dir4/file1.txt', 'dir3/dir4/file1.txt content');
|
||||
await myBucket.fastStore('file1.txt', 'file1 content');
|
||||
});
|
||||
|
||||
tap.test('should get base directory', async () => {
|
||||
baseDirectory = await myBucket.getBaseDirectory();
|
||||
const directories = await baseDirectory.listDirectories();
|
||||
console.log('Found the following directories:');
|
||||
console.log(directories);
|
||||
expect(directories.length).toEqual(3);
|
||||
const files = await baseDirectory.listFiles();
|
||||
console.log('Found the following files:');
|
||||
console.log(files);
|
||||
expect(files.length).toEqual(1);
|
||||
});
|
||||
|
||||
tap.test('should correctly build paths for sub directories', async () => {
|
||||
const dir4 = await baseDirectory.getSubDirectoryByName('dir3/dir4');
|
||||
expect(dir4).toBeInstanceOf(smartbucket.Directory);
|
||||
const dir4BasePath = dir4.getBasePath();
|
||||
console.log(dir4BasePath);
|
||||
});
|
||||
|
||||
tap.test('clean up directory style tests', async () => {
|
||||
await myBucket.fastRemove('dir1/file1.txt');
|
||||
await myBucket.fastRemove('dir1/file2.txt');
|
||||
await myBucket.fastRemove('dir2/file1.txt');
|
||||
await myBucket.fastRemove('dir3/file1.txt');
|
||||
await myBucket.fastRemove('dir3/dir4/file1.txt');
|
||||
await myBucket.fastRemove('file1.txt');
|
||||
});
|
||||
|
||||
tap.start();
|
||||
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartbucket',
|
||||
version: '2.0.3',
|
||||
description: 'simple cloud independent object storage'
|
||||
}
|
@ -1 +1,4 @@
|
||||
import * as plugins from './smartbucket.plugins';
|
||||
export * from './smartbucket.classes.smartbucket.js';
|
||||
export * from './smartbucket.classes.bucket.js';
|
||||
export * from './smartbucket.classes.directory.js';
|
||||
export * from './smartbucket.classes.file.js';
|
||||
|
@ -1,3 +1,124 @@
|
||||
import * as plugins from './smartbucket.plugins';
|
||||
import * as plugins from './smartbucket.plugins.js';
|
||||
import { SmartBucket } from './smartbucket.classes.smartbucket.js';
|
||||
import { Directory } from './smartbucket.classes.directory.js';
|
||||
|
||||
export class Bucket {}
|
||||
export class Bucket {
|
||||
public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) {
|
||||
const buckets = await smartbucketRef.minioClient.listBuckets();
|
||||
const foundBucket = buckets.find((bucket) => {
|
||||
return bucket.name === bucketNameArg;
|
||||
});
|
||||
|
||||
if (foundBucket) {
|
||||
console.log(`bucket with name ${bucketNameArg} exists.`);
|
||||
console.log(`Taking this as base for new Bucket instance`);
|
||||
return new this(smartbucketRef, bucketNameArg);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async createBucketByName(smartbucketRef: SmartBucket, bucketName: string) {
|
||||
await smartbucketRef.minioClient.makeBucket(bucketName, 'ams3').catch((e) => console.log(e));
|
||||
return new Bucket(smartbucketRef, bucketName);
|
||||
}
|
||||
|
||||
public static async removeBucketByName(smartbucketRef: SmartBucket, bucketName: string) {
|
||||
await smartbucketRef.minioClient.removeBucket(bucketName).catch((e) => console.log(e));
|
||||
}
|
||||
|
||||
public smartbucketRef: SmartBucket;
|
||||
public name: string;
|
||||
|
||||
constructor(smartbucketRef: SmartBucket, bucketName: string) {
|
||||
this.smartbucketRef = smartbucketRef;
|
||||
this.name = bucketName;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the base directory of the bucket
|
||||
*/
|
||||
public async getBaseDirectory() {
|
||||
return new Directory(this, null, '');
|
||||
}
|
||||
|
||||
// ===============
|
||||
// Fast Operations
|
||||
// ===============
|
||||
|
||||
/**
|
||||
* store file
|
||||
*/
|
||||
public async fastStore(pathArg: string, fileContent: string | Buffer): Promise<void> {
|
||||
const streamIntake = new plugins.smartstream.StreamIntake();
|
||||
const putPromise = this.smartbucketRef.minioClient
|
||||
.putObject(this.name, pathArg, streamIntake.getReadable())
|
||||
.catch((e) => console.log(e));
|
||||
streamIntake.pushData(fileContent);
|
||||
streamIntake.signalEnd();
|
||||
await putPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*/
|
||||
public async fastGet(pathArg: string): Promise<Buffer> {
|
||||
const done = plugins.smartpromise.defer();
|
||||
let completeFile: Buffer;
|
||||
const replaySubject = await this.fastGetStream(pathArg);
|
||||
const subscription = replaySubject.subscribe(
|
||||
(chunk) => {
|
||||
if (completeFile) {
|
||||
completeFile = Buffer.concat([completeFile, chunk]);
|
||||
} else {
|
||||
completeFile = chunk;
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
},
|
||||
() => {
|
||||
done.resolve();
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
);
|
||||
await done.promise;
|
||||
return completeFile;
|
||||
}
|
||||
|
||||
public async fastGetStream(pathArg: string): Promise<plugins.smartrx.rxjs.ReplaySubject<Buffer>> {
|
||||
const fileStream = await this.smartbucketRef.minioClient
|
||||
.getObject(this.name, pathArg)
|
||||
.catch((e) => console.log(e));
|
||||
const replaySubject = new plugins.smartrx.rxjs.ReplaySubject<Buffer>();
|
||||
const duplexStream = plugins.smartstream.createDuplexStream<Buffer, Buffer>(
|
||||
async (chunk) => {
|
||||
replaySubject.next(chunk);
|
||||
return chunk;
|
||||
},
|
||||
async (cb) => {
|
||||
replaySubject.complete();
|
||||
return Buffer.from('');
|
||||
}
|
||||
);
|
||||
|
||||
if (!fileStream) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const smartstream = new plugins.smartstream.StreamWrapper([
|
||||
fileStream,
|
||||
duplexStream,
|
||||
plugins.smartstream.cleanPipe(),
|
||||
]);
|
||||
smartstream.run();
|
||||
return replaySubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* removeObject
|
||||
*/
|
||||
public async fastRemove(pathArg: string) {
|
||||
await this.smartbucketRef.minioClient.removeObject(this.name, pathArg);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,226 @@
|
||||
import * as plugins from './smartbucket.plugins';
|
||||
import * as plugins from './smartbucket.plugins.js';
|
||||
import { Bucket } from './smartbucket.classes.bucket.js';
|
||||
import { File } from './smartbucket.classes.file.js';
|
||||
|
||||
export class Directory {}
|
||||
export class Directory {
|
||||
public bucketRef: Bucket;
|
||||
public parentDirectoryRef: Directory;
|
||||
public name: string;
|
||||
|
||||
public tree: string[];
|
||||
public files: string[];
|
||||
public folders: string[];
|
||||
|
||||
constructor(bucketRefArg: Bucket, parentDiretory: Directory, name: string) {
|
||||
this.bucketRef = bucketRefArg;
|
||||
this.parentDirectoryRef = parentDiretory;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an array of parent directories
|
||||
*/
|
||||
public getParentDirectories(): Directory[] {
|
||||
let parentDirectories: Directory[] = [];
|
||||
if (this.parentDirectoryRef) {
|
||||
parentDirectories.push(this.parentDirectoryRef);
|
||||
parentDirectories = parentDirectories.concat(this.parentDirectoryRef.getParentDirectories());
|
||||
}
|
||||
return parentDirectories;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the directory level
|
||||
*/
|
||||
public getDirectoryLevel(): number {
|
||||
return this.getParentDirectories().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the base path
|
||||
*/
|
||||
public getBasePath(): string {
|
||||
const parentDirectories = this.getParentDirectories();
|
||||
let basePath = '';
|
||||
for (const parentDir of parentDirectories) {
|
||||
if (!parentDir.name && !basePath) {
|
||||
basePath = this.name + '/';
|
||||
continue;
|
||||
}
|
||||
if (parentDir.name && !basePath) {
|
||||
basePath = parentDir.name + '/' + this.name + '/';
|
||||
continue;
|
||||
}
|
||||
if (parentDir.name && basePath) {
|
||||
basePath = parentDir.name + '/' + basePath;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* lists all files
|
||||
*/
|
||||
public async listFiles(): Promise<File[]> {
|
||||
const done = plugins.smartpromise.defer();
|
||||
const fileNameStream = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2(
|
||||
this.bucketRef.name,
|
||||
this.getBasePath(),
|
||||
false
|
||||
);
|
||||
const fileArray: File[] = [];
|
||||
const duplexStream = plugins.smartstream.createDuplexStream<plugins.minio.BucketItem, void>(
|
||||
async (bucketItem) => {
|
||||
if (bucketItem.prefix) {
|
||||
return;
|
||||
}
|
||||
if (!bucketItem.name) {
|
||||
return;
|
||||
}
|
||||
let subtractedPath = bucketItem.name.replace(this.getBasePath(), '');
|
||||
if (subtractedPath.startsWith('/')) {
|
||||
subtractedPath = subtractedPath.substr(1);
|
||||
}
|
||||
if (!subtractedPath.includes('/')) {
|
||||
fileArray.push(new File(this, subtractedPath));
|
||||
}
|
||||
},
|
||||
async (tools) => {
|
||||
done.resolve();
|
||||
}
|
||||
);
|
||||
fileNameStream.pipe(duplexStream);
|
||||
await done.promise;
|
||||
return fileArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* lists all folders
|
||||
*/
|
||||
public async listDirectories(): Promise<Directory[]> {
|
||||
const done = plugins.smartpromise.defer();
|
||||
const basePath = this.getBasePath();
|
||||
const completeDirStream = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2(
|
||||
this.bucketRef.name,
|
||||
this.getBasePath(),
|
||||
false
|
||||
);
|
||||
const directoryArray: Directory[] = [];
|
||||
const duplexStream = plugins.smartstream.createDuplexStream<plugins.minio.BucketItem, void>(
|
||||
async (bucketItem) => {
|
||||
if (bucketItem.name) {
|
||||
return;
|
||||
}
|
||||
let subtractedPath = bucketItem.prefix.replace(this.getBasePath(), '');
|
||||
if (subtractedPath.startsWith('/')) {
|
||||
subtractedPath = subtractedPath.substr(1);
|
||||
}
|
||||
if (subtractedPath.includes('/')) {
|
||||
const dirName = subtractedPath.split('/')[0];
|
||||
if (directoryArray.find((directory) => directory.name === dirName)) {
|
||||
return;
|
||||
}
|
||||
directoryArray.push(new Directory(this.bucketRef, this, dirName));
|
||||
}
|
||||
},
|
||||
async (tools) => {
|
||||
done.resolve();
|
||||
}
|
||||
);
|
||||
completeDirStream.pipe(duplexStream);
|
||||
await done.promise;
|
||||
return directoryArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets an array that has all objects with a certain prefix;
|
||||
*/
|
||||
public async getTreeArray() {
|
||||
const treeArray = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2(
|
||||
this.bucketRef.name,
|
||||
this.getBasePath(),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a sub directory
|
||||
*/
|
||||
public async getSubDirectoryByName(dirNameArg: string): Promise<Directory> {
|
||||
const dirNameArray = dirNameArg.split('/');
|
||||
|
||||
const getDirectory = async (directoryArg: Directory, dirNameToSearch: string) => {
|
||||
const directories = await directoryArg.listDirectories();
|
||||
return directories.find((directory) => {
|
||||
return directory.name === dirNameToSearch;
|
||||
});
|
||||
};
|
||||
let wantedDirectory: Directory;
|
||||
for (const dirNameToSearch of dirNameArray) {
|
||||
const directoryToSearchIn = wantedDirectory ? wantedDirectory : this;
|
||||
wantedDirectory = await getDirectory(directoryToSearchIn, dirNameToSearch);
|
||||
}
|
||||
return wantedDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* moves the directory
|
||||
*/
|
||||
public async move() {
|
||||
// TODO
|
||||
throw new Error('moving a directory is not yet implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a file within this directory
|
||||
* @param relativePathArg
|
||||
*/
|
||||
public async createEmptyFile(relativePathArg: string) {
|
||||
const emtpyFile = await File.createFileFromString(this, relativePathArg, '');
|
||||
}
|
||||
|
||||
// file operations
|
||||
public async fastStore(pathArg: string, contentArg: string | Buffer) {
|
||||
const path = plugins.path.join(this.getBasePath(), pathArg);
|
||||
await this.bucketRef.fastStore(path, contentArg);
|
||||
}
|
||||
|
||||
public async fastGet(pathArg: string) {
|
||||
const path = plugins.path.join(this.getBasePath(), pathArg);
|
||||
const result = await this.bucketRef.fastGet(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
public async fastGetStream(pathArg: string): Promise<plugins.smartrx.rxjs.ReplaySubject<Buffer>> {
|
||||
const path = plugins.path.join(this.getBasePath(), pathArg);
|
||||
const result = await this.bucketRef.fastGetStream(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
public async fastRemove(pathArg: string) {
|
||||
const path = plugins.path.join(this.getBasePath(), pathArg);
|
||||
await this.bucketRef.fastRemove(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes the directory with all its contents
|
||||
*/
|
||||
public async deleteWithAllContents() {
|
||||
const deleteDirectory = async (directoryArg: Directory) => {
|
||||
const childDirectories = await directoryArg.listDirectories();
|
||||
if (childDirectories.length === 0) {
|
||||
console.log('directory empty! Path complete!');
|
||||
} else {
|
||||
for (const childDir of childDirectories) {
|
||||
await deleteDirectory(childDir);
|
||||
}
|
||||
}
|
||||
const files = await directoryArg.listFiles();
|
||||
for (const file of files) {
|
||||
await directoryArg.fastRemove(file.name);
|
||||
}
|
||||
};
|
||||
await deleteDirectory(this);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,93 @@
|
||||
import * as plugins from './smartbucket.plugins';
|
||||
import * as plugins from './smartbucket.plugins.js';
|
||||
import { Directory } from './smartbucket.classes.directory.js';
|
||||
|
||||
export class File {}
|
||||
export interface IFileMetaData {
|
||||
name: string;
|
||||
fileType: string;
|
||||
size: string;
|
||||
}
|
||||
|
||||
export class File {
|
||||
// STATIC
|
||||
public static async createFileFromString(
|
||||
dirArg: Directory,
|
||||
fileName: string,
|
||||
fileContent: string
|
||||
) {
|
||||
await this.createFileFromBuffer(dirArg, fileName, Buffer.from(fileContent));
|
||||
}
|
||||
|
||||
public static async createFileFromBuffer(
|
||||
directoryRef: Directory,
|
||||
fileName: string,
|
||||
fileContent: Buffer
|
||||
) {
|
||||
const filePath = plugins.path.join(directoryRef.getBasePath(), fileName);
|
||||
const streamIntake = new plugins.smartstream.StreamIntake();
|
||||
const putPromise = directoryRef.bucketRef.smartbucketRef.minioClient
|
||||
.putObject(this.name, filePath, streamIntake.getReadable())
|
||||
.catch((e) => console.log(e));
|
||||
streamIntake.pushData(fileContent);
|
||||
streamIntake.signalEnd();
|
||||
await putPromise;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public parentDirectoryRef: Directory;
|
||||
public name: string;
|
||||
|
||||
public path: string;
|
||||
public metaData: IFileMetaData;
|
||||
|
||||
constructor(directoryRefArg: Directory, fileName: string) {
|
||||
this.parentDirectoryRef = directoryRefArg;
|
||||
this.name = fileName;
|
||||
}
|
||||
|
||||
public async getContentAsString() {
|
||||
const fileBuffer = await this.getContentAsBuffer();
|
||||
return fileBuffer.toString();
|
||||
}
|
||||
|
||||
public async getContentAsBuffer() {
|
||||
const done = plugins.smartpromise.defer();
|
||||
const fileStream = await this.parentDirectoryRef.bucketRef.smartbucketRef.minioClient
|
||||
.getObject(this.parentDirectoryRef.bucketRef.name, this.path)
|
||||
.catch((e) => console.log(e));
|
||||
let completeFile = Buffer.from('');
|
||||
const duplexStream = plugins.smartstream.createDuplexStream<Buffer, Buffer>(
|
||||
async (chunk) => {
|
||||
completeFile = Buffer.concat([chunk]);
|
||||
return chunk;
|
||||
},
|
||||
async (cb) => {
|
||||
done.resolve();
|
||||
return Buffer.from('');
|
||||
}
|
||||
);
|
||||
|
||||
if (!fileStream) {
|
||||
return null;
|
||||
}
|
||||
|
||||
fileStream.pipe(duplexStream);
|
||||
await done.promise;
|
||||
return completeFile;
|
||||
}
|
||||
|
||||
public async streamContent() {
|
||||
// TODO
|
||||
throw new Error('not yet implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* removes this file
|
||||
*/
|
||||
public async remove() {
|
||||
await this.parentDirectoryRef.bucketRef.smartbucketRef.minioClient.removeObject(
|
||||
this.parentDirectoryRef.bucketRef.name,
|
||||
this.path
|
||||
);
|
||||
await this.parentDirectoryRef.listFiles();
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,43 @@
|
||||
import * as plugins from './smartbucket.plugins';
|
||||
import * as plugins from './smartbucket.plugins.js';
|
||||
import { Bucket } from './smartbucket.classes.bucket.js';
|
||||
|
||||
export interface ISmartBucketConfig {
|
||||
provider: 'digitalocean';
|
||||
projectId: string;
|
||||
bucketName: string;
|
||||
endpoint: string;
|
||||
port?: number;
|
||||
useSsl?: boolean;
|
||||
accessKey: string;
|
||||
accessSecret: string;
|
||||
}
|
||||
|
||||
export class SmartBucket {
|
||||
public config: ISmartBucketConfig;
|
||||
|
||||
public minioClient: plugins.minio.Client;
|
||||
|
||||
/**
|
||||
* the constructor of SmartBucket
|
||||
*/
|
||||
constructor(configArg: ISmartBucketConfig) {
|
||||
this.config = configArg;
|
||||
this.minioClient = new plugins.minio.Client({
|
||||
endPoint: this.config.endpoint,
|
||||
port: configArg.port || 443,
|
||||
useSSL: configArg.useSsl !== undefined ? configArg.useSsl : true,
|
||||
accessKey: this.config.accessKey,
|
||||
secretKey: this.config.accessSecret,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes the Smartbucket
|
||||
*/
|
||||
public async init() {}
|
||||
public async createBucket(bucketNameArg: string) {
|
||||
const bucket = await Bucket.createBucketByName(this, bucketNameArg);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
public async removeBucket(bucketName: string) {
|
||||
await Bucket.removeBucketByName(this, bucketName);
|
||||
}
|
||||
|
||||
public async getBucketByName(bucketName: string) {
|
||||
return Bucket.getBucketByName(this, bucketName);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,16 @@
|
||||
import * as smartpromise from '@pushrocks/smartpromise';
|
||||
// node native
|
||||
import * as path from 'path';
|
||||
|
||||
export { smartpromise };
|
||||
export { path };
|
||||
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
import * as smartrx from '@push.rocks/smartrx';
|
||||
import * as smartstream from '@push.rocks/smartstream';
|
||||
|
||||
export { smartpath, smartpromise, smartrx, smartstream };
|
||||
|
||||
// third party scope
|
||||
import * as minio from 'minio';
|
||||
|
||||
export { minio };
|
||||
|
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
17
tslint.json
17
tslint.json
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
Reference in New Issue
Block a user