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.

287 lines
6.9 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. if parts[1] != "story" && parts[1] != "chapter" {
  72. continue
  73. }
  74. log.Println("Loaded", parts[1], parts[2], "from archive.")
  75. switch parts[1] {
  76. case "character":
  77. {
  78. character := models.Character{}
  79. err := json.NewDecoder(reader).Decode(&character)
  80. if err != nil {
  81. log.Fatalln("Could not parse character:", parts[2], err)
  82. }
  83. if *flagReplace {
  84. _ = db.Characters().Delete(ctx, character)
  85. }
  86. _, err = db.Characters().Insert(ctx, character)
  87. if err != nil {
  88. log.Fatalln("Could not insert character:", parts[2], err)
  89. }
  90. log.Println("Character", character.Name, "inserted.")
  91. }
  92. case "channel":
  93. {
  94. channel := models.Channel{}
  95. err := json.NewDecoder(reader).Decode(&channel)
  96. if err != nil {
  97. log.Fatalln("Could not parse channel:", parts[2], err)
  98. }
  99. if *flagReplace {
  100. _ = db.Channels().Remove(ctx, channel)
  101. }
  102. _, err = db.Channels().Insert(ctx, channel)
  103. if err != nil {
  104. log.Fatalln("Could not insert channel:", parts[2], err)
  105. }
  106. log.Println("Channel", channel.Name, "inserted.")
  107. }
  108. case "change":
  109. {
  110. change := models.Change{}
  111. err := json.NewDecoder(reader).Decode(&change)
  112. if err != nil {
  113. log.Fatalln("Could not parse character:", parts[2], err)
  114. }
  115. if *flagReplace {
  116. _ = db.Changes().Remove(ctx, change)
  117. }
  118. _, err = db.Changes().Insert(ctx, change)
  119. if err != nil {
  120. log.Fatalln("Could not insert character:", parts[2], err)
  121. }
  122. if change.Listed {
  123. log.Println("Change", change.ID, "inserted.")
  124. } else {
  125. log.Println("Unlisted change inserted.")
  126. }
  127. }
  128. case "story":
  129. {
  130. story := models.Story{}
  131. err := json.NewDecoder(reader).Decode(&story)
  132. if err != nil {
  133. log.Fatalln("Could not parse story:", parts[2], err)
  134. }
  135. _, err = db.Stories().Insert(ctx, story)
  136. if err != nil {
  137. log.Fatalln("Could not insert story:", parts[2], err)
  138. }
  139. if story.Listed {
  140. log.Println("Story", story.Name, "inserted.")
  141. } else {
  142. log.Println("Unlisted story inserted.")
  143. hideList[story.ID] = true
  144. }
  145. }
  146. case "chapter":
  147. {
  148. chapter := models.Chapter{}
  149. err := json.NewDecoder(reader).Decode(&chapter)
  150. if err != nil {
  151. log.Fatalln("Could not parse story:", parts[2], err)
  152. }
  153. _, err = db.Chapters().Insert(ctx, chapter)
  154. if err != nil {
  155. log.Fatalln("Could not insert story:", parts[2], err)
  156. }
  157. if !hideList[chapter.StoryID] {
  158. log.Println("Chapter", fmt.Sprintf("%s (id: %s)", chapter.Title, chapter.ID), "inserted.")
  159. } else {
  160. log.Println("Unlisted chapter inserted.")
  161. hideList[chapter.ID] = true
  162. }
  163. }
  164. case "comment":
  165. {
  166. comment := models.Comment{}
  167. err := json.NewDecoder(reader).Decode(&comment)
  168. if err != nil {
  169. log.Fatalln("Could not parse story:", parts[2], err)
  170. }
  171. _, err = db.Comments().Insert(ctx, comment)
  172. if err != nil {
  173. log.Fatalln("Could not insert story:", parts[2], err)
  174. }
  175. if !hideList[comment.ChapterID] {
  176. log.Println("Comment", comment.Subject, "inserted.")
  177. } else {
  178. log.Println("Unlisted comment inserted.")
  179. }
  180. }
  181. case "log":
  182. {
  183. logg := models.Log{}
  184. err := json.NewDecoder(reader).Decode(&logg)
  185. if err != nil {
  186. log.Fatalln("Could not parse log:", parts[2], err)
  187. }
  188. _, err = db.Logs().Insert(ctx, logg)
  189. if err != nil {
  190. log.Fatalln("Could not insert log:", parts[2], err)
  191. }
  192. log.Println("Log", logg.Date.Format(time.RFC3339)[:16], logg.ChannelName, "inserted.")
  193. }
  194. case "post":
  195. {
  196. post := models.Post{}
  197. err := json.NewDecoder(reader).Decode(&post)
  198. if err != nil {
  199. log.Fatalln("Could not parse post:", parts[2], err)
  200. }
  201. postMap[post.LogID] = append(postMap[post.LogID], &post)
  202. }
  203. case "user":
  204. {
  205. user := models.User{}
  206. err := json.NewDecoder(reader).Decode(&user)
  207. if err != nil {
  208. log.Fatalln("Could not parse post:", parts[2], err)
  209. }
  210. _, err = db.Users().Insert(ctx, user)
  211. if err != nil {
  212. log.Fatalln("Could not insert user:", parts[2], err)
  213. }
  214. log.Println("User", user.ID, "inserted.")
  215. }
  216. case "key":
  217. {
  218. if !*flagIncludeKeys {
  219. break
  220. }
  221. key := models.Key{}
  222. err := json.NewDecoder(reader).Decode(&key)
  223. if err != nil {
  224. log.Fatalln("Could not parse key:", parts[2], err)
  225. }
  226. _, err = db.Keys().Insert(ctx, key)
  227. if err != nil {
  228. log.Fatalln("Could not insert key:", parts[2], err)
  229. }
  230. log.Println("Key", key.ID, "inserted.")
  231. }
  232. }
  233. _ = reader.Close()
  234. }
  235. for _, posts := range postMap {
  236. _, err = db.Posts().InsertMany(ctx, posts...)
  237. if err != nil {
  238. log.Fatalln("Could not insert post for logId:", posts[0].LogID, err)
  239. }
  240. log.Printf("Inserted %d posts for log %s.", len(posts), posts[0].LogID)
  241. }
  242. }