func Example() { // Create file watcher watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatalln(err) } defer watcher.Close() // Watch dir err = watcher.Watch("/path/to/watched/dir") if err != nil { log.Fatalln(err) } // Start LiveReload server lr, err := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort) if err != nil { log.Fatalln(err) } go lr.ListenAndServe() // Start goroutine that requests reload upon watcher event go func() { for { event := <-watcher.Event lr.Reload(event.Name) } }() // Start serving html http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) { rw.Write([]byte(html)) }) http.ListenAndServe(":3000", nil) }
// launchServer sets up the http fileserver. Exciting! func launchServer() { r := mux.NewRouter(). StrictSlash(true) // Grab all our config junk and prepare to launch ip := viper.GetString("ListenAddr") port := viper.GetInt("ListenPort") fmt.Println(viper.GetInt("ListenPort")) // I... I guess, if you want TLS, you can totally have it cert, key := viper.GetString("CertFile"), viper.GetString("KeyFile") useTLS := len(cert) > 0 && len(key) > 0 scheme := "https" if !useTLS { if port == 0 { port = 80 } scheme = "http" } else if port == 0 { port = 443 } p := fmt.Sprintf("%s:%d", ip, port) root, files := viper.GetString("ServerRoot"), viper.GetString("StaticFiles") reload, err := lr.New(lr.DefaultName, lr.DefaultPort) if err != nil { fmt.Println(err) os.Exit(1) } go reload.ListenAndServe() r.PathPrefix(root). Handler( handlers.CombinedLoggingHandler( os.Stdout, injectReload(root, files, scheme), ), ) go func() { fmt.Printf("Launching ogload on %s\n", p) if !useTLS { if err := http.ListenAndServe(p, r); err != nil { fmt.Printf("Server failed! scheme=%s, addr=%s, err=%v\n", scheme, p, err) os.Exit(1) } return } if err := http.ListenAndServeTLS(p, cert, key, r); err != nil { fmt.Printf("TLS Server failed! scheme=%s, addr=%s, err=%v\n", scheme, p, err) os.Exit(1) } }() wait := watchDir(files, reload) <-wait }
func start() { lr := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort) go lr.ListenAndServe() loopIndex := 0 buildDelay := buildDelay() started := false go func() { for { loopIndex++ mainLog("Waiting (loop %d)...", loopIndex) eventName := <-startChannel mainLog("receiving first event %s", eventName) mainLog("sleeping for %d milliseconds", buildDelay) time.Sleep(buildDelay * time.Millisecond) mainLog("flushing events") flushEvents() mainLog("Started! (%d Goroutines)", runtime.NumGoroutine()) err := removeBuildErrorsLog() if err != nil { mainLog(err.Error()) } errorMessage, ok := build() if !ok { mainLog("Build Failed: \n %s", errorMessage) if !started { os.Exit(1) } createBuildErrorsLog(errorMessage) } else { if started { stopChannel <- true } run() liveReload(eventName, lr) } started = true mainLog(strings.Repeat("-", 20)) } }() }
//NewServer creates a new Server func NewHandler(c Config) (http.Handler, error) { s := &Handler{ c: c, served: map[string]bool{}, } _, err := os.Stat(c.Directory) if c.Directory == "" || err != nil { return nil, fmt.Errorf("Missing directory: %s", c.Directory) } if c.PushState { s.root = filepath.Join(c.Directory, "index.html") if _, err := os.Stat(s.root); err != nil { return nil, fmt.Errorf("'%s' is required for pushstate", s.root) } s.hasIndex = true } if c.Fallback != "" { u, err := url.Parse(c.Fallback) if err != nil { return nil, err } if !strings.HasPrefix(u.Scheme, "http") { return nil, fmt.Errorf("Invalid fallback protocol scheme") } s.fallbackHost = u.Host s.fallback = httputil.NewSingleHostReverseProxy(u) } if c.LiveReload { s.lr, _ = lrserver.New("serve-lr", lrserver.DefaultPort) discard := log.New(ioutil.Discard, "", 0) s.lr.SetErrorLog(discard) s.lr.SetStatusLog(discard) s.watching = map[string]bool{} s.watcher, err = fsnotify.NewWatcher() if err != nil { return nil, err } } if s.c.LiveReload { go func() { if err := s.lr.ListenAndServe(); err != nil { fmt.Printf("LiveReload server closed: %s", err) } }() go func() { for { event := <-s.watcher.Events switch event.Op { case fsnotify.Create, fsnotify.Rename, fsnotify.Write: s.lr.Reload(event.Name) case fsnotify.Remove: if s.watching[event.Name] { delete(s.watching, event.Name) } } } }() } h := http.Handler(s) //logging is enabled if !c.Quiet { h = requestlog.WrapWith(h, requestlog.Options{TimeFormat: c.TimeFmt}) } //listen return h, nil }
func run(ctx *cli.Context) { watchDirs := ctx.StringSlice("watch") services := ctx.StringSlice("service") watcher, err := fsnotify.NewWatcher() if err != nil { fmt.Fprintf(os.Stderr, "error setting up file watcher: %v", err) } for _, d := range watchDirs { watcher.Add(d) } defer watcher.Close() lr, err := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort) if err != nil { fmt.Fprintf(os.Stderr, "error starting live reload: %v", err) } go lr.ListenAndServe() composeBin, err := exec.LookPath("docker-compose") if err != nil { fmt.Fprintf(os.Stderr, "could not find docker-compose path") os.Exit(1) } var cmd *exec.Cmd var t <-chan time.Time var ignore bool MainLoop: for { select { case e := <-watcher.Events: select { case <-t: ignore = false default: if ignore { continue MainLoop } match, _ := filepath.Match("*.sw*", e.Name) if match || strings.HasSuffix(e.Name, "~") { continue MainLoop } } if len(services) == 0 { cmd = exec.Command(composeBin, "up") } else { args := []string{"up", "--no-deps"} args = append(args, services...) cmd = exec.Command(composeBin, args...) } cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { fmt.Fprintf(os.Stderr, "error reloading compose file: %v", err) } ignore = true time.Sleep(1 * time.Second) lr.Reload("") t = time.After(3 * time.Second) case err := <-watcher.Errors: fmt.Fprintf(os.Stderr, "error watching files: %v", err) os.Exit(1) } } }