// Command exod is the gRPC backend daemon for the exo system. // It is the sole owner of the SQLite database and blob store. package main import ( "flag" "log" "net" "os" "os/signal" "syscall" "google.golang.org/grpc" "git.wntrmute.dev/kyle/exo/blob" "git.wntrmute.dev/kyle/exo/config" "git.wntrmute.dev/kyle/exo/db" pb "git.wntrmute.dev/kyle/exo/proto/exo/v1" "git.wntrmute.dev/kyle/exo/server" ) var version = "dev" func main() { var ( listenAddr = flag.String("listen", "", "gRPC listen address (default from config)") basePath = flag.String("base", "", "base data directory (default $HOME/exo)") showVer = flag.Bool("version", false, "print version and exit") ) flag.Parse() if *showVer { log.Printf("exod %s", version) os.Exit(0) } cfg := config.Default() if *basePath != "" { cfg = config.FromBasePath(*basePath) } if *listenAddr != "" { cfg.GRPCListenAddr = *listenAddr } // Ensure data directories exist. if err := os.MkdirAll(cfg.BasePath, 0o750); err != nil { log.Fatalf("exod: failed to create base directory: %v", err) } if err := os.MkdirAll(cfg.BlobStorePath, 0o750); err != nil { log.Fatalf("exod: failed to create blob store directory: %v", err) } // Open and migrate the database. database, err := db.Open(cfg.DatabasePath) if err != nil { log.Fatalf("exod: failed to open database: %v", err) } defer func() { _ = database.Close() }() if err := db.Migrate(database); err != nil { log.Fatalf("exod: failed to migrate database: %v", err) } blobStore := blob.NewStore(cfg.BlobStorePath) // Start gRPC server. lis, err := net.Listen("tcp", cfg.GRPCListenAddr) if err != nil { log.Fatalf("exod: failed to listen on %s: %v", cfg.GRPCListenAddr, err) } grpcServer := grpc.NewServer() pb.RegisterArtifactServiceServer(grpcServer, server.NewArtifactServer(database, blobStore)) // Graceful shutdown on SIGINT/SIGTERM. sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) go func() { sig := <-sigCh log.Printf("exod: received %s, shutting down", sig) grpcServer.GracefulStop() }() log.Printf("exod %s listening on %s", version, cfg.GRPCListenAddr) if err := grpcServer.Serve(lis); err != nil { log.Fatalf("exod: gRPC server error: %v", err) } }