func autoUpdate(s mvc.State, token string) { tryAgain := true params := make(url.Values) params.Add("version", version.MajorMinor()) params.Add("os", runtime.GOOS) params.Add("arch", runtime.GOARCH) params.Add("user", token) updateUrl := updateEndpoint + "?" + params.Encode() checkUrl := checkEndpoint + "?" + params.Encode() update := func() { log.Info("Checking for update") available, err := update.NewDownload(checkUrl).Check() if err != nil { log.Error("Error while checking for update: %v", err) return } if !available { log.Info("No update available") return } // stop trying after a single download attempt // XXX: improve this so the we can: // 1. safely update multiple times // 2. only retry after a network connection failure tryAgain = false download := update.NewDownload(updateUrl) downloadComplete := make(chan int) go progressWatcher(s, download.Progress, downloadComplete) log.Info("Trying to update . . .") err, errRecover := download.GetAndUpdate() <-downloadComplete if err != nil { // log error to console log.Error("Error while updating ngrok: %v", err) if errRecover != nil { log.Error("Error while recovering from failed ngrok update, your binary may be missing: %v", errRecover.Error()) params.Add("errorRecover", errRecover.Error()) } // log error to ngrok.com's servers for debugging purposes params.Add("error", err.Error()) resp, reportErr := http.PostForm("https://dl.ngrok.com/update/error", params) if err != nil { log.Error("Error while reporting update error: %v, %v", err, reportErr) } resp.Body.Close() // tell the user to update manually s.SetUpdateStatus(mvc.UpdateAvailable) } else { if !download.Available { // this is the way the server tells us to update manually log.Info("Server wants us to update manually") s.SetUpdateStatus(mvc.UpdateAvailable) } else { // tell the user the update is ready log.Info("Update ready!") s.SetUpdateStatus(mvc.UpdateReady) } } return } // try to update immediately and then at a set interval update() for _ = range time.Tick(updateCheckInterval) { if !tryAgain { break } update() } }
func autoUpdate(s *State, ctl *ui.Controller, token string) { update := func() (updateSuccessful bool) { params := make(url.Values) params.Add("version", version.MajorMinor()) params.Add("os", runtime.GOOS) params.Add("arch", runtime.GOARCH) download := update.NewDownload() downloadComplete := make(chan int) go func() { for { select { case progress, ok := <-download.Progress: if !ok { close(downloadComplete) return } else if progress == 100 { s.update = ui.UpdateInstalling ctl.Update(s) close(downloadComplete) return } else { if progress%25 == 0 { log.Info("Downloading update %d%% complete", progress) } s.update = ui.UpdateStatus(progress) ctl.Update(s) } } } }() log.Info("Checking for update") err := download.UpdateFromUrl(updateEndpoint + "?" + params.Encode()) <-downloadComplete if err != nil { log.Error("Error while updating ngrok: %v", err) if download.Available { s.update = ui.UpdateError } else { s.update = ui.UpdateNone } // record the error to ngrok.com's servers for debugging purposes params.Add("error", err.Error()) params.Add("user", token) resp, err := http.PostForm("https://dl.ngrok.com/update/error", params) if err != nil { log.Error("Error while reporting update error") } resp.Body.Close() } else { if download.Available { log.Info("Marked update ready") s.update = ui.UpdateReady updateSuccessful = true } else { log.Info("No update available at this time") s.update = ui.UpdateNone } } ctl.Update(s) return } // try to update immediately and then at a set interval update() for _ = range time.Tick(updateCheckInterval) { if update() { // stop trying to update if the update function is successful // XXX: improve this by trying to download versions newer than // the last one we downloaded return } } }