2018-06-10 20:49:32 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-06-16 20:08:14 +00:00
|
|
|
"fmt"
|
2018-06-15 13:29:56 +00:00
|
|
|
e "git.xdrm.io/go/xb-api/err"
|
|
|
|
i "git.xdrm.io/go/xb-api/implement"
|
2018-06-16 20:08:14 +00:00
|
|
|
"github.com/go-redis/redis"
|
2018-06-10 20:49:32 +00:00
|
|
|
)
|
|
|
|
|
2018-06-16 20:08:14 +00:00
|
|
|
const NONCE = "go-tiny-url"
|
|
|
|
|
|
|
|
type db redis.Client
|
|
|
|
|
|
|
|
// Returns a connected client to dataset
|
|
|
|
func connect() *db {
|
|
|
|
cli := redis.NewClient(&redis.Options{
|
2018-06-16 16:04:28 +00:00
|
|
|
Addr: "127.0.0.1:6379",
|
|
|
|
Password: "",
|
|
|
|
DB: 0,
|
|
|
|
})
|
|
|
|
|
2018-06-16 20:08:14 +00:00
|
|
|
if _, err := cli.Ping().Result(); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return (*db)(cli)
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns value from key (nil if nothing)
|
|
|
|
func (c *db) get(key string) []byte {
|
|
|
|
|
|
|
|
// 1. Try to get
|
|
|
|
if val, err := c.Get(fmt.Sprintf("%s:%s", NONCE, key)).Result(); err != nil {
|
|
|
|
// 2. nil if nothing found
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
// 3. return if found
|
|
|
|
return []byte(val)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// stores a value for a key (success state in return)
|
|
|
|
func (c *db) set(key string, value string) bool {
|
|
|
|
|
|
|
|
// 1. Try to set
|
|
|
|
if c.Set(fmt.Sprintf("%s:%s", NONCE, key), value, 0).Err() != nil {
|
|
|
|
// 2. failure
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. success
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// deletes the value for a key (success state in return)
|
|
|
|
func (c *db) del(key string) bool {
|
|
|
|
|
|
|
|
// 1. Try to set
|
|
|
|
if c.Del(fmt.Sprintf("%s:%s", NONCE, key)).Err() != nil {
|
|
|
|
// 2. failure
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. success
|
|
|
|
return true
|
2018-06-16 16:04:28 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redirects to an url from a key
|
2018-06-10 20:49:32 +00:00
|
|
|
func Get(d i.Arguments, r *i.Response) i.Response {
|
2018-06-16 16:04:28 +00:00
|
|
|
|
|
|
|
/* (1) Init redis connection */
|
2018-06-16 20:08:14 +00:00
|
|
|
cli := connect()
|
|
|
|
if cli == nil {
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) Extract api input */
|
|
|
|
key, ok := d["url"].(string)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
r.Err = e.InvalidParam
|
|
|
|
r.Err.BindArgument("url")
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Check if match for this key */
|
2018-06-16 20:08:14 +00:00
|
|
|
val := cli.get(key)
|
|
|
|
if val == nil {
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.NoMatchFound
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) Redirect to value */
|
2018-06-16 20:08:14 +00:00
|
|
|
r.Set("_REDIRECT_", string(val))
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.Success
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stores a new tinyurl/fullurl combination
|
|
|
|
func Post(d i.Arguments, r *i.Response) i.Response {
|
|
|
|
/* (1) Init redis connection */
|
2018-06-16 20:08:14 +00:00
|
|
|
cli := connect()
|
|
|
|
if cli == nil {
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) Extract api input */
|
|
|
|
target, ok1 := d["target"].(string)
|
|
|
|
url, ok2 := d["url"].(string)
|
|
|
|
|
|
|
|
if !ok1 || !ok2 {
|
|
|
|
r.Err = e.InvalidParam
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Check if key already used */
|
2018-06-16 20:08:14 +00:00
|
|
|
if cli.get(url) != nil {
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.AlreadyExists
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) Store */
|
2018-06-16 20:08:14 +00:00
|
|
|
if !cli.set(url, target) {
|
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Err = e.Success
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overrides a existing tinyurl with new target
|
|
|
|
func Put(d i.Arguments, r *i.Response) i.Response {
|
|
|
|
|
|
|
|
/* (1) Init redis connection */
|
|
|
|
cli := connect()
|
|
|
|
if cli == nil {
|
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) Extract api input */
|
|
|
|
target, ok1 := d["target"].(string)
|
|
|
|
url, ok2 := d["url"].(string)
|
|
|
|
|
|
|
|
if !ok1 || !ok2 {
|
|
|
|
r.Err = e.InvalidParam
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Check if key already used */
|
|
|
|
if cli.get(url) == nil {
|
|
|
|
r.Err = e.NoMatchFound
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) Update */
|
|
|
|
if !cli.set(url, target) {
|
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Err = e.Success
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deletes an existing tinyurl
|
|
|
|
func Delete(d i.Arguments, r *i.Response) i.Response {
|
|
|
|
|
|
|
|
/* (1) Init redis connection */
|
|
|
|
cli := connect()
|
|
|
|
if cli == nil {
|
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) Extract api input */
|
|
|
|
url, ok := d["url"].(string)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
r.Err = e.InvalidParam
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Check if key already used */
|
|
|
|
if cli.get(url) == nil {
|
|
|
|
r.Err = e.NoMatchFound
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) Delete */
|
|
|
|
if !cli.del(url) {
|
2018-06-16 16:04:28 +00:00
|
|
|
r.Err = e.Failure
|
|
|
|
return *r
|
|
|
|
}
|
|
|
|
|
2018-06-10 20:49:32 +00:00
|
|
|
r.Err = e.Success
|
|
|
|
return *r
|
|
|
|
}
|