Initial commit

This commit is contained in:
2016-06-25 22:38:57 +01:00
commit 919883326b
3 changed files with 183 additions and 0 deletions

29
main.go Normal file
View File

@@ -0,0 +1,29 @@
package main
import (
"os"
"github.com/iris-contrib/middleware/logger"
"github.com/kataras/iris"
)
func main() {
shortner := NewShortner()
defer shortner.Close()
routes := Routes{Shortner: shortner}
iris.Use(logger.New(iris.Logger))
iris.Get("/set/:key/:value", routes.Set)
iris.Get("/get/:key", routes.Get)
iris.Get("/shorten/:url", routes.Shorten)
iris.Get("/lookup/:uid", routes.Lookup)
iris.Get("/", routes.Root)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
iris.Listen(":" + port)
}

54
routes.go Normal file
View File

@@ -0,0 +1,54 @@
package main
import "github.com/kataras/iris"
// Routes handles HTTP requests from iris.
type Routes struct {
Shortner *Shortner
}
// Root returns the root.
func (r *Routes) Root(c *iris.Context) {
c.Write("hello world")
}
// Get fetches a value for a given key.
func (r *Routes) Get(c *iris.Context) {
key := c.Param("key")
value := r.Shortner.Get([]byte(key))
c.Write(string(value))
}
// Set writes a given value to the specified key.
func (r *Routes) Set(c *iris.Context) {
key := []byte(c.Param("key"))
value := []byte(c.Param("value"))
err := r.Shortner.Set(key, value)
if err == nil {
c.Write("OK")
} else {
c.Log("ERROR: ", err.Error(), "\n")
c.Write("Oops >_<")
}
}
// Shorten attempts to shorten a URL to a UID
func (r *Routes) Shorten(c *iris.Context) {
url := []byte(c.Param("url"))
uid, err := r.Shortner.Shorten(url)
if err == nil {
c.Write("Shortened: %s", uid)
} else {
c.Log("ERROR: ", err.Error(), "\n")
c.Write("Oops >_<")
}
}
// Lookup attempts to fetch previously shortened URLs based on UID
func (r *Routes) Lookup(c *iris.Context) {
uid := []byte(c.Param("uid"))
url := r.Shortner.Lookup(uid)
c.Write("URL: %s", url)
}

100
shortner.go Normal file
View File

@@ -0,0 +1,100 @@
package main
import (
"log"
"strconv"
"github.com/jbenet/go-base58"
"github.com/syndtr/goleveldb/leveldb"
)
// NewShortner returns a new Shortner.
func NewShortner() *Shortner {
db, err := leveldb.OpenFile("shortner.db", nil)
if err != nil {
log.Fatal(err)
}
return &Shortner{
Db: db,
KeyPrefix: []byte("url:"),
}
}
// Shortner shortens URLs.
type Shortner struct {
Db *leveldb.DB
KeyPrefix []byte
}
// Close calls Close() on the goleveldb.
func (s *Shortner) Close() {
err := s.Db.Close()
if err != nil {
log.Fatal(err)
}
}
// Get reads from the database.
func (s *Shortner) Get(key []byte) []byte {
value, _ := s.Db.Get(key, nil)
return value
}
// Set writes to the database.
func (s *Shortner) Set(key []byte, value []byte) error {
return s.Db.Put(key, value, nil)
}
// Shorten shortens given URL
func (s *Shortner) Shorten(url []byte) ([]byte, error) {
uid, err := s.newUID()
if err != nil {
return []byte{}, err
}
key := s.makeKey(uid)
err = s.Set(key, url)
if err != nil {
return []byte{}, err
}
return uid, nil
}
// Lookup attempts to fetch the value for given UID
func (s *Shortner) Lookup(uid []byte) []byte {
return s.Get(s.makeKey(uid))
}
func (s *Shortner) makeKey(uid []byte) []byte {
return append(s.KeyPrefix, uid...)
}
func (s *Shortner) newUID() ([]byte, error) {
key := []byte("index")
tx, err := s.Db.OpenTransaction()
defer tx.Commit()
if err != nil {
return []byte{}, err
}
index, _ := tx.Get(key, nil)
if index == nil {
index = []byte("1")
}
num, _ := strconv.Atoi(string(index))
num++
index = []byte(strconv.Itoa(num))
err = tx.Put(key, index, nil)
if err != nil {
return []byte{}, err
}
uid := base58.Encode(index)
return []byte(uid), nil
}