Global Config Close #3

master
kreativmonkey 7 years ago
parent 9c36dd2732
commit b981f8b71c

@ -0,0 +1,18 @@
package main
import (
"net/http"
)
type response struct {
Action string `json:"action"`
Status string `json:"status_code"`
Result interface{} `json:"result"`
}
// GET: http://example.com/api/action/shorten?key=API_KEY_HERE&url=https://google.com&custom_ending=CUSTOM_ENDING
// Response: {"action": "shorten","result": "https://example.com/5kq"}
func APIRequest(w http.ResponseWriter, r *http.Request) {
}

@ -0,0 +1,64 @@
package main
import (
"flag"
"github.com/caarlos0/env"
"os"
)
func DefaultConfig() Config {
return Config{
DB: "./test.db",
APIkey: "thisIsNotASecretTokenNow",
Host: "localhost",
Port: "6889",
Title: "Sgot",
}
}
type Config struct {
DB string `env:"SHRT_DB_FILE"`
APIkey string `env:"SHRT_API_KEY"`
Host string `env:"SHRT_HOST"`
Port string `env:"SHRT_PORT"`
Domain string `env:"SHRT_DOMAIN"`
Title string `env:"SHRT_TITLE"`
}
func (c Config) HostPort() string {
return c.Host + ":" + c.Port
}
func ReadConfig() *Config {
c, err := readConfig(flag.NewFlagSet(os.Args[0], flag.ExitOnError), os.Args[1:])
if err != nil {
// sould never happen, because of flag default policy ExitOnError
panic(err)
}
return c
}
func readConfig(f *flag.FlagSet, args []string) (*Config, error){
config := DefaultConfig()
// Environment variables
err := env.Parse(&config)
if err != nil {
return nil, err
}
f.StringVar(&config.Host, "host", config.Host, "The host to listen on")
f.StringVar(&config.Port, "port", config.Port, "The port to listen on")
f.StringVar(&config.APIkey, "apikey", config.APIkey, "The Key to connect to the API")
f.StringVar(&config.DB, "db-file", config.DB, "The db file to use")
f.StringVar(&config.Domain, "domain", config.Domain, "The domain for redirect links")
f.StringVar(&config.Title, "title", config.Title, "The title on the Front")
// Arguments variables
err = f.Parse(args)
if err != nil {
return nil, err
}
return &config, err
}

@ -0,0 +1,69 @@
package main
import (
"testing"
"os"
"github.com/stretchr/testify/assert"
"flag"
)
func TestConfig_ReadConfigDefaults(t *testing.T){
originalArgs := os.Args
os.Args = []string{"shrt"}
defer func(){ os.Args = originalArgs }()
d := DefaultConfig()
assert.Equal(t, &d, ReadConfig())
}
func TestConfig_ReadConfig(t *testing.T){
input := []string{
"--host=host",
"--port=port",
"--db-file=db",
"--title=title",
"--apikey=apikey",
"--domain=domain",
}
expected := &Config{
Host: "host",
Port: "port",
DB: "db",
Title: "title",
APIkey: "apikey",
Domain: "domain",
}
cfg, err := readConfig(flag.NewFlagSet("", flag.ContinueOnError), input)
assert.NoError(t, err)
assert.Equal(t, expected, cfg)
}
func TestConfig_ReadConfigFromEnv(t *testing.T) {
assert.NoError(t, os.Setenv("SHRT_DB_FILE", "db"))
defer os.Unsetenv("SHRT_DB_FILE")
assert.NoError(t, os.Setenv("SHRT_API_KEY", "apikey"))
defer os.Unsetenv("SHRT_API_KEY")
assert.NoError(t, os.Setenv("SHRT_HOST", "host"))
defer os.Unsetenv("SHRT_HOST")
assert.NoError(t, os.Setenv("SHRT_PORT", "port"))
defer os.Unsetenv("SHRT_PORT")
assert.NoError(t, os.Setenv("SHRT_DOMAIN", "domain"))
defer os.Unsetenv("SHRT_DOMAIN")
assert.NoError(t, os.Setenv("SHRT_TITLE", "title"))
defer os.Unsetenv("SHRT_TITLE")
expected := &Config{
Host: "host",
Port: "port",
DB: "db",
Title: "title",
APIkey: "apikey",
Domain: "domain",
}
cfg, err := readConfig(flag.NewFlagSet("", flag.ContinueOnError), []string{})
assert.NoError(t, err)
assert.Equal(t, expected, cfg)
}

@ -6,7 +6,7 @@ import (
"fmt"
"text/template"
"net/url"
shorty "github.com/kreativmonkey/shrt/short"
"github.com/kreativmonkey/shrt/shrty"
)
type Page struct {
@ -15,15 +15,13 @@ type Page struct {
Body string
}
type response struct {
Action string `json:"action"`
Result interface{} `json:"result"`
}
// Load the main Page with an Imput field for the URL to short.
func index(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("template/index.gohtml")
t.Execute(w, Page{Title: "Shrt"})
t.Execute(w, Page{
Host: config.Host,
Title: config.Title,
})
}
// Redirect to the URL behind the requested token.
@ -38,8 +36,8 @@ func redirect(w http.ResponseWriter, r *http.Request){
//
func shorten(w http.ResponseWriter, r *http.Request){
var test string
token, err := short.Add(r.FormValue("url"), &test)
var token string
err := short.Short(r.FormValue("url"), &token)
if err != nil {
panic(err)
}
@ -55,13 +53,13 @@ func shortenJSON(w http.ResponseWriter, r *http.Request){
queryu, err := url.QueryUnescape(query.Get("url"))
check(err)
var test string
err = short.Short(queryu, &test)
var token string
err = short.Short(queryu, &token)
check(err)
respond := response{
respond := response{3
Action: "shorten",
Result: r.Host + "/" + test,
Result: r.Host + "/" + token,
}
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
@ -79,7 +77,7 @@ func lookupJSON(w http.ResponseWriter, r *http.Request){
queryu, err := url.QueryUnescape(query.Get("url_ending"))
check(err)
var result shorty.Shrt
var result shrty.Data
var respond response
if ok := short.GetAPI(queryu, &result); ok {
respond := response{

@ -3,23 +3,23 @@ package main
import (
"net/http"
//"github.com/spf13/viper"
shorty "github.com/kreativmonkey/shrt/short"
shrty "github.com/kreativmonkey/shrt/shrty"
"log"
"fmt"
)
const version = "0.02"
const port = "9090"
const db = "./test.db"
var (
short *shorty.Storage
short *shrty.Storage
// Global configuration Variable
config = ReadConfig()
)
func init() {
var err error
short, err = shorty.Open(db)
short, err = shrty.Open(config.DB)
if err != nil {
panic(err)
}
@ -56,10 +56,9 @@ func main() {
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("template/css"))))
http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("template/img"))))
*/
fmt.Printf("Shrt %s started on Port: %s \n", version, port)
fmt.Printf("Shrty %s is listen on Port: %s \n", version, config.Port)
fmt.Printf("For the API use following key: %s \n", version, config.APIkey)
http.Handle("/", router)
log.Fatal(http.ListenAndServe(":"+port, router))
log.Fatal(http.ListenAndServe(":"+ config.Port, router))
}

@ -1,4 +1,4 @@
package shrt
package shrty
import (
"bytes"
@ -13,13 +13,20 @@ import (
)
type Storage struct {
Token map[string]*Shrt `json:"token"`
Token map[string]*Data `json:"token"`
Url map[string]string `json:"url"`
}
type Shrt struct {
type Data struct {
URL string `json:"url"`
Date string `json:"datum"`
URLFetched string `json:"url_fetched"`
CanonicalURL string `json:"canonical_url"`
OriginalURL string `json:"original_url"`
Domain string `json:"domain"`
FavIconLink string `json:"favicon_url"`
HTTPStatusCode string `json:"http_code"`
Category string `json:"category"`
Created string `json:"created_at"`
Clicks int64 `json:"clicks"`
}
@ -31,7 +38,7 @@ var (
// Open up
func Open(path string) (*Storage, error) {
s := Storage{Token: make(map[string]*Shrt), Url: make(map[string]string)}
s := Storage{Token: make(map[string]*Data), Url: make(map[string]string)}
// Open db ore create if not exist!
if db, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644); err == nil {
json.Unmarshal(StreamToByte(db), &s)
@ -64,9 +71,9 @@ func (s *Storage) Short(URL string, value *string) error {
if _, ok := s.Token[hash[:hashShortestLen]]; !ok {
token := hash[:hashShortestLen]
t := time.Now()
s.Token[token] = &Shrt{
s.Token[token] = &Data{
URL: URL,
Date: t.String(),
Created: t.String(),
}
s.Url[hash] = token
*value = s.Url[hash]
@ -78,41 +85,6 @@ func (s *Storage) Short(URL string, value *string) error {
return ErrCreateToken
}
func (s *Storage) Add(URL string, value *string) (string, error) {
// Check if it is a valide Url found on:
// http://stackoverflow.com/questions/31480710/validate-url-with-standard-package-in-go
_, err := url.ParseRequestURI(URL)
if err != nil {
return "", ErrNoUrl
}
// Create a sha256 Hash from the URL
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(URL)))
// Test if the URL alraedy exist and return the key
if val, ok := s.Url[hash]; ok {
return val, nil
}
// Iterate to the length of hash to get the shortest output
for hashShortestLen := 1; hashShortestLen <= 32; hashShortestLen++ {
// Test if the Token not exist and return the new generated token
if _, ok := s.Token[hash[:hashShortestLen]]; !ok {
token := hash[:hashShortestLen]
t := time.Now()
s.Token[token] = &Shrt{
URL: URL,
Date: t.String(),
}
s.Url[hash] = token
*value = s.Url[hash]
s.Save()
return token, nil
}
}
return "", ErrCreateToken
}
func (s *Storage) Remove(URL string) error {
return nil
}
@ -129,7 +101,7 @@ func (s *Storage) Get(token string) (string, bool) {
}
// Get returns the URL for the given token
func (s *Storage) GetAPI(token string, value *Shrt) bool {
func (s *Storage) GetAPI(token string, value *Data) bool {
if shrt, ok := s.Token[token]; ok {
*value = *shrt
return true
Loading…
Cancel
Save