pg-mvc-service 2.0.42 → 2.0.43
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/dist/assets/favicon.ico +0 -0
- package/dist/models/TableDoc.js +4 -1
- package/package.json +8 -2
- package/index.d.ts +0 -189
- package/src/PoolManager.ts +0 -48
- package/src/Service.ts +0 -276
- package/src/Utils/DateTimeUtil.ts +0 -146
- package/src/Utils/NumberUtil.ts +0 -23
- package/src/Utils/StringUtil.ts +0 -33
- package/src/clients/AwsS3Client.ts +0 -310
- package/src/clients/Base64Client.ts +0 -305
- package/src/clients/EncryptClient.ts +0 -100
- package/src/clients/StringClient.ts +0 -19
- package/src/cron/BaseCron.ts +0 -122
- package/src/cron/CronExecuter.ts +0 -34
- package/src/cron/CronType.ts +0 -25
- package/src/documents/Swagger.ts +0 -105
- package/src/exceptions/Exception.ts +0 -72
- package/src/index.ts +0 -23
- package/src/models/ExpressionClient.ts +0 -72
- package/src/models/MigrateDatabase.ts +0 -135
- package/src/models/MigrateRollback.ts +0 -151
- package/src/models/MigrateTable.ts +0 -56
- package/src/models/SqlUtils/SelectExpression.ts +0 -97
- package/src/models/SqlUtils/UpdateExpression.ts +0 -29
- package/src/models/SqlUtils/ValidateValueUtil.ts +0 -354
- package/src/models/SqlUtils/WhereExpression.ts +0 -421
- package/src/models/TableDoc.ts +0 -366
- package/src/models/TableModel.ts +0 -701
- package/src/models/Type.ts +0 -62
- package/src/models/Utils/MessageUtil.ts +0 -60
- package/src/models/ValidateClient.ts +0 -182
- package/src/reqestResponse/ReqResType.ts +0 -170
- package/src/reqestResponse/RequestType.ts +0 -918
- package/src/reqestResponse/ResponseType.ts +0 -420
- package/tsconfig.json +0 -14
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { PDFDocument } from 'pdf-lib';
|
|
3
|
-
import sharp from 'sharp';
|
|
4
|
-
import { ValidateStringUtil } from 'type-utils-n-daira';
|
|
5
|
-
|
|
6
|
-
export type TPng = 'image/png';
|
|
7
|
-
export type TJpeg = 'image/jpeg';
|
|
8
|
-
export type TGif = 'image/gif';
|
|
9
|
-
export type TImage = TPng | TJpeg | TGif;
|
|
10
|
-
|
|
11
|
-
export type TPdf = 'application/pdf';
|
|
12
|
-
export type TJson = 'application/json';
|
|
13
|
-
|
|
14
|
-
export class Base64Client {
|
|
15
|
-
public readonly PREFIX_JPEG_DATA = '/9j/';
|
|
16
|
-
public readonly PREFIX_PNG_DATA = 'iVBORw0KGgo';
|
|
17
|
-
|
|
18
|
-
constructor() { }
|
|
19
|
-
|
|
20
|
-
// public encode(text: string): string {
|
|
21
|
-
// return Buffer.from(text).toString('base64');
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
public tryDecode(base64: string): Buffer<ArrayBuffer> | false {
|
|
25
|
-
try {
|
|
26
|
-
// Data URLのパターンをチェック
|
|
27
|
-
if (base64.startsWith('data:')) {
|
|
28
|
-
const matches = base64.match(/^data:([A-Za-z-+/]+);base64,(.+)$/);
|
|
29
|
-
if (!matches || matches.length !== 3) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
// base64部分のみを取得
|
|
33
|
-
base64 = matches[2];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (base64.length % 4 !== 0) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
41
|
-
if (!regex.test(base64)) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return Buffer.from(base64, 'base64');
|
|
46
|
-
} catch {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public getMimeType(data: string | Buffer<ArrayBuffer>): TImage | TPdf {
|
|
52
|
-
try {
|
|
53
|
-
let buffer;
|
|
54
|
-
if (typeof data === 'string') {
|
|
55
|
-
// Data URLのパターンをチェック
|
|
56
|
-
if (data.startsWith('data:')) {
|
|
57
|
-
const matches = data.match(/^data:([A-Za-z-+/]+);base64,(.+)$/);
|
|
58
|
-
if (!matches || matches.length !== 3) {
|
|
59
|
-
throw new Error('Invalid Data URL format');
|
|
60
|
-
}
|
|
61
|
-
// base64部分のみを取得
|
|
62
|
-
data = matches[2];
|
|
63
|
-
}
|
|
64
|
-
buffer = this.tryDecode(data);
|
|
65
|
-
} else {
|
|
66
|
-
buffer = data;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (buffer === false) {
|
|
70
|
-
throw new Error('Cannot getMineType because the input is not in base64 format.');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const header = buffer.subarray(0, 4);
|
|
74
|
-
if (header[0] === 0x25 && header[1] === 0x50 && header[2] === 0x44 && header[3] === 0x46) {
|
|
75
|
-
return 'application/pdf';
|
|
76
|
-
} else if (header[0] === 0x89 && header[1] === 0x50 && header[2] === 0x4E && header[3] === 0x47) {
|
|
77
|
-
return 'image/png';
|
|
78
|
-
} else if (header[0] === 0xFF && header[1] === 0xD8) {
|
|
79
|
-
return 'image/jpeg';
|
|
80
|
-
} else if (header[0] === 0x47 && header[1] === 0x49 && header[2] === 0x46 && header[3] === 0x38) {
|
|
81
|
-
return 'image/gif';
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
throw new Error('Cannot getMimeType because the file type is not PDF, PNG, JPEG, or GIF.');
|
|
85
|
-
} catch {
|
|
86
|
-
throw new Error('Cannot getMineType because the input is not in base64 format.');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public async mergeToPdfBase64(datas: string[]): Promise<string> {
|
|
91
|
-
const mergedPdf = await PDFDocument.create();
|
|
92
|
-
|
|
93
|
-
for (const data of datas) {
|
|
94
|
-
const buffer = this.tryDecode(data);
|
|
95
|
-
if (buffer === false) {
|
|
96
|
-
throw new Error('Cannot mergeToPdf because the input is not in base64 format.');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const fileType = this.getMimeType(buffer);
|
|
100
|
-
if (fileType === 'application/pdf') {
|
|
101
|
-
const pdfDoc = await PDFDocument.load(buffer);
|
|
102
|
-
const pages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
|
|
103
|
-
pages.forEach(page => mergedPdf.addPage(page));
|
|
104
|
-
} else {
|
|
105
|
-
// convert from image to pdf
|
|
106
|
-
const imagePdf = await this.convertImageToPdf(buffer);
|
|
107
|
-
const pdfDoc = await PDFDocument.load(imagePdf);
|
|
108
|
-
const pages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
|
|
109
|
-
pages.forEach(page => mergedPdf.addPage(page));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 結合したPDFをBase64に変換
|
|
114
|
-
const mergedPdfBytes = await mergedPdf.save();
|
|
115
|
-
return Buffer.from(mergedPdfBytes).toString('base64');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private async convertImageToPdf(imageBuffer: Buffer): Promise<Buffer> {
|
|
119
|
-
const fileType = this.getMimeType(imageBuffer);
|
|
120
|
-
|
|
121
|
-
let optimizedImage;
|
|
122
|
-
if (fileType === 'image/gif') {
|
|
123
|
-
// gifの場合はpngに変換して処理
|
|
124
|
-
optimizedImage = await sharp(imageBuffer)
|
|
125
|
-
.png()
|
|
126
|
-
.toBuffer();
|
|
127
|
-
} else {
|
|
128
|
-
optimizedImage = await sharp(imageBuffer).toBuffer();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 新しいPDFドキュメントを作成
|
|
132
|
-
const pdfDoc = await PDFDocument.create();
|
|
133
|
-
const page = pdfDoc.addPage();
|
|
134
|
-
|
|
135
|
-
// 画像をPDFに埋め込み
|
|
136
|
-
|
|
137
|
-
let image;
|
|
138
|
-
if (fileType === 'image/jpeg') {
|
|
139
|
-
image = await pdfDoc.embedJpg(optimizedImage);
|
|
140
|
-
} else {
|
|
141
|
-
image = await pdfDoc.embedPng(optimizedImage);
|
|
142
|
-
}
|
|
143
|
-
const { width, height } = image.scale(1);
|
|
144
|
-
|
|
145
|
-
// ページサイズを画像に合わせる
|
|
146
|
-
page.setSize(width, height);
|
|
147
|
-
|
|
148
|
-
// 画像を描画
|
|
149
|
-
page.drawImage(image, {
|
|
150
|
-
x: 0,
|
|
151
|
-
y: 0,
|
|
152
|
-
width,
|
|
153
|
-
height,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// PDFをバッファに変換
|
|
157
|
-
const pdfBytes = await pdfDoc.save();
|
|
158
|
-
return Buffer.from(pdfBytes);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
public isJpeg(value: any): value is string {
|
|
162
|
-
if (ValidateStringUtil.isBase64(value) === false) {
|
|
163
|
-
return false
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (value.startsWith('data:')) {
|
|
167
|
-
if (value.startsWith('data:image/jpeg,') === false && value.startsWith('data:image/jpg,') === false) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const valueParts = value.split(',');
|
|
172
|
-
if (valueParts.length !== 2) {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return valueParts[1].startsWith(this.PREFIX_JPEG_DATA);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return value.startsWith(this.PREFIX_JPEG_DATA);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
public isPng(value: any): value is string {
|
|
183
|
-
if (ValidateStringUtil.isBase64(value) === false) {
|
|
184
|
-
return false
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (value.startsWith('data:')) {
|
|
188
|
-
if (value.startsWith('data:image/png,') === false) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const valueParts = value.split(',');
|
|
193
|
-
if (valueParts.length !== 2) {
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return valueParts[1].startsWith(this.PREFIX_PNG_DATA);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return value.startsWith(this.PREFIX_PNG_DATA);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
public async tryConvertToPng(base64Value: any): Promise<string | false> {
|
|
204
|
-
if (ValidateStringUtil.isBase64(base64Value) === false) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const base64Data = base64Value.startsWith('data:') ? base64Value.split(',')[1] : base64Value;
|
|
209
|
-
if (this.isPng(base64Data)) {
|
|
210
|
-
return base64Data;
|
|
211
|
-
} else if (this.isJpeg(base64Data)) {
|
|
212
|
-
const buffer = Buffer.from(base64Data, 'base64');
|
|
213
|
-
try {
|
|
214
|
-
const pngBuffer = await sharp(buffer)
|
|
215
|
-
.ensureAlpha().png().toBuffer();
|
|
216
|
-
return pngBuffer.toString('base64');
|
|
217
|
-
} catch (e) {
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
public async resizeImage(base64Data: string, toSize: {w: number} | {h: number} | {w: number; h: number; func: 'max' | 'min'}| {rate: number}): Promise<string> {
|
|
226
|
-
if (ValidateStringUtil.isBase64(base64Data) === false) {
|
|
227
|
-
throw new Error("The specified data is not in base64 format");
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const imageBuffer = Buffer.from(base64Data, 'base64');
|
|
231
|
-
const metadata = await sharp(imageBuffer).metadata();
|
|
232
|
-
const { width, height, format } = metadata;
|
|
233
|
-
if (width === undefined || height === undefined) {
|
|
234
|
-
throw new Error("Failed to retrieve image dimensions");
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let rate = 1;
|
|
238
|
-
if ('rate' in toSize) {
|
|
239
|
-
rate = toSize.rate;
|
|
240
|
-
} else if ('w' in toSize && 'h' in toSize && 'func' in toSize) {
|
|
241
|
-
const wRate = toSize.w / width;
|
|
242
|
-
const hRate = toSize.h / height;
|
|
243
|
-
switch (toSize.func) {
|
|
244
|
-
case 'max':
|
|
245
|
-
rate = Math.max(wRate, hRate);
|
|
246
|
-
break;
|
|
247
|
-
case 'min':
|
|
248
|
-
rate = Math.min(wRate, hRate);
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
} else if ('w' in toSize) {
|
|
253
|
-
rate = toSize.w / width;
|
|
254
|
-
} else if ('h' in toSize) {
|
|
255
|
-
rate = toSize.h / height;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// 画像は1倍より大きくできないので
|
|
259
|
-
if (rate >= 1 || rate <= 0) {
|
|
260
|
-
return base64Data;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let resizedImage: Buffer;
|
|
264
|
-
|
|
265
|
-
// フォーマットに応じて処理を分岐
|
|
266
|
-
const targetWidth = Math.round(width * rate);
|
|
267
|
-
const targetHeight = Math.round(height * rate);
|
|
268
|
-
if (format === 'png') {
|
|
269
|
-
resizedImage = await sharp(imageBuffer)
|
|
270
|
-
.resize(targetWidth, targetHeight, {
|
|
271
|
-
fit: 'inside',
|
|
272
|
-
withoutEnlargement: true
|
|
273
|
-
})
|
|
274
|
-
.png({ quality: 90 })
|
|
275
|
-
.toBuffer();
|
|
276
|
-
} else {
|
|
277
|
-
// JPEG、その他のフォーマット
|
|
278
|
-
resizedImage = await sharp(imageBuffer)
|
|
279
|
-
.resize(targetWidth, targetHeight, {
|
|
280
|
-
fit: 'inside',
|
|
281
|
-
withoutEnlargement: true
|
|
282
|
-
})
|
|
283
|
-
.jpeg({ quality: 90 })
|
|
284
|
-
.toBuffer();
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return resizedImage.toString('base64');
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
public async fetchImageAsBase64(imageUrl: string): Promise<string> {
|
|
291
|
-
const res = await axios.get(imageUrl, {
|
|
292
|
-
responseType: 'arraybuffer' // これを追加
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// Content-Typeをチェック
|
|
296
|
-
const contentType = res.headers['content-type'];
|
|
297
|
-
if (!contentType?.startsWith('image/')) {
|
|
298
|
-
throw new Error(`Invalid content type: ${contentType}. Expected image/*`);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// ArrayBufferをBufferに変換してBase64にエンコード
|
|
302
|
-
const buffer = Buffer.from(res.data);
|
|
303
|
-
return buffer.toString('base64');
|
|
304
|
-
}
|
|
305
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
|
|
3
|
-
export class EncryptClient {
|
|
4
|
-
private secretKeyHex?: string;
|
|
5
|
-
get SecretKey(): Buffer<ArrayBuffer> {
|
|
6
|
-
if (this.secretKeyHex === undefined) {
|
|
7
|
-
throw new Error("Please set the secret key.");
|
|
8
|
-
}
|
|
9
|
-
return Buffer.from(this.secretKeyHex, 'hex');
|
|
10
|
-
}
|
|
11
|
-
private hmacKeyBase64?: string;
|
|
12
|
-
get HmacKey(): Buffer<ArrayBuffer> {
|
|
13
|
-
if (this.hmacKeyBase64 === undefined) {
|
|
14
|
-
throw new Error("Please set the hmac key.");
|
|
15
|
-
}
|
|
16
|
-
return Buffer.from(this.hmacKeyBase64, 'base64');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
constructor(params: {secretKeyHex?: string, hmacKeyBase64?: string}) {
|
|
20
|
-
this.secretKeyHex = params?.secretKeyHex;
|
|
21
|
-
this.hmacKeyBase64 = params?.hmacKeyBase64;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public encryptAndSign(data: string | {[key: string]: any}): string {
|
|
25
|
-
const iv = crypto.randomBytes(12);
|
|
26
|
-
const cipher = crypto.createCipheriv('aes-256-gcm', this.SecretKey, iv);
|
|
27
|
-
|
|
28
|
-
const plaintext = typeof data === 'string' ? data : JSON.stringify(data);
|
|
29
|
-
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
30
|
-
const authTag = cipher.getAuthTag();
|
|
31
|
-
|
|
32
|
-
const combined = Buffer.concat([iv, authTag, encrypted]);
|
|
33
|
-
const payload = this.base64urlEncode(combined);
|
|
34
|
-
|
|
35
|
-
const hmac = crypto.createHmac('sha256', this.HmacKey).update(payload).digest();
|
|
36
|
-
const signature = this.base64urlEncode(hmac);
|
|
37
|
-
|
|
38
|
-
return `${payload}.${signature}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public isValidToken(token: string): boolean {
|
|
42
|
-
// 形式チェック、.で区切られているか?
|
|
43
|
-
const [payload, signature] = token.split('.');
|
|
44
|
-
if (!payload || !signature) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 改竄チェック
|
|
49
|
-
const expectedSig = crypto.createHmac('sha256', this.HmacKey).update(payload).digest();
|
|
50
|
-
const expectedSigStr = this.base64urlEncode(expectedSig);
|
|
51
|
-
|
|
52
|
-
if (signature !== expectedSigStr) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public decrypt<T>(token: string): T {
|
|
60
|
-
// 形式チェック、.で区切られているか?
|
|
61
|
-
const [payload, signature] = token.split('.');
|
|
62
|
-
if (!payload || !signature) {
|
|
63
|
-
throw new Error('Invalid token format');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 改竄チェック
|
|
67
|
-
const expectedSig = crypto.createHmac('sha256', this.HmacKey).update(payload).digest();
|
|
68
|
-
const expectedSigStr = this.base64urlEncode(expectedSig);
|
|
69
|
-
if (signature !== expectedSigStr){
|
|
70
|
-
throw new Error('The token appears to have been tampered with');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const combined = this.base64urlDecode(payload);
|
|
74
|
-
const iv = combined.subarray(0, 12);
|
|
75
|
-
const authTag = combined.subarray(12, 28);
|
|
76
|
-
const encrypted = combined.subarray(28);
|
|
77
|
-
|
|
78
|
-
const decipher = crypto.createDecipheriv('aes-256-gcm', this.SecretKey, iv);
|
|
79
|
-
decipher.setAuthTag(authTag);
|
|
80
|
-
|
|
81
|
-
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
82
|
-
return JSON.parse(decrypted.toString('utf8')) as T;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
private base64urlEncode(buffer: Buffer): string {
|
|
87
|
-
return buffer.toString('base64')
|
|
88
|
-
.replace(/\+/g, '-')
|
|
89
|
-
.replace(/\//g, '_')
|
|
90
|
-
.replace(/=+$/, '');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private base64urlDecode(str: string): Buffer {
|
|
94
|
-
str = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
95
|
-
while (str.length % 4 !== 0) {
|
|
96
|
-
str += '=';
|
|
97
|
-
}
|
|
98
|
-
return Buffer.from(str, 'base64');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from 'crypto';
|
|
2
|
-
import StringUtil from '../Utils/StringUtil';
|
|
3
|
-
|
|
4
|
-
export class StringClient {
|
|
5
|
-
constructor() { }
|
|
6
|
-
|
|
7
|
-
public generateUUIDv7(): string {
|
|
8
|
-
const timestamp = BigInt(Date.now()) * BigInt(10000) + BigInt(process.hrtime.bigint() % BigInt(10000));
|
|
9
|
-
const timeHex = timestamp.toString(16).padStart(16, '0');
|
|
10
|
-
|
|
11
|
-
const randomHex = randomBytes(8).toString('hex');
|
|
12
|
-
|
|
13
|
-
return `${timeHex.slice(0, 8)}-${timeHex.slice(8, 12)}-7${timeHex.slice(13, 16)}-${randomHex.slice(0, 4)}-${randomHex.slice(4)}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public isUUID(value: any) {
|
|
17
|
-
return StringUtil.isUUID(value);
|
|
18
|
-
}
|
|
19
|
-
}
|
package/src/cron/BaseCron.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { Pool, PoolClient } from "pg";
|
|
2
|
-
import { DateType, DayType, HourType, MinuteSecondType, MonthType } from "./CronType";
|
|
3
|
-
import PoolManager from "../PoolManager";
|
|
4
|
-
import { AwsS3Client } from "../clients/AwsS3Client";
|
|
5
|
-
import { Base64Client } from "../clients/Base64Client";
|
|
6
|
-
|
|
7
|
-
export class BaseCron {
|
|
8
|
-
|
|
9
|
-
protected readonly isTest: boolean = process.env.NODE_ENV === 'test';
|
|
10
|
-
protected dbUser?: string = this.isTest ? process.env.TEST_DB_USER : process.env.DB_USER;
|
|
11
|
-
protected dbHost?: string = this.isTest ? process.env.TEST_DB_HOST : process.env.DB_HOST;
|
|
12
|
-
protected dbName?: string = this.isTest ? process.env.TEST_DB_DATABASE : process.env.DB_DATABASE;
|
|
13
|
-
protected dbPassword?: string = this.isTest ? process.env.TEST_DB_PASSWORD : process.env.DB_PASSWORD;
|
|
14
|
-
protected dbPort?: string | number = this.isTest ? process.env.TEST_DB_PORT : process.env.DB_PORT;
|
|
15
|
-
protected dbIsSslConnect: boolean = (this.isTest ? process.env.TEST_DB_IS_SSL : process.env.DB_IS_SSL) === 'true';
|
|
16
|
-
|
|
17
|
-
private isExecuteRollback: boolean = false;
|
|
18
|
-
private pool?: Pool;
|
|
19
|
-
private client?: PoolClient;
|
|
20
|
-
protected get Client(): PoolClient {
|
|
21
|
-
if (this.client === undefined) {
|
|
22
|
-
throw new Error("Please call this.PoolClient after using the setClient method.");
|
|
23
|
-
}
|
|
24
|
-
return this.client;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
protected async commit(): Promise<void> {
|
|
28
|
-
await this.Client.query('COMMIT');
|
|
29
|
-
this.isExecuteRollback = false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
protected async rollback(): Promise<void> {
|
|
33
|
-
if (this.isExecuteRollback) {
|
|
34
|
-
await this.Client.query('ROLLBACK');
|
|
35
|
-
}
|
|
36
|
-
this.isExecuteRollback = false;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// **********************************************************************
|
|
40
|
-
// こちらのメソッド、プロパティを各サブクラスで設定してください
|
|
41
|
-
// **********************************************************************
|
|
42
|
-
protected cronCode: string = '';
|
|
43
|
-
protected minute: MinuteSecondType | '*' = '*';
|
|
44
|
-
protected hour: HourType | '*' = '*';
|
|
45
|
-
protected date: DateType | '*' = '*';
|
|
46
|
-
protected month: MonthType | '*' = '*';
|
|
47
|
-
protected day: DayType | '*' = '*';
|
|
48
|
-
public async run() { }
|
|
49
|
-
|
|
50
|
-
// **********************************************************************
|
|
51
|
-
// ベースクラスで設定
|
|
52
|
-
// **********************************************************************
|
|
53
|
-
get CronSchedule(): string {
|
|
54
|
-
let schedule = '';
|
|
55
|
-
schedule += this.minute.toString() + ' ';
|
|
56
|
-
schedule += this.hour.toString() + ' ';
|
|
57
|
-
schedule += this.date.toString() + ' ';
|
|
58
|
-
schedule += this.month.toString() + ' ';
|
|
59
|
-
schedule += this.day.toString();
|
|
60
|
-
return schedule;
|
|
61
|
-
}
|
|
62
|
-
get CronCode(): string { return this.cronCode; }
|
|
63
|
-
|
|
64
|
-
public async setUp() {
|
|
65
|
-
if (this.dbUser === undefined) {
|
|
66
|
-
throw new Error("Database user is not configured");
|
|
67
|
-
}
|
|
68
|
-
if (this.dbHost === undefined) {
|
|
69
|
-
throw new Error("Database host is not configured");
|
|
70
|
-
}
|
|
71
|
-
if (this.dbName === undefined) {
|
|
72
|
-
throw new Error("Database name is not configured");
|
|
73
|
-
}
|
|
74
|
-
if (this.dbPassword === undefined) {
|
|
75
|
-
throw new Error("Database password is not configured");
|
|
76
|
-
}
|
|
77
|
-
if (this.dbPort === undefined) {
|
|
78
|
-
throw new Error("Database port is not configured");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.pool = PoolManager.getPool(this.dbUser, this.dbHost, this.dbName, this.dbPassword, this.dbPort, this.dbIsSslConnect);
|
|
82
|
-
this.pool.query(`SET TIME ZONE '${process.env.TZ ?? 'Asia/Tokyo'}';`);
|
|
83
|
-
this.client = await this.pool.connect();
|
|
84
|
-
await this.Client.query('BEGIN');
|
|
85
|
-
this.isExecuteRollback = true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public async tearDown() {
|
|
89
|
-
try {
|
|
90
|
-
if (this.isExecuteRollback === false) {
|
|
91
|
-
await this.rollback();
|
|
92
|
-
}
|
|
93
|
-
} finally {
|
|
94
|
-
// クライアント接続をリリース
|
|
95
|
-
if (this.client) {
|
|
96
|
-
this.client.release();
|
|
97
|
-
this.client = undefined;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private s3Client?: AwsS3Client;
|
|
103
|
-
get S3Client(): AwsS3Client {
|
|
104
|
-
if (this.s3Client === undefined) {
|
|
105
|
-
this.s3Client = new AwsS3Client({
|
|
106
|
-
bucketName: process.env.S3_BUCKET_NAME,
|
|
107
|
-
region: process.env.S3_REGION,
|
|
108
|
-
accessKeyId: process.env.S3_ACCESS_KEY_ID,
|
|
109
|
-
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
return this.s3Client;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private base64Client? : Base64Client;
|
|
116
|
-
get Base64Client(): Base64Client {
|
|
117
|
-
if (this.base64Client === undefined) {
|
|
118
|
-
this.base64Client = new Base64Client();
|
|
119
|
-
}
|
|
120
|
-
return this.base64Client;
|
|
121
|
-
}
|
|
122
|
-
}
|
package/src/cron/CronExecuter.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const cron = require('node-cron');
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { BaseCron } from "./BaseCron";
|
|
5
|
-
|
|
6
|
-
export const runCron = async (dir: string, logCallback?: (ex: Error) => Promise<void>) => {
|
|
7
|
-
const files = fs.readdirSync(dir);
|
|
8
|
-
for (let file of files) {
|
|
9
|
-
if (['BaseCron.ts'].includes(file)) {
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const filePath = path.join(dir, file);
|
|
14
|
-
const module = await import(filePath);
|
|
15
|
-
const cronClass = module.default;
|
|
16
|
-
const cronInstance: BaseCron = new cronClass();
|
|
17
|
-
|
|
18
|
-
cron.schedule(cronInstance.CronSchedule, async () => {
|
|
19
|
-
try {
|
|
20
|
-
await cronInstance.setUp();
|
|
21
|
-
await cronInstance.run();
|
|
22
|
-
} catch (ex: unknown) {
|
|
23
|
-
if (logCallback !== undefined && ex instanceof Error) {
|
|
24
|
-
await logCallback(ex).
|
|
25
|
-
catch(() => {
|
|
26
|
-
// ログ送信時にエラーになっても握りつぶす
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
} finally {
|
|
30
|
-
await cronInstance.tearDown();
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/cron/CronType.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export type DayType =
|
|
2
|
-
1 | 2 | 3 | 4 | 5 | 6 | 7
|
|
3
|
-
|
|
4
|
-
export type MonthType =
|
|
5
|
-
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
|
6
|
-
10 | 11 | 12
|
|
7
|
-
|
|
8
|
-
export type DateType =
|
|
9
|
-
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
|
10
|
-
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
|
|
11
|
-
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
|
|
12
|
-
30 | 31
|
|
13
|
-
|
|
14
|
-
export type HourType =
|
|
15
|
-
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
|
16
|
-
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
|
|
17
|
-
20 | 21 | 22 | 23
|
|
18
|
-
|
|
19
|
-
export type MinuteSecondType =
|
|
20
|
-
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
|
21
|
-
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
|
|
22
|
-
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
|
|
23
|
-
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
|
|
24
|
-
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
|
|
25
|
-
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59
|