forked from jhaals/url-shortener
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
116 lines (97 loc) · 2.69 KB
/
main.go
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
package main
import (
"encoding/json"
"github.com/asaskevich/govalidator"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"log"
"math"
"net/http"
"os"
"path"
"strings"
)
const base string = "0123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ"
func encode(n int64) string {
var s string
var num = float64(n)
for num > 0 {
s = string(base[int(num)%len(base)]) + s
num = math.Floor(num / float64(len(base)))
}
return s
}
func decode(s string) int {
var num = 0
for _, element := range strings.Split(s, "") {
num = num*len(base) + strings.Index(base, element)
}
return num
}
func decodeHandler(response http.ResponseWriter, request *http.Request, db Database) {
id := decode(mux.Vars(request)["id"])
id -= 1000000
url, err := db.Get(id)
if err != nil {
http.Error(response, `{"error": "No such URL"}`, http.StatusNotFound)
return
}
http.Redirect(response, request, url, 301)
}
func encodeHandler(response http.ResponseWriter, request *http.Request, db Database, baseURL string) {
decoder := json.NewDecoder(request.Body)
var data struct {
URL string `json:"url"`
Secret string `json:"secret"`
}
err := decoder.Decode(&data)
if err != nil {
http.Error(response, `{"error": "Unable to parse json"}`, http.StatusBadRequest)
return
}
if data.Secret != os.Getenv("SECRET") {
http.Error(response, `{"error": "Incorrect Secret"}`, http.StatusBadRequest)
return
}
if !govalidator.IsURL(data.URL) {
http.Error(response, `{"error": "Not a valid URL"}`, http.StatusBadRequest)
return
}
id, err := db.Save(data.URL)
if err != nil {
log.Println(err)
return
}
id += 1000000
resp := map[string]string{"url": baseURL + encode(id), "id": encode(id), "error": ""}
jsonData, _ := json.Marshal(resp)
response.Write(jsonData)
}
func main() {
if os.Getenv("BASE_URL") == "" {
log.Fatal("BASE_URL environment variable must be set")
}
if os.Getenv("DB_PATH") == "" {
log.Fatal("DB_PATH environment variable must be set")
}
if os.Getenv("SECRET") == "" {
log.Fatal("SECRET environment variable must be set")
}
db := sqlite{Path: path.Join(os.Getenv("DB_PATH"), "db.sqlite")}
db.Init()
baseURL := os.Getenv("BASE_URL")
if !strings.HasSuffix(baseURL, "/") {
baseURL += "/"
}
r := mux.NewRouter()
r.HandleFunc("/save",
func(response http.ResponseWriter, request *http.Request) {
encodeHandler(response, request, db, baseURL)
}).Methods("POST")
r.HandleFunc("/{id}", func(response http.ResponseWriter, request *http.Request) {
decodeHandler(response, request, db)
})
r.PathPrefix("/").Handler(http.FileServer(http.Dir("public")))
log.Println("Starting server on port :1337")
log.Fatal(http.ListenAndServe(":1337", handlers.LoggingHandler(os.Stdout, r)))
}