|
|
package main
import ( "context" "flag" "fmt" "log" "net" "net/http" "os"
"git.chrishayward.xyz/x/users/proto" "git.chrishayward.xyz/x/users/server" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/grpc" "google.golang.org/grpc/reflection" "gopkg.in/yaml.v3" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" )
var configPath = flag.String("config", "./config/server.yaml", "--config=./config/server.yaml")
type config struct { Port int `yaml:"port"` Secret string `yaml:"secret"` Gateway struct { URL string `yaml:"url"` Port int `yaml:"port"` } Database struct { Type string `yaml:"type"` File string `yaml:"file"` Host string `yaml:"host"` Port int `yaml:"port"` Name string `yaml:"name"` User string `yaml:"user"` Password string `yaml:"password"` } `yaml:"database"` }
func main() { // Create the context.
ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel()
// Parse the application flags.
flag.Parse()
// Read the config file.
config := &config{} file, err := os.Open(*configPath) if err != nil { log.Fatalf("Failed to open config file: %v", err) } defer file.Close() if err := yaml.NewDecoder(file).Decode(&config); err != nil { log.Fatalf("Failed to read config file: %v", err) }
// Create the server network listener.
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", config.Port)) if err != nil { log.Fatal(err) }
// Initialize the database.
var db *gorm.DB switch config.Database.Type { case "postgres": db, _ = gorm.Open(postgres.Open(fmt.Sprintf( "host=%s user=%s password=%s dbname=%s port=%d sslmode=disable", config.Database.Host, config.Database.User, config.Database.Password, config.Database.Name, config.Database.Port))) case "sqlite": fallthrough default: db, _ = gorm.Open(sqlite.Open(config.Database.File), &gorm.Config{}) }
// Create the server.
grpcServer := grpc.NewServer() proto.RegisterUsersServer(grpcServer, server.NewUsersServer(config.Secret, db)) reflection.Register(grpcServer) go grpcServer.Serve(lis)
// Create the gateway client connection.
conn, err := grpc.Dial(fmt.Sprintf("localhost:%d", config.Port), grpc.WithInsecure()) if err != nil { log.Fatalf("Failed to create client connection: %v", err) } defer conn.Close()
// Create the gRPC gateway.
rmux := runtime.NewServeMux() client := proto.NewUsersClient(conn) err = proto.RegisterUsersHandlerClient(ctx, rmux, client) if err != nil { log.Fatalf("Failed to register client handler: %v", err) }
// Create a standard HTTP router.
mux := http.NewServeMux()
// Mount the gRPC gateway.
mux.Handle("/", rmux)
// Create the gRPC OpenAPI UI.
mux.HandleFunc("/swagger-ui/swagger.json", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./proto/users.swagger.json") }) mux.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("./modules/swagger-ui/dist"))))
// Start listening for requests.
log.Println(fmt.Sprintf("Listening on:\n=>\tgRPC[::]:%d\n=>\tHTTP[::]:%d", config.Port, config.Gateway.Port)) err = http.ListenAndServe(fmt.Sprintf(":%d", config.Gateway.Port), mux) if err != nil { log.Fatalf("Failed to listen: %v", err) } }
|