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.

295 lines
7.0 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. if *flagReplace {
  133. _ = db.Stories().Delete(ctx, story)
  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. if *flagReplace {
  154. _ = db.Chapters().Delete(ctx, chapter)
  155. }
  156. _, err = db.Chapters().Insert(ctx, chapter)
  157. if err != nil {
  158. log.Fatalln("Could not insert story:", parts[2], err)
  159. }
  160. if !hideList[chapter.StoryID] {
  161. log.Println("Chapter", fmt.Sprintf("%s (id: %s)", chapter.Title, chapter.ID), "inserted.")
  162. } else {
  163. log.Println("Unlisted chapter inserted.")
  164. hideList[chapter.ID] = true
  165. }
  166. }
  167. case "comment":
  168. {
  169. comment := models.Comment{}
  170. err := json.NewDecoder(reader).Decode(&comment)
  171. if err != nil {
  172. log.Fatalln("Could not parse story:", parts[2], err)
  173. }
  174. if *flagReplace {
  175. _ = db.Comments().Delete(ctx, comment)
  176. }
  177. _, err = db.Comments().Insert(ctx, comment)
  178. if err != nil {
  179. log.Fatalln("Could not insert story:", parts[2], err)
  180. }
  181. if !hideList[comment.ChapterID] {
  182. log.Println("Comment", comment.Subject, "inserted.")
  183. } else {
  184. log.Println("Unlisted comment inserted.")
  185. }
  186. }
  187. case "log":
  188. {
  189. logg := models.Log{}
  190. err := json.NewDecoder(reader).Decode(&logg)
  191. if err != nil {
  192. log.Fatalln("Could not parse log:", parts[2], err)
  193. }
  194. _, err = db.Logs().Insert(ctx, logg)
  195. if err != nil {
  196. log.Fatalln("Could not insert log:", parts[2], err)
  197. }
  198. log.Println("Log", logg.Date.Format(time.RFC3339)[:16], logg.ChannelName, "inserted.")
  199. }
  200. case "post":
  201. {
  202. post := models.Post{}
  203. err := json.NewDecoder(reader).Decode(&post)
  204. if err != nil {
  205. log.Fatalln("Could not parse post:", parts[2], err)
  206. }
  207. postMap[post.LogID] = append(postMap[post.LogID], &post)
  208. }
  209. case "user":
  210. {
  211. user := models.User{}
  212. err := json.NewDecoder(reader).Decode(&user)
  213. if err != nil {
  214. log.Fatalln("Could not parse post:", parts[2], err)
  215. }
  216. _, err = db.Users().Insert(ctx, user)
  217. if err != nil {
  218. log.Fatalln("Could not insert user:", parts[2], err)
  219. }
  220. log.Println("User", user.ID, "inserted.")
  221. }
  222. case "key":
  223. {
  224. if !*flagIncludeKeys {
  225. break
  226. }
  227. key := models.Key{}
  228. err := json.NewDecoder(reader).Decode(&key)
  229. if err != nil {
  230. log.Fatalln("Could not parse key:", parts[2], err)
  231. }
  232. _, err = db.Keys().Insert(ctx, key)
  233. if err != nil {
  234. log.Fatalln("Could not insert key:", parts[2], err)
  235. }
  236. log.Println("Key", key.ID, "inserted.")
  237. }
  238. }
  239. _ = reader.Close()
  240. }
  241. for _, posts := range postMap {
  242. _, err = db.Posts().InsertMany(ctx, posts...)
  243. if err != nil {
  244. log.Fatalln("Could not insert post for logId:", posts[0].LogID, err)
  245. }
  246. log.Printf("Inserted %d posts for log %s.", len(posts), posts[0].LogID)
  247. }
  248. }