package main import ( "context" "fmt" "git.aiterp.net/rpdata/api/space" "log" "net/http" "runtime/debug" "strings" "git.aiterp.net/rpdata/api/database" "git.aiterp.net/rpdata/api/graph2" "git.aiterp.net/rpdata/api/internal/config" "git.aiterp.net/rpdata/api/internal/instrumentation" "git.aiterp.net/rpdata/api/models" "git.aiterp.net/rpdata/api/services" "github.com/99designs/gqlgen/handler" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { cfg := config.Global() db, err := database.Init(cfg.Database) if err != nil { log.Fatalln("Failed to init db:", err) } defer db.Close(context.Background()) var spaceClient *space.Client if cfg.Space.Enabled { spaceClient, err = space.Connect(cfg.Space) if err != nil { log.Fatalln("Failed to init space:", err) } log.Println("Space loaded") } else { log.Println("Space is disabled, file upload will not work!") } serviceBundle := services.NewBundle(db, spaceClient) instrumentation.Register() http.Handle("/", handler.Playground("RPData API", "/graphql")) http.Handle("/graphql", queryHandler(serviceBundle)) http.Handle("/metrics", promhttp.Handler()) go func() { err := serviceBundle.Logs.RefreshAllLogCharacters(context.Background()) if err != nil { log.Println("Refresh Characters:", err) } err = serviceBundle.Logs.FixImportDateBug(context.Background()) if err != nil { log.Println("Fix date bug:", err) } }() go logListedChanges(serviceBundle.Changes) log.Fatal(http.ListenAndServe(":8081", nil)) } func logListedChanges(changes *services.ChangeService) { sub := changes.Subscribe(context.Background(), models.ChangeFilter{}) for change := range sub { log.Printf("Change: Author=%#+v Model=%#+v Op=%#+v", change.Author, change.Model, change.Op) for _, object := range change.Objects() { switch object := object.(type) { case models.Log: log.Printf("\tLog: %s (%s)", object.ID, object.ShortID) case models.Character: log.Printf("\tCharacter: %s", object.ID) case models.Channel: log.Printf("\tChannel: %s", object.Name) case models.Post: log.Printf("\tPost: %s", object.ID) case models.Story: log.Printf("\tStory: %s", object.ID) case models.Tag: log.Printf("\tTag: (%s,%s)", object.Kind, object.Name) case models.Chapter: log.Printf("\tChapter: %s", object.ID) case models.Comment: log.Printf("\tComment: %s", object.ID) } } } log.Println("Change subscription closed.") } func queryHandler(services *services.Bundle) http.HandlerFunc { handler := handler.GraphQL( graph2.New(services), handler.UploadMaxSize(10485760), handler.UploadMaxMemory(1048576), handler.RecoverFunc(func(ctx context.Context, err interface{}) error { log.Println(err) log.Println(string(debug.Stack())) return fmt.Errorf("The server failed to serve your request due to an internal error, it has been logged") }), handler.ComplexityLimit(300), handler.RequestMiddleware(instrumentation.RequestMiddleware()), handler.ResolverMiddleware(instrumentation.ResolverMiddleware()), ) return func(w http.ResponseWriter, r *http.Request) { // >_> if strings.HasPrefix(r.Header.Get("Authorization"), "Bearer of the curse") { w.Header().Set("X-Emerald-Herald", "Seek souls. Larger, more powerful souls.") w.Header().Add("X-Emerald-Herald", "Seek the king, that is the only way.") w.Header().Add("X-Emerald-Herald", "Lest this land swallow you whole... As it has so many others.") } r = services.Auth.RequestWithToken(r) handler.ServeHTTP(w, r) } }