@e-mc/cloud 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -3
- package/index.js +41 -31
- package/package.json +4 -4
- package/util.js +19 -21
package/README.md
CHANGED
|
@@ -1,7 +1,80 @@
|
|
|
1
|
-
|
|
1
|
+
# @e-mc/cloud
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
* NodeJS 14
|
|
4
|
+
* ES2020
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## General Usage
|
|
7
|
+
|
|
8
|
+
* [Read the Docs](https://e-mc.readthedocs.io)
|
|
9
|
+
|
|
10
|
+
## Interface
|
|
11
|
+
|
|
12
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/index.d.ts
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import type { IHost, IScopeOrigin } from "./index";
|
|
16
|
+
import type { ExternalAsset } from "./asset";
|
|
17
|
+
import type { BucketWebsiteOptions, CloudDatabase, CloudFeatures, CloudFunctions, CloudService, CloudStorage, CloudStorageDownload, CloudStorageUpload } from "./cloud";
|
|
18
|
+
import type { ClientDbConstructor, IClientDb } from "./core";
|
|
19
|
+
import type { BatchQueryResult, QueryResult } from "./db";
|
|
20
|
+
import type { LogMessageOptions } from "./logger";
|
|
21
|
+
import type { CloudModule, CloudServiceOptions, CloudSettings, DbCoerceSettings } from "./settings";
|
|
22
|
+
|
|
23
|
+
interface ICloud extends IClientDb<IHost, CloudModule, CloudDatabase, CloudServiceOptions, DbCoerceSettings> {
|
|
24
|
+
module: CloudModule;
|
|
25
|
+
readonly uploaded: string[];
|
|
26
|
+
readonly downloaded: string[];
|
|
27
|
+
createBucket(service: string, credential: unknown, bucket: string, acl?: unknown, options?: unknown): Promise<boolean>;
|
|
28
|
+
createBucket(service: string, credential: unknown, bucket: string, publicRead?: boolean): Promise<boolean>;
|
|
29
|
+
setBucketPolicy(service: string, credential: unknown, bucket: string, options: unknown): Promise<boolean>;
|
|
30
|
+
setBucketWebsite(service: string, credential: unknown, bucket: string, options: BucketWebsiteOptions): Promise<boolean>;
|
|
31
|
+
deleteObjects(service: string, credential: unknown, bucket: string, recursive?: boolean): Promise<void>;
|
|
32
|
+
uploadObject(service: string, credential: unknown, bucket: string, upload: CloudStorageUpload, localUri: string, beforeResolve?: (value: string) => Promise<void> | void): Promise<string>;
|
|
33
|
+
downloadObject(service: string, credential: unknown, bucket: string, download: CloudStorageDownload, beforeResolve?: (value: Buffer | string | null) => Promise<string | undefined> | void): Promise<Buffer | string>;
|
|
34
|
+
getStorage(action: CloudFunctions, data: CloudStorage[] | undefined): CloudStorage | undefined;
|
|
35
|
+
hasStorage(action: CloudFunctions, storage: CloudStorage): CloudStorageUpload | false;
|
|
36
|
+
getDatabaseRows(item: CloudDatabase, ignoreErrors: boolean, sessionKey?: string): Promise<QueryResult>;
|
|
37
|
+
getDatabaseRows(item: CloudDatabase, sessionKey?: string): Promise<QueryResult>;
|
|
38
|
+
getDatabaseBatchRows(batch: CloudDatabase[], ignoreErrors: boolean, sessionKey?: string): Promise<BatchQueryResult>;
|
|
39
|
+
getDatabaseBatchRows(batch: CloudDatabase[], sessionKey?: string): Promise<BatchQueryResult>;
|
|
40
|
+
hasCredential(feature: CloudFeatures, data: CloudService, credential?: unknown): boolean;
|
|
41
|
+
getCredential(item: CloudService, unused?: boolean): Record<string | number | symbol, unknown>;
|
|
42
|
+
getSettings(service: string): Record<string, unknown> | undefined;
|
|
43
|
+
settingsOf(service: string, name: "cache"): unknown;
|
|
44
|
+
settingsOf(service: string, name: "coerce", component: keyof DbCoerceSettings): unknown;
|
|
45
|
+
getUploadHandler(service: string, credential: unknown): (...args: unknown[]) => void;
|
|
46
|
+
getDownloadHandler(service: string, credential: unknown): (...args: unknown[]) => void;
|
|
47
|
+
resolveService(service: string, folder?: string): string;
|
|
48
|
+
getUserSettings(): unknown;
|
|
49
|
+
get settings(): CloudSettings;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface CloudConstructor extends ClientDbConstructor<IHost> {
|
|
53
|
+
LOG_CLOUD_FAIL: LogMessageOptions;
|
|
54
|
+
LOG_CLOUD_COMMAND: LogMessageOptions;
|
|
55
|
+
LOG_CLOUD_WARN: LogMessageOptions;
|
|
56
|
+
LOG_CLOUD_UPLOAD: LogMessageOptions;
|
|
57
|
+
LOG_CLOUD_DOWNLOAD: LogMessageOptions;
|
|
58
|
+
LOG_CLOUD_DELETE: LogMessageOptions;
|
|
59
|
+
LOG_CLOUD_DELAYED: LogMessageOptions;
|
|
60
|
+
finalize(this: IHost, instance: ICloud): Promise<unknown>;
|
|
61
|
+
uploadAsset(state: IScopeOrigin<IFileManager, ICloud<IFileManager>>, file: ExternalAsset, ignoreProcess: boolean): Promise<unknown>[];
|
|
62
|
+
uploadAsset(state: IScopeOrigin<IFileManager, ICloud<IFileManager>>, file: ExternalAsset, contentType?: string, ignoreProcess?: boolean): Promise<unknown>[];
|
|
63
|
+
sanitizeAssets(assets: ExternalAsset[]): ExternalAsset[];
|
|
64
|
+
readonly prototype: ICloud;
|
|
65
|
+
new(module?: CloudModule, database?: CloudDatabase[], ...args: unknown[]): ICloud;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## References
|
|
70
|
+
|
|
71
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/asset.d.ts
|
|
72
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/cloud.d.ts
|
|
73
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/core.d.ts
|
|
74
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/db.d.ts
|
|
75
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/logger.d.ts
|
|
76
|
+
- https://www.unpkg.com/@e-mc/types@0.8.4/lib/settings.d.ts
|
|
77
|
+
|
|
78
|
+
## LICENSE
|
|
6
79
|
|
|
7
80
|
BSD 3-Clause
|
package/index.js
CHANGED
|
@@ -23,17 +23,19 @@ function hasSameBucket({ upload, service, bucket }, other) {
|
|
|
23
23
|
return (service && other.service || endpoint && endpoint === other.upload.endpoint) && bucket === other.bucket;
|
|
24
24
|
}
|
|
25
25
|
function getFiles(file, data) {
|
|
26
|
-
const
|
|
26
|
+
const localUri = file.localUri;
|
|
27
|
+
const grouped = [localUri && core_1.ClientDb.isPath(localUri, true) ? localUri : ''];
|
|
27
28
|
if (data.all) {
|
|
28
|
-
const individual = new Set();
|
|
29
|
-
if (!file.cloudUrl) {
|
|
30
|
-
file.transforms?.forEach(value => individual.add(value));
|
|
31
|
-
}
|
|
32
|
-
file.torrentFiles?.forEach(value => individual.add(value));
|
|
33
29
|
if (file.descendants) {
|
|
34
30
|
grouped.push(...file.descendants);
|
|
35
31
|
}
|
|
36
|
-
|
|
32
|
+
const individual = !file.cloudUrl && file.transforms || [];
|
|
33
|
+
if (file.torrentFiles) {
|
|
34
|
+
individual.push(...file.torrentFiles);
|
|
35
|
+
}
|
|
36
|
+
if (individual.length) {
|
|
37
|
+
return [grouped, Array.from(new Set(individual))];
|
|
38
|
+
}
|
|
37
39
|
}
|
|
38
40
|
return [grouped];
|
|
39
41
|
}
|
|
@@ -161,7 +163,7 @@ class Cloud extends core_1.ClientDb {
|
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
for (const [item, data] of localStorage) {
|
|
164
|
-
getFiles(item, data).forEach(group => group.forEach(value => this.deleteFile(value, { emptyDir: true })));
|
|
166
|
+
getFiles(item, data).forEach(group => group.forEach(value => value && this.deleteFile(value, { emptyDir: true })));
|
|
165
167
|
}
|
|
166
168
|
for (const item of this.assets) {
|
|
167
169
|
const cloudStorage = item.cloudStorage;
|
|
@@ -172,12 +174,11 @@ class Cloud extends core_1.ClientDb {
|
|
|
172
174
|
}
|
|
173
175
|
const download = data.download;
|
|
174
176
|
const { pathname, filename, waitStatus, overwrite } = download;
|
|
175
|
-
let active = download.active;
|
|
176
177
|
if (!filename) {
|
|
177
178
|
continue;
|
|
178
179
|
}
|
|
179
180
|
const localUri = item.localUri;
|
|
180
|
-
let downloadUri;
|
|
181
|
+
let active = download.active, downloadUri;
|
|
181
182
|
if (pathname && path.isAbsolute(pathname)) {
|
|
182
183
|
downloadUri = path.join(pathname, filename);
|
|
183
184
|
if (!Cloud.isPath(downloadUri) && !this.canWrite(pathname)) {
|
|
@@ -196,6 +197,7 @@ class Cloud extends core_1.ClientDb {
|
|
|
196
197
|
active = true;
|
|
197
198
|
}
|
|
198
199
|
else if (!Cloud.createDir(destDir)) {
|
|
200
|
+
instance.writeFail(["Unable to create directory" /* ERR_MESSAGE.CREATE_DIRECTORY */, filename], (0, types_1.errorValue)("Path is not a directory" /* ERR_MESSAGE.NOT_DIRECTORY */, destDir), { type: 64 /* LOG_TYPE.CLOUD */, fatal: !!active, startTime });
|
|
199
201
|
continue;
|
|
200
202
|
}
|
|
201
203
|
else if (active) {
|
|
@@ -269,16 +271,17 @@ class Cloud extends core_1.ClientDb {
|
|
|
269
271
|
contentType = file.mimeType;
|
|
270
272
|
}
|
|
271
273
|
const { host, instance } = state;
|
|
272
|
-
|
|
274
|
+
const cloudStorage = file.cloudStorage;
|
|
275
|
+
if (instance.aborted || !Array.isArray(cloudStorage)) {
|
|
273
276
|
return [];
|
|
274
277
|
}
|
|
275
278
|
const tasks = [];
|
|
276
|
-
for (const storage of
|
|
279
|
+
for (const storage of cloudStorage) {
|
|
277
280
|
if (!instance.hasStorage('upload', storage)) {
|
|
278
281
|
continue;
|
|
279
282
|
}
|
|
280
283
|
const upload = storage.upload;
|
|
281
|
-
const active = storage === instance.getStorage('upload',
|
|
284
|
+
const active = storage === instance.getStorage('upload', cloudStorage);
|
|
282
285
|
if (active && upload.localStorage === false) {
|
|
283
286
|
state.localStorage.set(file, upload);
|
|
284
287
|
}
|
|
@@ -301,30 +304,37 @@ class Cloud extends core_1.ClientDb {
|
|
|
301
304
|
const uploading = [];
|
|
302
305
|
getFiles(file, upload).forEach(async (group, index) => {
|
|
303
306
|
let fileGroup;
|
|
304
|
-
if (index === 0
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
+
if (index === 0) {
|
|
308
|
+
if (!group[0]) {
|
|
309
|
+
instance.writeFail("Unable to read file" /* ERR_MESSAGE.READ_FILE */, (0, types_1.errorValue)("File not found" /* ERR_MESSAGE.NOTFOUND_FILE */, service), { type: 64 /* LOG_TYPE.CLOUD */, fatal: true });
|
|
310
|
+
return;
|
|
307
311
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
if (group.length > 1) {
|
|
313
|
+
if (SERVICE_CLIENT.get(service)?.CLOUD_UPLOAD_FROMDISK) {
|
|
314
|
+
fileGroup = group.slice(1).filter(value => this.isPath(value, true)).map(value => [value, path.extname(value), value]);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
fileGroup = [];
|
|
318
|
+
for (let i = 1; i < group.length; ++i) {
|
|
319
|
+
const value = group[i];
|
|
320
|
+
if (this.isPath(value, true)) {
|
|
321
|
+
try {
|
|
322
|
+
fileGroup.push([typeof minStreamSize === 'number' ? await this.streamFile(value, { minStreamSize, cache: false, signal: instance.signal }) : fs.readFileSync(value), path.extname(value), value]);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(value)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: false });
|
|
326
|
+
}
|
|
315
327
|
}
|
|
316
328
|
}
|
|
317
|
-
catch (err) {
|
|
318
|
-
instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(value)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: false });
|
|
319
|
-
}
|
|
320
329
|
}
|
|
330
|
+
group = [group[0]];
|
|
321
331
|
}
|
|
322
|
-
group = [group[0]];
|
|
323
332
|
}
|
|
324
|
-
for (
|
|
325
|
-
const
|
|
333
|
+
for (let i = 0; i < group.length; ++i) {
|
|
334
|
+
const localUri = group[i];
|
|
335
|
+
const exists = index === 0 || this.isPath(localUri, true);
|
|
326
336
|
if (!exists || !instance.canRead(localUri, { ownPermissionOnly: true })) {
|
|
327
|
-
instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(localUri)], (0, types_1.errorValue)(exists ? "Not permitted to read file" /* ERR_MESSAGE.UNSUPPORTED_READ */ : "File not found" /* ERR_MESSAGE.NOTFOUND_FILE */, localUri), { type: 64 /* LOG_TYPE.CLOUD */, fatal: index === 0 });
|
|
337
|
+
instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(localUri)], (0, types_1.errorValue)(exists ? "Not permitted to read file" /* ERR_MESSAGE.UNSUPPORTED_READ */ : "File not found" /* ERR_MESSAGE.NOTFOUND_FILE */, localUri), { type: 64 /* LOG_TYPE.CLOUD */, fatal: i === 0 && index === 0 });
|
|
328
338
|
continue;
|
|
329
339
|
}
|
|
330
340
|
let buffer, filename;
|
|
@@ -348,7 +358,7 @@ class Cloud extends core_1.ClientDb {
|
|
|
348
358
|
options.contentType = contentType;
|
|
349
359
|
}
|
|
350
360
|
uploading.push(instance.uploadObject(service, { ...credential }, bucket, options, localUri, callback)
|
|
351
|
-
.catch(err => instance.writeFail(["Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */, path.basename(localUri)], err, { type: 64 /* LOG_TYPE.CLOUD */, fatal: index === 0 })));
|
|
361
|
+
.catch(err => instance.writeFail(["Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */, path.basename(localUri)], err, { type: 64 /* LOG_TYPE.CLOUD */, fatal: i === 0 && index === 0 })));
|
|
352
362
|
}
|
|
353
363
|
});
|
|
354
364
|
instance.allSettled(uploading, [`Upload file "${contentType || "Unknown" /* ERR_MESSAGE.UNKNOWN */}"`, storage.service + ': ' + path.basename(file.localUri)]).then(() => resolve());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/cloud",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Cloud constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"license": "BSD 3-Clause",
|
|
21
21
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/core": "0.8.
|
|
24
|
-
"@e-mc/db": "0.8.
|
|
25
|
-
"@e-mc/types": "0.8.
|
|
23
|
+
"@e-mc/core": "0.8.4",
|
|
24
|
+
"@e-mc/db": "0.8.4",
|
|
25
|
+
"@e-mc/types": "0.8.4",
|
|
26
26
|
"mime-types": "^2.1.35"
|
|
27
27
|
}
|
|
28
28
|
}
|
package/util.js
CHANGED
|
@@ -42,32 +42,30 @@ function createKeyAndBody(filename, items, mimeType, errorCallback) {
|
|
|
42
42
|
const body = [];
|
|
43
43
|
const type = [];
|
|
44
44
|
for (let [content, ext, localFile] of items) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
case 'object':
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
continue;
|
|
45
|
+
let buffer;
|
|
46
|
+
if (typeof content === 'string') {
|
|
47
|
+
try {
|
|
48
|
+
if (content === localFile || fs.existsSync(content)) {
|
|
49
|
+
buffer = fs.readFileSync(content);
|
|
50
|
+
localFile = content;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
buffer = Buffer.from(content);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
errorCallback?.(err);
|
|
62
58
|
}
|
|
59
|
+
}
|
|
60
|
+
else if (Buffer.isBuffer(content)) {
|
|
61
|
+
buffer = content;
|
|
62
|
+
}
|
|
63
|
+
if (buffer) {
|
|
63
64
|
const output = filename + ext;
|
|
64
65
|
key.push(ext === '.map' && localFile ? path.basename(localFile) : output);
|
|
65
|
-
body.push(
|
|
66
|
+
body.push(buffer);
|
|
66
67
|
type.push(ext !== '.map' && mime.lookup(output) || mimeType || 'application/octet-stream');
|
|
67
68
|
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
errorCallback?.(err);
|
|
70
|
-
}
|
|
71
69
|
}
|
|
72
70
|
return [key, body, type];
|
|
73
71
|
}
|