fix(core): update

This commit is contained in:
Philipp Kunz 2024-05-21 01:22:21 +02:00
parent 1e1f65119c
commit eaf2e7e6bb
11 changed files with 440 additions and 174 deletions

View File

@ -19,6 +19,7 @@
"@push.rocks/tapbundle": "^5.0.23" "@push.rocks/tapbundle": "^5.0.23"
}, },
"dependencies": { "dependencies": {
"@push.rocks/smartmime": "^2.0.0",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.3", "@push.rocks/smartpromise": "^4.0.3",
"@push.rocks/smartrx": "^3.0.7", "@push.rocks/smartrx": "^3.0.7",

66
pnpm-lock.yaml generated
View File

@ -8,6 +8,9 @@ importers:
.: .:
dependencies: dependencies:
'@push.rocks/smartmime':
specifier: ^2.0.0
version: 2.0.0
'@push.rocks/smartpath': '@push.rocks/smartpath':
specifier: ^5.0.18 specifier: ^5.0.18
version: 5.0.18 version: 5.0.18
@ -409,6 +412,9 @@ packages:
'@push.rocks/smartmime@1.0.6': '@push.rocks/smartmime@1.0.6':
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==} resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
'@push.rocks/smartmime@2.0.0':
resolution: {integrity: sha512-yNEYrQzWjxwinCT8djw9eFumpCIvIQQS9KXWLH0LT9COlFoaP/ruk7pogrGYKCo20tFITJyO6NmMCa24402rvA==}
'@push.rocks/smartnetwork@3.0.2': '@push.rocks/smartnetwork@3.0.2':
resolution: {integrity: sha512-s6CNGzQ1n/d/6cOKXbxeW6/tO//dr1woLqI01g7XhqTriw0nsm2G2kWaZh2J0VOguGNWBgQVCIpR0LjdRNWb3g==} resolution: {integrity: sha512-s6CNGzQ1n/d/6cOKXbxeW6/tO//dr1woLqI01g7XhqTriw0nsm2G2kWaZh2J0VOguGNWBgQVCIpR0LjdRNWb3g==}
@ -609,6 +615,9 @@ packages:
'@tempfix/watcher@2.3.0': '@tempfix/watcher@2.3.0':
resolution: {integrity: sha512-a2qVQffcrnetehvwsN+LdipxQ6jejwZLgAvS9/91+C0gP4CKyikY01c0tSs0I4tSL7qHdCw1Fx0quLw+A9uyLA==} resolution: {integrity: sha512-a2qVQffcrnetehvwsN+LdipxQ6jejwZLgAvS9/91+C0gP4CKyikY01c0tSs0I4tSL7qHdCw1Fx0quLw+A9uyLA==}
'@tokenizer/token@0.3.0':
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
'@tsclass/tsclass@3.0.48': '@tsclass/tsclass@3.0.48':
resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==} resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==}
@ -1445,6 +1454,10 @@ packages:
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
engines: {node: '>=18'} engines: {node: '>=18'}
file-type@19.0.0:
resolution: {integrity: sha512-s7cxa7/leUWLiXO78DVVfBVse+milos9FitauDLG1pI7lNaJ2+5lzPnr2N24ym+84HVwJL6hVuGfgVE+ALvU8Q==}
engines: {node: '>=18'}
fill-range@7.0.1: fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2142,6 +2155,11 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
hasBin: true hasBin: true
mime@4.0.3:
resolution: {integrity: sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==}
engines: {node: '>=16'}
hasBin: true
mimic-fn@2.1.0: mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2358,6 +2376,10 @@ packages:
resolution: {integrity: sha512-AHXsYi9EcYlSm3uUANz7h5WSktHiyTnUeHqdWmyRdjdMhgq9LgZ8pggl9FOUGuCLVfe+NKxp2k9sEMCH3tHIEg==} resolution: {integrity: sha512-AHXsYi9EcYlSm3uUANz7h5WSktHiyTnUeHqdWmyRdjdMhgq9LgZ8pggl9FOUGuCLVfe+NKxp2k9sEMCH3tHIEg==}
engines: {node: '>=14'} engines: {node: '>=14'}
peek-readable@5.0.0:
resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
engines: {node: '>=14.16'}
pend@1.2.0: pend@1.2.0:
resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=} resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=}
@ -2464,6 +2486,10 @@ packages:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
readable-web-to-node-stream@3.0.2:
resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
engines: {node: '>=8'}
readdirp@3.6.0: readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
@ -2682,6 +2708,10 @@ packages:
strnum@1.0.5: strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
strtok3@7.0.0:
resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
engines: {node: '>=14.16'}
stubborn-fs@1.2.5: stubborn-fs@1.2.5:
resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==}
@ -2732,6 +2762,10 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
token-types@5.0.1:
resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==}
engines: {node: '>=14.16'}
tr46@0.0.3: tr46@0.0.3:
resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=} resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=}
@ -3630,6 +3664,12 @@ snapshots:
'@types/mime-types': 2.1.4 '@types/mime-types': 2.1.4
mime-types: 2.1.35 mime-types: 2.1.35
'@push.rocks/smartmime@2.0.0':
dependencies:
'@types/mime-types': 2.1.4
file-type: 19.0.0
mime: 4.0.3
'@push.rocks/smartnetwork@3.0.2': '@push.rocks/smartnetwork@3.0.2':
dependencies: dependencies:
'@pushrocks/smartping': 1.0.8 '@pushrocks/smartping': 1.0.8
@ -4037,6 +4077,8 @@ snapshots:
dependencies: dependencies:
stubborn-fs: 1.2.5 stubborn-fs: 1.2.5
'@tokenizer/token@0.3.0': {}
'@tsclass/tsclass@3.0.48': '@tsclass/tsclass@3.0.48':
dependencies: dependencies:
type-fest: 2.19.0 type-fest: 2.19.0
@ -4969,6 +5011,12 @@ snapshots:
dependencies: dependencies:
is-unicode-supported: 2.0.0 is-unicode-supported: 2.0.0
file-type@19.0.0:
dependencies:
readable-web-to-node-stream: 3.0.2
strtok3: 7.0.0
token-types: 5.0.1
fill-range@7.0.1: fill-range@7.0.1:
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
@ -5956,6 +6004,8 @@ snapshots:
mime@1.6.0: {} mime@1.6.0: {}
mime@4.0.3: {}
mimic-fn@2.1.0: {} mimic-fn@2.1.0: {}
mimic-response@3.1.0: {} mimic-response@3.1.0: {}
@ -6125,6 +6175,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
peek-readable@5.0.0: {}
pend@1.2.0: {} pend@1.2.0: {}
picocolors@1.0.1: {} picocolors@1.0.1: {}
@ -6248,6 +6300,10 @@ snapshots:
string_decoder: 1.3.0 string_decoder: 1.3.0
util-deprecate: 1.0.2 util-deprecate: 1.0.2
readable-web-to-node-stream@3.0.2:
dependencies:
readable-stream: 3.6.2
readdirp@3.6.0: readdirp@3.6.0:
dependencies: dependencies:
picomatch: 2.3.1 picomatch: 2.3.1
@ -6530,6 +6586,11 @@ snapshots:
strnum@1.0.5: {} strnum@1.0.5: {}
strtok3@7.0.0:
dependencies:
'@tokenizer/token': 0.3.0
peek-readable: 5.0.0
stubborn-fs@1.2.5: {} stubborn-fs@1.2.5: {}
supports-color@5.5.0: supports-color@5.5.0:
@ -6588,6 +6649,11 @@ snapshots:
toidentifier@1.0.1: {} toidentifier@1.0.1: {}
token-types@5.0.1:
dependencies:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
tr46@0.0.3: {} tr46@0.0.3: {}
tr46@2.1.0: tr46@2.1.0:

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartbucket', name: '@push.rocks/smartbucket',
version: '3.0.3', version: '3.0.4',
description: 'A TypeScript library that offers simple, cloud-independent object storage with features like bucket creation, file management, and directory management.' description: 'A TypeScript library that offers simple, cloud-independent object storage with features like bucket creation, file management, and directory management.'
} }

View File

@ -1,6 +1,6 @@
import * as plugins from './smartbucket.plugins.js'; import * as plugins from './plugins.js';
import { SmartBucket } from './smartbucket.classes.smartbucket.js'; import { SmartBucket } from './classes.smartbucket.js';
import { Directory } from './smartbucket.classes.directory.js'; import { Directory } from './classes.directory.js';
export class Bucket { export class Bucket {
public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) { public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) {
@ -52,15 +52,35 @@ export class Bucket {
public async fastPut(optionsArg: { public async fastPut(optionsArg: {
path: string; path: string;
contents: string | Buffer; contents: string | Buffer;
overwrite?: boolean;
}): Promise<void> { }): Promise<void> {
try {
// Check if the object already exists
const exists = await this.fastExists({ path: optionsArg.path });
if (exists && !optionsArg.overwrite) {
console.error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`);
return;
} else if (exists && optionsArg.overwrite) {
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`);
} else {
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`);
}
// Proceed with putting the object
const streamIntake = new plugins.smartstream.StreamIntake(); const streamIntake = new plugins.smartstream.StreamIntake();
const putPromise = this.smartbucketRef.minioClient const putPromise = this.smartbucketRef.minioClient.putObject(this.name, optionsArg.path, streamIntake);
.putObject(this.name, optionsArg.path, streamIntake)
.catch((e) => console.log(e));
streamIntake.pushData(optionsArg.contents); streamIntake.pushData(optionsArg.contents);
streamIntake.signalEnd(); streamIntake.signalEnd();
const response = await putPromise; await putPromise;
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`);
} catch (error) {
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
throw error;
} }
}
/** /**
* get file * get file
@ -126,7 +146,22 @@ export class Bucket {
path: string; path: string;
dataStream: plugins.stream.Readable; dataStream: plugins.stream.Readable;
nativeMetadata?: { [key: string]: string }; nativeMetadata?: { [key: string]: string };
overwrite?: boolean;
}): Promise<void> { }): Promise<void> {
try {
// Check if the object already exists
const exists = await this.fastExists({ path: optionsArg.path });
if (exists && !optionsArg.overwrite) {
console.error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`);
return;
} else if (exists && optionsArg.overwrite) {
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`);
} else {
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`);
}
// Proceed with putting the object
await this.smartbucketRef.minioClient.putObject( await this.smartbucketRef.minioClient.putObject(
this.name, this.name,
optionsArg.path, optionsArg.path,
@ -139,7 +174,14 @@ export class Bucket {
})() })()
: {}) : {})
); );
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`);
} catch (error) {
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
throw error;
} }
}
public async copyObject(optionsArg: { public async copyObject(optionsArg: {
/** /**
@ -198,7 +240,12 @@ export class Bucket {
await this.smartbucketRef.minioClient.removeObject(this.name, optionsArg.path); await this.smartbucketRef.minioClient.removeObject(this.name, optionsArg.path);
} }
public async doesObjectExist(optionsArg: { /**
* check wether file exists
* @param optionsArg
* @returns
*/
public async fastExists(optionsArg: {
path: string; path: string;
}): Promise<boolean> { }): Promise<boolean> {
try { try {
@ -215,4 +262,10 @@ export class Bucket {
} }
} }
} }
public async fastStat(optionsArg: {
path: string;
}) {
return this.smartbucketRef.minioClient.statObject(this.name, optionsArg.path);
}
} }

View File

@ -1,6 +1,6 @@
import * as plugins from './smartbucket.plugins.js'; import * as plugins from './plugins.js';
import { Bucket } from './smartbucket.classes.bucket.js'; import { Bucket } from './classes.bucket.js';
import { File } from './smartbucket.classes.file.js'; import { File } from './classes.file.js';
export class Directory { export class Directory {
public bucketRef: Bucket; public bucketRef: Bucket;
@ -59,6 +59,32 @@ export class Directory {
return basePath; return basePath;
} }
/**
* gets a file by name
*/
public async getFile(optionsArg: {
name: string;
createWithContents?: string | Buffer;
}): Promise<File> {
// check wether the file exists
const exists = await this.bucketRef.fastExists({
path: this.getBasePath() + optionsArg.name,
});
if (!exists && !optionsArg.createWithContents) {
return null;
}
if (!exists && optionsArg.createWithContents) {
await this.fastPut({
path: optionsArg.name,
contents: optionsArg.createWithContents,
});
}
return new File({
directoryRefArg: this,
fileName: optionsArg.name,
})
}
/** /**
* lists all files * lists all files
*/ */

154
ts/classes.file.ts Normal file
View File

@ -0,0 +1,154 @@
import * as plugins from './plugins.js';
import { Directory } from './classes.directory.js';
import { MetaData } from './classes.metadata.js';
/**
* represents a file in a directory
*/
export class File {
// STATIC
/**
* creates a file in draft mode
* you need to call .save() to store it in s3
* @param optionsArg
*/
public static async create(optionsArg: {
directory: Directory;
name: string;
contents: Buffer | string | plugins.stream.Readable;
/**
* if contents are of type string, you can specify the encoding here
*/
encoding?: 'utf8' | 'binary';
}): Promise<File> {
const contents =
typeof optionsArg.contents === 'string'
? Buffer.from(optionsArg.contents, optionsArg.encoding)
: optionsArg.contents;
const file = new File({
directoryRefArg: optionsArg.directory,
fileName: optionsArg.name,
});
if (contents instanceof plugins.stream.Readable) {} else {
await optionsArg.directory.fastPut({
path: optionsArg.name,
contents: contents,
});
}
return file;
}
// INSTANCE
public parentDirectoryRef: Directory;
public name: string;
public getBasePath(): string {
return plugins.path.join(this.parentDirectoryRef.getBasePath(), this.name);
};
constructor(optionsArg: { directoryRefArg: Directory; fileName: string }) {
this.parentDirectoryRef = optionsArg.directoryRefArg;
this.name = optionsArg.fileName;
}
public async getContentsAsString(): Promise<string> {
const fileBuffer = await this.getContents();
return fileBuffer.toString();
}
public async getContents(): Promise<Buffer> {
const resultBuffer = await this.parentDirectoryRef.bucketRef.fastGet({
path: this.getBasePath(),
});
return resultBuffer;
}
public async getReadStream() {
const readStream = this.parentDirectoryRef.bucketRef.fastGetStream({
path: this.getBasePath(),
});
}
/**
* removes this file
* for using recycling mechanics use .delete()
*/
public async remove() {
await this.parentDirectoryRef.bucketRef.fastRemove({
path: this.getBasePath(),
});
if (!this.name.endsWith('.metadata')) {
await this.parentDirectoryRef.bucketRef.fastRemove({
path: this.getBasePath() + '.metadata',
});
}
await this.parentDirectoryRef.listFiles();
}
/**
* deletes the file with recycling mechanics
*/
public async delete() {
await this.remove();
}
/**
* allows locking the file
* @param optionsArg
*/
public async lock(optionsArg?: { timeoutMillis?: number }) {
const metadata = await this.getMetaData();
await metadata.setLock({
lock: 'locked',
expires: new Date(Date.now() + (optionsArg?.timeoutMillis || 1000)),
});
}
/**
* actively unlocks a file
*
*/
public async unlock(optionsArg?: {
/**
* unlock the file even if not locked from this instance
*/
force?: boolean;
}) {
}
public async updateWithContents(optionsArg: {
contents: Buffer | string | plugins.stream.Readable;
encoding?: 'utf8' | 'binary';
}) {
if (optionsArg.contents instanceof plugins.stream.Readable) {
await this.parentDirectoryRef.bucketRef.fastPutStream({
path: this.getBasePath(),
dataStream: optionsArg.contents,
});
} else if (Buffer.isBuffer(optionsArg.contents)) {
await this.parentDirectoryRef.bucketRef.fastPut({
path: this.getBasePath(),
contents: optionsArg.contents,
});
} else if (typeof optionsArg.contents === 'string') {
await this.parentDirectoryRef.bucketRef.fastPut({
path: this.getBasePath(),
contents: Buffer.from(optionsArg.contents, optionsArg.encoding),
});
}
}
/**
* allows updating the metadata of a file
* @param updatedMetadata
*/
public async getMetaData() {
const metadata = await MetaData.createForFile({
file: this,
});
return metadata;
}
}

105
ts/classes.metadata.ts Normal file
View File

@ -0,0 +1,105 @@
import * as plugins from './plugins.js';
import { File } from './classes.file.js';
export class MetaData {
// static
public static async createForFile(optionsArg: {
file: File;
}) {
const metaData = new MetaData();
metaData.fileRef = optionsArg.file;
// lets find the existing metadata file
metaData.metadataFile = await metaData.fileRef.parentDirectoryRef.getFile({
name: metaData.fileRef.name + '.metadata',
createWithContents: '{}',
});
return metaData;
}
// instance
/**
* the file that contains the metadata
*/
metadataFile: File;
/**
* the file that the metadata is for
*/
fileRef: File;
public async getFileType(optionsArg?: {
useFileExtension?: boolean;
useMagicBytes?: boolean;
}): Promise<string> {
if (optionsArg && optionsArg.useFileExtension || optionsArg.useFileExtension === undefined) {
return plugins.path.extname(this.fileRef.name);
}
};
/**
* gets the size of the fileRef
*/
public async getSizeInBytes(): Promise<number> {
const stat = await this.fileRef.parentDirectoryRef.bucketRef.fastStat({
path: this.fileRef.getBasePath(),
});
return stat.size;
};
private prefixCustomMetaData = 'custom_';
public async storeCustomMetaData<T = any>(optionsArg: {
key: string;
value: T;
}) {
const json = await this.metadataFile.getContentsAsString();
const parsed = await JSON.parse(json);
parsed[this.prefixCustomMetaData + optionsArg.key] = optionsArg.value;
await this.metadataFile.updateWithContents({
contents: JSON.stringify(parsed),
});
}
public async getCustomMetaData<T = any>(optionsArg: {
key: string;
}): Promise<T> {
const json = await this.metadataFile.getContentsAsString();
const parsed = await JSON.parse(json);
return parsed[this.prefixCustomMetaData + optionsArg.key];
}
public async deleteCustomMetaData(optionsArg: {
key: string;
}) {
const json = await this.metadataFile.getContentsAsString();
const parsed = await JSON.parse(json);
delete parsed[this.prefixCustomMetaData + optionsArg.key];
await this.metadataFile.updateWithContents({
contents: JSON.stringify(parsed),
});
}
/**
* set a lock on the ref file
* @param optionsArg
*/
public async setLock(optionsArg: {
lock: string;
expires: Date;
}) {
}
/**
* remove the lock on the ref file
* @param optionsArg
*/
public async removeLock(optionsArg: {
force: boolean;
}) {
}
}

View File

@ -1,5 +1,5 @@
import * as plugins from './smartbucket.plugins.js'; import * as plugins from './plugins.js';
import { Bucket } from './smartbucket.classes.bucket.js'; import { Bucket } from './classes.bucket.js';
export class SmartBucket { export class SmartBucket {
public config: plugins.tsclass.storage.IS3Descriptor; public config: plugins.tsclass.storage.IS3Descriptor;

View File

@ -1,4 +1,4 @@
export * from './smartbucket.classes.smartbucket.js'; export * from './classes.smartbucket.js';
export * from './smartbucket.classes.bucket.js'; export * from './classes.bucket.js';
export * from './smartbucket.classes.directory.js'; export * from './classes.directory.js';
export * from './smartbucket.classes.file.js'; export * from './classes.file.js';

View File

@ -5,12 +5,13 @@ import * as stream from 'stream';
export { path, stream }; export { path, stream };
// @push.rocks scope // @push.rocks scope
import * as smartmime from '@push.rocks/smartmime';
import * as smartpath from '@push.rocks/smartpath'; import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise'; import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrx from '@push.rocks/smartrx'; import * as smartrx from '@push.rocks/smartrx';
import * as smartstream from '@push.rocks/smartstream'; import * as smartstream from '@push.rocks/smartstream';
export { smartpath, smartpromise, smartrx, smartstream }; export { smartmime, smartpath, smartpromise, smartrx, smartstream };
// @tsclass // @tsclass
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';

View File

@ -1,140 +0,0 @@
import * as plugins from './smartbucket.plugins.js';
import { Directory } from './smartbucket.classes.directory.js';
export interface IFileMetaData {
name: string;
fileType: string;
size: string;
}
/**
* represents a file in a directory
*/
export class File {
// STATIC
/**
* creates a file in draft mode
* you need to call .save() to store it in s3
* @param optionsArg
*/
public static async create(optionsArg: {
directory: Directory;
name: string;
contents: Buffer | string | plugins.stream.Readable;
/**
* if contents are of type string, you can specify the encoding here
*/
encoding?: 'utf8' | 'binary';
}): Promise<File> {
const contents =
typeof optionsArg.contents === 'string'
? Buffer.from(optionsArg.contents, optionsArg.encoding)
: optionsArg.contents;
const file = new File({
directoryRefArg: optionsArg.directory,
fileName: optionsArg.name,
});
if (contents instanceof plugins.stream.Readable) {} else {
await optionsArg.directory.fastPut({
path: optionsArg.name,
contents: contents,
});
}
return file;
}
// INSTANCE
public parentDirectoryRef: Directory;
public name: string;
public path: string;
public metaData: IFileMetaData;
constructor(optionsArg: { directoryRefArg: Directory; fileName: string }) {
this.parentDirectoryRef = optionsArg.directoryRefArg;
this.name = optionsArg.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 = new plugins.smartstream.SmartDuplex<Buffer, Buffer>(
{
writeFunction: async (chunk) => {
completeFile = Buffer.concat([chunk]);
return chunk;
},
finalFunction: async (cb) => {
done.resolve();
return Buffer.from('');
},
}
);
if (!fileStream) {
return null;
}
fileStream.pipe(duplexStream);
await done.promise;
return completeFile;
}
public async readStreaming() {
// 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();
}
/**
* deletes the file
*/
public async delete() {}
/**
* allows locking the file
* @param optionsArg
*/
public async lock(optionsArg?: { timeoutMillis?: number }) {}
/**
* actively unlocks a file
*
*/
public async unlock(optionsArg?: {
/**
* unlock the file even if not locked from this instance
*/
force?: boolean;
}) {}
public async updateWithContents(optionsArg: {
contents: Buffer | string | plugins.stream.Readable;
encoding?: 'utf8' | 'binary';
}) {}
/**
* allows updating the metadata of a file
* @param updatedMetadata
*/
public async updateMetaData(updatedMetadata: any) {}
}