@@ -5,12 +5,16 @@ import { PdcTs } from "pdc-ts";
55import { deleteFile , errorRefiner } from "./src/utils" ;
66import { z } from "zod" ;
77
8- export const schema = z . object ( {
9- userId : z . string ( ) ,
10- markdown : z . string ( ) ,
11- setNumber : z . number ( ) ,
12- moduleSlug : z . string ( ) ,
13- } ) ;
8+ const TypeOfFileSchema = z . enum ( [ "PDF" , "TEX" ] ) ;
9+
10+ export const schema = z . array (
11+ z . object ( {
12+ userId : z . string ( ) ,
13+ fileName : z . string ( ) ,
14+ typeOfFile : TypeOfFileSchema ,
15+ markdown : z . string ( ) ,
16+ } )
17+ ) ;
1418
1519export const handler = async function (
1620 event : APIGatewayEvent
@@ -34,88 +38,124 @@ export const handler = async function (
3438 }
3539
3640 const requestData = parsed . data ;
37- const humanSetNumber = requestData . setNumber + 1 ;
38- const timestamp = new Date ( )
39- . toISOString ( )
40- . replace ( / [ - : T . ] / g, "" )
41- . slice ( 0 , 14 ) ;
42- const filename = `${ requestData . moduleSlug } _S${ humanSetNumber } _${ timestamp } .pdf` ;
4341
44- const localPath = `/tmp/ ${ filename } ` ;
45- const s3Path = ` ${ requestData . userId } / ${ filename } ` ;
46- let url : string | undefined ;
42+ const region = "eu-west-2" ;
43+ const s3Client = new S3Client ( { region } ) ;
44+ const s3Bucket = process . env . PUBLIC_S3_BUCKET ;
4745
4846 const pdcTs = new PdcTs ( ) ;
4947
50- const markdown = requestData . markdown ;
51- try {
52- await pdcTs . Execute ( {
53- from : "markdown-implicit_figures" , // pandoc source format (disabling the implicit_figures extension to remove all image captions)
54- to : "latex" , // pandoc output format
55- pandocArgs : [ "--pdf-engine=pdflatex" , `--template=./template.latex` ] ,
56- spawnOpts : { argv0 : "+RTS -M512M -RTS" } ,
57- outputToFile : true , // Controls whether the output will be returned as a string or written to a file
58- sourceText : markdown , // Use this if your input is a string. If you set this, the file input will be ignored
59- destFilePath : localPath ,
60- } ) ;
61- } catch ( e : unknown ) {
62- if ( e instanceof Error ) {
63- console . error ( e . message ) ;
64- } else {
65- console . error ( e ) ;
66- }
67-
68- const TeXoutput = await pdcTs . Execute ( {
69- from : "markdown-implicit_figures" , // pandoc source format (disabling the implicit_figures extension to remove all image captions)
70- to : "latex" , // pandoc output format
71- pandocArgs : [ "--pdf-engine=pdflatex" , `--template=./template.latex` ] ,
72- outputToFile : false , // Controls whether the output will be returned as a string or written to a file
73- sourceText : markdown , // Use this if your input is a string. If you set this, the file input will be ignored
74- destFilePath : localPath ,
75- } ) ;
76-
77- // Find the offending text from the error message:
78- e = errorRefiner ( String ( e ) , TeXoutput , false ) ;
79-
80- return {
81- statusCode : 500 ,
82- body : JSON . stringify ( { e } ) ,
83- } ;
84- }
48+ // Generate file
49+ const generateFile = async (
50+ pandocArgs : string [ ] ,
51+ destFilePath : string ,
52+ markdown : string
53+ ) => {
54+ try {
55+ await pdcTs . Execute ( {
56+ from : "markdown-implicit_figures" , // pandoc source format (disabling the implicit_figures extension to remove all image captions)
57+ to : "latex" , // pandoc output format
58+ pandocArgs,
59+ spawnOpts : { argv0 : "+RTS -M512M -RTS" } ,
60+ outputToFile : true , // Controls whether the output will be returned as a string or written to a file
61+ sourceText : markdown , // Use this if your input is a string. If you set this, the file input will be ignored
62+ destFilePath,
63+ } ) ;
64+ } catch ( e : unknown ) {
65+ if ( e instanceof Error ) {
66+ console . error ( e . message ) ;
67+ } else {
68+ console . error ( e ) ;
69+ }
8570
86- try {
87- const region = "eu-west-2" ;
88- const fileStream = fs . createReadStream ( localPath ) ;
89- const s3Client = new S3Client ( { region } ) ;
90- const s3Bucket = process . env . PUBLIC_S3_BUCKET ;
91- const params = {
92- Bucket : s3Bucket ,
93- Key : s3Path ,
94- Body : fileStream ,
95- } ;
71+ const TeXoutput = await pdcTs . Execute ( {
72+ from : "markdown-implicit_figures" , // pandoc source format (disabling the implicit_figures extension to remove all image captions)
73+ to : "latex" , // pandoc output format
74+ pandocArgs,
75+ outputToFile : false , // Controls whether the output will be returned as a string or written to a file
76+ sourceText : markdown , // Use this if your input is a string. If you set this, the file input will be ignored
77+ destFilePath,
78+ } ) ;
9679
97- const command = new PutObjectCommand ( params ) ;
98- await s3Client . send ( command ) ;
80+ // Find the offending text from the error message:
81+ e = errorRefiner ( String ( e ) , TeXoutput , false ) ;
9982
100- url = `https://${ s3Bucket } .s3.${ region } .amazonaws.com/${ s3Path } ` ;
101- } catch ( e : unknown ) {
102- console . error ( "S3 upload failed" ) ;
103- if ( e instanceof Error ) {
104- console . error ( e . message ) ;
10583 return {
10684 statusCode : 500 ,
107- body : e . message ,
85+ body : JSON . stringify ( { e } ) ,
10886 } ;
109- } else {
110- console . error ( e ) ;
111- return {
112- statusCode : 500 ,
113- body : "S3 Upload failed" ,
87+ }
88+ } ;
89+
90+ const saveFileToS3 = async ( localPathPDF : string , s3Path : string ) => {
91+ // Save PDF file to S3 bucket
92+ try {
93+ const fileStream = fs . createReadStream ( localPathPDF ) ;
94+ const params = {
95+ Bucket : s3Bucket ,
96+ Key : s3Path ,
97+ Body : fileStream ,
11498 } ;
99+
100+ const command = new PutObjectCommand ( params ) ;
101+ await s3Client . send ( command ) ;
102+ } catch ( e : unknown ) {
103+ console . error ( "S3 upload failed" ) ;
104+ if ( e instanceof Error ) {
105+ console . error ( e . message ) ;
106+ return {
107+ statusCode : 500 ,
108+ body : e . message ,
109+ } ;
110+ } else {
111+ console . error ( e ) ;
112+ return {
113+ statusCode : 500 ,
114+ body : "S3 Upload failed" ,
115+ } ;
116+ }
117+ } finally {
118+ // cleanup
119+ deleteFile ( localPathPDF ) ;
120+ }
121+ } ;
122+
123+ let url = "" ;
124+ for ( let eachRequestData of requestData ) {
125+ const markdown = eachRequestData . markdown ;
126+
127+ switch ( eachRequestData . typeOfFile ) {
128+ case "PDF" :
129+ const filenamePDF = `${ eachRequestData . fileName } .pdf` ;
130+ const localPathPDF = `/tmp/${ filenamePDF } ` ;
131+ const generatePDFResult = await generateFile (
132+ [ "--pdf-engine=pdflatex" , `--template=./template.latex` ] ,
133+ localPathPDF ,
134+ markdown
135+ ) ;
136+
137+ if ( generatePDFResult ?. statusCode ) {
138+ return generatePDFResult ;
139+ }
140+ const s3PathPDF = `${ eachRequestData . userId } /${ filenamePDF } ` ;
141+ await saveFileToS3 ( localPathPDF , s3PathPDF ) ;
142+ url = `https://${ s3Bucket } .s3.${ region } .amazonaws.com/${ s3PathPDF } ` ;
143+ break ;
144+ case "TEX" :
145+ const filenameTEX = `${ eachRequestData . fileName } .tex` ;
146+ const localPathTEX = `/tmp/${ filenameTEX } ` ;
147+
148+ await generateFile (
149+ [ `--template=./template.latex` ] ,
150+ localPathTEX ,
151+ markdown
152+ ) ;
153+
154+ const s3PathTEX = `${ eachRequestData . userId } /${ filenameTEX } ` ;
155+
156+ await saveFileToS3 ( localPathTEX , s3PathTEX ) ;
157+ break ;
115158 }
116- } finally {
117- // cleanup
118- deleteFile ( localPath ) ;
119159 }
120160
121161 return {
0 commit comments