mirror of
https://github.com/jimeh/ozu.io.git
synced 2026-02-19 08:06:39 +00:00
Turn shortener.Shortener into an interface
And have the default shortener be Base58Shortener.
This commit is contained in:
87
shortener/base58_shortener.go
Normal file
87
shortener/base58_shortener.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package shortener
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
|
||||
"github.com/jimeh/go-base58"
|
||||
"github.com/jimeh/ozu.io/storage"
|
||||
)
|
||||
|
||||
var urlKeyPrefix = []byte("url:")
|
||||
var uidKeyPrefix = []byte("uid:")
|
||||
|
||||
// NewBase58 returns a new *Base58Shortner that uses the given storage.Store.
|
||||
func NewBase58(store storage.Store) *Base58Shortener {
|
||||
return &Base58Shortener{Store: store}
|
||||
}
|
||||
|
||||
// Base58Shortener shortens URLs via base 58 encoding.
|
||||
type Base58Shortener struct {
|
||||
Store storage.Store
|
||||
}
|
||||
|
||||
// Shorten a given URL.
|
||||
func (s *Base58Shortener) Shorten(rawURL []byte) (uid []byte, url []byte, err error) {
|
||||
url, err = NormalizeURL(rawURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
urlKey := s.makeURLKey(url)
|
||||
uid, err = s.Store.Get(urlKey)
|
||||
|
||||
if uid != nil && err == nil {
|
||||
return uid, url, nil
|
||||
} else if err != nil && err.Error() != "not found" {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uid, err = s.newUID()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = s.Store.Set(urlKey, uid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uidKey := s.makeUIDKey(uid)
|
||||
err = s.Store.Set(uidKey, url)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return uid, url, nil
|
||||
}
|
||||
|
||||
// Lookup the URL of a given UID.
|
||||
func (s *Base58Shortener) Lookup(uid []byte) ([]byte, error) {
|
||||
uidKey := s.makeUIDKey(uid)
|
||||
|
||||
url, err := s.Store.Get(uidKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
func (s *Base58Shortener) newUID() ([]byte, error) {
|
||||
index, err := s.Store.NextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return base58.Encode(index), nil
|
||||
}
|
||||
|
||||
func (s *Base58Shortener) makeUIDKey(uid []byte) []byte {
|
||||
return append(uidKeyPrefix, uid...)
|
||||
}
|
||||
|
||||
func (s *Base58Shortener) makeURLKey(rawURL []byte) []byte {
|
||||
urlSHA := fmt.Sprintf("%x", sha1.Sum(rawURL))
|
||||
return append(urlKeyPrefix, urlSHA...)
|
||||
}
|
||||
@@ -17,22 +17,22 @@ import (
|
||||
|
||||
// Suite Setup
|
||||
|
||||
type ShortenerSuite struct {
|
||||
type Base58ShortenerSuite struct {
|
||||
suite.Suite
|
||||
store *mocks.Store
|
||||
shortener *Shortener
|
||||
shortener *Base58Shortener
|
||||
errNotFound error
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) SetupTest() {
|
||||
func (s *Base58ShortenerSuite) SetupTest() {
|
||||
s.store = new(mocks.Store)
|
||||
s.shortener = New(s.store)
|
||||
s.shortener = NewBase58(s.store)
|
||||
s.errNotFound = errors.New("not found")
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
func (s *ShortenerSuite) TestShortenExisting() {
|
||||
func (s *Base58ShortenerSuite) TestShortenExisting() {
|
||||
rawURL := []byte("http://google.com/")
|
||||
uid := []byte("ig")
|
||||
urlSHA := fmt.Sprintf("%x", sha1.Sum(rawURL))
|
||||
@@ -46,7 +46,7 @@ func (s *ShortenerSuite) TestShortenExisting() {
|
||||
s.store.AssertExpectations(s.T())
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) TestShortenNew() {
|
||||
func (s *Base58ShortenerSuite) TestShortenNew() {
|
||||
rawURL := []byte("https://google.com")
|
||||
url := []byte("https://google.com/")
|
||||
uid := []byte("ig")
|
||||
@@ -65,7 +65,7 @@ func (s *ShortenerSuite) TestShortenNew() {
|
||||
s.store.AssertExpectations(s.T())
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) TestShortenInvalidURL() {
|
||||
func (s *Base58ShortenerSuite) TestShortenInvalidURL() {
|
||||
examples := []struct {
|
||||
url string
|
||||
error string
|
||||
@@ -100,7 +100,7 @@ func (s *ShortenerSuite) TestShortenInvalidURL() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) TestShortenStoreError() {
|
||||
func (s *Base58ShortenerSuite) TestShortenStoreError() {
|
||||
url := []byte("https://google.com/")
|
||||
storeErr := errors.New("leveldb: something wrong")
|
||||
urlKey := append([]byte("url:"), fmt.Sprintf("%x", sha1.Sum(url))...)
|
||||
@@ -113,7 +113,7 @@ func (s *ShortenerSuite) TestShortenStoreError() {
|
||||
s.EqualError(err, storeErr.Error())
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) TestLookupExisting() {
|
||||
func (s *Base58ShortenerSuite) TestLookupExisting() {
|
||||
url := []byte("https://google.com/")
|
||||
uid := []byte("ig")
|
||||
|
||||
@@ -126,7 +126,7 @@ func (s *ShortenerSuite) TestLookupExisting() {
|
||||
s.store.AssertExpectations(s.T())
|
||||
}
|
||||
|
||||
func (s *ShortenerSuite) TestLookupNonExistant() {
|
||||
func (s *Base58ShortenerSuite) TestLookupNonExistant() {
|
||||
uid := []byte("ig")
|
||||
|
||||
s.store.On("Get", append([]byte("uid:"), uid...)).Return(nil, s.errNotFound)
|
||||
@@ -141,5 +141,5 @@ func (s *ShortenerSuite) TestLookupNonExistant() {
|
||||
// Run Suite
|
||||
|
||||
func TestShortenerSuite(t *testing.T) {
|
||||
suite.Run(t, new(ShortenerSuite))
|
||||
suite.Run(t, new(Base58ShortenerSuite))
|
||||
}
|
||||
8
shortener/new.go
Normal file
8
shortener/new.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package shortener
|
||||
|
||||
import "github.com/jimeh/ozu.io/storage"
|
||||
|
||||
// New returns a new *Base58Shortner that uses the given storage.Store.
|
||||
func New(store storage.Store) Shortener {
|
||||
return NewBase58(store)
|
||||
}
|
||||
@@ -1,87 +1,7 @@
|
||||
package shortener
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
|
||||
"github.com/jimeh/go-base58"
|
||||
"github.com/jimeh/ozu.io/storage"
|
||||
)
|
||||
|
||||
// New returns a new *Shortner that uses the given storage.Store.
|
||||
func New(store storage.Store) *Shortener {
|
||||
return &Shortener{Store: store}
|
||||
}
|
||||
|
||||
var urlKeyPrefix = []byte("url:")
|
||||
var uidKeyPrefix = []byte("uid:")
|
||||
|
||||
// Shortner interface
|
||||
type Shortener struct {
|
||||
Store storage.Store
|
||||
}
|
||||
|
||||
// Shorten a given URL.
|
||||
func (s *Shortener) Shorten(rawURL []byte) (uid []byte, url []byte, err error) {
|
||||
url, err = NormalizeURL(rawURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
urlKey := s.makeURLKey(url)
|
||||
uid, err = s.Store.Get(urlKey)
|
||||
|
||||
if uid != nil && err == nil {
|
||||
return uid, url, nil
|
||||
} else if err != nil && err.Error() != "not found" {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uid, err = s.newUID()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = s.Store.Set(urlKey, uid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uidKey := s.makeUIDKey(uid)
|
||||
err = s.Store.Set(uidKey, url)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return uid, url, nil
|
||||
}
|
||||
|
||||
// Lookup the URL of a given UID.
|
||||
func (s *Shortener) Lookup(uid []byte) ([]byte, error) {
|
||||
uidKey := s.makeUIDKey(uid)
|
||||
|
||||
url, err := s.Store.Get(uidKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
func (s *Shortener) newUID() ([]byte, error) {
|
||||
index, err := s.Store.NextSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return base58.Encode(index), nil
|
||||
}
|
||||
|
||||
func (s *Shortener) makeUIDKey(uid []byte) []byte {
|
||||
return append(uidKeyPrefix, uid...)
|
||||
}
|
||||
|
||||
func (s *Shortener) makeURLKey(rawURL []byte) []byte {
|
||||
urlSHA := fmt.Sprintf("%x", sha1.Sum(rawURL))
|
||||
return append(urlKeyPrefix, urlSHA...)
|
||||
// Shortener defines a shortener interface for shortening URLs.
|
||||
type Shortener interface {
|
||||
Shorten([]byte) ([]byte, []byte, error)
|
||||
Lookup([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user