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.

246 lines
6.5 KiB

  1. package main
  2. import (
  3. "archive/zip"
  4. "context"
  5. "encoding/json"
  6. "flag"
  7. "fmt"
  8. "git.aiterp.net/rpdata/api/database"
  9. "git.aiterp.net/rpdata/api/database/mongodb"
  10. "git.aiterp.net/rpdata/api/internal/config"
  11. "git.aiterp.net/rpdata/api/models"
  12. "log"
  13. "os"
  14. "time"
  15. )
  16. var flagDriver = flag.String("driver", "mongodb", "The database driver to use.")
  17. var flagHost = flag.String("host", "127.0.0.1", "The host to connect to.")
  18. var flagPort = flag.Int("port", 27017, "The port to connect on.")
  19. var flagDb = flag.String("db", "rpdata", "The database name")
  20. var flagUsername = flag.String("username", "", "")
  21. var flagPassword = flag.String("password", "", "")
  22. var flagMechanism = flag.String("mechanism", "", "")
  23. var flagOutputFile = flag.String("outfile", "dump.zip", "The file to write to.")
  24. var flagIncludeKeys = flag.Bool("include-keys", false, "Whether to include the keys.")
  25. func main() {
  26. flag.Parse()
  27. trueValue := true
  28. truePtr := &trueValue
  29. cfg := config.Database{
  30. Driver: *flagDriver,
  31. Host: *flagHost,
  32. Port: *flagPort,
  33. Db: *flagDb,
  34. Username: *flagUsername,
  35. Password: *flagPassword,
  36. Mechanism: *flagMechanism,
  37. }
  38. mongodb.DisableFixes = true
  39. db, err := database.Init(cfg)
  40. if err != nil {
  41. log.Fatalln("Failed to open database:", err)
  42. }
  43. file, err := os.OpenFile(*flagOutputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
  44. if err != nil {
  45. log.Fatalln("Failed to open output file:", err)
  46. }
  47. zipWriter := zip.NewWriter(file)
  48. defer func() {
  49. err = zipWriter.Close()
  50. if err != nil {
  51. log.Fatalln("Failed to close output file:", err)
  52. }
  53. }()
  54. ctx, cancel := context.WithTimeout(context.Background(), time.Minute*30)
  55. defer cancel()
  56. log.Println("Dumping characters...")
  57. characters, err := db.Characters().List(ctx, models.CharacterFilter{})
  58. if err != nil {
  59. log.Println("Failed to get characters:", err)
  60. }
  61. if len(characters) == 0 {
  62. log.Println("No characters to dump.")
  63. }
  64. for i, character := range characters {
  65. err := writeJsonFile(zipWriter, "character", i, character.ID, time.Now(), character)
  66. if err != nil {
  67. log.Println("Failed to write character", character.ID, ":", err)
  68. continue
  69. }
  70. }
  71. log.Println("Dumping channels...")
  72. channels, err := db.Channels().List(ctx, models.ChannelFilter{})
  73. if err != nil {
  74. log.Println("Failed to get channels:", err)
  75. }
  76. if len(channels) == 0 {
  77. log.Println("No channels to dump.")
  78. }
  79. for i, channel := range channels {
  80. err := writeJsonFile(zipWriter, "channel", i, channel.Name, time.Now(), channel)
  81. if err != nil {
  82. log.Println("Failed to write channel", channel.Name, ":", err)
  83. continue
  84. }
  85. }
  86. log.Println("Dumping changes...")
  87. changes, err := db.Changes().List(ctx, models.ChangeFilter{})
  88. if err != nil {
  89. log.Println("Failed to get changes:", err)
  90. }
  91. if len(changes) == 0 {
  92. log.Println("No changes to dump.")
  93. }
  94. for i, change := range changes {
  95. err := writeJsonFile(zipWriter, "change", i, change.ID, change.Date, change)
  96. if err != nil {
  97. log.Println("Failed to write change", change.ID, ":", err)
  98. continue
  99. }
  100. }
  101. log.Println("Dumping stories...")
  102. stories, err := db.Stories().List(ctx, models.StoryFilter{})
  103. if err != nil {
  104. log.Println("Failed to get stories:", err)
  105. }
  106. unlistedStories, err := db.Stories().List(ctx, models.StoryFilter{Unlisted: truePtr})
  107. if err != nil {
  108. log.Println("Failed to get unlisted stories:", err)
  109. } else {
  110. stories = append(stories, unlistedStories...)
  111. }
  112. if len(stories) == 0 {
  113. log.Println("No stories to dump.")
  114. }
  115. for i, story := range stories {
  116. err := writeJsonFile(zipWriter, "story", i, story.ID, story.CreatedDate, story)
  117. if err != nil {
  118. log.Println("Failed to write story", story.ID, ":", err)
  119. continue
  120. }
  121. }
  122. log.Println("Dumping chapters...")
  123. chapters, err := db.Chapters().List(ctx, models.ChapterFilter{})
  124. if err != nil {
  125. log.Println("Failed to get chapters:", err)
  126. }
  127. if len(chapters) == 0 {
  128. log.Println("No chapters to dump.")
  129. }
  130. for i, chapter := range chapters {
  131. err := writeJsonFile(zipWriter, "chapter", i, chapter.ID, chapter.CreatedDate, chapter)
  132. if err != nil {
  133. log.Println("Failed to write chapter", chapter.ID, ":", err)
  134. continue
  135. }
  136. }
  137. log.Println("Dumping comments...")
  138. comments, err := db.Comments().List(ctx, models.CommentFilter{})
  139. if err != nil {
  140. log.Println("Failed to get comments:", err)
  141. }
  142. if len(comments) == 0 {
  143. log.Println("No comments to dump.")
  144. }
  145. for i, comment := range comments {
  146. err := writeJsonFile(zipWriter, "comment", i, comment.ID, comment.CreatedDate, comment)
  147. if err != nil {
  148. log.Println("Failed to write comment", comment.ID, ":", err)
  149. continue
  150. }
  151. }
  152. log.Println("Dumping posts...")
  153. posts, err := db.Posts().List(ctx, models.PostFilter{})
  154. if err != nil {
  155. log.Println("Failed to get posts:", err)
  156. }
  157. if len(posts) == 0 {
  158. log.Println("No posts to dump.")
  159. }
  160. for i, post := range posts {
  161. err := writeJsonFile(zipWriter, "post", i, post.ID, post.Time, post)
  162. if err != nil {
  163. log.Println("Failed to write post", post.ID, ":", err)
  164. continue
  165. }
  166. }
  167. log.Println("Dumping logs...")
  168. logs, err := db.Logs().List(ctx, models.LogFilter{})
  169. if err != nil {
  170. log.Println("Failed to get logs:", err)
  171. }
  172. if len(logs) == 0 {
  173. log.Println("No logs to dump.")
  174. }
  175. for i, logEntry := range logs {
  176. err := writeJsonFile(zipWriter, "post", i, logEntry.ID, logEntry.Date, logEntry)
  177. if err != nil {
  178. log.Println("Failed to write post", logEntry.ID, ":", err)
  179. continue
  180. }
  181. }
  182. log.Println("Dumping users...")
  183. users, err := db.Users().List(ctx)
  184. if err != nil {
  185. log.Println("Failed to get users:", err)
  186. }
  187. if len(users) == 0 {
  188. log.Println("No users to dump.")
  189. }
  190. for i, userEntry := range users {
  191. err := writeJsonFile(zipWriter, "user", i, userEntry.ID, time.Now(), userEntry)
  192. if err != nil {
  193. log.Println("Failed to write user", userEntry.ID, ":", err)
  194. continue
  195. }
  196. }
  197. if *flagIncludeKeys {
  198. log.Println("Dumping keys...")
  199. keys, err := db.Keys().List(ctx, models.KeyFilter{})
  200. if err != nil {
  201. log.Println("Failed to get users:", err)
  202. }
  203. if len(keys) == 0 {
  204. log.Println("No users to dump.")
  205. }
  206. for i, keyEntry := range keys {
  207. err := writeJsonFile(zipWriter, "key", i, keyEntry.ID, time.Now(), keyEntry)
  208. if err != nil {
  209. log.Println("Failed to write key", keyEntry.ID, ":", err)
  210. continue
  211. }
  212. }
  213. }
  214. }
  215. func writeJsonFile(zw *zip.Writer, model string, idx int, id string, t time.Time, data interface{}) error {
  216. w, err := zw.CreateHeader(&zip.FileHeader{
  217. Name: fmt.Sprintf("rpdata_dump_v1/%s/%06d_%s.json", model, idx, id),
  218. Modified: t,
  219. })
  220. if err != nil {
  221. return err
  222. }
  223. return json.NewEncoder(w).Encode(data)
  224. }