any2pdf/main.go

169 lines
3.5 KiB
Go

package main
import (
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
func getPort(default_port string) string {
port := os.Getenv("PORT")
if port == "" {
return default_port
}
return port
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/html")
http.ServeFile(w, r, "./index.html")
}
const UPLOADS_FOLDER_PREFIX = "./uploads/"
func saveFilesOnDisk(files []*multipart.FileHeader) (folderPath string, filesPaths []string, err error) {
// Create folder for uploaded files
folderPath = UPLOADS_FOLDER_PREFIX + strconv.FormatInt(time.Now().Unix(), 10)
if err := os.MkdirAll(folderPath, os.ModePerm); err != nil {
return "", filesPaths, err
}
filesPaths = make([]string, len(files))
for i, fileHeader := range files {
// Open file from request
file, err := fileHeader.Open()
if err != nil {
return "", filesPaths, err
}
defer file.Close()
// Generate and store file name
fileName := strconv.Itoa(i) + strings.ToLower(filepath.Ext(fileHeader.Filename))
filesPaths[i] = folderPath + "/" + fileName
// Create file on disk
dst, err := os.Create(filesPaths[i])
if err != nil {
return "", filesPaths, err
}
defer dst.Close()
_, err = io.Copy(dst, file)
if err != nil {
return "", filesPaths, err
}
}
return folderPath, filesPaths, nil
}
type ContentType int
const (
Images ContentType = iota
Office
Pdfs
)
func detectContentType(files []*multipart.FileHeader) (contentType ContentType, err error) {
for _, file := range files {
fileExt := strings.ToLower(filepath.Ext(file.Filename))
switch fileExt {
case ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".odt", ".ods", ".odp":
if len(files) == 1 {
return Office, nil
} else {
return contentType, fmt.Errorf("expected one document, got %d", len(files))
}
case ".jpg", ".jpeg", ".png":
contentType = Images
case ".pdf":
contentType = Pdfs
default:
return contentType, fmt.Errorf("%s file extension is unsupported yet", fileExt)
}
}
return contentType, nil
}
const MAX_UPLOAD_SIZE = (1 << 27)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// Restrict to POST http method
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Restrict max size of a bunch of files
r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE)
// Parse body
if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
files := r.MultipartForm.File["files"]
folderPath, filesPaths, err := saveFilesOnDisk(files)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer os.RemoveAll(folderPath)
contType, err := detectContentType(files)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
resultFileName := ""
if len(r.MultipartForm.Value["filename"]) > 0 {
resultFileName = r.MultipartForm.Value["filename"][0]
}
resFile, err := ConvertToPDF(folderPath, filesPaths, contType, resultFileName)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Disposition", "attachment; filename=\""+filepath.Base(resFile)+"\"")
http.ServeFile(w, r, resFile)
}
func main() {
http.HandleFunc("/", indexHandler)
http.HandleFunc("/upload", uploadHandler)
port := getPort("80")
fmt.Printf("Listening on %s\n", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}