Browse Source

initial prototype

master
Brett Langdon 10 years ago
parent
commit
2a59874787
5 changed files with 109 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +5
    -0
      Makefile
  3. +22
    -0
      cmd/terse/terse.go
  4. +61
    -0
      server.go
  5. +20
    -0
      url.go

+ 1
- 0
.gitignore View File

@ -0,0 +1 @@
/terse

+ 5
- 0
Makefile View File

@ -0,0 +1,5 @@
terse: ./url.go ./server.go ./cmd/terse/terse.go
go build ./cmd/terse
clean:
rm -f ./terse

+ 22
- 0
cmd/terse/terse.go View File

@ -0,0 +1,22 @@
package main
import (
"log"
"github.com/brettlangdon/go-arg"
"github.com/brettlangdon/terse"
)
var args struct {
MaxEntries int `arg:"-m,--max,help:max number of links to keep [default: 1000]"`
Bind string `arg:"-b,--bind,help:\"[host]:<port>\" to bind the server to [default: 127.0.0.1:5892]"`
}
func main() {
args.MaxEntries = 1000
args.Bind = "127.0.0.1:5892"
arg.MustParse(&args)
server := terse.NewServer(args.Bind, args.MaxEntries)
log.Fatal(server.ListenAndServe())
}

+ 61
- 0
server.go View File

@ -0,0 +1,61 @@
package terse
import (
"bufio"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/golang/groupcache/lru"
)
type Handler struct {
cache *lru.Cache
}
func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
handler.HandleGet(w, r)
case "POST":
handler.HandlePost(w, r)
default:
http.Error(w, fmt.Sprintf("Method \"%s\" Not Allowed", r.Method), http.StatusMethodNotAllowed)
}
}
func (handler *Handler) HandleGet(w http.ResponseWriter, r *http.Request) {
url := strings.Trim(r.URL.Path, "/")
code := strings.SplitN(url, "/", 2)[0]
value, ok := handler.cache.Get(code)
if ok {
switch url := value.(type) {
case string:
http.Redirect(w, r, url, http.StatusMovedPermanently)
return
}
}
http.NotFound(w, r)
}
func (handler *Handler) HandlePost(w http.ResponseWriter, r *http.Request) {
reader := bufio.NewScanner(r.Body)
reader.Scan()
url, err := url.ParseRequestURI(reader.Text())
if err != nil {
panic(err)
}
code := GetShortCode([]byte(url.String()))
handler.cache.Add(code, url.String())
fmt.Fprintf(w, code)
}
func NewServer(bind string, maxEntries int) *http.Server {
return &http.Server{
Addr: bind,
Handler: &Handler{
cache: lru.New(maxEntries),
},
}
}

+ 20
- 0
url.go View File

@ -0,0 +1,20 @@
package terse
import (
"bytes"
"hash/crc32"
)
const ALPHABET string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"
const BASE uint32 = uint32(len(ALPHABET))
func GetShortCode(url []byte) string {
var code bytes.Buffer
num := crc32.ChecksumIEEE(url)
for num > 0 {
next := (num % BASE)
code.WriteRune(rune(ALPHABET[next]))
num = num / 62
}
return code.String()
}

Loading…
Cancel
Save