commit 415f91390f5fba22aa9b2d9d43bf35bfc50ae81c
parent b350c5923b76b1f73ac5d5d4876e8cb7f0b86d8f
Author: Daniel Moch <daniel@danielmoch.com>
Date: Sat, 5 Dec 2020 19:32:40 -0500
Add init argument; move main into cmd subdir
Diffstat:
M | .gitignore | | | 2 | +- |
A | Makefile | | | 16 | ++++++++++++++++ |
A | cmd/shrt/main.go | | | 229 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | main.go | | | 143 | ------------------------------------------------------------------------------- |
M | shrtfile.go | | | 65 | ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
5 files changed, 298 insertions(+), 157 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,3 +1,3 @@
-go-shrt
+shrt
shrt.conf
shrt.db
diff --git a/Makefile b/Makefile
@@ -0,0 +1,15 @@
+VERSION := 0.1.0-dev0
+
+all: shrt
+
+go.mod: cmd/shrt/main.go *.go
+ go mod tidy
+ touch go.mod
+
+shrt: go.mod
+ go build -ldflags "-X main.version=${VERSION}" ./cmd/shrt
+
+clean:
+ rm -f shrt
+
+.PHONY: all clean+
\ No newline at end of file
diff --git a/cmd/shrt/main.go b/cmd/shrt/main.go
@@ -0,0 +1,229 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "strings"
+
+ goshrt "djmo.ch/go-shrt"
+)
+
+const (
+ errNone = iota
+ errArgNum
+ errDatabase
+ errShrtFile
+ errRepeatToken
+ errInit
+)
+
+var (
+ arg0 = path.Base(os.Args[0])
+
+ shrt, cfg *goshrt.ShrtFile
+ version string
+)
+
+func usage(r int) {
+ fmt.Printf("usage: %s [-hv] [-d dbpath] [-c cfgpath] [-l listenaddr] [init]\n", arg0)
+ os.Exit(r)
+}
+
+func print_version() {
+ fmt.Printf("%s version %s\n", arg0, version)
+ os.Exit(errNone)
+}
+
+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 strings.Contains(key, "/") {
+ log.Println("bad request: " + key)
+ w.WriteHeader(http.StatusForbidden)
+ w.Write([]byte("Request path not allowed\n"))
+ return
+ }
+ if strings.Contains(key, "/") {
+ log.Println("bad request: " + key)
+ w.WriteHeader(http.StatusForbidden)
+ w.Write([]byte("Request path not allowed\n"))
+ return
+ }
+
+ if key == "robots.txt" {
+ log.Println("incoming robot")
+ resp := "# Welcome to Shrt\n"
+ resp += "User-Agent: *\n"
+ resp += "Disallow:\n"
+ w.Write([]byte(resp))
+ return
+ }
+ if key == "robots.txt" {
+ log.Println("incoming robot")
+ resp := "# Welcome to Shrt\n"
+ resp += "User-Agent: *\n"
+ resp += "Disallow:\n"
+ w.Write([]byte(resp))
+ return
+ }
+
+ if key == "" && cfg.Get("barerdr") != "" {
+ log.Println("shortlink request for /")
+ w.Header().Add("Location", cfg.Get("barerdr"))
+ w.WriteHeader(http.StatusFound)
+ w.Write([]byte("Redirecting\n"))
+ return
+ }
+
+ if val := shrt.Get(key); val != "" {
+ log.Println("shortlink request for", key)
+ w.Header().Add("Location", val)
+ w.WriteHeader(http.StatusMovedPermanently)
+ w.Write([]byte("Redirecting\n"))
+ return
+ }
+
+ repo := key
+ log.Println("go-get request for", repo)
+ 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.Get("srvname"), repo, cfg.Get("scmtype"),
+ cfg.Get("rdrname"), repo, cfg.Get("suffix"))
+ resp += `<meta http-equiv="refresh" content="0; `
+ resp += fmt.Sprintf("url=https://godoc.org/%s/%s\">\n",
+ cfg.Get("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.Get("srvname"), repo, cfg.Get("srvname"), repo)
+ resp += "</body>\n"
+ resp += "</html>\n"
+ w.Write([]byte(resp))
+ return
+}
+
+func doInit(path string) {
+ r := bufio.NewReader(os.Stdin)
+ m, err := goshrt.NewShrtFile(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: error creating config -- %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+
+ fmt.Printf("server name: ")
+ srvname, err := r.ReadString('\n')
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+ m.Put("srvname", srvname)
+
+ fmt.Printf("SCM type: ")
+ scmtype, err := r.ReadString('\n')
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+ m.Put("scmtype", scmtype)
+
+ fmt.Printf("repo suffix (blank for none): ")
+ suffix, err := r.ReadString('\n')
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+ m.Put("suffix", suffix)
+
+ fmt.Printf("redirect base url: ")
+ rdrname, err := r.ReadString('\n')
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+ m.Put("rdrname", rdrname)
+
+ fmt.Printf("bare redirect url: ")
+ barerdr, err := r.ReadString('\n')
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", arg0, err.Error())
+ os.Exit(errInit)
+ }
+ m.Put("barerdr", barerdr)
+ m.Write()
+}
+
+func main() {
+ var err error
+ if len(os.Args) > 4 {
+ usage(errArgNum)
+ }
+
+ dbpath := "shrt.db"
+ cfgpath := "shrt.conf"
+ listenaddr := ":8080"
+ doinit := false
+ for i := 1; i < len(os.Args); i++ {
+ switch os.Args[i] {
+ case "-h":
+ usage(errNone)
+ case "-v":
+ print_version()
+ case "-d":
+ i += 1
+ dbpath = os.Args[i]
+ case "-c":
+ i += 1
+ cfgpath = os.Args[i]
+ case "-l":
+ i += 1
+ listenaddr = 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(cfgpath)
+ os.Exit(errNone)
+ }
+
+ cfg, err = goshrt.ReadShrtFile(cfgpath)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: config error -- %s\n", arg0, err.Error())
+ os.Exit(errShrtFile)
+ }
+
+ shrt, err = goshrt.ReadShrtFile(dbpath)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: db error -- %s\n", arg0, err.Error())
+ os.Exit(errShrtFile)
+ }
+
+ http.Handle("/", http.HandlerFunc(handl))
+ log.Println("listening on", listenaddr)
+ log.Fatal(http.ListenAndServe(listenaddr, nil))
+}
diff --git a/main.go b/main.go
@@ -1,143 +0,0 @@
-package main
-
-import (
- "fmt"
- "log"
- "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] [-l listenaddr] [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 strings.Contains(key, "/") {
- log.Println("bad request: " + key)
- w.WriteHeader(http.StatusForbidden)
- w.Write([]byte("Request path not allowed\n"))
- return
- }
-
- if key == "" && (*cfg)["barerdr"] != "" {
- log.Println("shortlink request for /")
- w.Header().Add("Location", (*cfg)["barerdr"])
- w.WriteHeader(http.StatusFound)
- w.Write([]byte("Redirecting\n"))
- return
- }
-
- if key == "robots.txt" {
- log.Println("incoming robot")
- resp := "# Welcome to Shrt\n"
- resp += "User-Agent: *\n"
- resp += "Disallow:\n"
- w.Write([]byte(resp))
- return
- }
-
- if val, ok := (*shrt)[key]; ok {
- log.Println("shortlink request for", key)
- w.Header().Add("Location", val)
- w.WriteHeader(http.StatusMovedPermanently)
- w.Write([]byte("Redirecting\n"))
- return
- }
-
- repo := key
- log.Println("go-get request for", repo)
- 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
-}
-
-func main() {
- if len(os.Args) > 4 {
- usage(errArgNum)
- }
-
- dbpath := "shrt.db"
- cfgpath := "shrt.conf"
- listenaddr := ":8080"
- //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 "-l":
- i += 1
- listenaddr = 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))
- log.Println("listening on", listenaddr)
- log.Fatal(http.ListenAndServe(listenaddr, nil))
-}
diff --git a/shrtfile.go b/shrtfile.go
@@ -1,4 +1,4 @@
-package main
+package shrt
import (
"bufio"
@@ -7,16 +7,30 @@ import (
"strings"
)
-type shrtFile map[string]string
+type ShrtFile struct {
+ m map[string]string
+ path string
+}
+
+func NewShrtFile(path string) (*ShrtFile, error) {
+ // we fail if the file already exists, so the logic is reversed
+ // from the usual here
+ f, err := os.Open(path)
+ if err == nil {
+ f.Close()
+ return nil,
+ fmt.Errorf("File already exists. Please delete and try again.")
+ }
+
+ return &ShrtFile{m: make(map[string]string), path: path}, nil
+}
-func readShrtFile(db string) *shrtFile {
- var newFile shrtFile
- newFile = make(map[string]string)
+func ReadShrtFile(db string) (*ShrtFile, error) {
+ var newFile ShrtFile
+ newFile.m = 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)
+ return nil, fmt.Errorf("error opening shrtfile -- %s", err.Error())
}
defer f.Close()
@@ -25,11 +39,36 @@ func readShrtFile(db string) *shrtFile {
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)
+ if _, ok := newFile.m[strings.Trim(tok[0], " ")]; ok {
+ return nil, fmt.Errorf("repeat token -- %s", tok[0])
+ }
+ newFile.m[strings.Trim(tok[0], " ")] = strings.Trim(tok[1], " ")
+ }
+ return &newFile, nil
+}
+
+func (s *ShrtFile) Get(key string) string {
+ return s.m[key]
+}
+
+func (s *ShrtFile) Put(key, value string) {
+ s.m[key] = value
+}
+
+func (s *ShrtFile) Write() error {
+ f, err := os.Create(s.path)
+ if err != nil {
+ return fmt.Errorf("error opening ShrtFile: %s", err.Error())
+ }
+ defer f.Close()
+
+ w := bufio.NewWriter(f)
+ for k, v := range s.m {
+ _, err = w.WriteString(fmt.Sprintf("%s = %s", k, v))
+ if err != nil {
+ return fmt.Errorf("error writing ShrtFile: %s", err.Error())
}
- newFile[strings.Trim(tok[0], " ")] = strings.Trim(tok[1], " ")
}
- return &newFile
+ w.Flush()
+ return nil
}