refactor: get env from config and delegate startup to bootstrap
This commit is contained in:
@@ -12,8 +12,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.fossy.my.id/bagas/tunnel-please-controller/db/sqlc/repository"
|
|
||||||
"git.fossy.my.id/bagas/tunnel-please-controller/internal/config"
|
"git.fossy.my.id/bagas/tunnel-please-controller/internal/config"
|
||||||
|
"git.fossy.my.id/bagas/tunnel-please-controller/internal/db/sqlc/repository"
|
||||||
proto "git.fossy.my.id/bagas/tunnel-please-grpc/gen"
|
proto "git.fossy.my.id/bagas/tunnel-please-grpc/gen"
|
||||||
"github.com/lestrrat-go/jwx/v3/jwk"
|
"github.com/lestrrat-go/jwx/v3/jwk"
|
||||||
"github.com/lestrrat-go/jwx/v3/jwt"
|
"github.com/lestrrat-go/jwx/v3/jwt"
|
||||||
@@ -42,19 +42,19 @@ type Server struct {
|
|||||||
Database *repository.Queries
|
Database *repository.Queries
|
||||||
Subscribers map[string]*Subscriber
|
Subscribers map[string]*Subscriber
|
||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
authToken string
|
|
||||||
jwkCache *jwk.Cache
|
jwkCache *jwk.Cache
|
||||||
|
config config.Config
|
||||||
proto.UnimplementedEventServiceServer
|
proto.UnimplementedEventServiceServer
|
||||||
proto.UnimplementedUserServiceServer
|
proto.UnimplementedUserServiceServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(database *repository.Queries, authToken string, jwkCache *jwk.Cache) *Server {
|
func New(database *repository.Queries, jwkCache *jwk.Cache, config config.Config) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
Database: database,
|
Database: database,
|
||||||
Subscribers: make(map[string]*Subscriber),
|
Subscribers: make(map[string]*Subscriber),
|
||||||
mu: new(sync.RWMutex),
|
mu: new(sync.RWMutex),
|
||||||
authToken: authToken,
|
|
||||||
jwkCache: jwkCache,
|
jwkCache: jwkCache,
|
||||||
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ func (s *Server) Subscribe(event grpc.BidiStreamingServer[proto.Node, proto.Even
|
|||||||
return status.Error(codes.InvalidArgument, "missing identity")
|
return status.Error(codes.InvalidArgument, "missing identity")
|
||||||
}
|
}
|
||||||
token := payload.AuthEvent.AuthToken
|
token := payload.AuthEvent.AuthToken
|
||||||
if token != s.authToken {
|
if token != s.config.AuthToken() {
|
||||||
return status.Error(codes.Unauthenticated, "invalid auth token")
|
return status.Error(codes.Unauthenticated, "invalid auth token")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ func (s *Server) StartAPI(ctx context.Context, Addr string) error {
|
|||||||
WriteTimeout: 15 * time.Second,
|
WriteTimeout: 15 * time.Second,
|
||||||
IdleTimeout: 60 * time.Second,
|
IdleTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
jwkURL := config.Getenv("JWKS_URL", "")
|
jwkURL := s.config.JwksURL()
|
||||||
if jwkURL != "" {
|
if jwkURL != "" {
|
||||||
registerCtx, cancel := context.WithTimeout(ctx, jwkRegisterTimeout)
|
registerCtx, cancel := context.WithTimeout(ctx, jwkRegisterTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -629,6 +629,7 @@ func (s *Server) StartAPI(ctx context.Context, Addr string) error {
|
|||||||
|
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
|
log.Printf("Listening api on %s", httpServer.Addr)
|
||||||
errCh <- httpServer.ListenAndServe()
|
errCh <- httpServer.ListenAndServe()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -697,18 +698,19 @@ func (s *Server) StartController(ctx context.Context, Addr string) error {
|
|||||||
|
|
||||||
serveErr := make(chan error, 1)
|
serveErr := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
|
log.Printf("Listening controller on %s", s.config.ControllerAddr())
|
||||||
serveErr <- grpcServer.Serve(listener)
|
serveErr <- grpcServer.Serve(listener)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
grpcServer.GracefulStop()
|
grpcServer.GracefulStop()
|
||||||
err := <-serveErr
|
err = <-serveErr
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
case err := <-serveErr:
|
case err = <-serveErr:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +1,25 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"git.fossy.my.id/bagas/tunnel-please-controller/db/sqlc/repository"
|
"git.fossy.my.id/bagas/tunnel-please-controller/internal/bootstrap"
|
||||||
"git.fossy.my.id/bagas/tunnel-please-controller/server"
|
"git.fossy.my.id/bagas/tunnel-please-controller/internal/config"
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"github.com/lestrrat-go/httprc/v3"
|
|
||||||
"github.com/lestrrat-go/jwx/v3/jwk"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if _, err := os.Stat(".env"); err == nil {
|
|
||||||
if err = godotenv.Load(".env"); err != nil {
|
|
||||||
log.Printf("Warning: Failed to load .env file: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
||||||
defer stop()
|
|
||||||
|
|
||||||
log.SetOutput(os.Stdout)
|
log.SetOutput(os.Stdout)
|
||||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|
||||||
dbURL := os.Getenv("DATABASE_URL")
|
conf, err := config.MustLoad()
|
||||||
if dbURL == "" {
|
|
||||||
log.Fatal("DATABASE_URL is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
controllerAddr := getenv("CONTROLLER_ADDR", ":8080")
|
|
||||||
apiAddr := getenv("API_ADDR", ":8081")
|
|
||||||
authToken := getenv("AUTH_TOKEN", "")
|
|
||||||
if authToken == "" {
|
|
||||||
authToken = generateAuthToken()
|
|
||||||
log.Printf("No AUTH_TOKEN provided. Generated token: %s", authToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
connect, err := pgx.Connect(ctx, dbURL)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatalf("Config load error: %v", err)
|
||||||
}
|
}
|
||||||
defer func(connect *pgx.Conn, ctx context.Context) {
|
|
||||||
err = connect.Close(ctx)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}(connect, ctx)
|
|
||||||
|
|
||||||
repo := repository.New(connect)
|
boot := bootstrap.New(conf)
|
||||||
client := httprc.NewClient()
|
|
||||||
jwkCache, err := jwk.NewCache(ctx, client)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to initialize jwk cache : %s", err)
|
|
||||||
}
|
|
||||||
s := server.New(repo, authToken, jwkCache)
|
|
||||||
|
|
||||||
log.Printf("Listening controller on %s", controllerAddr)
|
if err = boot.Run(); err != nil {
|
||||||
log.Printf("Listening api on %s", apiAddr)
|
log.Fatalf("Application error: %v", err)
|
||||||
|
|
||||||
errCh := make(chan error, 2)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err = s.StartAPI(ctx, apiAddr); err != nil && !errors.Is(err, context.Canceled) {
|
|
||||||
errCh <- err
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err = s.StartController(ctx, controllerAddr); err != nil && !errors.Is(err, context.Canceled) {
|
|
||||||
errCh <- err
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
log.Printf("shutting down: %v", ctx.Err())
|
|
||||||
case err = <-errCh:
|
|
||||||
log.Fatalf("server error: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getenv(key, def string) string {
|
|
||||||
if val := os.Getenv(key); val != "" {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateAuthToken() string {
|
|
||||||
buf := make([]byte, 32)
|
|
||||||
if _, err := rand.Read(buf); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return base64.StdEncoding.EncodeToString(buf)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user