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.

116 lines
3.3 KiB

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "runtime/debug"
  8. "strings"
  9. "git.aiterp.net/rpdata/api/database"
  10. "git.aiterp.net/rpdata/api/graph2"
  11. "git.aiterp.net/rpdata/api/internal/auth"
  12. "git.aiterp.net/rpdata/api/internal/config"
  13. "git.aiterp.net/rpdata/api/internal/instrumentation"
  14. "git.aiterp.net/rpdata/api/internal/loader"
  15. "git.aiterp.net/rpdata/api/internal/store"
  16. "git.aiterp.net/rpdata/api/models"
  17. "git.aiterp.net/rpdata/api/services"
  18. "github.com/99designs/gqlgen/handler"
  19. "github.com/prometheus/client_golang/prometheus/promhttp"
  20. )
  21. func main() {
  22. err := store.Init()
  23. if err != nil {
  24. log.Fatalln("Failed to init store:", err)
  25. }
  26. db, err := database.Init(config.Global().Database)
  27. if err != nil {
  28. log.Fatalln("Failed to init db:", err)
  29. }
  30. defer db.Close(context.Background())
  31. serviceBundle := services.NewBundle(db)
  32. instrumentation.Register()
  33. http.Handle("/", handler.Playground("RPData API", "/graphql"))
  34. http.Handle("/graphql", queryHandler(serviceBundle))
  35. http.Handle("/metrics", promhttp.Handler())
  36. go func() {
  37. err := serviceBundle.Logs.RefreshAllLogCharacters(context.Background())
  38. if err != nil {
  39. log.Println(err)
  40. }
  41. log.Println("Characters updated")
  42. }()
  43. go logListedChanges(serviceBundle.Changes)
  44. log.Fatal(http.ListenAndServe(":8081", nil))
  45. }
  46. func logListedChanges(changes *services.ChangeService) {
  47. sub := changes.Subscribe(context.Background(), models.ChangeFilter{})
  48. for change := range sub {
  49. log.Printf("Change: Author=%#+v Model=%#+v Op=%#+v", change.Author, change.Model, change.Op)
  50. for _, object := range change.Objects() {
  51. switch object := object.(type) {
  52. case models.Log:
  53. log.Printf("\tLog: %s (%s)", object.ID, object.ShortID)
  54. case models.Character:
  55. log.Printf("\tCharacter: %s", object.ID)
  56. case models.Channel:
  57. log.Printf("\tChannel: %s", object.Name)
  58. case models.Post:
  59. log.Printf("\tPost: %s", object.ID)
  60. case models.Story:
  61. log.Printf("\tStory: %s", object.ID)
  62. case models.Tag:
  63. log.Printf("\tTag: (%s,%s)", object.Kind, object.Name)
  64. case models.Chapter:
  65. log.Printf("\tChapter: %s", object.ID)
  66. case models.Comment:
  67. log.Printf("\tComment: %s", object.ID)
  68. }
  69. }
  70. }
  71. log.Println("Change subscription closed.")
  72. }
  73. func queryHandler(services *services.Bundle) http.HandlerFunc {
  74. handler := handler.GraphQL(
  75. graph2.New(services),
  76. handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
  77. log.Println(err)
  78. log.Println(string(debug.Stack()))
  79. return fmt.Errorf("The server failed to serve your request due to an internal error, it has been logged")
  80. }),
  81. handler.ComplexityLimit(300),
  82. handler.RequestMiddleware(instrumentation.RequestMiddleware()),
  83. handler.ResolverMiddleware(instrumentation.ResolverMiddleware()),
  84. )
  85. return func(w http.ResponseWriter, r *http.Request) {
  86. l := loader.New()
  87. r = r.WithContext(l.ToContext(r.Context()))
  88. // >_>
  89. if strings.HasPrefix(r.Header.Get("Authorization"), "Bearer of the curse") {
  90. w.Header().Set("X-Emerald-Herald", "Seek souls. Larger, more powerful souls.")
  91. w.Header().Add("X-Emerald-Herald", "Seek the king, that is the only way.")
  92. w.Header().Add("X-Emerald-Herald", "Lest this land swallow you whole... As it has so many others.")
  93. }
  94. r = auth.RequestWithToken(r)
  95. handler.ServeHTTP(w, r)
  96. }
  97. }