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.

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