Skip to content

Commit 5e4428c

Browse files
committed
chore: Refactor PDF conversion handler and update Dockerfile and environment configurations
1 parent d95eac7 commit 5e4428c

25 files changed

+181
-106
lines changed

.dockerignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ example.env
22
.git
33
.gitignore
44

5-
images/
5+
img/
66
pdf/

.env.example

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
# SERVER
12
GIN_MODE=release
23
IMAGE_STORAGE_PATH=/path/to/image/storage
34
PDF_STORAGE_PATH=/path/to/pdf/storage
5+
PORT=8080
46

5-
# SERVER
6-
7+
# SERVICE
78
SERVER_SERVICE_PORT=8000
89
SERVER_SERVICE="localhost" # SERVICE NAME
910
SERVER_SERVICE_ORIGIN="http://${SERVER_SERVICE}:${SERVER_SERVICE_PORT}"

.github/workflows/default.yml

+18-18
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ jobs:
1212
- name: Checkout the repository
1313
uses: actions/checkout@v4
1414

15-
- name: executing remote ssh commands using password
16-
uses: appleboy/ssh-action@v1.0.3
17-
with:
18-
host: ${{ secrets.SSH_HOST }}
19-
username: root
20-
password: ${{ secrets.SSH_PASSWORD }}
21-
script: |
22-
whoami
23-
cd /critik-v
24-
rm -rf ./${{github.event.repository.name}}
25-
git clone https://github.com/${{github.repository}}.git
26-
cd ./${{github.event.repository.name}}
27-
cp .env.example .env
28-
sed -i "s/GIN_MODE=.*$/GIN_MODE=production/" .env
29-
sed -i "s/IMAGE_STORAGE_PATH=.*$/IMAGE_STORAGE_PATH=images/" .env
30-
sed -i "s/PDF_STORAGE_PATH=.*$/PDF_STORAGE_PATH=pdf/" .env
31-
sed -i "s/SERVER_SERVICE_PORT=.*$/SERVER_SERVICE_PORT=${{secrets.SERVER_PORT}}/" .env
32-
sed -i "s/SERVER_SERVICE=.*$/SERVER_SERVICE=${{secrets.SERVER_SERVICE}}/" .env
15+
# - name: executing remote ssh commands using password
16+
# uses: appleboy/ssh-action@v1.0.3
17+
# with:
18+
# host: ${{ secrets.SSH_HOST }}
19+
# username: root
20+
# password: ${{ secrets.SSH_PASSWORD }}
21+
# script: |
22+
# whoami
23+
# cd /critik-v
24+
# rm -rf ./${{github.event.repository.name}}
25+
# git clone https://github.com/${{github.repository}}.git
26+
# cd ./${{github.event.repository.name}}
27+
# cp .env.example .env
28+
# sed -i "s/GIN_MODE=.*$/GIN_MODE=production/" .env
29+
# sed -i "s/IMAGE_STORAGE_PATH=.*$/IMAGE_STORAGE_PATH=images/" .env
30+
# sed -i "s/PDF_STORAGE_PATH=.*$/PDF_STORAGE_PATH=pdf/" .env
31+
# sed -i "s/SERVER_SERVICE_PORT=.*$/SERVER_SERVICE_PORT=${{secrets.SERVER_PORT}}/" .env
32+
# sed -i "s/SERVER_SERVICE=.*$/SERVER_SERVICE=${{secrets.SERVER_SERVICE}}/" .env

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
.vscode/
99
.idea/
1010

11-
images/
11+
img/

dockerfile

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ FROM golang:1.22 AS builder
33
WORKDIR /builder
44

55
COPY go.mod .
6-
76
COPY go.sum .
8-
97
RUN go mod download
108

119
RUN apt-get update && apt-get install -y libmupdf-dev
@@ -14,7 +12,7 @@ COPY . .
1412

1513
RUN go build -o /main .
1614

17-
FROM ubuntu:latest
15+
FROM debian:bullseye-slim
1816

1917
EXPOSE 5001
2018

handlers/convertPdf.go renamed to handlers/pdf.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ import (
99
"github.com/gin-gonic/gin"
1010
)
1111

12+
// body represents the request body
1213
type body struct {
1314
FileName string `json:"filename"`
1415
}
1516

16-
func ConvertPdf(ctx *gin.Context) {
17+
// ConvertPdf converts a PDF file to a JPEG image
18+
func POSTConvertPdf(ctx *gin.Context) {
1719
var body body
18-
finished := make(chan bool)
19-
mutex := &sync.Mutex{}
2020

21+
// Create a mutex to lock the goroutine
22+
mutex := &sync.Mutex{}
2123
mutex.Lock()
24+
25+
// Create a channel to notify when the goroutine is finished
26+
finished := make(chan bool)
27+
28+
// Convert the PDF to JPEG in a goroutine
2229
go func() {
2330
defer mutex.Unlock()
2431
err := ctx.BindJSON(&body)

main.go

+12-13
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,44 @@ package main
22

33
import (
44
"go-pdf2jpeg/handlers"
5+
"go-pdf2jpeg/utils"
56
"log"
6-
"os"
77

88
"github.com/gin-contrib/cors"
99
"github.com/gin-gonic/gin"
1010
"github.com/joho/godotenv"
1111
)
1212

13-
const serverPort string = ":5001"
13+
const envFile = ".env" // Name of the .env file
1414

1515
func init() {
1616
// Load .env file
17-
err := godotenv.Load(".env")
17+
err := godotenv.Load(envFile)
1818
if err != nil {
19-
log.Fatalf("Error loading .env file: %s", err)
19+
log.Fatal(err)
2020
}
2121
}
2222

2323
func main() {
24-
if os.Getenv("GIN_MODE") == "production" {
24+
// Set Gin mode to release if the application is running in production mode
25+
if prodMode := utils.IsProduction(); prodMode {
2526
gin.SetMode(gin.ReleaseMode)
2627
}
28+
29+
// Create server instance
2730
server := gin.Default()
2831

29-
// Middleware
30-
var serverOrigin string = os.Getenv("SERVER_SERVICE_ORIGIN")
31-
if serverOrigin == "" {
32-
serverOrigin = "*"
33-
}
32+
// CORS middleware configuration to allow only POST requests from the specified origin
3433
server.Use(cors.New(cors.Config{
35-
AllowOrigins: []string{serverOrigin},
34+
AllowOrigins: []string{utils.GetCorsOrigin()},
3635
AllowMethods: []string{"POST"},
3736
AllowHeaders: []string{"Origin"},
3837
AllowCredentials: true,
3938
}))
4039

4140
// Routes
42-
server.POST("/convert", handlers.ConvertPdf)
41+
server.POST("/convert", handlers.POSTConvertPdf)
4342

4443
// Run server
45-
server.Run(serverPort)
44+
server.Run(utils.GetPort())
4645
}

pdf/test-0.pdf

100755100644
-2.16 MB
Binary file not shown.

pdf/test-1.pdf

100755100644
-2.16 MB
Binary file not shown.

pdf/test-10.pdf

-1.44 MB
Binary file not shown.

pdf/test-11.pdf

-1.5 MB
Binary file not shown.

pdf/test-12.pdf

-1.5 MB
Binary file not shown.

pdf/test-2.pdf

100755100644
-2.16 MB
Binary file not shown.

pdf/test-3.pdf

-1.44 MB
Binary file not shown.

pdf/test-4.pdf

-1.44 MB
Binary file not shown.

pdf/test-5.pdf

-1.44 MB
Binary file not shown.

pdf/test-6.pdf

-1.44 MB
Binary file not shown.

pdf/test-7.pdf

-1.44 MB
Binary file not shown.

pdf/test-8.pdf

-1.44 MB
Binary file not shown.

pdf/test-9.pdf

-1.44 MB
Binary file not shown.

pdf/test.pdf

-1.44 MB
Binary file not shown.

service/pdf.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package service
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"go-pdf2jpeg/utils"
7+
"image/jpeg"
8+
"os"
9+
"path/filepath"
10+
11+
"github.com/gen2brain/go-fitz"
12+
)
13+
14+
const jpegQuality int = 7 // Quality of the JPEG image
15+
const imgExt string = ".jpg" // Extension of
16+
const docExt string = ".pdf" // Extension of the document
17+
18+
var (
19+
ErrPickingPage = errors.New("error picking page") // Error when picking the first page of the PDF
20+
ErrCreatingJpeg = errors.New("error creating jpeg image") // Error when creating the jpeg image
21+
ErrEncodingJpeg = errors.New("error encoding jpeg image") // Error when encoding the jpeg image
22+
ErrPdfDirNotExist = errors.New("pdf directory does not exist") // Error when the pdf directory does not exist
23+
ErrImgDirCreation = errors.New("image directory creation failed") // Error when the image directory creation fails
24+
)
25+
26+
/*
27+
outPutFileName returns the name of the output file
28+
by appending the image extension to the fileName
29+
*/
30+
func outPutFileName(fileName string) string {
31+
return fmt.Sprintf("%v%v", fileName, imgExt)
32+
}
33+
34+
/*
35+
pdfPath returns the path to the PDF file
36+
by appending the document extension to the fileName
37+
*/
38+
func pdfPath(dir, fileName string) string {
39+
return fmt.Sprintf("%v/%v%v", dir, fileName, docExt)
40+
}
41+
42+
/*
43+
convert converts the first page of the PDF to a JPEG image
44+
and saves it in the imgDir directory
45+
*/
46+
func convert(doc *fitz.Document, imgDir string, fileName string) error {
47+
img, err := doc.Image(0)
48+
if err != nil {
49+
return errors.Join(ErrPickingPage, err)
50+
}
51+
52+
// Create a new file in the img directory
53+
f, err := os.Create(filepath.Join(imgDir, outPutFileName(fileName)))
54+
if err != nil {
55+
return errors.Join(ErrCreatingJpeg, err)
56+
}
57+
defer f.Close()
58+
59+
// Encode the image to JPEG
60+
err = jpeg.Encode(f, img, &jpeg.Options{Quality: int(jpegQuality)})
61+
if err != nil {
62+
return errors.Join(ErrEncodingJpeg, err)
63+
}
64+
return nil
65+
}
66+
67+
/**
68+
* PdfToJpeg converts the first page of the PDF to a JPEG image
69+
* and saves it in the img directory
70+
*/
71+
func PdfToJpeg(fileName string) error {
72+
pdfDir := utils.GetPdfDir() // Path to the directory where the PDFs are stored
73+
imgDir := utils.GetImgDir() // Path to the directory where the images will be stored
74+
75+
doc, err := fitz.New(pdfPath(pdfDir, fileName))
76+
if err != nil {
77+
return errors.Join(ErrPdfDirNotExist, err)
78+
}
79+
defer doc.Close()
80+
81+
// Check if the img directory exists
82+
if _, err := os.Stat(imgDir); os.IsNotExist(err) {
83+
// img directory does not exist
84+
err = os.Mkdir(imgDir, os.ModePerm)
85+
if err != nil {
86+
return errors.Join(ErrImgDirCreation, err)
87+
}
88+
return convert(doc, imgDir, fileName)
89+
}
90+
// img directory already exists
91+
return convert(doc, imgDir, fileName)
92+
}

service/pdfToJpeg.go

-65
This file was deleted.
File renamed without changes.

utils/utils.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package utils
2+
3+
import "os"
4+
5+
const defaultPdfDir = "pdf" // Default directory where the PDFs are stored
6+
const defaultImgDir = "img" // Default directory where the images will be stored
7+
8+
// IsProduction returns true if the application is running in production mode
9+
func IsProduction() bool {
10+
return os.Getenv("GIN_MODE") == "production"
11+
}
12+
13+
// GetPort returns the port where the server will be running
14+
func GetPort() string {
15+
return ":5001"
16+
}
17+
18+
// GetPdfDir returns the path to the directory where the PDFs are stored
19+
func GetPdfDir() string {
20+
name := os.Getenv("PDF_STORAGE_PATH")
21+
if name == "" {
22+
return defaultPdfDir
23+
}
24+
return name
25+
}
26+
27+
// GetImgDir returns the path to the directory where the images will be stored
28+
func GetImgDir() string {
29+
name := os.Getenv("IMAGE_STORAGE_PATH")
30+
if name == "" {
31+
return defaultImgDir
32+
}
33+
return name
34+
}
35+
36+
// GetCorsOrigin returns the origin to be allowed by the CORS middleware
37+
func GetCorsOrigin() string {
38+
origin := os.Getenv("SERVER_SERVICE_ORIGIN")
39+
if origin == "" {
40+
return "*"
41+
}
42+
return origin
43+
}

0 commit comments

Comments
 (0)