2018-11-11 16:56:30 -09:00
|
|
|
package bolt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"qurl/qurl"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-11-17 07:47:39 -09:00
|
|
|
QURLBucket = []byte{0x00}
|
2018-11-11 16:56:30 -09:00
|
|
|
ReverseBucket = []byte{0x01}
|
|
|
|
|
|
|
|
URLField = []byte{0x00}
|
|
|
|
CreatedField = []byte{0x01}
|
|
|
|
IPField = []byte{0x02}
|
|
|
|
BrowserField = []byte{0x03}
|
|
|
|
)
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
func (stor *BoltStorage) AddQURL(q *qurl.QURL) error {
|
2018-11-11 16:56:30 -09:00
|
|
|
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
|
2018-11-17 07:47:39 -09:00
|
|
|
if q.ID == 0 {
|
|
|
|
s, err := rb.NextSequence()
|
2018-11-11 16:56:30 -09:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-11-17 07:47:39 -09:00
|
|
|
|
|
|
|
// Bolt's sequence starts at 1, so for
|
|
|
|
// backwards compatibility we have subtract
|
|
|
|
// one so we're zero-based
|
|
|
|
q.ID = (s - 1)
|
2018-11-11 16:56:30 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a byte array from the ID
|
|
|
|
bid := make([]byte, 8)
|
2018-11-17 07:47:39 -09:00
|
|
|
binary.BigEndian.PutUint64(bid, q.ID)
|
2018-11-11 16:56:30 -09:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2018-11-17 07:47:39 -09:00
|
|
|
err = ab.Put([]byte(q.URL), bid)
|
2018-11-11 16:56:30 -09:00
|
|
|
|
|
|
|
qb, err := rb.CreateBucketIfNotExists(bid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the ID to URL
|
2018-11-17 07:47:39 -09:00
|
|
|
err = qb.Put(URLField, []byte(q.URL))
|
2018-11-11 16:56:30 -09:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
if !q.Created.IsZero() {
|
2018-11-11 16:56:30 -09:00
|
|
|
// Create byte array from the Created date
|
2018-11-17 07:47:39 -09:00
|
|
|
bdt, err := q.Created.MarshalBinary()
|
2018-11-11 16:56:30 -09:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the Created date
|
|
|
|
err = qb.Put(CreatedField, bdt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
if q.IP != nil {
|
|
|
|
err = qb.Put(IPField, q.IP)
|
2018-11-11 16:56:30 -09:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
if len(q.Browser) > 0 {
|
|
|
|
err = qb.Put(BrowserField, []byte(q.Browser))
|
2018-11-11 16:56:30 -09:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
// 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)
|
2018-11-11 16:56:30 -09:00
|
|
|
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (stor *BoltStorage) GetQURLByURL(u string) (*qurl.QURL, error) {
|
|
|
|
tx, err := stor.DB.Begin(false)
|
2018-11-17 07:47:39 -09:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
2018-11-11 16:56:30 -09:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
q := &qurl.QURL{ID: binary.BigEndian.Uint64(bid)}
|
2018-11-11 16:56:30 -09:00
|
|
|
|
|
|
|
qu := qb.Get(URLField)
|
|
|
|
if qu != nil {
|
2018-11-17 07:47:39 -09:00
|
|
|
q.URL = string(qu)
|
2018-11-11 16:56:30 -09:00
|
|
|
}
|
|
|
|
|
2018-11-17 07:47:39 -09:00
|
|
|
return q, nil
|
2018-11-11 16:56:30 -09:00
|
|
|
}
|
2018-11-23 19:07:39 -09:00
|
|
|
|
|
|
|
func (stor *BoltStorage) GetQURLByID(id uint64) (*qurl.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 := &qurl.QURL{ID: id}
|
|
|
|
|
|
|
|
qu := qb.Get(URLField)
|
|
|
|
if qu != nil {
|
|
|
|
q.URL = string(qu)
|
|
|
|
}
|
|
|
|
|
|
|
|
return q, nil
|
|
|
|
}
|