diff --git a/manifest.json b/manifest.json index 7e1f65e..0e629ce 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "info": "redirects to given tiny url", "scope": [[]], "in": { - "URL#0": { "info": "tiny url to redirect to", "name": "url", "type": "varchar(3,30)" } + "URL#0": { "info": "tiny url to redirect to", "name": "url", "type": "varchar(1,30)" } }, "out": {} }, @@ -13,10 +13,29 @@ "info": "creates a new tiny url", "scope": [[]], "in": { - "url": { "info": "preferred tiny url", "type": "varchar(3,30)" }, + "URL#0": { "info": "preferred tiny url", "type": "varchar(1,30)", "name": "url" }, "target": { "info": "url to shorten", "type": "varchar(5,300)" } }, "out": {} + }, + + "PUT": { + "info": "overrides an existing tiny url", + "scope": [[]], + "in": { + "URL#0": { "info": "preferred tiny url", "type": "varchar(1,30)", "name": "url" }, + "target": { "info": "url to shorten", "type": "varchar(5,300)" } + }, + "out": {} + }, + + "DELETE": { + "info": "removes an existing tiny url", + "scope": [[]], + "in": { + "URL#0": { "info": "preferred tiny url", "type": "varchar(1,30)", "name": "url" } + }, + "out": {} } } \ No newline at end of file diff --git a/root/i.go b/root/i.go index af4f1a4..90d8a73 100644 --- a/root/i.go +++ b/root/i.go @@ -1,30 +1,79 @@ package main import ( + "fmt" e "git.xdrm.io/go/xb-api/err" i "git.xdrm.io/go/xb-api/implement" - r "github.com/go-redis/redis" + "github.com/go-redis/redis" ) -// Initiates connection to redis dataset -func redisConnect() (*r.Client, error) { - cli := r.NewClient(&r.Options{ +const NONCE = "go-tiny-url" + +type db redis.Client + +// Returns a connected client to dataset +func connect() *db { + cli := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "", DB: 0, }) - _, err := cli.Ping().Result() + 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 - return cli, err } // Redirects to an url from a key func Get(d i.Arguments, r *i.Response) i.Response { /* (1) Init redis connection */ - cli, err := redisConnect() - if err != nil { + cli := connect() + if cli == nil { r.Err = e.Failure return *r } @@ -39,14 +88,14 @@ func Get(d i.Arguments, r *i.Response) i.Response { } /* (3) Check if match for this key */ - val, err := cli.Get(key).Result() - if err != nil { + val := cli.get(key) + if val == nil { r.Err = e.NoMatchFound return *r } /* (4) Redirect to value */ - r.Set("_REDIRECT_", val) + r.Set("_REDIRECT_", string(val)) r.Err = e.Success return *r } @@ -54,8 +103,8 @@ func Get(d i.Arguments, r *i.Response) i.Response { // Stores a new tinyurl/fullurl combination func Post(d i.Arguments, r *i.Response) i.Response { /* (1) Init redis connection */ - cli, err := redisConnect() - if err != nil { + cli := connect() + if cli == nil { r.Err = e.Failure return *r } @@ -70,15 +119,82 @@ func Post(d i.Arguments, r *i.Response) i.Response { } /* (3) Check if key already used */ - _, err = cli.Get(url).Result() - if err == nil { + if cli.get(url) != nil { r.Err = e.AlreadyExists return *r } /* (4) Store */ - err = cli.Set(url, target, 0).Err() - if err != nil { + 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) { r.Err = e.Failure return *r }