5htp-core 0.2.9 → 0.3.0
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/package.json +7 -5
- package/src/client/app/component.tsx +2 -2
- package/src/client/assets/css/text/titres.less +4 -0
- package/src/client/components/Dialog/card.tsx +1 -1
- package/src/client/components/Dialog/index.less +3 -3
- package/src/client/components/inputv3/date/index.tsx +1 -1
- package/src/client/components/inputv3/index.tsx +14 -4
- package/src/client/pages/_layout/index.tsx +3 -3
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/useHeader.tsx +2 -1
- package/src/client/services/router/components/router.tsx +1 -1
- package/src/client/services/router/index.tsx +5 -1
- package/src/client/services/router/response/index.tsx +5 -2
- package/src/common/data/objets.ts +0 -25
- package/src/common/router/index.ts +8 -12
- package/src/common/router/layouts.ts +3 -1
- package/src/common/router/register.ts +5 -3
- package/src/common/router/response/index.ts +3 -3
- package/src/server/app/commands.ts +2 -11
- package/src/server/app/{config.ts → container/config.ts} +4 -1
- package/src/server/app/container/index.ts +84 -0
- package/src/server/app/index.ts +73 -136
- package/src/server/app/instance.ts +3 -0
- package/src/server/app/service/container.ts +136 -0
- package/src/server/app/service/index.ts +219 -0
- package/src/server/index.ts +9 -3
- package/src/server/services/cache/index.ts +42 -16
- package/src/server/services/cache/service.json +6 -0
- package/src/server/services/console/index.ts +35 -22
- package/src/server/services/console/service.json +6 -0
- package/src/server/services/cron/index.ts +11 -11
- package/src/server/services/cron/service.json +6 -0
- package/src/server/services/database/connection.ts +26 -34
- package/src/server/services/database/index.ts +41 -21
- package/src/server/services/database/metas.ts +12 -7
- package/src/server/services/database/repository.ts +0 -9
- package/src/server/services/database/service.json +6 -0
- package/src/server/services/database/stats.ts +3 -3
- package/src/server/services/disks/driver.ts +9 -7
- package/src/server/services/disks/drivers/local/index.ts +199 -0
- package/src/server/services/disks/drivers/local/service.json +6 -0
- package/src/server/services/disks/drivers/s3/index.ts +282 -0
- package/src/server/services/disks/drivers/s3/service.json +6 -0
- package/src/server/services/disks/index.ts +47 -16
- package/src/server/services/disks/service.json +6 -0
- package/src/server/services/email/index.ts +16 -4
- package/src/server/services/email/service.json +6 -0
- package/src/server/services/fetch/index.ts +52 -8
- package/src/server/services/fetch/service.json +6 -0
- package/src/server/services/router/http/index.ts +12 -9
- package/src/server/services/router/index.ts +95 -68
- package/src/server/services/router/request/api.ts +1 -1
- package/src/server/services/router/response/index.ts +13 -19
- package/src/server/services/router/service.json +6 -0
- package/src/server/services/router/service.ts +16 -29
- package/src/server/services/schema/{router.ts → router/index.ts} +19 -7
- package/src/server/services/schema/router/service.json +6 -0
- package/src/server/services/schema/service.json +6 -0
- package/src/server/services/security/encrypt/{aes.ts → aes/index.ts} +16 -3
- package/src/server/services/security/encrypt/aes/service.json +6 -0
- package/src/server/services/socket/index.ts +39 -13
- package/src/server/services/socket/service.json +6 -0
- package/src/server/services/users/index.ts +16 -4
- package/src/server/services/users/old.ts +1 -1
- package/src/server/services/users/router/index.ts +21 -14
- package/src/server/services/users/router/service.json +6 -0
- package/src/server/services/users/service.json +6 -0
- package/src/types/aliases.d.ts +5 -0
- package/tsconfig.common.json +2 -0
- package/src/server/app/service.ts +0 -109
- /package/src/server/{patch.ts → app/container/patch.ts} +0 -0
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
import hInterval from 'human-interval';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
+
import type { Application } from '@server/app';
|
|
9
10
|
import Service from '@server/app/service';
|
|
10
11
|
import type CacheService from '../cache';
|
|
11
|
-
import type SQL from '
|
|
12
|
+
import type SQL from '.';
|
|
12
13
|
|
|
13
14
|
/*----------------------------------
|
|
14
15
|
- CONST
|
|
@@ -76,8 +77,7 @@ export default class StatsService extends Service<TStatsServiceConfig> {
|
|
|
76
77
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
public async start() {}
|
|
80
|
+
protected async start() {}
|
|
81
81
|
|
|
82
82
|
public async fetchStats<TDonnees extends TObjDonneesStats>(
|
|
83
83
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Core
|
|
6
|
-
import
|
|
6
|
+
import type { Application } from '@server/app';
|
|
7
|
+
import Service from '@server/app/service';
|
|
7
8
|
|
|
8
9
|
/*----------------------------------
|
|
9
10
|
- CONFIG
|
|
@@ -51,11 +52,7 @@ export type TReadFileOptions = {
|
|
|
51
52
|
export default abstract class FsDriver<
|
|
52
53
|
Config extends TDrivercnfig = TDrivercnfig,
|
|
53
54
|
TBucketName = keyof Config["buckets"]
|
|
54
|
-
> {
|
|
55
|
-
|
|
56
|
-
public constructor( public app: Application, public config: Config ) {
|
|
57
|
-
|
|
58
|
-
}
|
|
55
|
+
> extends Service<Config, {}, Application> {
|
|
59
56
|
|
|
60
57
|
public abstract mount(): Promise<void>;
|
|
61
58
|
|
|
@@ -73,7 +70,12 @@ export default abstract class FsDriver<
|
|
|
73
70
|
|
|
74
71
|
public abstract move( bucketName: TBucketName, source: string, destination: string, options: { overwrite?: boolean }): Promise<void>;
|
|
75
72
|
|
|
76
|
-
public abstract outputFile(
|
|
73
|
+
public abstract outputFile(
|
|
74
|
+
bucketName: TBucketName,
|
|
75
|
+
filename: string,
|
|
76
|
+
content: string | Buffer,
|
|
77
|
+
options?: TOutputFileOptions
|
|
78
|
+
): Promise<{
|
|
77
79
|
path: string
|
|
78
80
|
}>;
|
|
79
81
|
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPS
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
/*
|
|
5
|
+
A simple adapter to use fs-extra functions with AWS S3 buckets
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Node
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import dayjs from 'dayjs';
|
|
11
|
+
|
|
12
|
+
// Npm
|
|
13
|
+
import fs from 'fs-extra';
|
|
14
|
+
|
|
15
|
+
// Core
|
|
16
|
+
import AppContainer from '@server/app/container';
|
|
17
|
+
|
|
18
|
+
// Specific
|
|
19
|
+
import DiskDriver, { TDrivercnfig, SourceFile, TOutputFileOptions } from '../../driver';
|
|
20
|
+
|
|
21
|
+
/*----------------------------------
|
|
22
|
+
- CONFIG
|
|
23
|
+
----------------------------------*/
|
|
24
|
+
|
|
25
|
+
/*----------------------------------
|
|
26
|
+
- TYPES
|
|
27
|
+
----------------------------------*/
|
|
28
|
+
|
|
29
|
+
export type TConfig = TDrivercnfig & {
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*----------------------------------
|
|
34
|
+
- SERVICE
|
|
35
|
+
----------------------------------*/
|
|
36
|
+
export default class LocalFS<
|
|
37
|
+
Config extends TConfig = TConfig,
|
|
38
|
+
TBucketName = keyof Config["buckets"]
|
|
39
|
+
> extends DiskDriver<TConfig> {
|
|
40
|
+
|
|
41
|
+
public rootDir = AppContainer.path.var;
|
|
42
|
+
|
|
43
|
+
/*----------------------------------
|
|
44
|
+
- SERVICE LIFECYCLE
|
|
45
|
+
----------------------------------*/
|
|
46
|
+
|
|
47
|
+
public async start() {
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public async ready() {
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async shutdown() {
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*----------------------------------
|
|
60
|
+
- DISK LIFECYCLE
|
|
61
|
+
----------------------------------*/
|
|
62
|
+
|
|
63
|
+
public async mount() {
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public async unmount() {
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/*----------------------------------
|
|
72
|
+
- ACTIONS
|
|
73
|
+
----------------------------------*/
|
|
74
|
+
|
|
75
|
+
public async readDir( bucketName: TBucketName, dirname?: string ) {
|
|
76
|
+
|
|
77
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
78
|
+
|
|
79
|
+
const fullPath = path.join( this.rootDir, bucketDir, dirname || '.' );
|
|
80
|
+
|
|
81
|
+
// Combine the files list of all source directory
|
|
82
|
+
const files: SourceFile[] = [];
|
|
83
|
+
const sources = fs.readdirSync( fullPath, { withFileTypes: true });
|
|
84
|
+
for (const source of sources) {
|
|
85
|
+
|
|
86
|
+
if (!source.isDirectory())
|
|
87
|
+
continue;
|
|
88
|
+
|
|
89
|
+
const parentFolder = source.name;
|
|
90
|
+
const csvFiles = fs.readdirSync(
|
|
91
|
+
path.join( fullPath, parentFolder ),
|
|
92
|
+
{ withFileTypes: true }
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
for (const file of csvFiles) {
|
|
96
|
+
|
|
97
|
+
if (!file.isFile() || !file.name.endsWith('.csv'))
|
|
98
|
+
continue;
|
|
99
|
+
|
|
100
|
+
const relPath = path.join( source.name, file.name );
|
|
101
|
+
const fullpath = path.join( fullPath, relPath );
|
|
102
|
+
const stats = fs.statSync(fullpath);
|
|
103
|
+
|
|
104
|
+
const rowsCount = fs.readFileSync( fullpath, 'utf-8').split('\n').length - 1;
|
|
105
|
+
|
|
106
|
+
const name = dayjs(stats.mtime).format('DD/MM HH:mm:ss')
|
|
107
|
+
+ ' : ' + path.join( source.name, file.name )
|
|
108
|
+
+ ' : ' + rowsCount + ' contacts'
|
|
109
|
+
|
|
110
|
+
files.push({
|
|
111
|
+
name,
|
|
112
|
+
path: relPath,
|
|
113
|
+
parentFolder,
|
|
114
|
+
source: source.name,
|
|
115
|
+
modified: stats.mtimeMs
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.config.debug && console.log(`readDir ${fullPath}: ${files.length} objects`);
|
|
122
|
+
return files;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public async readFile( bucketName: TBucketName, filename: string ) {
|
|
126
|
+
|
|
127
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
128
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
129
|
+
|
|
130
|
+
this.config.debug && console.log(`readFile ${fullPath}`);
|
|
131
|
+
return fs.readFileSync( fullPath ).toString();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public createReadStream( bucketName: TBucketName, filename: string ) {
|
|
135
|
+
|
|
136
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
137
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
138
|
+
|
|
139
|
+
this.config.debug && console.log(`createReadStream ${fullPath}`);
|
|
140
|
+
return fs.createReadStream( fullPath );
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public async exists( bucketName: TBucketName, filename: string ) {
|
|
144
|
+
|
|
145
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
146
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
147
|
+
|
|
148
|
+
this.config.debug && console.log(`exists ${fullPath}`);
|
|
149
|
+
return fs.existsSync( fullPath );
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async move( bucketName: TBucketName, source: string, destination: string, options: { overwrite?: boolean } = {}) {
|
|
153
|
+
|
|
154
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
155
|
+
const fullPathSource = path.join( this.rootDir, bucketDir, source );
|
|
156
|
+
const fullPathDestination = path.join( this.rootDir, bucketDir, destination );
|
|
157
|
+
|
|
158
|
+
this.config.debug && console.log(`move ${fullPathSource} to ${fullPathDestination}`);
|
|
159
|
+
return fs.moveSync(fullPathSource, fullPathDestination, options);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public async outputFile(
|
|
163
|
+
bucketName: TBucketName,
|
|
164
|
+
filename: string,
|
|
165
|
+
content: string | Buffer,
|
|
166
|
+
options?: TOutputFileOptions
|
|
167
|
+
) {
|
|
168
|
+
|
|
169
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
170
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
171
|
+
this.config.debug && console.log(`outputFile`, fullPath);
|
|
172
|
+
|
|
173
|
+
fs.outputFileSync( fullPath, content, options );
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
path: fullPath
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public async readJSON( bucketName: TBucketName, filename: string ) {
|
|
181
|
+
|
|
182
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
183
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
184
|
+
|
|
185
|
+
this.config.debug && console.log(`readJSON ${fullPath}`);
|
|
186
|
+
return fs.readJsonSync( fullPath );
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public async delete( bucketName: TBucketName, filename: string ) {
|
|
190
|
+
|
|
191
|
+
const bucketDir = this.config.buckets[bucketName];
|
|
192
|
+
const fullPath = path.join( this.rootDir, bucketDir, filename );
|
|
193
|
+
|
|
194
|
+
this.config.debug && console.log(`delete ${fullPath}`);
|
|
195
|
+
fs.removeSync( fullPath );
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPS
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
/*
|
|
5
|
+
A simple adapter to use fs-extra functions with AWS S3 buckets
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Node
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
// Npm
|
|
12
|
+
import AWS from 'aws-sdk';
|
|
13
|
+
import dayjs from 'dayjs';
|
|
14
|
+
|
|
15
|
+
// Core
|
|
16
|
+
import type { Application } from '@server/app';
|
|
17
|
+
import type { AnyService, TRegisteredServicesIndex } from '@server/app/service';
|
|
18
|
+
|
|
19
|
+
// Specific
|
|
20
|
+
import DiskDriver, {
|
|
21
|
+
TDrivercnfig,
|
|
22
|
+
SourceFile,
|
|
23
|
+
TOutputFileOptions,
|
|
24
|
+
TReadFileOptions
|
|
25
|
+
} from '@server/services/disks/driver';
|
|
26
|
+
|
|
27
|
+
/*----------------------------------
|
|
28
|
+
- CONFIG
|
|
29
|
+
----------------------------------*/
|
|
30
|
+
|
|
31
|
+
const debug = false;
|
|
32
|
+
|
|
33
|
+
/*----------------------------------
|
|
34
|
+
- TYPES
|
|
35
|
+
----------------------------------*/
|
|
36
|
+
|
|
37
|
+
export type TConfig = TDrivercnfig & {
|
|
38
|
+
accessKeyId: string,
|
|
39
|
+
secretAccessKey: string,
|
|
40
|
+
region: string,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/*----------------------------------
|
|
44
|
+
- SERVICE
|
|
45
|
+
----------------------------------*/
|
|
46
|
+
export default class S3Driver<
|
|
47
|
+
Config extends TConfig = TConfig,
|
|
48
|
+
TBucketName = keyof Config["buckets"]
|
|
49
|
+
> extends DiskDriver<TConfig> {
|
|
50
|
+
|
|
51
|
+
public s3: AWS.S3;
|
|
52
|
+
|
|
53
|
+
public constructor(
|
|
54
|
+
public parent: AnyService,
|
|
55
|
+
public config: TConfig,
|
|
56
|
+
public services: TRegisteredServicesIndex,
|
|
57
|
+
public app: Application
|
|
58
|
+
) {
|
|
59
|
+
|
|
60
|
+
super( parent, config, services, app );
|
|
61
|
+
|
|
62
|
+
AWS.config.update({
|
|
63
|
+
accessKeyId: this.config.accessKeyId,
|
|
64
|
+
secretAccessKey: this.config.secretAccessKey,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.s3 = new AWS.S3();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/*----------------------------------
|
|
71
|
+
- SERVICE LIFECYCLE
|
|
72
|
+
----------------------------------*/
|
|
73
|
+
|
|
74
|
+
public async start() {
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async ready() {
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public async shutdown() {
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*----------------------------------
|
|
87
|
+
- DISK LIFECYCLE
|
|
88
|
+
----------------------------------*/
|
|
89
|
+
|
|
90
|
+
public async mount() {
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public async unmount() {
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/*----------------------------------
|
|
99
|
+
- ACTIONS
|
|
100
|
+
----------------------------------*/
|
|
101
|
+
|
|
102
|
+
public readDir( bucketName: TBucketName, dirname?: string ) {
|
|
103
|
+
const bucket = this.config.buckets[bucketName];
|
|
104
|
+
return new Promise<SourceFile[]>((resolve, reject) => {
|
|
105
|
+
debug && console.log(`readDir ` + (dirname === undefined ? bucket : path.join( bucket, dirname )));
|
|
106
|
+
this.s3.listObjectsV2({ Bucket: bucket }, async (err, data) => {
|
|
107
|
+
|
|
108
|
+
if (err) return reject(err);
|
|
109
|
+
|
|
110
|
+
const files: SourceFile[] = [];
|
|
111
|
+
for (const file of data.Contents) {
|
|
112
|
+
|
|
113
|
+
const [source, ...hierarchy] = file.Key.split('/');
|
|
114
|
+
if (hierarchy.length > 1) // Take only direct childs
|
|
115
|
+
continue;
|
|
116
|
+
|
|
117
|
+
const filename = hierarchy.join('/');
|
|
118
|
+
if (!filename.endsWith('.csv'))
|
|
119
|
+
continue;
|
|
120
|
+
|
|
121
|
+
debug && console.log('-', file.Key);
|
|
122
|
+
|
|
123
|
+
const fileContent = await this.readFile( bucketName, file.Key );
|
|
124
|
+
const rowsCount = (fileContent as unknown as string).split('\n').length - 1;
|
|
125
|
+
|
|
126
|
+
const name = dayjs(file.LastModified).format('DD/MM HH:mm:ss')
|
|
127
|
+
+ ' : ' + path.join( source, filename )
|
|
128
|
+
+ ' : ' + rowsCount + ' contacts'
|
|
129
|
+
|
|
130
|
+
files.push({
|
|
131
|
+
name,
|
|
132
|
+
path: file.Key,
|
|
133
|
+
source: source,
|
|
134
|
+
modified: file.LastModified,
|
|
135
|
+
parentFolder: source
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
debug && console.log(`readDir ${bucket}/${dirname || ''}: ${files.length} objects`);
|
|
141
|
+
resolve(files);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public readFile(
|
|
147
|
+
bucketName: TBucketName,
|
|
148
|
+
filename: string,
|
|
149
|
+
options: TReadFileOptions = {}
|
|
150
|
+
) {
|
|
151
|
+
const bucket = this.config.buckets[bucketName];
|
|
152
|
+
debug && console.log(`readFile ${bucket}/${filename}`);
|
|
153
|
+
return new Promise<string>(( resolve, reject ) => {
|
|
154
|
+
this.s3.getObject({
|
|
155
|
+
Bucket: bucket,
|
|
156
|
+
Key: filename
|
|
157
|
+
}, (err, data) => {
|
|
158
|
+
|
|
159
|
+
if (err) return reject(err);
|
|
160
|
+
|
|
161
|
+
let body: any;
|
|
162
|
+
switch (options.encoding) {
|
|
163
|
+
case 'string':
|
|
164
|
+
body = data.Body?.toString()
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
body = data.Body;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resolve( body );
|
|
172
|
+
});
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public createReadStream( bucketName: TBucketName, filename: string ) {
|
|
177
|
+
const bucket = this.config.buckets[bucketName];
|
|
178
|
+
debug && console.log(`createReadStream ${bucket}/${filename}`);
|
|
179
|
+
return this.s3.getObject({
|
|
180
|
+
Bucket: bucket,
|
|
181
|
+
Key: filename
|
|
182
|
+
}).createReadStream();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public exists( bucketName: TBucketName, filename: string ) {
|
|
186
|
+
const bucket = this.config.buckets[bucketName];
|
|
187
|
+
debug && console.log(`exists`, path.join(bucket, filename));
|
|
188
|
+
return new Promise<boolean>(( resolve, reject ) => {
|
|
189
|
+
this.s3.headObject({
|
|
190
|
+
Bucket: bucket,
|
|
191
|
+
Key: filename
|
|
192
|
+
}, (err, metadata) => {
|
|
193
|
+
|
|
194
|
+
if (!err)
|
|
195
|
+
resolve(true);
|
|
196
|
+
else if (err.name === 'NotFound')
|
|
197
|
+
resolve(false);
|
|
198
|
+
else
|
|
199
|
+
reject(err);
|
|
200
|
+
});
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public async move( bucketName: TBucketName, source: string, destination: string, options: { overwrite?: boolean } = {}) {
|
|
205
|
+
const bucket = this.config.buckets[bucketName];
|
|
206
|
+
debug && console.log(`move ${bucket}/${source} to ${bucket}/${destination}`);
|
|
207
|
+
|
|
208
|
+
if (options.overwrite)
|
|
209
|
+
await this.s3.deleteObject({
|
|
210
|
+
Bucket: bucket,
|
|
211
|
+
Key: destination,
|
|
212
|
+
}).promise();
|
|
213
|
+
|
|
214
|
+
await this.s3.copyObject({
|
|
215
|
+
Bucket: bucket,
|
|
216
|
+
CopySource: source,
|
|
217
|
+
Key: destination
|
|
218
|
+
}).promise();
|
|
219
|
+
|
|
220
|
+
debug && console.log(`Move ${bucket}/${source} to ${bucket}/${destination}: OK`);
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public outputFile(
|
|
225
|
+
bucketName: TBucketName,
|
|
226
|
+
filename: string,
|
|
227
|
+
content: string | Buffer,
|
|
228
|
+
options?: TOutputFileOptions
|
|
229
|
+
) {
|
|
230
|
+
const bucket = this.config.buckets[bucketName];
|
|
231
|
+
debug && console.log(`outputFile ${bucket}/${filename}`);
|
|
232
|
+
return new Promise(( resolve, reject ) => {
|
|
233
|
+
this.s3.upload({
|
|
234
|
+
Bucket: bucket,
|
|
235
|
+
Key: filename,
|
|
236
|
+
Body: content,
|
|
237
|
+
ACL: 'public-read'
|
|
238
|
+
}, (err, data) => {
|
|
239
|
+
|
|
240
|
+
if (err) return reject(err);
|
|
241
|
+
debug && console.log(`outputFile ${bucket}/${filename}: OK (${data.Location})`);
|
|
242
|
+
|
|
243
|
+
resolve({
|
|
244
|
+
path: data.Location
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
public async readJSON( bucketName: TBucketName, filename: string ) {
|
|
251
|
+
const bucket = this.config.buckets[bucketName];
|
|
252
|
+
debug && console.log(`readJSON ${bucket}/${filename}`);
|
|
253
|
+
const filecontent = await this.readFile(bucketName, filename);
|
|
254
|
+
try {
|
|
255
|
+
debug && console.log(`readJSON: ${bucket}/${filename} : PARSE JSON`);
|
|
256
|
+
return JSON.parse(filecontent);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error(`Failed to parse file "${filename}" as JSON: `, error);
|
|
259
|
+
throw new Error(`Failed to parse file "${filename}" as JSON: ` + error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public delete( bucketName: TBucketName, filename: string ) {
|
|
264
|
+
const bucket = this.config.buckets[bucketName];
|
|
265
|
+
debug && console.log(`delete ${bucket}/${filename}`);
|
|
266
|
+
return new Promise<boolean>(( resolve, reject ) => {
|
|
267
|
+
this.s3.deleteObject({
|
|
268
|
+
Bucket: bucket,
|
|
269
|
+
Key: filename
|
|
270
|
+
}, (err, metadata) => {
|
|
271
|
+
|
|
272
|
+
if (!err)
|
|
273
|
+
resolve(true);
|
|
274
|
+
else if (err.name === 'NotFound')
|
|
275
|
+
resolve(false);
|
|
276
|
+
else
|
|
277
|
+
reject(err);
|
|
278
|
+
});
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
}
|
|
@@ -3,61 +3,92 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Core
|
|
6
|
-
import
|
|
6
|
+
import type { Application } from '@server/app';
|
|
7
|
+
import Service, { AnyService } from '@server/app/service';
|
|
8
|
+
import type { TRegisteredServicesIndex } from '@server/app/service/container';
|
|
7
9
|
|
|
8
10
|
// Specific
|
|
9
11
|
import type Driver from './driver';
|
|
12
|
+
export type { default as Driver } from './driver';
|
|
10
13
|
|
|
11
14
|
/*----------------------------------
|
|
12
15
|
- TYPES
|
|
13
16
|
----------------------------------*/
|
|
14
17
|
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
default: keyof MountpointList,
|
|
18
|
+
type Config = {
|
|
19
|
+
debug: boolean,
|
|
20
|
+
default: string,//keyof MountpointList,
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export type Hooks = {
|
|
22
24
|
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
type TMountpointList = { [name: string]: Driver }
|
|
28
|
+
|
|
25
29
|
/*----------------------------------
|
|
26
30
|
- SERVICE
|
|
27
31
|
----------------------------------*/
|
|
28
32
|
export default class DisksManager<
|
|
29
33
|
MountpointList extends TMountpointList = {},
|
|
30
|
-
TConfig extends Config
|
|
34
|
+
TConfig extends Config = Config,
|
|
31
35
|
TApplication extends Application = Application
|
|
32
36
|
> extends Service<TConfig, Hooks, TApplication> {
|
|
33
37
|
|
|
34
38
|
public default: Driver;
|
|
35
39
|
|
|
40
|
+
public mounted: TMountpointList = this.services;
|
|
41
|
+
|
|
36
42
|
public constructor(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
parent: AnyService,
|
|
44
|
+
config: TConfig,
|
|
45
|
+
drivers: TRegisteredServicesIndex< Driver >,
|
|
46
|
+
app: TApplication,
|
|
40
47
|
) {
|
|
41
48
|
|
|
42
|
-
super(
|
|
49
|
+
super(parent, config, drivers, app);
|
|
50
|
+
|
|
51
|
+
if (Object.keys( drivers ).length === 0)
|
|
52
|
+
throw new Error("At least one disk driver should be mounted.");
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*----------------------------------
|
|
57
|
+
- LIFECYCLE
|
|
58
|
+
----------------------------------*/
|
|
43
59
|
|
|
44
|
-
|
|
45
|
-
throw new Error("At least one disk should be mounted.");
|
|
60
|
+
public async start() {
|
|
46
61
|
|
|
47
|
-
const defaultDisk = mounted[ config.default ];
|
|
62
|
+
const defaultDisk = this.mounted[ this.config.default ];
|
|
48
63
|
if (defaultDisk === undefined)
|
|
49
|
-
console.log(`Default disk "${config.default as string}" not mounted.`);
|
|
64
|
+
console.log(`Default disk "${this.config.default as string}" not mounted.`);
|
|
50
65
|
|
|
51
66
|
this.default = defaultDisk;
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public async ready() {
|
|
52
71
|
|
|
53
72
|
}
|
|
54
73
|
|
|
55
|
-
public async
|
|
74
|
+
public async shutdown() {
|
|
56
75
|
|
|
57
76
|
}
|
|
58
77
|
|
|
59
|
-
|
|
78
|
+
/*----------------------------------
|
|
79
|
+
- LIFECYCLE
|
|
80
|
+
----------------------------------*/
|
|
81
|
+
|
|
82
|
+
public get( diskName?: 'default' | keyof MountpointList ): Driver {
|
|
83
|
+
|
|
84
|
+
const disk = diskName == 'default' || diskName === undefined
|
|
85
|
+
? this.default
|
|
86
|
+
: this.mounted[diskName];
|
|
87
|
+
|
|
88
|
+
if (disk === undefined)
|
|
89
|
+
throw new Error(`Disk "${diskName as string}" not found.`);
|
|
60
90
|
|
|
91
|
+
return disk;
|
|
61
92
|
}
|
|
62
93
|
|
|
63
94
|
}
|