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.

165 lines
2.8 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. package bolt
  2. import (
  3. "encoding/binary"
  4. "qurl/qurl"
  5. )
  6. var (
  7. QURLBucket = []byte{0x00}
  8. ReverseBucket = []byte{0x01}
  9. URLField = []byte{0x00}
  10. CreatedField = []byte{0x01}
  11. IPField = []byte{0x02}
  12. BrowserField = []byte{0x03}
  13. )
  14. func (stor *BoltStorage) AddQURL(q *qurl.QURL) error {
  15. err := q.CheckValid()
  16. if err != nil {
  17. return err
  18. }
  19. tx, err := stor.DB.Begin(true)
  20. if err != nil {
  21. return err
  22. }
  23. defer tx.Rollback()
  24. rb, err := tx.CreateBucketIfNotExists(QURLBucket)
  25. if err != nil {
  26. return err
  27. }
  28. // Populate the ID from the sequence if we don't have one
  29. if q.ID == 0 {
  30. s, err := rb.NextSequence()
  31. if err != nil {
  32. return err
  33. }
  34. // Bolt's sequence starts at 1, so for
  35. // backwards compatibility we have subtract
  36. // one so we're zero-based
  37. q.ID = (s - 1)
  38. }
  39. // Create a byte array from the ID
  40. bid := make([]byte, 8)
  41. binary.BigEndian.PutUint64(bid, q.ID)
  42. // Add an entry into the reverse indexed bucket for quickly
  43. // determining if a URL is already in the database
  44. ab, err := tx.CreateBucketIfNotExists(ReverseBucket)
  45. if err != nil {
  46. return err
  47. }
  48. err = ab.Put([]byte(q.URL), bid)
  49. qb, err := rb.CreateBucketIfNotExists(bid)
  50. if err != nil {
  51. return err
  52. }
  53. // Write the ID to URL
  54. err = qb.Put(URLField, []byte(q.URL))
  55. if err != nil {
  56. return err
  57. }
  58. if !q.Created.IsZero() {
  59. // Create byte array from the Created date
  60. bdt, err := q.Created.MarshalBinary()
  61. if err != nil {
  62. return err
  63. }
  64. // Write the Created date
  65. err = qb.Put(CreatedField, bdt)
  66. if err != nil {
  67. return err
  68. }
  69. }
  70. if q.IP != nil {
  71. err = qb.Put(IPField, q.IP)
  72. if err != nil {
  73. return err
  74. }
  75. }
  76. if len(q.Browser) > 0 {
  77. err = qb.Put(BrowserField, []byte(q.Browser))
  78. if err != nil {
  79. return err
  80. }
  81. }
  82. if err := tx.Commit(); err != nil {
  83. return err
  84. }
  85. return nil
  86. }
  87. func (stor *BoltStorage) SetQURLSequence(seq uint64) error {
  88. tx, err := stor.DB.Begin(true)
  89. if err != nil {
  90. return err
  91. }
  92. defer tx.Rollback()
  93. qb, err := tx.CreateBucketIfNotExists(QURLBucket)
  94. if err != nil {
  95. return err
  96. }
  97. // Since the sequence number is decremented by one
  98. // for backwards compatibility (see above)
  99. // we increment it by one when setting the sequence
  100. qb.SetSequence(seq + 1)
  101. if err := tx.Commit(); err != nil {
  102. return err
  103. }
  104. return nil
  105. }
  106. func (stor *BoltStorage) GetQURLByURL(u string) (*qurl.QURL, error) {
  107. tx, err := stor.DB.Begin(false)
  108. if err != nil {
  109. return nil, err
  110. }
  111. defer tx.Rollback()
  112. ab := tx.Bucket(ReverseBucket)
  113. if ab == nil {
  114. return nil, nil
  115. }
  116. bid := ab.Get([]byte(u))
  117. if bid == nil {
  118. return nil, nil
  119. }
  120. rb := tx.Bucket(QURLBucket)
  121. if rb == nil {
  122. return nil, nil
  123. }
  124. qb := rb.Bucket(bid)
  125. if qb == nil {
  126. return nil, nil
  127. }
  128. q := &qurl.QURL{ID: binary.BigEndian.Uint64(bid)}
  129. qu := qb.Get(URLField)
  130. if qu != nil {
  131. q.URL = string(qu)
  132. }
  133. return q, nil
  134. }