Skip to content

Instantly share code, notes, and snippets.

@creasty
Created March 18, 2022 03:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creasty/29859f62968bd3d30ce7ca56e9be1465 to your computer and use it in GitHub Desktop.
Save creasty/29859f62968bd3d30ce7ca56e9be1465 to your computer and use it in GitHub Desktop.
Convert MS Office documents to PDF
package main
import (
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"time"
"github.com/creasty/defaults"
)
var httpClient = &http.Client{
Transport: &http.Transport{
MaxIdleConnsPerHost: 20,
},
Timeout: time.Second * 30,
}
type Converter struct {
SrcURL string
TimeoutSec time.Duration `default:"600"`
}
func (c *Converter) download() (*os.File, error) {
res, err := httpClient.Get(c.SrcURL)
if err != nil {
return nil, err
}
defer res.Body.Close()
fp, err := ioutil.TempFile("", "foo")
if err != nil {
return nil, err
}
defer fp.Close()
if _, err := io.Copy(fp, res.Body); err != nil {
return fp, err
}
return fp, err
}
func (c *Converter) convert(downloaded *os.File) (*os.File, error) {
cmd := exec.Command(
"libreoffice",
"--headless",
"--nodefault",
"--nofirststartwizard",
"--nolockcheck",
"--nologo",
"--norestore",
"--invisible",
"--convert-to",
"pdf",
"--outdir",
os.TempDir(),
downloaded.Name(),
)
if err := cmd.Start(); err != nil {
return nil, err
}
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
}()
select {
case <-time.After(c.TimeoutSec * time.Second):
if err := cmd.Process.Kill(); err != nil {
log.Printf("Conversion time limit exceeded. url = %s\n", c.SrcURL)
return nil, err
}
case err := <-done:
if err != nil {
return nil, err
}
}
fp, err := os.Open(downloaded.Name() + ".pdf")
if err != nil {
return nil, err
}
return fp, nil
}
func (c *Converter) Perform(callback func(fp *os.File) error) error {
if err := defaults.Set(c); err != nil {
return err
}
downloaded, err := c.download()
if err != nil {
return err
}
defer os.Remove(downloaded.Name())
converted, err := c.convert(downloaded)
if err != nil {
return err
}
defer os.Remove(converted.Name())
return callback(converted)
}
FROM ubuntu:16.04
RUN set -ex \
&& apt-get update \
&& apt-get install -y locales \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
ENV LC_ALL C
ENV LC_ALL en_US.UTF-8
ENV DEBIAN_FRONTEND noninteractive
RUN set -ex \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
curl \
software-properties-common \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
# LibreOffice
# Based on xcgd/libreoffice
# @see https://hub.docker.com/r/xcgd/libreoffice/~/dockerfile/
RUN set -ex \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
ure \
libreoffice-java-common \
libreoffice-core \
libreoffice-common \
fonts-opensymbol \
hyphen-fr \
hyphen-de \
hyphen-en-us \
hyphen-it \
hyphen-ru \
fonts-dejavu \
fonts-dejavu-core \
fonts-dejavu-extra \
fonts-dustin \
fonts-f500 \
fonts-fanwood \
fonts-freefont-ttf \
fonts-liberation \
fonts-lmodern \
fonts-lyx \
fonts-sil-gentium \
fonts-texgyre \
fonts-tlwg-purisa \
fonts-ipafont \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
RUN mkdir /app
COPY ./bin /app/bin
EXPOSE 80
CMD ["/app/bin/server"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment