You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
3.7 KiB
Go

package shrt
import (
"bytes"
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"time"
)
type Storage struct {
Token map[string]*Shrt `json:"token"`
Url map[string]string `json:"url"`
}
type Shrt struct {
URL string `json:"url"`
Date string `json:"datum"`
Clicks int64 `json:"clicks"`
}
var (
ErrNotFound = errors.New("Url not Found")
ErrCreateToken = errors.New("There are some problems while creating Token")
ErrNoUrl = errors.New("String is no Url!")
)
// Open up
func Open(path string) (*Storage, error) {
s := Storage{Token: make(map[string]*Shrt), 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)
db.Close()
return &s, nil
} else {
return &s, err
}
}
func (s *Storage) Short(URL string, value *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 {
*value = val
return 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 nil
}
}
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
}
// Get returns the URL for the given token
func (s *Storage) Get(token string) (string, bool) {
if shrt, ok := s.Token[token]; ok {
fmt.Printf("Url mit dem Token %s gefunden: %s \n", token, shrt.URL)
s.Token[token].Clicks += 1
s.Save()
return shrt.URL, true
}
return "", false
}
// Get returns the URL for the given token
func (s *Storage) GetAPI(token string, value *Shrt) bool {
if shrt, ok := s.Token[token]; ok {
*value = *shrt
return true
}
return false
}
// Get all entries
func (s *Storage) All() string {
b, err := json.Marshal(&s)
if err != nil {
return ""
}
return string(b)
}
func (s *Storage) Save() error {
if db, err := os.OpenFile("./test.db", os.O_RDWR|os.O_CREATE, 0644); err == nil {
b, err := json.Marshal(&s)
db.Write(b)
db.Close()
return err
} else {
return err
}
}
func StreamToByte(stream io.Reader) []byte {
buf := new(bytes.Buffer)
buf.ReadFrom(stream)
return buf.Bytes()
}