~yerinalexey/gobin

ref: 3ca827036bd6322c25e0d050e69cae68eadf3e0c gobin/main.go -rw-r--r-- 3.3 KiB
3ca82703 — Alexey Yerin Use Host: header instead of base URL 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// gobin - Simple self-hosted service for sharing text snippets
// Copyright (c) 2020-2021 Alexey Yerin
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <https://www.gnu.org/licenses/>.

package main

import (
	"context"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"path"
	"strconv"
	"flag"

	"git.sr.ht/~yerinalexey/gobin/config"
	"git.sr.ht/~yerinalexey/gobin/paste"

	"github.com/gorilla/mux"
	"github.com/jackc/pgx/v4/pgxpool"
)

func main() {
	configFile := flag.String("config", "config.toml", "path to configuration file")
	flag.Parse()

	config, err := config.New(*configFile)

	if err != nil {
		log.Fatalln("Invalid configuration:", err)
	}

	pool, err := pgxpool.Connect(context.Background(), config.DatabaseUri)
	if err != nil {
		log.Fatalln("Can't connect to the database: ", err)
	}
	defer pool.Close()

	tmpl := template.Must(template.ParseGlob(path.Join(config.TemplateRoot, "*.html")))

	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		pastes, err := paste.GetPublicPastes(pool, r)

		if err != nil {
			log.Printf("Failed to get paste list: %v\n", err)
			w.WriteHeader(500)

			return
		}

		tmpl.ExecuteTemplate(w, "home", pastes)
	})

	r.HandleFunc("/new", func(w http.ResponseWriter, req *http.Request) {
		tmpl.ExecuteTemplate(w, "new", nil)
	}).Methods("GET")

	r.HandleFunc("/new", func(w http.ResponseWriter, req *http.Request) {
		contents := req.FormValue("contents")
		public := req.FormValue("public") == "on"

		id, err := paste.Insert(pool, contents, public)

		if err != nil {
			// Not Fatalf because nobody wants server to crash when database
			// insert fails
			log.Printf("Failed to submit paste: %v\n", err)
			w.WriteHeader(500)

			return
		}

		link := paste.CreatePermalink(id, req.Host, config.Insecure)

		tmpl.ExecuteTemplate(w, "saved", link)
	}).Methods("POST")

	r.HandleFunc("/paste/{id}", func(w http.ResponseWriter, req *http.Request) {
		vars := mux.Vars(req)
		id, err := strconv.Atoi(vars["id"])

		if err != nil {
			w.WriteHeader(404)
			tmpl.ExecuteTemplate(w, "not-found", nil)

			return
		}

		data, err := paste.GetById(pool, id)

		if err != nil {
			log.Println("Error:", err)

			w.WriteHeader(404)
			tmpl.ExecuteTemplate(w, "not-found", nil)

			return
		}

		tmpl.ExecuteTemplate(w, "paste", *data)
	}).Name("paste")

	// Static files
	fs := http.FileServer(http.Dir(config.StaticRoot))
	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))

	// Not found page
	r.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.WriteHeader(404)
		tmpl.ExecuteTemplate(w, "not-found", nil)
	})

	log.Printf("Staring on port %d\n", config.Port)
	log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), r))
}