From 75ac1466c77b98a77e9e9b7f0fe815181032cc6e Mon Sep 17 00:00:00 2001 From: MengYX Date: Sat, 7 Nov 2020 16:27:58 +0800 Subject: [PATCH] Init --- .gitignore | 2 + builder/main.go | 132 +++++++++++++++++++++++++++++++++++++++++++++ builder/version.go | 79 +++++++++++++++++++++++++++ go.mod | 9 ++++ go.sum | 9 ++++ main.go | 52 ++++++++++++++++++ 6 files changed, 283 insertions(+) create mode 100644 .gitignore create mode 100644 builder/main.go create mode 100644 builder/version.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4afcf19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +build \ No newline at end of file diff --git a/builder/main.go b/builder/main.go new file mode 100644 index 0000000..b89ef45 --- /dev/null +++ b/builder/main.go @@ -0,0 +1,132 @@ +package main + +import ( + "archive/tar" + "compress/gzip" + "github.com/tidwall/gjson" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "path" + "strconv" + "time" +) + +const buildTempDir = "./build" +const checkVersionUrl = "https://api.github.com/repos/ix64/unlock-music/releases/latest" +const assetFilename = "modern.tar.gz" +const checksumFilename = "sha256sum.txt" + +func main() { + if err := checkTempDirExist(); err != nil { + log.Fatal(err) + } + log.Println("gathering version info: " + checkVersionUrl) + v, err := getLatestVersionInfo() + if err != nil { + log.Fatal(err) + } + for i := 0; i < 3; i++ { + + if !v.checkAssetExist() { + log.Printf("downloading %s to %s\n", v.AssetUrl, v.getAssetPath("")) + if err := v.downloadAsset(); err != nil { + log.Fatal(err) + } + } + log.Printf("gathering checksum info: %s\n", v.ChecksumUrl) + expect, err := v.downloadChecksum() + if err != nil { + log.Fatal(err) + } + log.Printf("checksum of %s should be: %s\n", assetFilename, expect) + + actual, err := v.calcAssetChecksum() + if err != nil { + log.Fatal(err) + } + log.Printf("checksum of %s is: %s\n", assetFilename, actual) + + if expect != actual { + newFilename := v.getAssetPath("unexpected-" + strconv.FormatInt(time.Now().Unix(), 10) + "-") + if err := os.Rename(v.getAssetPath(""), newFilename); err != nil { + log.Fatal(err) + } + } else { + if err := unArchive(v.getAssetPath(""), path.Join(buildTempDir, "for-build")); err != nil { + log.Fatal(err) + } + return + } + } + log.Fatal("failed for 3 times") +} + +func checkTempDirExist() error { + _, err := os.Stat(buildTempDir) + if os.IsNotExist(err) { + err = os.Mkdir(buildTempDir, 0755) + } + return err +} + +func getLatestVersionInfo() (info *versionInfo, err error) { + resp, err := http.Get(checkVersionUrl) + if err != nil { + return + } + defer resp.Body.Close() + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return + } + asset := gjson.GetBytes(respBody, "assets.#(name="+assetFilename+")") + checksum := gjson.GetBytes(respBody, "assets.#(name="+checksumFilename+")") + return &versionInfo{ + Version: gjson.GetBytes(respBody, "tag_name").String(), + ChecksumUrl: checksum.Get("browser_download_url").String(), + AssetUrl: asset.Get("browser_download_url").String(), + AssetSize: asset.Get("size").Int(), + }, nil +} +func unArchive(source string, destination string) error { + src, err := os.Open(source) + if err != nil { + return nil + } + defer src.Close() + uncompressed, err := gzip.NewReader(src) + if err != nil { + return nil + } + arc := tar.NewReader(uncompressed) + for { + var f *tar.Header + f, err = arc.Next() + if err != nil { + if err != io.EOF { + return err + } + break + } + if f.FileInfo().IsDir() { + err = os.MkdirAll(path.Join(destination, f.Name), 0755) + if err != nil { + return err + } + } else { + dst, err := os.OpenFile(path.Join(destination, f.Name), os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + _, err = io.CopyN(dst, arc, f.Size) + dst.Close() + if err != nil { + return err + } + } + } + return nil +} diff --git a/builder/version.go b/builder/version.go new file mode 100644 index 0000000..b5521fa --- /dev/null +++ b/builder/version.go @@ -0,0 +1,79 @@ +package main + +import ( + "bufio" + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "net/http" + "os" + "path" + "strings" +) + +type versionInfo struct { + Version string + ChecksumUrl string + AssetUrl string + AssetSize int64 +} + +func (v versionInfo) getAssetPath(prefix string) string { + return path.Join(buildTempDir, prefix+v.Version+"_"+assetFilename) +} + +func (v versionInfo) checkAssetExist() bool { + _, err := os.Stat(v.getAssetPath("")) + return !os.IsNotExist(err) +} + +func (v versionInfo) downloadAsset() (err error) { + file, err := os.OpenFile(v.getAssetPath(""), os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return + } + defer file.Close() + + resp, err := http.Get(v.AssetUrl) + if err != nil { + return + } + defer resp.Body.Close() + _, err = io.Copy(file, resp.Body) + return err +} + +func (v versionInfo) downloadChecksum() (checksum string, err error) { + resp, err := http.Get(v.ChecksumUrl) + if err != nil { + return + } + defer resp.Body.Close() + r := bufio.NewReader(resp.Body) + var line []byte + for err == nil { + line, _, err = r.ReadLine() + lineStr := string(line) + if strings.Contains(lineStr, assetFilename) { + checksum = strings.ToLower(strings.TrimSpace(strings.Split(lineStr, " ")[0])) + return + } + } + return "", fmt.Errorf("checksum for %s not found", assetFilename) +} + +func (v versionInfo) calcAssetChecksum() (checksum string, err error) { + file, err := os.Open(v.getAssetPath("")) + if err != nil { + return + } + defer file.Close() + sha := sha256.New() + _, err = io.Copy(sha, file) + if err != nil { + return + } + checksum = hex.EncodeToString(sha.Sum(nil)) + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cef510d --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module github.com/unlock-music/simple-server + +go 1.16 + +require ( + github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 + github.com/tidwall/gjson v1.6.3 + github.com/tidwall/match v1.0.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ce117e0 --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI= +github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.0.2 h1:uuqvHuBGSedK7awZ2YoAtpnimfwBGFjHuWLuLqQj+bU= +github.com/tidwall/match v1.0.2/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d910135 --- /dev/null +++ b/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "embed" + _ "embed" + "github.com/pkg/browser" + "io/fs" + "log" + "net/http" + "os" + "os/signal" + "path" +) + +//go:generate go run ./builder +//go:embed build/for-build +var asset embed.FS + +func main() { + pfxFs := WithPrefix(asset, "build/for-build") + go func() { + err := http.ListenAndServe("localhost:6280", http.FileServer(http.FS(pfxFs))) + if err != nil { + log.Fatal(err) + } + }() + log.Println("you can now open browser with: http://localhost:6280 to access this tool.") + err := browser.OpenURL("http://localhost:6280") + if err != nil { + log.Println("error while opening browser:", err) + } + sign := make(chan os.Signal, 1) + signal.Notify(sign, os.Interrupt, os.Kill) + <-sign +} + +type WrappedFS struct { + inner fs.FS + prefix string +} + +func (f WrappedFS) Open(p string) (fs.File, error) { + p = path.Join(f.prefix, p) + log.Printf("serving: %s\n", p) + return f.inner.Open(p) +} + +// same thing but for ReadFile, Stat, ReadDir, Glob, and maybe Rename, OpenFile? + +func WithPrefix(f fs.FS, p string) WrappedFS { + return WrappedFS{f, p} +}