go-shrt

Shortlinks and go-get redirects
git clone git://git.danielmoch.com/go-shrt.git
Log | Files | Refs | README | LICENSE

commit 6feda36dc93548141d2b52d68932cef10a17d199
Author: Daniel Moch <daniel@danielmoch.com>
Date:   Sat,  7 Nov 2020 20:04:28 -0500

Initial commit

Diffstat:
A.gitignore | 3+++
ALICENSE | 17+++++++++++++++++
AREADME | 10++++++++++
Ago.mod | 3+++
Ago.sum | 0
Amain.go | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashrtfile.go | 35+++++++++++++++++++++++++++++++++++
7 files changed, 184 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +go-shrt +shrt.conf +shrt.db diff --git a/LICENSE b/LICENSE @@ -0,0 +1,17 @@ +ISC License (ISC) + +Copyright 2020 Daniel Moch + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA +OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/README b/README @@ -0,0 +1,10 @@ +go-shrt +======== + +This is a URL shortener. There are many like it, but this is mine. Try +putting all the vowels in "shrt" and enjoy yourself! + +Also handles go-get redirects. + +There's no UI to add a new shortlink at this time. Just edit the DB by +hand. diff --git a/go.mod b/go.mod @@ -0,0 +1,3 @@ +module djmo.ch/go-shrt + +go 1.15 diff --git a/go.sum b/go.sum diff --git a/main.go b/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "path" + "strings" +) + +const ( + errNone = iota + errArgNum + errDatabase + errNoFile + errRepeatToken +) + +var ( + arg0 = path.Base(os.Args[0]) + + shrt, cfg *shrtFile +) + +func usage(r int) { + fmt.Printf("usage: %s [-d dbpath] [-c cfgpath] [init]\n", arg0) + os.Exit(r) +} + +func handl(w http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + w.Write([]byte("Method not allowed\n")) + return + } + + key := req.URL.Path + if strings.HasPrefix(key, "/") { + key = key[1:] + } + + if req.URL.Query().Get("go-get") == "1" { + repo := key + resp := "<!DOCTYPE html>\n" + resp += "<html>\n" + resp += "<head>\n" + resp += `<meta http-equiv="Content-Type" ` + resp += "content=\"text/html; charset=utf-8\"/>\n" + resp += "<meta name=\"go-import\" " + resp += fmt.Sprintf("content=\"%s/%s %s %s/%s%s\">\n", + (*cfg)["srvname"], repo, (*cfg)["scmtype"], + (*cfg)["rdrname"], repo, (*cfg)["suffix"]) + resp += `<meta http-equiv="refresh" content="0; ` + resp += fmt.Sprintf("url=https://godoc.org/%s/%s\">\n", + (*cfg)["srvname"], repo) + resp += "</head>\n" + resp += "<body>\n" + resp += `Redirecting to docs at <a href="https://godoc.org/` + resp += fmt.Sprintf("%s/%s\">godoc.org/%s/%s</a>...\n", + (*cfg)["srvname"], repo, (*cfg)["srvname"], repo) + resp += "</body>\n" + resp += "</html>\n" + w.Write([]byte(resp)) + return + } + + if val, ok := (*shrt)[key]; ok { + w.Header().Add("Location", val) + w.WriteHeader(http.StatusMovedPermanently) + w.Write([]byte("Redirecting\n")) + } else { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Short link not found\n")) + } + +} + +func main() { + if len(os.Args) > 4 { + usage(errArgNum) + } + + dbpath := "shrt.db" + cfgpath := "shrt.conf" + //doinit := false + for i := 1; i < len(os.Args); i++ { + switch os.Args[i] { + case "-h": + usage(errNone) + case "-d": + i += 1 + dbpath = os.Args[i] + case "-c": + i += 1 + cfgpath = os.Args[i] + case "init": + //doinit = true + break + default: + fmt.Fprintf(os.Stderr, "%s: unknown option -- %s\n", + arg0, os.Args[i]) + + } + } + + // if doinit { + // doInit(dbpath) + // os.Exit(errNone) + // } + + cfg = readShrtFile(cfgpath) + shrt = readShrtFile(dbpath) + + http.Handle("/", http.HandlerFunc(handl)) + http.ListenAndServe(":8080", nil) +} diff --git a/shrtfile.go b/shrtfile.go @@ -0,0 +1,35 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +type shrtFile map[string]string + +func readShrtFile(db string) *shrtFile { + var newFile shrtFile + newFile = make(map[string]string) + f, err := os.Open(db) + if err != nil { + fmt.Fprintf(os.Stderr, "%s: error opening shrtfile -- %s\n", + arg0, err.Error()) + os.Exit(errNoFile) + } + + defer f.Close() + + scnr := bufio.NewScanner(f) + + for scnr.Scan() { + tok := strings.SplitN(scnr.Text(), "=", 2) + if _, ok := newFile[strings.Trim(tok[0], " ")]; ok { + fmt.Fprintf(os.Stderr, "%s: repeat token -- %s\n", arg0, tok[0]) + os.Exit(errRepeatToken) + } + newFile[strings.Trim(tok[0], " ")] = strings.Trim(tok[1], " ") + } + return &newFile +}