This commit is contained in:
Adrien Marquès 2018-07-07 23:41:25 +02:00
commit 81dcfe03af
7 changed files with 283 additions and 109 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
*.so
*.so
.build

View File

@ -7,13 +7,14 @@ import (
func main() {
srv, err := gfw.Init("manifest.json", nil)
server, err := aicra.New("manifest.json")
if err != nil {
log.Fatal(err)
log.Fatal("cannot load config", err)
}
log.Printf("Server up and running\n")
err = srv.Launch(4444)
log.Printf("[Server up] 0.0.0.0:4242\n")
err = server.Listen(4242)
if err != nil {
log.Fatalf("*** server failed (%s)\n", err)
}

View File

@ -1,115 +1,56 @@
{
"GET": {
"info": "returns api information",
"info": "redirects to given tiny url",
"scope": [[]],
"in": {},
"out": {
"version": { "info": "current api version", "type": "varchar(1,8)" },
"info": { "info": "api information details", "type": "<any>" }
}
"in": {
"URL#0": { "info": "tiny url to redirect to", "name": "url", "type": "varchar(1,30)" }
},
"out": {}
},
"POST": {
"info": "creates a new tiny url",
"scope": [["admin"]],
"in": {
"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": [["admin"]],
"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": [["admin"]],
"in": {
"URL#0": { "info": "preferred tiny url", "type": "varchar(1,30)", "name": "url" }
},
"out": {}
},
"/": {
"user": {
"GET": {
"info": "gets all | a specific user by id",
"auth": {
"POST": {
"info": "returns a 1-minute access token",
"scope": [[]],
"in": {
"URL#0": { "info": "optional user id | all users are returned if missing", "name": "uid", "type": "?int", "default": null }
"username": { "info": "user name", "type": "varchar(3,20)" },
"password": { "info": "password", "type": "varchar(5,150)" }
},
"out": {
"users": { "info": "matching user(s) data", "type": "<any>" }
}
},
"POST": {
"info": "creates a new user",
"scope": [["admin"]],
"in": {
"firstname": { "info": "new first name", "type": "varchar(3,20)" },
"lastname": { "info": "new last name", "type": "varchar(3,20)" },
"mail": { "info": "new mail", "type": "string" }
},
"out": {
"user": { "info": "user data to acknowledge creation", "type": "<any>" }
}
},
"PUT": {
"info": "updates data of an existing user; only the data given will be updated, all fields are optional",
"scope": [["admin"], ["user"]],
"in": {
"URL#0": { "info": "id of the user to update", "type": "int", "name": "user_id" },
"firstname": { "info": "new first name", "type": "?varchar(3,20)", "default": null },
"lastname": { "info": "new last name", "type": "?varchar(3,20)", "default": null },
"mail": { "info": "new mail", "type": "?string", "default": null }
},
"out": {
"user": { "info": "new updated data to acknowledge updates", "type": "<any>" }
}
},
"DELETE": {
"info": "deletes an existing user",
"scope": [["admin"], ["user"]],
"in": {
"URL#0": { "info": "id of the user to delete", "type": "int" }
},
"out": {}
},
"/": {
"post": {
"GET": {
"info": "gets all | a specific post for an existing user",
"scope": [["user"], []],
"in": {
"URL#0": { "info": "optional post id", "type": "int", "name": "?post_id", "default": null },
"URL#1": { "info": "user id (if missing, current connected user)", "type": "int", "name": "?user_id", "default": null }
},
"out": {
"posts": { "info": "matching post(s) data", "type": "<any>" }
}
},
"POST": {
"info": "creates a new post for the current connected user",
"scope": [["user"]],
"in": {
"title": { "info": "new post title", "type": "varchar(3,20)" },
"content": { "info": "new post content", "type": "string" }
},
"out": {
"post": { "info": "post data to acknowledge creation", "type": "<any>" }
}
},
"PUT": {
"info": "updates data of an existing post of the current connected user; only the data given will be updated, all fields are optional",
"scope": [["user"]],
"in": {
"title": { "info": "new post title", "type": "?varchar(3,20)", "default": null },
"content": { "info": "new post content", "type": "?string", "default": null }
},
"out": {
"post": { "info": "new updated data to acknowledge updates", "type": "<any>" }
}
},
"DELETE": {
"info": "deletes an existing post of the current connected user",
"scope": [["user"]],
"in": {
"URL#0": { "info": "id of the post to delete", "type": "int", "name": "post_id" }
},
"out": {}
}
"token": { "info": "access token", "type": "varchar(256,256)" }
}
}
}
}
}

11
middleware/1-auth/main.go Normal file
View File

@ -0,0 +1,11 @@
package main
import (
"git.xdrm.io/go/aicra/middleware"
"net/http"
)
// Authentication middleware
func Inspect(req http.Request, scope *middleware.Scope) {
*scope = append(*scope, "admin")
}

18
root/authi.go Normal file
View File

@ -0,0 +1,18 @@
package main
import (
"fmt"
e "git.xdrm.io/go/aicra/err"
i "git.xdrm.io/go/aicra/implement"
)
// Builds an access token from credentials
func Post(d i.Arguments, r *i.Response) i.Response {
if d.Has("_AUTHORIZATION_") {
fmt.Printf("authorization: '%s'\n", d["_AUTHORIZATION_"].(string))
}
r.Err = e.Success
return *r
}

75
root/db/db.go Normal file
View File

@ -0,0 +1,75 @@
package db
import (
"fmt"
"github.com/go-redis/redis"
)
const NONCE = "go-tiny-url"
var domain = "data"
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,
})
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 := (*redis.Client)(c).Get(fmt.Sprintf("%s:%s:%s", NONCE, domain, 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 (*redis.Client)(c).Set(fmt.Sprintf("%s:%s:%s", NONCE, domain, 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 (*redis.Client)(c).Del(fmt.Sprintf("%s:%s:%s", NONCE, domain, key)).Err() != nil {
// 2. failure
return false
}
// 3. success
return true
}
// Switch following operations to DATA dataset
func (c *db) SwitchData() { domain = "data" }
// Switch following operations to AUTH dataset
func (c *db) SwitchAuth() { domain = "auth" }

135
root/i.go
View File

@ -1,15 +1,142 @@
package main
import (
"fmt"
"git.xdrm.io/example/aicra/root/db"
e "git.xdrm.io/go/aicra/err"
i "git.xdrm.io/go/aicra/implement"
)
// Redirects to an url from a key
func Get(d i.Arguments, r *i.Response) i.Response {
fmt.Printf("GET /\n")
r.Set("api_version", 1.2)
r.Set("received_data", d)
/* (1) Init redis connection */
cli := db.Connect()
if cli == nil {
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 */
val := cli.Get(key)
if val == nil {
r.Err = e.NoMatchFound
return *r
}
/* (4) Redirect to value */
r.Set("_REDIRECT_", string(val))
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 */
cli := db.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.AlreadyExists
return *r
}
/* (4) Store */
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 := db.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 := db.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
}
r.Err = e.Success
return *r
}