a simple url shortener in Go (check it out at qurl.org)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

191 lines
3.3 KiB

package bolt
import (
"encoding/binary"
"git.binarythought.com/cdramey/qurl/obj"
)
var (
QURLBucket = []byte{0x00}
ReverseBucket = []byte{0x01}
URLField = []byte{0x00}
CreatedField = []byte{0x01}
IPField = []byte{0x02}
BrowserField = []byte{0x03}
)
func (stor *BoltStorage) AddQURL(q *obj.QURL) error {
tx, err := stor.DB.Begin(true)
if err != nil {
return err
}
defer tx.Rollback()
rb, err := tx.CreateBucketIfNotExists(QURLBucket)
if err != nil {
return err
}
// Populate the ID from the sequence if we don't have one
if q.ID == 0 {
s, err := rb.NextSequence()
if err != nil {
return err
}
// Bolt's sequence starts at 1, so for
// backwards compatibility we have subtract
// one so we're zero-based
q.ID = (s - 1)
}
// Create a byte array from the ID
bid := make([]byte, 8)
binary.BigEndian.PutUint64(bid, q.ID)
// Add an entry into the reverse indexed bucket for quickly
// determining if a URL is already in the database
ab, err := tx.CreateBucketIfNotExists(ReverseBucket)
if err != nil {
return err
}
err = ab.Put([]byte(q.URL), bid)
qb, err := rb.CreateBucketIfNotExists(bid)
if err != nil {
return err
}
// Write the ID to URL
err = qb.Put(URLField, []byte(q.URL))
if err != nil {
return err
}
if !q.Created.IsZero() {
// Create byte array from the Created date
bdt, err := q.Created.MarshalBinary()
if err != nil {
return err
}
// Write the Created date
err = qb.Put(CreatedField, bdt)
if err != nil {
return err
}
}
if q.IP != nil {
err = qb.Put(IPField, q.IP)
if err != nil {
return err
}
}
if len(q.Browser) > 0 {
err = qb.Put(BrowserField, []byte(q.Browser))
if err != nil {
return err
}
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}
func (stor *BoltStorage) SetQURLSequence(seq uint64) error {
tx, err := stor.DB.Begin(true)
if err != nil {
return err
}
defer tx.Rollback()
qb, err := tx.CreateBucketIfNotExists(QURLBucket)
if err != nil {
return err
}
// Since the sequence number is decremented by one
// for backwards compatibility (see above)
// we increment it by one when setting the sequence
qb.SetSequence(seq + 1)
if err := tx.Commit(); err != nil {
return err
}
return nil
}
func (stor *BoltStorage) GetQURLByURL(u string) (*obj.QURL, error) {
tx, err := stor.DB.Begin(false)
if err != nil {
return nil, err
}
defer tx.Rollback()
ab := tx.Bucket(ReverseBucket)
if ab == nil {
return nil, nil
}
bid := ab.Get([]byte(u))
if bid == nil {
return nil, nil
}
rb := tx.Bucket(QURLBucket)
if rb == nil {
return nil, nil
}
qb := rb.Bucket(bid)
if qb == nil {
return nil, nil
}
q := &obj.QURL{ID: binary.BigEndian.Uint64(bid)}
qu := qb.Get(URLField)
if qu != nil {
q.URL = string(qu)
}
return q, nil
}
func (stor *BoltStorage) GetQURLByID(id uint64) (*obj.QURL, error) {
tx, err := stor.DB.Begin(false)
if err != nil {
return nil, err
}
defer tx.Rollback()
// Create a byte array from the ID
bid := make([]byte, 8)
binary.BigEndian.PutUint64(bid, id)
rb := tx.Bucket(QURLBucket)
if rb == nil {
return nil, nil
}
qb := rb.Bucket(bid)
if qb == nil {
return nil, nil
}
q := &obj.QURL{ID: id}
qu := qb.Get(URLField)
if qu != nil {
q.URL = string(qu)
}
return q, nil
}