Init
This commit is contained in:
commit
75ac1466c7
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea
|
||||
build
|
132
builder/main.go
Normal file
132
builder/main.go
Normal 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
79
builder/version.go
Normal 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
9
go.mod
Normal 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
9
go.sum
Normal 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
52
main.go
Normal 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}
|
||||
}
|
Reference in New Issue
Block a user