增加检查更新
This commit is contained in:
parent
31c7d18db7
commit
439d979bbb
|
@ -43,8 +43,9 @@ jobs:
|
|||
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
||||
if $IS_PR ; then echo $PR_PROMPT; fi
|
||||
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
||||
export LD_FLAGS="-w -s -X main.Version=${COMMIT_ID::7}"
|
||||
go mod tidy
|
||||
go build -o "output/$BINARY_NAME" ./
|
||||
go build -o "output/$BINARY_NAME" -trimpath -ldflags "$LD_FLAGS" ./
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ !github.head_ref }}
|
||||
|
|
3
go.mod
3
go.mod
|
@ -6,11 +6,14 @@ replace github.com/willf/bitset v1.2.1 => github.com/bits-and-blooms/bitset v1.2
|
|||
|
||||
require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/gin-gonic/gin v1.7.1
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0-beta.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/guonaihong/gout v0.2.9
|
||||
github.com/imroc/req/v3 v3.8.2
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
github.com/klauspost/compress v1.15.5
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/makiuchi-d/gozxing v0.1.1
|
||||
github.com/mxschmitt/playwright-go v0.1400.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -50,8 +50,12 @@ github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUB
|
|||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/klauspost/compress v1.15.5 h1:qyCLMz2JCrKADihKOh9FxnW3houKeNsp2h5OEz0QSEA=
|
||||
github.com/klauspost/compress v1.15.5/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
|
|
|
@ -60,7 +60,7 @@ func (c *Core) RespondDaily(user *model.User, model string) {
|
|||
log.Errorln("添加cookie信息失败,已退出答题")
|
||||
return
|
||||
}
|
||||
page.Goto("https://pc.xuexi.cn/points/my-points.html")
|
||||
_, _ = page.Goto("https://pc.xuexi.cn/points/my-points.html")
|
||||
|
||||
log.Infoln("已加载答题模块")
|
||||
|
||||
|
@ -70,7 +70,7 @@ func (c *Core) RespondDaily(user *model.User, model string) {
|
|||
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("跳转页面失败")
|
||||
log.Errorln("跳转页面失败" + err.Error())
|
||||
return
|
||||
}
|
||||
switch model {
|
||||
|
|
18
main.go
18
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -16,12 +17,21 @@ import (
|
|||
"github.com/huoxue1/study_xxqg/lib"
|
||||
"github.com/huoxue1/study_xxqg/model"
|
||||
"github.com/huoxue1/study_xxqg/push"
|
||||
"github.com/huoxue1/study_xxqg/utils/update"
|
||||
"github.com/huoxue1/study_xxqg/web"
|
||||
)
|
||||
|
||||
var (
|
||||
u bool
|
||||
)
|
||||
|
||||
var VERSION = "unknown"
|
||||
|
||||
func init() {
|
||||
|
||||
flag.BoolVar(&u, "u", false, "update the study_xxqg")
|
||||
flag.Parse()
|
||||
|
||||
config = lib.GetConfig()
|
||||
logFormatter := &easy.Formatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
|
@ -64,6 +74,14 @@ func init() {
|
|||
}
|
||||
|
||||
func main() {
|
||||
go update.CheckUpdate(VERSION)
|
||||
|
||||
if u {
|
||||
update.SelfUpdate("", VERSION)
|
||||
log.Infoln("请重启应用")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if config.Web.Enable {
|
||||
engine := web.RouterInit()
|
||||
go func() {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// Package update 该包为程序自我更新,代码源于https://github.com/Mrs4s/go-cqhttp/blob/master/internal/selfupdate/update.go
|
||||
package update
|
|
@ -0,0 +1,249 @@
|
|||
package update
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/kardianos/osext"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
// CheckUpdate 检查更新
|
||||
func CheckUpdate(version string) {
|
||||
log.Infof("正在检查更新.")
|
||||
if version == "(devel)" {
|
||||
log.Warnf("检查更新失败: 使用的 Actions 测试版或自编译版本.")
|
||||
return
|
||||
}
|
||||
if version == "unknown" {
|
||||
log.Warnf("检查更新失败: 使用的未知版本.")
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(version, "v") {
|
||||
log.Warnf("版本格式错误")
|
||||
return
|
||||
}
|
||||
latest, err := lastVersion()
|
||||
if err != nil {
|
||||
log.Warnf("检查更新失败: %v", err)
|
||||
return
|
||||
}
|
||||
if versionCompare(version, latest) {
|
||||
log.Infof("当前有更新的 study_xxqg 可供更新, 请前往 https://github.com/johlanse/study_xxqg/releases 下载.")
|
||||
log.Infof("当前版本: %v 最新版本: %v", version, latest)
|
||||
return
|
||||
}
|
||||
log.Infof("检查更新完成. 当前已运行最新版本.")
|
||||
}
|
||||
|
||||
func readLine() (str string) {
|
||||
console := bufio.NewReader(os.Stdin)
|
||||
str, _ = console.ReadString('\n')
|
||||
str = strings.TrimSpace(str)
|
||||
return
|
||||
}
|
||||
|
||||
func lastVersion() (string, error) {
|
||||
response, err := http.Get("https://api.github.com/repos/johlanse/study_xxqg/releases/latest")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, _ := io.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
return gjson.GetBytes(data, "tag_name").Str, nil
|
||||
}
|
||||
|
||||
//
|
||||
// versionCompare
|
||||
// @Description: 检测是否有更新,有返回true
|
||||
// @param nowVersion
|
||||
// @param lastVersion
|
||||
// @return bool
|
||||
//
|
||||
func versionCompare(nowVersion, lastVersion string) bool {
|
||||
NowBeta := strings.Contains(nowVersion, "beta")
|
||||
LastBeta := strings.Contains(lastVersion, "beta")
|
||||
|
||||
// 获取主要版本号
|
||||
nowMainVersion := strings.Split(nowVersion, "-")
|
||||
lastMainVersion := strings.Split(lastVersion, "-")
|
||||
|
||||
nowMainIntVersion, _ := strconv.Atoi(strings.ReplaceAll(strings.TrimLeft(nowMainVersion[0], "v"), ".", ""))
|
||||
lastMainIntVersion, _ := strconv.Atoi(strings.ReplaceAll(strings.TrimLeft(lastMainVersion[0], "v"), ".", ""))
|
||||
|
||||
if nowMainIntVersion < lastMainIntVersion {
|
||||
return true
|
||||
}
|
||||
// 如果最新版本是beta
|
||||
if LastBeta {
|
||||
// 如果当前版本也是beta
|
||||
if NowBeta {
|
||||
// 对beta后面的数字进行比较
|
||||
nowBetaVersion, _ := strconv.Atoi(strings.TrimLeft(nowMainVersion[1], "beta"))
|
||||
lastBetaVersion, _ := strconv.Atoi(strings.TrimLeft(lastMainVersion[1], "beta"))
|
||||
if nowBetaVersion < lastBetaVersion {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
// 如果当前版本部署beta,需要更新
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
// 最新版本不是beta,需要更新
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func binaryName() string {
|
||||
goarch := runtime.GOARCH
|
||||
if goarch == "arm" {
|
||||
goarch += "v7"
|
||||
}
|
||||
ext := "tar.gz"
|
||||
if runtime.GOOS == "windows" {
|
||||
ext = "zip"
|
||||
}
|
||||
return fmt.Sprintf("study_xxqg_%v_%v.%v", runtime.GOOS, goarch, ext)
|
||||
}
|
||||
|
||||
func checksum(github, version string) []byte {
|
||||
sumURL := fmt.Sprintf("%v/johlanse/study_xxqg/releases/download/%v/study_xxqg_checksums.txt", github, version)
|
||||
response, err := http.Get(sumURL)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
rd := bufio.NewReader(response.Body)
|
||||
for {
|
||||
str, err := rd.ReadString('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if strings.HasSuffix(str, binaryName()) {
|
||||
sum, _ := hex.DecodeString(strings.TrimSuffix(str, " "+binaryName()))
|
||||
return sum
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func wait() {
|
||||
log.Info("按 Enter 继续....")
|
||||
readLine()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// SelfUpdate 自更新
|
||||
func SelfUpdate(github string, version string) {
|
||||
if github == "" {
|
||||
github = "https://github.com"
|
||||
}
|
||||
|
||||
log.Infof("正在检查更新.")
|
||||
latest, err := lastVersion()
|
||||
if err != nil {
|
||||
log.Warnf("获取最新版本失败: %v", err)
|
||||
wait()
|
||||
}
|
||||
url := fmt.Sprintf("%v/johlanse/study_xxqg/releases/download/%v/%v", github, latest, binaryName())
|
||||
if version == latest {
|
||||
log.Info("当前版本已经是最新版本!")
|
||||
wait()
|
||||
}
|
||||
log.Info("当前最新版本为 ", latest)
|
||||
log.Info("正在更新,请稍等...")
|
||||
sum := checksum(github, latest)
|
||||
if sum != nil {
|
||||
err = update(url, sum)
|
||||
if err != nil {
|
||||
log.Error("更新失败: ", err)
|
||||
} else {
|
||||
log.Info("更新成功!")
|
||||
}
|
||||
} else {
|
||||
log.Error("checksum 失败!")
|
||||
}
|
||||
}
|
||||
|
||||
// writeSumCounter 写入量计算实例
|
||||
type writeSumCounter struct {
|
||||
total uint64
|
||||
hash hash.Hash
|
||||
}
|
||||
|
||||
// Write 方法将写入的byte长度追加至写入的总长度Total中
|
||||
func (wc *writeSumCounter) Write(p []byte) (int, error) {
|
||||
n := len(p)
|
||||
wc.total += uint64(n)
|
||||
wc.hash.Write(p)
|
||||
fmt.Printf("\r ")
|
||||
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.total))
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// FromStream copy form getlantern/go-update
|
||||
func fromStream(updateWith io.Reader) (err error, errRecover error) {
|
||||
updatePath, err := osext.Executable()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// get the directory the executable exists in
|
||||
updateDir := filepath.Dir(updatePath)
|
||||
filename := filepath.Base(updatePath)
|
||||
// Copy the contents of of newbinary to a the new executable file
|
||||
newPath := filepath.Join(updateDir, fmt.Sprintf(".%s.new", filename))
|
||||
fp, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o755)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// We won't log this error, because it's always going to happen.
|
||||
defer func() { _ = fp.Close() }()
|
||||
if _, err = io.Copy(fp, bufio.NewReader(updateWith)); err != nil {
|
||||
log.Errorf("Unable to copy data: %v\n", err)
|
||||
}
|
||||
|
||||
// if we don't call fp.Close(), windows won't let us move the new executable
|
||||
// because the file will still be "in use"
|
||||
if err := fp.Close(); err != nil {
|
||||
log.Errorf("Unable to close file: %v\n", err)
|
||||
}
|
||||
// this is where we'll move the executable to so that we can swap in the updated replacement
|
||||
oldPath := filepath.Join(updateDir, fmt.Sprintf(".%s.old", filename))
|
||||
|
||||
// delete any existing old exec file - this is necessary on Windows for two reasons:
|
||||
// 1. after a successful update, Windows can't remove the .old file because the process is still running
|
||||
// 2. windows rename operations fail if the destination file already exists
|
||||
_ = os.Remove(oldPath)
|
||||
|
||||
// move the existing executable to a new file in the same directory
|
||||
err = os.Rename(updatePath, oldPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// move the new executable in to become the new program
|
||||
err = os.Rename(newPath, updatePath)
|
||||
|
||||
if err != nil {
|
||||
// copy unsuccessful
|
||||
errRecover = os.Rename(oldPath, updatePath)
|
||||
} else {
|
||||
// copy successful, remove the old binary
|
||||
_ = os.Remove(oldPath)
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package update
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/klauspost/compress/gzip"
|
||||
)
|
||||
|
||||
// update study_xxqg自我更新
|
||||
func update(url string, sum []byte) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
wc := writeSumCounter{
|
||||
hash: sha256.New(),
|
||||
}
|
||||
rsp, err := io.ReadAll(io.TeeReader(resp.Body, &wc))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(wc.hash.Sum(nil), sum) {
|
||||
return errors.New("文件已损坏")
|
||||
}
|
||||
gr, err := gzip.NewReader(bytes.NewReader(rsp))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tr := tar.NewReader(gr)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if header.Name == "study_xxqg" {
|
||||
err, _ := fromStream(tr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package update
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_versionCompare(t *testing.T) {
|
||||
println(versionCompare("v2.0.1", "v2.0.3"))
|
||||
println(versionCompare("v2.0.2", "v2.0.2"))
|
||||
println(versionCompare("v2.0.2", "v2.0.2-beta1"))
|
||||
println(versionCompare("v2.0.2-beta1", "v2.0.2-beta3"))
|
||||
println(versionCompare("v2.0.2-beta1", "v2.0.2-beta1"))
|
||||
}
|
||||
|
||||
func Test_CheckUpdate(t *testing.T) {
|
||||
CheckUpdate("v1.0.22")
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package update
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/klauspost/compress/zip"
|
||||
)
|
||||
|
||||
// update study_xxqg自我更新
|
||||
func update(url string, sum []byte) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
wc := writeSumCounter{
|
||||
hash: sha256.New(),
|
||||
}
|
||||
rsp, err := io.ReadAll(io.TeeReader(resp.Body, &wc))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(wc.hash.Sum(nil), sum) {
|
||||
return errors.New("文件已损坏")
|
||||
}
|
||||
reader, _ := zip.NewReader(bytes.NewReader(rsp), resp.ContentLength)
|
||||
file, err := reader.Open("study_xxqg.exe")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err, _ = fromStream(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue