Browse Source

Initial commit

William Petit 4 months ago
commit
59a4a16281
13 changed files with 276 additions and 0 deletions
  1. 2
    0
      .dockerignore
  2. 4
    0
      .editorconfig
  3. 2
    0
      .gitignore
  4. 45
    0
      Dockerfile
  5. 25
    0
      Makefile
  6. 7
    0
      README.md
  7. 7
    0
      go.mod
  8. 8
    0
      go.sum
  9. 124
    0
      main.go
  10. 1
    0
      misc/dokku/Procfile
  11. 5
    0
      misc/dokku/app.json
  12. 4
    0
      modd.conf
  13. 42
    0
      static/index.html

+ 2
- 0
.dockerignore View File

@@ -0,0 +1,2 @@
1
+/tiff
2
+/bin

+ 4
- 0
.editorconfig View File

@@ -0,0 +1,4 @@
1
+[*.html]
2
+charset = utf-8
3
+indent_style = space
4
+indent_size = 2

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+/bin
2
+/tiff

+ 45
- 0
Dockerfile View File

@@ -0,0 +1,45 @@
1
+FROM golang:1.11 AS builder
2
+
3
+RUN apt-get update -y && apt-get -y install git-core curl build-essential
4
+
5
+COPY ./ /src
6
+
7
+WORKDIR /src
8
+
9
+RUN go clean -v
10
+
11
+RUN make bin/tiff-optimizer
12
+
13
+FROM alpine:3.8
14
+
15
+ARG HTTP_PROXY=
16
+ARG HTTPS_PROXY=
17
+ARG http_proxy=
18
+ARG https_proxy=
19
+
20
+RUN echo "@edge http://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories; \
21
+    echo "@edgecommunity http://nl.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories; \
22
+    echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories;
23
+
24
+RUN apk add --no-cache bash libcrypto1.1@edge gdal@testing
25
+
26
+RUN adduser -S tiff-optimizer
27
+
28
+COPY misc/dokku/app.json "/app/app.json"
29
+COPY misc/dokku/Procfile "/app/Procfile"
30
+COPY --from=builder /src/bin/tiff-optimizer /app/bin/tiff-optimizer
31
+COPY static /app/static
32
+
33
+RUN chmod +x /app/bin/*
34
+RUN chown -R tiff-optimizer: /app\
35
+  && mkdir -p /data\
36
+  && chown -R tiff-optimizer: /data
37
+
38
+USER tiff-optimizer
39
+
40
+EXPOSE 3000
41
+VOLUME /data
42
+
43
+WORKDIR /app
44
+
45
+CMD ["./bin/tiff-optimizer", "-tiff", "/data", "-static", "/app/static"]

+ 25
- 0
Makefile View File

@@ -0,0 +1,25 @@
1
+build: bin/tiff-optimizer
2
+	docker build \
3
+		--build-arg "HTTP_PROXY=$(HTTP_PROXY)" \
4
+		--build-arg "HTTPS_PROXY=$(HTTPS_PROXY)" \
5
+		--build-arg "http_proxy=$(http_proxy)" \
6
+		--build-arg "https_proxy=$(https_proxy)" \
7
+		-t tiff-optimizer \
8
+		.
9
+
10
+run:
11
+	docker run \
12
+		--rm -it \
13
+		-p "3000:3000" \
14
+		tiff-optimizer:latest
15
+
16
+bin/tiff-optimizer:
17
+	CGO_ENABLED=0 go build -o ./bin/tiff-optimizer ./
18
+
19
+server: bin/tiff-optimizer
20
+	./bin/tiff-optimizer
21
+
22
+watch:
23
+	modd
24
+
25
+.PHONY: bin/tiff-optimizer

+ 7
- 0
README.md View File

@@ -0,0 +1,7 @@
1
+# Tiff Optimizer
2
+
3
+Application web simple d'optimisation de fichiers Tiff
4
+
5
+## Licence
6
+
7
+AGPL-3.0

+ 7
- 0
go.mod View File

@@ -0,0 +1,7 @@
1
+module forge.cadoles.com/Pyxis/tiff-optimizer
2
+
3
+require (
4
+	github.com/davecgh/go-spew v1.1.1
5
+	github.com/go-chi/chi v4.0.1+incompatible
6
+	github.com/pborman/uuid v1.2.0
7
+)

+ 8
- 0
go.sum View File

@@ -0,0 +1,8 @@
1
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3
+github.com/go-chi/chi v4.0.1+incompatible h1:RSRC5qmFPtO90t7pTL0DBMNpZFsb/sHF3RXVlDgFisA=
4
+github.com/go-chi/chi v4.0.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
5
+github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
6
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
7
+github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
8
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=

+ 124
- 0
main.go View File

@@ -0,0 +1,124 @@
1
+package main
2
+
3
+import (
4
+	"flag"
5
+	"fmt"
6
+	"io"
7
+	"io/ioutil"
8
+	"log"
9
+	"net/http"
10
+	"os"
11
+	"os/exec"
12
+	"path"
13
+
14
+	"github.com/go-chi/chi/middleware"
15
+	"github.com/pborman/uuid"
16
+
17
+	"github.com/go-chi/chi"
18
+)
19
+
20
+var (
21
+	address   string = ":3000"
22
+	staticDir string = "./static"
23
+	tiffDir   string = "./tiff"
24
+)
25
+
26
+func init() {
27
+	flag.StringVar(&address, "address", address, "Server HTTP address")
28
+	flag.StringVar(&staticDir, "static", staticDir, "Static files directory")
29
+	flag.StringVar(&tiffDir, "tiff", tiffDir, "Tiff files directory")
30
+}
31
+
32
+func main() {
33
+
34
+	flag.Parse()
35
+
36
+	if err := os.MkdirAll(tiffDir, os.FileMode(0740)); err != nil {
37
+		panic(err)
38
+	}
39
+
40
+	r := chi.NewRouter()
41
+
42
+	r.Use(middleware.Logger)
43
+	r.Use(middleware.Recoverer)
44
+	r.Use(middleware.Throttle(1))
45
+
46
+	r.Post("/", uploadImage)
47
+	r.Get("/results/{ID}", downloadResult)
48
+	r.Get("/", http.FileServer(http.Dir(staticDir)).ServeHTTP)
49
+
50
+	log.Printf("listening on '%s'", address)
51
+	if err := http.ListenAndServe(address, r); err != nil {
52
+		panic(err)
53
+	}
54
+
55
+}
56
+
57
+func uploadImage(w http.ResponseWriter, r *http.Request) {
58
+
59
+	if err := r.ParseForm(); err != nil {
60
+		panic(err)
61
+	}
62
+
63
+	file, _, err := r.FormFile("tiffImage")
64
+	if err != nil {
65
+		panic(err)
66
+	}
67
+
68
+	sourceFile, err := ioutil.TempFile("", "tiff-optimizer")
69
+	if err != nil {
70
+		panic(err)
71
+	}
72
+	defer os.Remove(sourceFile.Name())
73
+
74
+	if _, err := io.Copy(sourceFile, file); err != nil {
75
+		panic(err)
76
+	}
77
+
78
+	resultID := uuid.New()
79
+	destFile := path.Join(tiffDir, resultID+".tif")
80
+
81
+	cmd := exec.CommandContext(
82
+		r.Context(),
83
+		"gdal_translate",
84
+		"-co", "COMPRESS=LZW",
85
+		sourceFile.Name(),
86
+		destFile,
87
+	)
88
+
89
+	cmd.Stdout = os.Stdout
90
+	cmd.Stderr = os.Stderr
91
+
92
+	log.Printf("executing '%s'", cmd.Args)
93
+
94
+	if err := cmd.Run(); err != nil {
95
+		panic(err)
96
+	}
97
+
98
+	url := fmt.Sprintf("/results/%s", resultID)
99
+
100
+	http.Redirect(w, r, url, http.StatusSeeOther)
101
+
102
+}
103
+
104
+func downloadResult(w http.ResponseWriter, r *http.Request) {
105
+
106
+	resultID := chi.URLParam(r, "ID")
107
+	if resultID == "" {
108
+		http.Redirect(w, r, "/", http.StatusSeeOther)
109
+		return
110
+	}
111
+
112
+	filePath := path.Join(tiffDir, resultID+".tif")
113
+	if _, err := os.Stat(filePath); err != nil {
114
+		if os.IsNotExist(err) {
115
+			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
116
+			return
117
+		}
118
+		panic(err)
119
+	}
120
+
121
+	w.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.tif\"", resultID))
122
+	http.ServeFile(w, r, filePath)
123
+
124
+}

+ 1
- 0
misc/dokku/Procfile View File

@@ -0,0 +1 @@
1
+web: bin/tiff-optimizer

+ 5
- 0
misc/dokku/app.json View File

@@ -0,0 +1,5 @@
1
+{
2
+  "scripts": {
3
+    "dokku": {}
4
+  }
5
+}

+ 4
- 0
modd.conf View File

@@ -0,0 +1,4 @@
1
+**/*.go {
2
+    prep: make bin/tiff-optimizer
3
+    daemon: make server
4
+}

+ 42
- 0
static/index.html View File

@@ -0,0 +1,42 @@
1
+<html>
2
+<head>
3
+  <meta charset="utf8">
4
+  <meta name="viewport" content="width=device-width, initial-scale=1">
5
+  <title>Tiff Optimizer</title>
6
+  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
7
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
8
+</head>
9
+<body>
10
+  <div class="container">
11
+    <div class="columns">
12
+      <div class="column">
13
+        <div class="level is-mobile is-marginless">
14
+          <div class="level-left">
15
+            <h1 class="is-size-1 level-item">Tiff Optimizer</h1>
16
+          </div>
17
+        </div>
18
+        <form action="." method="POST" enctype="multipart/form-data">
19
+          <div class="file is-primary is-large" style="justify-content:center">
20
+            <label class="file-label">
21
+              <input class="file-input"
22
+              id="tiffImage"
23
+              name="tiffImage"
24
+              accept=".tif"
25
+              onchange="javascript:this.form.submit()"
26
+              type="file" name="resume">
27
+              <span class="file-cta">
28
+                <span class="file-icon">
29
+                  <i class="fas fa-upload"></i>
30
+                </span>
31
+                <span class="file-label">
32
+                  Optimiser un fichier Tiff
33
+                </span>
34
+              </span>
35
+            </label>
36
+          </div>
37
+        </form>
38
+      </div>
39
+    </div>
40
+  </div>
41
+</body>
42
+</html>