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.

283 lines
6.8 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. "strings"
  14. "time"
  15. )
  16. var flagDriver = flag.String("driver", "postgres", "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", 5432, "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 flagInputFile = flag.String("infile", "dump.zip", "The file to read from.")
  24. var flagIncludeKeys = flag.Bool("include-keys", false, "Whether to include the keys.")
  25. var flagReplace = flag.Bool("replace", false, "Replace existing content")
  26. func main() {
  27. flag.Parse()
  28. cfg := config.Database{
  29. Driver: *flagDriver,
  30. Host: *flagHost,
  31. Port: *flagPort,
  32. Db: *flagDb,
  33. Username: *flagUsername,
  34. Password: *flagPassword,
  35. Mechanism: *flagMechanism,
  36. RestoreIDs: true,
  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. cfg2 := cfg
  44. cfg2.RestoreIDs = false
  45. zipReader, err := zip.OpenReader(*flagInputFile)
  46. if err != nil {
  47. log.Fatalln("Failed to open input file:", err)
  48. }
  49. defer func() {
  50. err = zipReader.Close()
  51. if err != nil {
  52. log.Fatalln("Failed to close input file:", err)
  53. }
  54. }()
  55. ctx, cancel := context.WithTimeout(context.Background(), time.Minute*30)
  56. defer cancel()
  57. postMap := make(map[string][]*models.Post)
  58. for _, file := range zipReader.File {
  59. if strings.HasSuffix(file.Name, "/") {
  60. continue
  61. }
  62. parts := strings.Split(file.Name, "/")
  63. if len(parts) < 3 || parts[0] != "rpdata_dump_v1" {
  64. log.Fatalln("Unrecognized file path:", file.Name)
  65. }
  66. reader, err := file.Open()
  67. if err != nil {
  68. log.Fatalln("Unrecognized file:", file.Name, err)
  69. }
  70. hideList := make(map[string]bool)
  71. log.Println("Loaded", parts[1], parts[2], "from archive.")
  72. switch parts[1] {
  73. case "character":
  74. {
  75. character := models.Character{}
  76. err := json.NewDecoder(reader).Decode(&character)
  77. if err != nil {
  78. log.Fatalln("Could not parse character:", parts[2], err)
  79. }
  80. if *flagReplace {
  81. _ = db.Characters().Delete(ctx, character)
  82. }
  83. _, err = db.Characters().Insert(ctx, character)
  84. if err != nil {
  85. log.Fatalln("Could not insert character:", parts[2], err)
  86. }
  87. log.Println("Character", character.Name, "inserted.")
  88. }
  89. case "channel":
  90. {
  91. channel := models.Channel{}
  92. err := json.NewDecoder(reader).Decode(&channel)
  93. if err != nil {
  94. log.Fatalln("Could not parse channel:", parts[2], err)
  95. }
  96. if *flagReplace {
  97. _ = db.Channels().Remove(ctx, channel)
  98. }
  99. _, err = db.Channels().Insert(ctx, channel)
  100. if err != nil {
  101. log.Fatalln("Could not insert channel:", parts[2], err)
  102. }
  103. log.Println("Channel", channel.Name, "inserted.")
  104. }
  105. case "change":
  106. {
  107. change := models.Change{}
  108. err := json.NewDecoder(reader).Decode(&change)
  109. if err != nil {
  110. log.Fatalln("Could not parse character:", parts[2], err)
  111. }
  112. if *flagReplace {
  113. _ = db.Changes().Remove(ctx, change)
  114. }
  115. _, err = db.Changes().Insert(ctx, change)
  116. if err != nil {
  117. log.Fatalln("Could not insert character:", parts[2], err)
  118. }
  119. if change.Listed {
  120. log.Println("Change", change.ID, "inserted.")
  121. } else {
  122. log.Println("Unlisted change inserted.")
  123. }
  124. }
  125. case "story":
  126. {
  127. story := models.Story{}
  128. err := json.NewDecoder(reader).Decode(&story)
  129. if err != nil {
  130. log.Fatalln("Could not parse story:", parts[2], err)
  131. }
  132. _, err = db.Stories().Insert(ctx, story)
  133. if err != nil {
  134. log.Fatalln("Could not insert story:", parts[2], err)
  135. }
  136. if story.Listed {
  137. log.Println("Story", story.Name, "inserted.")
  138. } else {
  139. log.Println("Unlisted story inserted.")
  140. hideList[story.ID] = true
  141. }
  142. }
  143. case "chapter":
  144. {
  145. chapter := models.Chapter{}
  146. err := json.NewDecoder(reader).Decode(&chapter)
  147. if err != nil {
  148. log.Fatalln("Could not parse story:", parts[2], err)
  149. }
  150. _, err = db.Chapters().Insert(ctx, chapter)
  151. if err != nil {
  152. log.Fatalln("Could not insert story:", parts[2], err)
  153. }
  154. if !hideList[chapter.StoryID] {
  155. log.Println("Chapter", fmt.Sprintf("%s (id: %s)", chapter.Title, chapter.ID), "inserted.")
  156. } else {
  157. log.Println("Unlisted chapter inserted.")
  158. hideList[chapter.ID] = true
  159. }
  160. }
  161. case "comment":
  162. {
  163. comment := models.Comment{}
  164. err := json.NewDecoder(reader).Decode(&comment)
  165. if err != nil {
  166. log.Fatalln("Could not parse story:", parts[2], err)
  167. }
  168. _, err = db.Comments().Insert(ctx, comment)
  169. if err != nil {
  170. log.Fatalln("Could not insert story:", parts[2], err)
  171. }
  172. if !hideList[comment.ChapterID] {
  173. log.Println("Comment", comment.Subject, "inserted.")
  174. } else {
  175. log.Println("Unlisted comment inserted.")
  176. }
  177. }
  178. case "log":
  179. {
  180. logg := models.Log{}
  181. err := json.NewDecoder(reader).Decode(&logg)
  182. if err != nil {
  183. log.Fatalln("Could not parse log:", parts[2], err)
  184. }
  185. _, err = db.Logs().Insert(ctx, logg)
  186. if err != nil {
  187. log.Fatalln("Could not insert log:", parts[2], err)
  188. }
  189. log.Println("Log", logg.Date.Format(time.RFC3339)[:16], logg.ChannelName, "inserted.")
  190. }
  191. case "post":
  192. {
  193. post := models.Post{}
  194. err := json.NewDecoder(reader).Decode(&post)
  195. if err != nil {
  196. log.Fatalln("Could not parse post:", parts[2], err)
  197. }
  198. postMap[post.LogID] = append(postMap[post.LogID], &post)
  199. }
  200. case "user":
  201. {
  202. user := models.User{}
  203. err := json.NewDecoder(reader).Decode(&user)
  204. if err != nil {
  205. log.Fatalln("Could not parse post:", parts[2], err)
  206. }
  207. _, err = db.Users().Insert(ctx, user)
  208. if err != nil {
  209. log.Fatalln("Could not insert user:", parts[2], err)
  210. }
  211. log.Println("User", user.ID, "inserted.")
  212. }
  213. case "key":
  214. {
  215. if !*flagIncludeKeys {
  216. break
  217. }
  218. key := models.Key{}
  219. err := json.NewDecoder(reader).Decode(&key)
  220. if err != nil {
  221. log.Fatalln("Could not parse key:", parts[2], err)
  222. }
  223. _, err = db.Keys().Insert(ctx, key)
  224. if err != nil {
  225. log.Fatalln("Could not insert key:", parts[2], err)
  226. }
  227. log.Println("Key", key.ID, "inserted.")
  228. }
  229. }
  230. _ = reader.Close()
  231. }
  232. for _, posts := range postMap {
  233. _, err = db.Posts().InsertMany(ctx, posts...)
  234. if err != nil {
  235. log.Fatalln("Could not insert post for logId:", posts[0].LogID, err)
  236. }
  237. log.Printf("Inserted %d posts for log %s.", len(posts), posts[0].LogID)
  238. }
  239. }