-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pages are uploaded now to a cloud storage (s3 or openstack swift with s3-like api enabled) Dont use s3, its not even cheap, go and get your services at your local cloud company or any other not-that-big provider. Also you can always write me if you want to hear my opinion. Peace.
- Loading branch information
1 parent
25e816b
commit 3eed304
Showing
9 changed files
with
291 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Credentials, Endpoint, S3 } from "aws-sdk"; | ||
|
||
const s3 = new S3(); | ||
s3.config.credentials = new Credentials(process.env.S3_ACCESS_KEY_ID as string, process.env.S3_SECRET_ACCESS_KEY as string); | ||
s3.endpoint = new Endpoint(process.env.S3_ENDPOINT as string); | ||
s3.config.endpoint = process.env.S3_ENDPOINT; | ||
s3.config.region = process.env.S3_REGION; | ||
|
||
export default s3; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Controller, MultipartFile, PathParams, PlatformMulterFile, Post } from "@tsed/common"; | ||
import { NotFound, BadRequest, InternalServerError, Exception } from "@tsed/exceptions"; | ||
import { Description, Returns, Summary } from "@tsed/schema"; | ||
import { isNaturalNumber } from "../modules/DataValidation"; | ||
import S3Storage from "../modules/S3Storage"; | ||
import { StatusService } from "../services/StatusService"; | ||
|
||
@Controller("/upload") | ||
export class UploadController { | ||
constructor(private statusService: StatusService) {} | ||
|
||
@Post("/:id/:page") | ||
@Summary("Add new chapter page") | ||
@Description( | ||
'Upload chapter pages, one by one.<br>This call has an extra parameter named "file" in the body, it is a multipart to attach a page.' | ||
) | ||
@(Returns(201).Description("Created, no response expected")) | ||
@Returns(400, BadRequest) | ||
@Returns(404, NotFound) | ||
async post( | ||
@Description("A status (chapter) ID") | ||
@PathParams("id") | ||
id: number, | ||
@Description("A page number") | ||
@PathParams("page") | ||
page: number, | ||
@Description("A page file") | ||
@MultipartFile("file") | ||
file: PlatformMulterFile | ||
): Promise<string | Exception> { | ||
return new Promise<string | Exception>(async (resolve, reject) => { | ||
try { | ||
if (!isNaturalNumber(id)) { | ||
throw new BadRequest("ID is not a Number"); | ||
} | ||
if (!isNaturalNumber(page)) { | ||
throw new BadRequest("Page is not a Number"); | ||
} | ||
|
||
if (!(await this.statusService.exists(id))) { | ||
throw new NotFound("Chapter ID was not found"); | ||
} | ||
|
||
resolve(); | ||
} catch (error) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
new S3Storage().deleteFile(file.path, (error: any, metadata?: any) => { | ||
if (error) reject(new InternalServerError("An error ocurred while managing the file (" + metadata + ")")); | ||
else reject(error); | ||
}); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { PlatformMulterFile } from "@tsed/common"; | ||
import { Exception } from "@tsed/exceptions"; | ||
import { AWSError, Request as S3Request, S3 } from "aws-sdk"; | ||
import s3 from "../config/s3"; | ||
|
||
export default class S3Storage { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public putFile(path: string, file: Buffer, cb: (error: any, metadata?: any) => void): void { | ||
const params: S3.Types.PutObjectRequest = { | ||
Bucket: process.env.S3_BUCKET as string, | ||
Key: path, | ||
Body: file | ||
}; | ||
|
||
if (file.byteLength > 10485760) { | ||
// 10MB | ||
return cb(new Exception(400, "File too big")); | ||
} | ||
|
||
s3.putObject(params) | ||
.on("build", (req: S3Request<S3.PutObjectOutput, AWSError>) => { | ||
req.httpRequest.headers["X-Delete-After"] = process.env.S3_TIME_TO_LIVE || "3600"; | ||
}) | ||
.send((err: AWSError, data: S3.PutObjectOutput) => { | ||
if (err) return cb(err); | ||
else cb(null, data); | ||
}); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public deleteFile(path: string, cb: (error: any, metadata?: any) => void): void { | ||
const params: S3.Types.PutObjectRequest = { | ||
Bucket: process.env.S3_BUCKET as string, | ||
Key: path | ||
}; | ||
|
||
s3.deleteObject(params, (err: AWSError, data: S3.DeleteObjectOutput) => { | ||
if (err) return cb(err); | ||
else cb(null, data); | ||
}); | ||
} | ||
|
||
public MulterFileToBuffer(file: PlatformMulterFile): Promise<Buffer> { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const bufs: any[] = []; | ||
|
||
return new Promise<Buffer>((resolve, reject) => { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
file.stream.on("data", function (chunk: any) { | ||
bufs.push(chunk); | ||
}); | ||
file.stream.on("end", function () { | ||
resolve(Buffer.concat(bufs)); | ||
}); | ||
file.stream.on("error", function (err: Error) { | ||
reject(err); | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { PlatformMulterFile, Req } from "@tsed/common"; | ||
import { StorageEngine } from "multer"; | ||
import S3Storage from "./S3Storage"; | ||
|
||
export default class MulterS3Storage implements StorageEngine { | ||
private s3Utils = new S3Storage(); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
_handleFile = (req: Req, file: PlatformMulterFile, cb: (error: any, metadata?: any) => void): void => { | ||
file.path = req.params.id + "/" + req.params.page + this.getFileExtension(file.originalname); | ||
|
||
this.s3Utils.MulterFileToBuffer(file).then((bufferFile: Buffer) => { | ||
this.s3Utils.putFile(file.path, bufferFile, cb); | ||
}); | ||
}; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
_removeFile = (req: Req, file: PlatformMulterFile, cb: (error: any, metadata?: any) => void): void => { | ||
this.s3Utils.deleteFile(file.path, cb); | ||
}; | ||
|
||
private getFileExtension(filename: string): string | undefined { | ||
let extension = filename.split(".").pop(); | ||
if (extension) { | ||
extension = "." + extension; | ||
} | ||
return extension; | ||
} | ||
} | ||
|
||
export function storageEngine(): MulterS3Storage { | ||
return new MulterS3Storage(); | ||
} | ||
|
||
export type ContentTypeFunction = (req: Request, file: Express.Multer.File) => string | undefined; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters