This commit is contained in:
MengYX 2020-11-07 16:27:58 +08:00
commit 75ac1466c7
No known key found for this signature in database
GPG Key ID: E63F9C7303E8F604
6 changed files with 283 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
build

132
builder/main.go Normal file
View File

@ -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
}

79
builder/version.go Normal file
View File

@ -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
}

9
go.mod Normal file
View File

@ -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
)

9
go.sum Normal file
View File

@ -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=

52
main.go Normal file
View File

@ -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}
}