@@ -92,6 +92,7 @@ func cmdServe(args []string) error {
9292 withSync := fs .Bool ("sync" , false , "run the incremental sync loop inside the server" )
9393 importAttachments := fs .String ("import-attachments" , "" ,
9494 "seed the attachment cache from a directory holding manifest.json (see examples/attachments)" )
95+ noOpen := fs .Bool ("no-open" , false , "do not open the browser after the server starts" )
9596 if err := fs .Parse (args ); err != nil {
9697 return err
9798 }
@@ -207,6 +208,9 @@ func cmdServe(args []string) error {
207208 if len (cfg .Projects ) == 0 {
208209 log .Printf ("no projects configured — run `scry init`" )
209210 }
211+ if ! * noOpen {
212+ go openOnceUp (browseAddr (* addr ))
213+ }
210214 err = srv .ListenAndServe ()
211215 if err == http .ErrServerClosed {
212216 return nil
@@ -574,6 +578,7 @@ func cmdDemo(args []string) error {
574578 addr := fs .String ("addr" , "127.0.0.1:7878" , "listen address" )
575579 static := fs .String ("static" , "dist/app" , "directory holding the built web UI" )
576580 dbPath := fs .String ("db" , "examples/demo.db" , "snapshot to serve" )
581+ noOpen := fs .Bool ("no-open" , false , "do not open the browser after the server starts" )
577582 if err := fs .Parse (args ); err != nil {
578583 return err
579584 }
@@ -608,7 +613,41 @@ func cmdDemo(args []string) error {
608613 }
609614 log .Printf ("demo mirror in %s (deleted on exit)" , home )
610615 defer os .RemoveAll (home )
611- return cmdServe ([]string {"--addr" , * addr , "--static" , * static })
616+ serveArgs := []string {"--addr" , * addr , "--static" , * static }
617+ if * noOpen {
618+ serveArgs = append (serveArgs , "--no-open" )
619+ }
620+ return cmdServe (serveArgs )
621+ }
622+
623+ // browseAddr turns a listen address into the URL a person should visit:
624+ // a blank or wildcard host becomes localhost.
625+ func browseAddr (addr string ) string {
626+ host , port , err := net .SplitHostPort (addr )
627+ if err != nil {
628+ return "http://" + addr
629+ }
630+ if host == "" || host == "0.0.0.0" || host == "::" {
631+ host = "localhost"
632+ }
633+ return "http://" + net .JoinHostPort (host , port )
634+ }
635+
636+ // openOnceUp opens the browser as soon as the server answers /healthz, so the
637+ // tab never lands on a connection error. Gives up quietly after ~5s — a browser
638+ // failing to open must never take the server down with it.
639+ func openOnceUp (u string ) {
640+ for i := 0 ; i < 50 ; i ++ {
641+ res , err := http .Get (u + "/healthz" )
642+ if err == nil {
643+ res .Body .Close ()
644+ if err := openBrowser (u ); err != nil {
645+ log .Printf ("could not open a browser: %v — visit %s" , err , u )
646+ }
647+ return
648+ }
649+ time .Sleep (100 * time .Millisecond )
650+ }
612651}
613652
614653func cmdProfiles () error {
0 commit comments