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.

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