package shrty import ( "bytes" "crypto/sha256" "encoding/json" "errors" "fmt" "io" "net/url" "os" "time" ) type Storage struct { Token map[string]*Data `json:"token"` Url map[string]string `json:"url"` } type Data struct { URL string `json:"url"` 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"` } 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]*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) 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] = &Data{ URL: URL, Created: t.String(), } s.Url[hash] = token *value = s.Url[hash] s.Save() return 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 *Data) 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() }