feat: add PawSQL docs examples and image CI
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 2m28s
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 2m28s
This commit is contained in:
103
cmd/pawsql/main.go
Normal file
103
cmd/pawsql/main.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/barkstack/pawsql/internal/config"
|
||||
"github.com/barkstack/pawsql/internal/postgres"
|
||||
"github.com/barkstack/pawsql/internal/router"
|
||||
"github.com/barkstack/pawsql/internal/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
if err := run(os.Args[1:], logger); err != nil {
|
||||
logger.Error("pawsql failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(args []string, logger *slog.Logger) error {
|
||||
validateOnly, configPath, err := parseArguments(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := config.ParseFile(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid configuration: %w", err)
|
||||
}
|
||||
certificate, err := tls.LoadX509KeyPair(cfg.TLS.CertFile, cfg.TLS.KeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load TLS certificate and key: %w", err)
|
||||
}
|
||||
if validateOnly {
|
||||
logger.Info("configuration is valid", "config", configPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
staticResolver, err := router.NewStaticResolver(cfg.Databases)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build route resolver: %w", err)
|
||||
}
|
||||
resolver := postgres.NewResolver(staticResolver, cfg.Databases, postgres.NewProvisioner(logger))
|
||||
routingServer, err := server.New(&tls.Config{Certificates: []tls.Certificate{certificate}}, resolver, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listener, err := net.Listen("tcp", cfg.Listen)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen on %s: %w", cfg.Listen, err)
|
||||
}
|
||||
logger.Info("pawsql listening", "address", listener.Addr().String())
|
||||
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(signals)
|
||||
serveErrors := make(chan error, 1)
|
||||
go func() { serveErrors <- routingServer.Serve(listener) }()
|
||||
|
||||
select {
|
||||
case received := <-signals:
|
||||
logger.Info("shutdown signal received", "signal", received.String())
|
||||
if err := routingServer.Shutdown(); err != nil && !errors.Is(err, net.ErrClosed) {
|
||||
return fmt.Errorf("stop listener: %w", err)
|
||||
}
|
||||
if err := <-serveErrors; err != nil {
|
||||
return err
|
||||
}
|
||||
routingServer.Wait()
|
||||
logger.Info("pawsql shutdown complete")
|
||||
return nil
|
||||
case err := <-serveErrors:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func parseArguments(args []string) (validateOnly bool, configPath string, err error) {
|
||||
if len(args) > 0 && args[0] == "validate" {
|
||||
validateOnly = true
|
||||
args = args[1:]
|
||||
}
|
||||
flags := flag.NewFlagSet("pawsql", flag.ContinueOnError)
|
||||
flags.SetOutput(os.Stderr)
|
||||
configPath = "Barkfile"
|
||||
flags.StringVar(&configPath, "config", configPath, "path to Barkfile")
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if flags.NArg() != 0 {
|
||||
return false, "", fmt.Errorf("unexpected arguments: %v", flags.Args())
|
||||
}
|
||||
return validateOnly, configPath, nil
|
||||
}
|
||||
Reference in New Issue
Block a user