package main import ( "context" "flag" "log" "net/http" "os" "os/exec" "os/signal" "path/filepath" "sync" "syscall" "time" ) var ( devMode = flag.Bool("dev", false, "Run yarn autoreload underneath Go") ) const ( publicWebPath = "./web/public/" ) func main() { flag.Parse() var wg sync.WaitGroup c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) ctx, cancel := context.WithCancel(context.Background()) go func() { oscall := <-c log.Printf("system call:%+v", oscall) cancel() }() wg.Add(1) go serveHTTP(ctx, &wg) if *devMode { wg.Add(1) go runYarn(ctx, &wg) } wg.Wait() } func serveHTTP(ctx context.Context, wg *sync.WaitGroup) { fs := http.FileServer(http.Dir(publicWebPath)) mux := http.NewServeMux() mux.Handle("/", fs) srv := &http.Server{ Addr: ":5000", Handler: mux, } go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen:%+s\n", err) } }() log.Printf("Listening on port :5000") <-ctx.Done() log.Printf("server stopped") ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctxShutDown); err != nil { if err != http.ErrServerClosed { log.Fatalf("server Shutdown Failed:%+s", err) } } log.Printf("server exited properly") wg.Done() return } func runYarn(ctx context.Context, wg *sync.WaitGroup) { var err error cmd := exec.Command("yarn", "dev") cmd.Env = append(cmd.Env, "SKIP_SERVE=1") cmd.Dir, err = filepath.Abs("./web/") cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err != nil { panic(err) } err = cmd.Start() if err != nil { panic(err) } <-ctx.Done() log.Println("closing") err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) if err != nil { panic(err) } wg.Done() return }