marky.go (2262B)
1 package main 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "log" 8 "net/http" 9 "os" 10 "os/signal" 11 "syscall" 12 "time" 13 14 dbpkg "git.sr.ht/~dce/marky/internal" 15 ) 16 17 func main() { 18 // Resolve default DB path from internal package. 19 defaultDBPath, _ := dbpkg.DefaultPath() 20 21 // Usage/help 22 flag.Usage = func() { 23 fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options]\n\n", os.Args[0]) 24 fmt.Fprintf(flag.CommandLine.Output(), "Options:\n") 25 flag.PrintDefaults() 26 } 27 28 // Flags 29 addr := flag.String("addr", ":8080", "listen address (e.g. :8080, 127.0.0.1:8080)") 30 dbPath := flag.String("db", defaultDBPath, "path to SQLite DB file (created if missing)") 31 disableSignup := flag.Bool("disable-signup", false, "disable signup endpoint and hide from UI") 32 baseURL := flag.String("base-url", "", "public base URL (e.g. https://bookmarks.example.com)") 33 34 // Also accept explicit --help to exit 0 with usage. 35 for _, a := range os.Args[1:] { 36 if a == "--help" { 37 flag.Usage() 38 return 39 } 40 } 41 42 flag.Parse() 43 44 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) 45 defer stop() 46 47 // Open database (creates and migrates if needed) 48 db, err := dbpkg.OpenAtPath(ctx, *dbPath) 49 if err != nil { 50 log.Fatalf("open db: %v", err) 51 } 52 defer db.Close() 53 54 // Build the shared HTTP handler (API + UI) 55 h, err := dbpkg.NewHandlerWithConfig(db, dbpkg.HandlerConfig{ 56 DisableSignup: *disableSignup, 57 BaseURL: *baseURL, 58 }) 59 if err != nil { 60 log.Fatalf("build handler: %v", err) 61 } 62 63 srv := &http.Server{ 64 Addr: *addr, 65 Handler: logging(h), 66 ReadHeaderTimeout: 5 * time.Second, 67 } 68 69 go func() { 70 log.Printf("marky API listening on %s", srv.Addr) 71 if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { 72 log.Fatalf("server error: %v", err) 73 } 74 }() 75 76 <-ctx.Done() 77 shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 78 defer cancel() 79 if err := srv.Shutdown(shutdownCtx); err != nil { 80 log.Printf("server shutdown error: %v", err) 81 } 82 } 83 84 func logging(next http.Handler) http.Handler { 85 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 86 start := time.Now() 87 next.ServeHTTP(w, r) 88 log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start)) 89 }) 90 }