spoon icon indicating copy to clipboard operation
spoon copied to clipboard

where this looks for its updates

Open joeblew99 opened this issue 9 years ago • 3 comments

I might have this wrong, but i assumed that this looks for a new binary from a server, and then does the update (without forking :) )

The example does not show the server being involved.

the other one i am playing with is this right now. https://github.com/sanbornm/go-selfupdate

joeblew99 avatar Dec 22 '16 12:12 joeblew99

@joeblew99 this package doesn't actually look for anything, it's completely up to you how to grab the updated binary... I'll get a simple example up for you sometime later today, it's pretty simple using http.

I do intend to update this package to use https://github.com/go-playground/kms for the graceful shutdown portion of the logic.

deankarn avatar Dec 22 '16 12:12 deankarn

thanks for the update.

btw https://github.com/sanbornm/go-selfupdate code has a nice way to package code for each golang OS ARCH and upload it to the Update Server. They have put alot of functionality into it.

On Thu, Dec 22, 2016 at 1:41 PM Dean Karn [email protected] wrote:

@joeblew99 https://github.com/joeblew99 this package doesn't actually look for anything, it's completely up to you how to grab the updated binary... I'll get a simple example up for you sometime later today, it's pretty simple using http.

I do intend to update this package to use https://github.com/go-playground/kms for the graceful shutdown portion of the logic.

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/go-playground/spoon/issues/1#issuecomment-268791893, or mute the thread https://github.com/notifications/unsubscribe-auth/ALcac47bUH-7HyTj89O0zb0L9kdZfcYZks5rKnALgaJpZM4LT7BX .

joeblew99 avatar Dec 22 '16 14:12 joeblew99

Thanks @joeblew99, our packages are a little different though, I not only update the binary but also allow for restarting the application gracefully after the update as well.

This package is not yet v1.0, need to integrate my kms for better graceful shutdown of an entire application not just http; also because of the current signal I believe this will only work on *nix systems and not windows...yet.

so here is a quick example of updating and restarting:

// server

checksum := func(checksumOnly bool, path string, w http.ResponseWriter, r *http.Request) {

		existingChecksum := r.Header.Get(updateCurrentChecksumKey)
		if existingChecksum == "" {
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return
		}

		_, err := os.Stat(path)
		if err != nil {
			// no file exists on disk
			return
		}

		f, err := os.Open(path)
		if err != nil {
			http.Error(w, "Error Opening File", http.StatusInternalServerError)
			return
		}
		defer f.Close()

		hash := sha256.New()
		_, err = io.Copy(hash, f)
		if err != nil {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}

		currentChecksum := fmt.Sprintf("%x", string(hash.Sum(nil)))

		// current version is equal, nothing to update.
		if existingChecksum == currentChecksum {
			return
		}

		w.Header().Set("checksum", currentChecksum)

		if checksumOnly {
			return
		}

		// reset file
		f.Seek(0, 0)

		_, err = io.Copy(w, f)
		if err != nil {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
	}

	fn := func(w http.ResponseWriter, r *http.Request) {

		if r.Method != "GET" && r.Method != "HEAD" {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}

		apiKey := r.Header.Get(updateAPIKey)

		if apiKey != fnAPIKey {
			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
			return
		}

		checksum(r.Method == "HEAD", updatePath, w, r)
	}

// use fn as http handler
// client

req, err := http.NewRequest("GET", updateURL, nil)
		if err != nil {
			panic(err)
		}
		req.Header.Set("Update-Api-Key", updateAPIKey)

		upgradeFn = func() {

			m.Lock()
			defer m.Unlock()

			cc := sp.Checksum()

			// request upgrade...
			client := &http.Client{}

			req.Method = "HEAD"
			req.Header.Set("Current-Checksum", cc)

			resp, err := client.Do(req)
			if err != nil {
				return
			}
			defer resp.Body.Close()

			checksum := resp.Header.Get("checksum")
			if checksum == "" {
				return
			}

			// there are updates....processing
			req.Method = "GET"

			resp, err = client.Do(req)
			if err != nil {
				return
			}
			defer resp.Body.Close()

			if err = sp.UpgradeFullBinary(resp.Body, checksum); err != nil {
				return
			}
		}

// run upgradeFn in a CRON job

deankarn avatar Dec 23 '16 03:12 deankarn