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.

128 lines
3.2 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. package main
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "log"
  7. "net"
  8. "net/http"
  9. "os"
  10. "git.chrishayward.xyz/x/users/proto"
  11. "git.chrishayward.xyz/x/users/server"
  12. "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
  13. "google.golang.org/grpc"
  14. "google.golang.org/grpc/reflection"
  15. "gopkg.in/yaml.v3"
  16. "gorm.io/driver/postgres"
  17. "gorm.io/driver/sqlite"
  18. "gorm.io/gorm"
  19. )
  20. var configPath = flag.String("config", "./config/server.yaml", "--config=./config/server.yaml")
  21. type config struct {
  22. Port int `yaml:"port"`
  23. Secret string `yaml:"secret"`
  24. Gateway struct {
  25. URL string `yaml:"url"`
  26. Port int `yaml:"port"`
  27. }
  28. Database struct {
  29. Type string `yaml:"type"`
  30. File string `yaml:"file"`
  31. Host string `yaml:"host"`
  32. Port int `yaml:"port"`
  33. Name string `yaml:"name"`
  34. User string `yaml:"user"`
  35. Password string `yaml:"password"`
  36. } `yaml:"database"`
  37. }
  38. func main() {
  39. // Create the context.
  40. ctx := context.Background()
  41. ctx, cancel := context.WithCancel(ctx)
  42. defer cancel()
  43. // Parse the application flags.
  44. flag.Parse()
  45. // Read the config file.
  46. config := &config{}
  47. file, err := os.Open(*configPath)
  48. if err != nil {
  49. log.Fatalf("Failed to open config file: %v", err)
  50. }
  51. defer file.Close()
  52. if err := yaml.NewDecoder(file).Decode(&config); err != nil {
  53. log.Fatalf("Failed to read config file: %v", err)
  54. }
  55. // Create the server network listener.
  56. lis, err := net.Listen("tcp", fmt.Sprintf(":%d", config.Port))
  57. if err != nil {
  58. log.Fatal(err)
  59. }
  60. // Initialize the database.
  61. var db *gorm.DB
  62. switch config.Database.Type {
  63. case "postgres":
  64. db, _ = gorm.Open(postgres.Open(fmt.Sprintf(
  65. "host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
  66. config.Database.Host,
  67. config.Database.User,
  68. config.Database.Password,
  69. config.Database.Name,
  70. config.Database.Port)))
  71. case "sqlite":
  72. fallthrough
  73. default:
  74. db, _ = gorm.Open(sqlite.Open(config.Database.File), &gorm.Config{})
  75. }
  76. // Create the server.
  77. grpcServer := grpc.NewServer()
  78. proto.RegisterUsersServer(grpcServer, server.NewUsersServer(config.Secret, db))
  79. reflection.Register(grpcServer)
  80. go grpcServer.Serve(lis)
  81. // Create the gateway client connection.
  82. conn, err := grpc.Dial(fmt.Sprintf("localhost:%d", config.Port), grpc.WithInsecure())
  83. if err != nil {
  84. log.Fatalf("Failed to create client connection: %v", err)
  85. }
  86. defer conn.Close()
  87. // Create the gRPC gateway.
  88. rmux := runtime.NewServeMux()
  89. client := proto.NewUsersClient(conn)
  90. err = proto.RegisterUsersHandlerClient(ctx, rmux, client)
  91. if err != nil {
  92. log.Fatalf("Failed to register client handler: %v", err)
  93. }
  94. // Create a standard HTTP router.
  95. mux := http.NewServeMux()
  96. // Mount the gRPC gateway.
  97. mux.Handle("/", rmux)
  98. // Create the gRPC OpenAPI UI.
  99. mux.HandleFunc("/swagger-ui/swagger.json", func(w http.ResponseWriter, r *http.Request) {
  100. http.ServeFile(w, r, "./proto/users.swagger.json")
  101. })
  102. mux.Handle("/swagger-ui/",
  103. http.StripPrefix("/swagger-ui/",
  104. http.FileServer(http.Dir("./modules/swagger-ui/dist"))))
  105. // Start listening for requests.
  106. log.Println(fmt.Sprintf("Listening on:\n=>\tgRPC[::]:%d\n=>\tHTTP[::]:%d",
  107. config.Port, config.Gateway.Port))
  108. err = http.ListenAndServe(fmt.Sprintf(":%d", config.Gateway.Port), mux)
  109. if err != nil {
  110. log.Fatalf("Failed to listen: %v", err)
  111. }
  112. }