GraphQL API and utilities for the rpdata project
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.

201 lines
3.7 KiB

  1. package mongodb
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/globalsign/mgo/bson"
  6. "time"
  7. "git.aiterp.net/rpdata/api/internal/config"
  8. "git.aiterp.net/rpdata/api/repositories"
  9. "github.com/globalsign/mgo"
  10. )
  11. type MongoDB struct {
  12. session *mgo.Session
  13. changes repositories.ChangeRepository
  14. channels *channelRepository
  15. characters repositories.CharacterRepository
  16. tags repositories.TagRepository
  17. logs *logRepository
  18. posts *postRepository
  19. files *fileRepository
  20. story repositories.StoryRepository
  21. }
  22. func (m *MongoDB) Changes() repositories.ChangeRepository {
  23. return m.changes
  24. }
  25. func (m *MongoDB) Characters() repositories.CharacterRepository {
  26. return m.characters
  27. }
  28. func (m *MongoDB) Tags() repositories.TagRepository {
  29. return m.tags
  30. }
  31. func (m *MongoDB) Logs() repositories.LogRepository {
  32. return m.logs
  33. }
  34. func (m *MongoDB) Posts() repositories.PostRepository {
  35. return m.posts
  36. }
  37. func (m *MongoDB) Channels() repositories.ChannelRepository {
  38. return m.channels
  39. }
  40. func (m *MongoDB) Files() repositories.FileRepository {
  41. return m.files
  42. }
  43. func (m *MongoDB) Story() repositories.StoryRepository {
  44. return m.story
  45. }
  46. func (m *MongoDB) Close(ctx context.Context) error {
  47. m.session.Close()
  48. return nil
  49. }
  50. // Init initializes the mongodb database
  51. func Init(cfg config.Database) (*MongoDB, error) {
  52. port := cfg.Port
  53. if port <= 0 {
  54. port = 27017
  55. }
  56. session, err := mgo.DialWithInfo(&mgo.DialInfo{
  57. Addrs: []string{fmt.Sprintf("%s:%d", cfg.Host, port)},
  58. Timeout: 30 * time.Second,
  59. Database: cfg.Db,
  60. Username: cfg.Username,
  61. Password: cfg.Password,
  62. Mechanism: cfg.Mechanism,
  63. Source: cfg.Db,
  64. })
  65. if err != nil {
  66. return nil, err
  67. }
  68. db := session.DB(cfg.Db)
  69. characters, err := newCharacterRepository(db)
  70. if err != nil {
  71. session.Close()
  72. return nil, err
  73. }
  74. channels, err := newChannelRepository(db)
  75. if err != nil {
  76. session.Close()
  77. return nil, err
  78. }
  79. changes, err := newChangeRepository(db)
  80. if err != nil {
  81. session.Close()
  82. return nil, err
  83. }
  84. logs, err := newLogRepository(db)
  85. if err != nil {
  86. session.Close()
  87. return nil, err
  88. }
  89. posts, err := newPostRepository(db)
  90. if err != nil {
  91. session.Close()
  92. return nil, err
  93. }
  94. files, err := newFileRepository(db)
  95. if err != nil {
  96. session.Close()
  97. return nil, err
  98. }
  99. story, err := newStoryRepository(db)
  100. if err != nil {
  101. session.Close()
  102. return nil, err
  103. }
  104. go posts.fixPositions(logs)
  105. return &MongoDB{
  106. session: session,
  107. changes: changes,
  108. characters: characters,
  109. channels: channels,
  110. tags: newTagRepository(db),
  111. story: story,
  112. logs: logs,
  113. posts: posts,
  114. files: files,
  115. }, nil
  116. }
  117. type counter struct {
  118. coll *mgo.Collection
  119. category string
  120. name string
  121. }
  122. func newCounter(db *mgo.Database, category, name string) *counter {
  123. return &counter{
  124. coll: db.C("core.counters"),
  125. category: category,
  126. name: name,
  127. }
  128. }
  129. func (c *counter) WithName(name string) *counter {
  130. return &counter{
  131. coll: c.coll,
  132. category: c.category,
  133. name: name,
  134. }
  135. }
  136. func (c *counter) WithCategory(category string) *counter {
  137. return &counter{
  138. coll: c.coll,
  139. category: category,
  140. name: c.name,
  141. }
  142. }
  143. func (c *counter) With(category, name string) *counter {
  144. return &counter{
  145. coll: c.coll,
  146. category: category,
  147. name: name,
  148. }
  149. }
  150. func (c *counter) Increment(amount int) (int, error) {
  151. type counterDoc struct {
  152. ID string `bson:"_id"`
  153. Value int `bson:"value"`
  154. }
  155. id := c.category + "." + c.name
  156. doc := counterDoc{}
  157. _, err := c.coll.Find(bson.M{"_id": id}).Apply(mgo.Change{
  158. Update: bson.M{"$inc": bson.M{"value": amount}},
  159. Upsert: true,
  160. ReturnNew: true,
  161. }, &doc)
  162. if err != nil {
  163. return -1, err
  164. }
  165. return doc.Value, nil
  166. }