Plan stuff. Log stuff.
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.

197 lines
4.2 KiB

4 years ago
  1. package bolt
  2. import (
  3. "context"
  4. "github.com/gisle/stufflog/database/repositories"
  5. "github.com/gisle/stufflog/models"
  6. "github.com/gisle/stufflog/slerrors"
  7. "github.com/vmihailenco/msgpack/v4"
  8. "go.etcd.io/bbolt"
  9. )
  10. var bnUserSessions = []byte("UserSession")
  11. type userSessionRepository struct {
  12. userIdIdx *index
  13. db *bbolt.DB
  14. }
  15. func (r *userSessionRepository) FindID(ctx context.Context, id string) (*models.UserSession, error) {
  16. session := new(models.UserSession)
  17. err := r.db.View(func(tx *bbolt.Tx) error {
  18. value := tx.Bucket(bnUserSessions).Get(unsafeStringToBytes(id))
  19. if value == nil {
  20. return slerrors.NotFound("Session")
  21. }
  22. err := msgpack.Unmarshal(value, session)
  23. if err != nil {
  24. return err
  25. }
  26. return nil
  27. })
  28. if err != nil {
  29. return nil, err
  30. }
  31. return session, nil
  32. }
  33. func (r *userSessionRepository) List(ctx context.Context) ([]*models.UserSession, error) {
  34. sessions := make([]*models.UserSession, 0, 16)
  35. err := r.db.View(func(tx *bbolt.Tx) error {
  36. cursor := tx.Bucket(bnUserSessions).Cursor()
  37. for key, value := cursor.First(); key != nil; key, value = cursor.Next() {
  38. session := new(models.UserSession)
  39. err := msgpack.Unmarshal(value, session)
  40. if err != nil {
  41. return err
  42. }
  43. sessions = append(sessions, session)
  44. }
  45. return nil
  46. })
  47. if err != nil {
  48. return nil, err
  49. }
  50. return sessions, nil
  51. }
  52. func (r *userSessionRepository) ListUser(ctx context.Context, user models.User) ([]*models.UserSession, error) {
  53. var sessions []*models.UserSession
  54. err := r.db.View(func(tx *bbolt.Tx) error {
  55. bucket := tx.Bucket(bnUserSessions)
  56. ids, err := r.userIdIdx.WithTx(tx).Get(user.ID)
  57. if err != nil {
  58. return err
  59. }
  60. sessions = make([]*models.UserSession, len(ids))
  61. for i, id := range ids {
  62. value := bucket.Get(id)
  63. session := new(models.UserSession)
  64. err := msgpack.Unmarshal(value, session)
  65. if err != nil {
  66. return err
  67. }
  68. sessions[i] = session
  69. }
  70. return nil
  71. })
  72. if err != nil {
  73. return nil, err
  74. }
  75. return sessions, nil
  76. }
  77. func (r *userSessionRepository) Save(ctx context.Context, session models.UserSession) error {
  78. value, err := msgpack.Marshal(&session)
  79. if err != nil {
  80. return err
  81. }
  82. return r.db.Update(func(tx *bbolt.Tx) error {
  83. err := tx.Bucket(bnUserSessions).Put(unsafeStringToBytes(session.ID), value)
  84. if err != nil {
  85. return err
  86. }
  87. err = r.userIdIdx.WithTx(tx).Set(unsafeStringToBytes(session.ID), session.UserID)
  88. if err != nil {
  89. return err
  90. }
  91. return nil
  92. })
  93. }
  94. func (r *userSessionRepository) Remove(ctx context.Context, session models.UserSession) error {
  95. return r.db.Update(func(tx *bbolt.Tx) error {
  96. err := tx.Bucket(bnUserSessions).Delete(unsafeStringToBytes(session.ID))
  97. if err != nil {
  98. return err
  99. }
  100. err = r.userIdIdx.WithTx(tx).Set(unsafeStringToBytes(session.ID))
  101. if err != nil {
  102. return err
  103. }
  104. return nil
  105. })
  106. }
  107. func (r *userSessionRepository) RemoveUser(ctx context.Context, user models.User) error {
  108. return r.db.Update(func(tx *bbolt.Tx) error {
  109. bucket := tx.Bucket(bnUserSessions)
  110. ids, err := r.userIdIdx.WithTx(tx).Get(user.ID)
  111. if err != nil {
  112. return err
  113. }
  114. for _, id := range ids {
  115. err := bucket.Delete(id)
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. return nil
  121. })
  122. }
  123. func (r *userSessionRepository) reindex() error {
  124. return r.db.Update(func(tx *bbolt.Tx) error {
  125. cursor := tx.Bucket(bnUserSessions).Cursor()
  126. err := r.userIdIdx.Reset(tx)
  127. if err != nil {
  128. return err
  129. }
  130. userIdIdxTx := r.userIdIdx.WithTx(tx)
  131. for key, value := cursor.First(); key != nil; key, value = cursor.Next() {
  132. session := new(models.UserSession)
  133. err := msgpack.Unmarshal(value, session)
  134. if err != nil {
  135. return err
  136. }
  137. err = userIdIdxTx.Set(unsafeStringToBytes(session.ID), session.UserID)
  138. if err != nil {
  139. return err
  140. }
  141. }
  142. return nil
  143. })
  144. }
  145. func newUserSessionRepository(db *bbolt.DB) (repositories.UserSessionRepository, error) {
  146. err := db.Update(func(tx *bbolt.Tx) error {
  147. _, err := tx.CreateBucketIfNotExists(bnUserSessions)
  148. return err
  149. })
  150. if err != nil {
  151. return nil, err
  152. }
  153. idx, err := newModelIndex(db, "UserSession", "UserID")
  154. if err != nil {
  155. return nil, err
  156. }
  157. return &userSessionRepository{
  158. db: db,
  159. userIdIdx: idx,
  160. }, nil
  161. }