main.go raw

   1  // orly-launcher is a process supervisor that manages the database and relay
   2  // processes in split mode. It starts the database server first, waits for it
   3  // to be ready, then starts the relay with the gRPC database backend.
   4  package main
   5  
   6  import (
   7  	"context"
   8  	"fmt"
   9  	"os"
  10  	"os/signal"
  11  	"syscall"
  12  
  13  	"next.orly.dev/pkg/lol/chk"
  14  	"next.orly.dev/pkg/lol/log"
  15  	"next.orly.dev/pkg/version"
  16  )
  17  
  18  func main() {
  19  	cfg, err := loadConfig()
  20  	if err != nil {
  21  		fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err)
  22  		os.Exit(1)
  23  	}
  24  
  25  	// Handle version request
  26  	if len(os.Args) > 1 && (os.Args[1] == "version" || os.Args[1] == "-v" || os.Args[1] == "--version") {
  27  		fmt.Println(version.V)
  28  		os.Exit(0)
  29  	}
  30  
  31  	// Handle help request
  32  	if len(os.Args) > 1 && (os.Args[1] == "help" || os.Args[1] == "-h" || os.Args[1] == "--help") {
  33  		printHelp()
  34  		os.Exit(0)
  35  	}
  36  
  37  	ctx, cancel := context.WithCancel(context.Background())
  38  	defer cancel()
  39  
  40  	supervisor := NewSupervisor(ctx, cancel, cfg)
  41  
  42  	// Handle shutdown signals
  43  	sigChan := make(chan os.Signal, 1)
  44  	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
  45  
  46  	go func() {
  47  		sig := <-sigChan
  48  		log.I.F("received signal %v, shutting down...", sig)
  49  		cancel()
  50  	}()
  51  
  52  	log.I.F("starting orly-launcher %s", version.V)
  53  	if cfg.ServicesEnabled {
  54  		log.I.F("database binary: %s", cfg.DBBinary)
  55  		log.I.F("relay binary: %s", cfg.RelayBinary)
  56  		log.I.F("database listen: %s", cfg.DBListen)
  57  	} else {
  58  		log.I.F("services disabled - running admin UI only")
  59  	}
  60  
  61  	// Start admin server if enabled
  62  	var adminServer *AdminServer
  63  	if cfg.AdminEnabled {
  64  		adminServer = NewAdminServer(cfg, supervisor)
  65  
  66  		// Ensure binary directory structure exists
  67  		if err := adminServer.updater.EnsureDirectories(); chk.E(err) {
  68  			log.W.F("failed to create binary directories: %v", err)
  69  		}
  70  
  71  		go func() {
  72  			if err := adminServer.Start(ctx); err != nil {
  73  				// Don't exit on admin server error, just log it
  74  				log.W.F("admin server stopped: %v", err)
  75  			}
  76  		}()
  77  		log.I.F("admin UI available at http://localhost:%d/admin", cfg.AdminPort)
  78  		if len(cfg.AdminOwners) > 0 {
  79  			log.I.F("admin owners: %v", cfg.AdminOwners)
  80  		} else {
  81  			log.W.F("no admin owners configured - admin API access disabled")
  82  		}
  83  	}
  84  
  85  	// Only start services if enabled
  86  	if cfg.ServicesEnabled {
  87  		if err := supervisor.Start(); chk.E(err) {
  88  			fmt.Fprintf(os.Stderr, "failed to start: %v\n", err)
  89  			os.Exit(1)
  90  		}
  91  	}
  92  
  93  	// Wait for context cancellation (signal received)
  94  	<-ctx.Done()
  95  
  96  	if cfg.ServicesEnabled {
  97  		log.I.F("stopping supervisor...")
  98  		if err := supervisor.Stop(); chk.E(err) {
  99  			log.E.F("error during shutdown: %v", err)
 100  		}
 101  	}
 102  
 103  	log.I.F("orly-launcher stopped")
 104  }
 105  
 106  func printHelp() {
 107  	fmt.Printf(`orly-launcher %s
 108  
 109  Process supervisor for split-mode deployment of ORLY relay with admin web UI.
 110  
 111  Usage: orly-launcher [command]
 112  
 113  Commands:
 114    help, -h, --help       Show this help
 115    version, -v, --version Show version
 116  
 117  Environment Variables:
 118    Process Management:
 119      ORLY_LAUNCHER_SERVICES_ENABLED Start DB/relay on launch (default: true)
 120      ORLY_LAUNCHER_DB_BINARY        Path to orly-db binary (default: orly-db-{backend})
 121      ORLY_LAUNCHER_RELAY_BINARY     Path to orly binary (default: orly)
 122      ORLY_LAUNCHER_ACL_BINARY       Path to orly-acl binary (default: orly-acl-{mode})
 123      ORLY_LAUNCHER_DB_BACKEND       Database backend: badger, neo4j (default: badger)
 124      ORLY_LAUNCHER_DB_LISTEN        Address for database server (default: 127.0.0.1:50051)
 125      ORLY_LAUNCHER_ACL_LISTEN       Address for ACL server (default: 127.0.0.1:50052)
 126      ORLY_LAUNCHER_ACL_ENABLED      Enable ACL server (default: false)
 127      ORLY_ACL_MODE                  ACL mode: follows, managed, curation (default: follows)
 128      ORLY_LAUNCHER_DB_READY_TIMEOUT Timeout waiting for DB ready (default: 30s)
 129      ORLY_LAUNCHER_STOP_TIMEOUT     Timeout for graceful stop (default: 30s)
 130      ORLY_DATA_DIR                  Data directory (passed to orly-db)
 131      ORLY_LOG_LEVEL                 Log level for all processes (default: info)
 132  
 133    Admin UI:
 134      ORLY_LAUNCHER_ADMIN_ENABLED    Enable admin HTTP server (default: true)
 135      ORLY_LAUNCHER_ADMIN_PORT       Admin server port (default: 8080)
 136      ORLY_LAUNCHER_OWNERS           Comma-separated hex pubkeys for admin access
 137      ORLY_LAUNCHER_BIN_DIR          Directory for versioned binaries
 138  
 139  The launcher will:
 140  1. Start the admin HTTP server (optional)
 141  2. Start the database server (orly-db)
 142  3. Wait for the database to be ready
 143  4. Start the ACL server if enabled (orly-acl)
 144  5. Start sync services if enabled
 145  6. Start the relay (orly) with ORLY_DB_TYPE=grpc
 146  7. Monitor all processes and restart if they crash
 147  8. On shutdown, stop in reverse dependency order
 148  
 149  Admin UI Features:
 150  - View process status and versions
 151  - Update binaries from release URLs
 152  - Edit configuration
 153  - Restart/rollback binaries
 154  
 155  Example:
 156    # Start with default binaries in PATH
 157    orly-launcher
 158  
 159    # Start with admin access for a specific pubkey
 160    ORLY_LAUNCHER_OWNERS=abc123... orly-launcher
 161  
 162    # Start with custom binary paths
 163    ORLY_LAUNCHER_DB_BINARY=/opt/orly/orly-db-badger \
 164    ORLY_LAUNCHER_RELAY_BINARY=/opt/orly/orly \
 165    orly-launcher
 166  `, version.V)
 167  }
 168