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.

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