mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-07-25 23:26:42 +08:00
feat: add update command and callback for version checking and upgrading
This commit is contained in:
@@ -19,12 +19,13 @@ import (
|
|||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init(ctx context.Context) {
|
func Init(ctx context.Context) (<-chan struct{}) {
|
||||||
log.FromContext(ctx).Info("初始化 Bot...")
|
log.FromContext(ctx).Info("初始化 Bot...")
|
||||||
resultChan := make(chan struct {
|
resultChan := make(chan struct {
|
||||||
client *gotgproto.Client
|
client *gotgproto.Client
|
||||||
err error
|
err error
|
||||||
})
|
})
|
||||||
|
shouldRestart := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
var resolver dcs.Resolver
|
var resolver dcs.Resolver
|
||||||
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
||||||
@@ -55,7 +56,11 @@ func Init(ctx context.Context) {
|
|||||||
MaxRetries: config.C().Telegram.RpcRetry,
|
MaxRetries: config.C().Telegram.RpcRetry,
|
||||||
AutoFetchReply: true,
|
AutoFetchReply: true,
|
||||||
ErrorHandler: func(ctx *ext.Context, u *ext.Update, s string) error {
|
ErrorHandler: func(ctx *ext.Context, u *ext.Update, s string) error {
|
||||||
log.FromContext(ctx).Errorf("Unhandled error: %s", s)
|
if s == "SAVEANTBOT-RESTART" {
|
||||||
|
shouldRestart <- struct{}{}
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
log.FromContext(ctx).Errorf("unhandled error: %s", s)
|
||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -103,4 +108,5 @@ func Init(ctx context.Context) {
|
|||||||
handlers.Register(result.client.Dispatcher)
|
handlers.Register(result.client.Dispatcher)
|
||||||
log.FromContext(ctx).Info("Bot 初始化完成")
|
log.FromContext(ctx).Info("Bot 初始化完成")
|
||||||
}
|
}
|
||||||
|
return shouldRestart
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ func Register(disp dispatcher.Dispatcher) {
|
|||||||
disp.AddHandler(handlers.NewCommand("unwatch", handleUnwatchCmd))
|
disp.AddHandler(handlers.NewCommand("unwatch", handleUnwatchCmd))
|
||||||
disp.AddHandler(handlers.NewCommand("save", handleSilentMode(handleSaveCmd, handleSilentSaveReplied)))
|
disp.AddHandler(handlers.NewCommand("save", handleSilentMode(handleSaveCmd, handleSilentSaveReplied)))
|
||||||
disp.AddHandler(handlers.NewCommand("config", handleConfigCmd))
|
disp.AddHandler(handlers.NewCommand("config", handleConfigCmd))
|
||||||
|
disp.AddHandler(handlers.NewCommand("update", handleUpdateCmd))
|
||||||
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("update"), handleUpdateCallback))
|
||||||
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeAdd), handleAddCallback))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeAdd), handleAddCallback))
|
||||||
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeSetDefault), handleSetDefaultCallback))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeSetDefault), handleSetDefaultCallback))
|
||||||
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeCancel), handleCancelCallback))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix(tcbdata.TypeCancel), handleCancelCallback))
|
||||||
|
|||||||
105
client/bot/handlers/update.go
Normal file
105
client/bot/handlers/update.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/blang/semver"
|
||||||
|
"github.com/celestix/gotgproto/dispatcher"
|
||||||
|
"github.com/celestix/gotgproto/ext"
|
||||||
|
"github.com/gotd/td/telegram/message/html"
|
||||||
|
"github.com/gotd/td/tg"
|
||||||
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
|
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleUpdateCmd(ctx *ext.Context, u *ext.Update) error {
|
||||||
|
currentV, err := semver.Parse(config.Version)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("You are in dev or the version var failed to inject: %v", err)), nil)
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
latest, ok, err := selfupdate.DetectLatest(config.GitRepo)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("检测最新版本失败: %v", err)), nil)
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
ctx.Reply(u, ext.ReplyTextString("没有找到版本信息"), nil)
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
if latest.Version.Equals(currentV) {
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
if latest.Version.LT(currentV) || latest.Version.Equals(currentV) {
|
||||||
|
ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("当前已经是最新版本: %s", config.Version)), nil)
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
ctx.Sender.To(u.GetUserChat().AsInputPeer()).StyledText(ctx, html.String(nil, func() string {
|
||||||
|
md := latest.ReleaseNotes
|
||||||
|
md = regexp.MustCompile(`(?m)^###\s+ (.+)$`).ReplaceAllString(md, "<b>$1</b>")
|
||||||
|
md = regexp.MustCompile(`(?m)^#####\s+ (.+)$`).ReplaceAllString(md, "<i>$1</i>")
|
||||||
|
|
||||||
|
md = regexp.MustCompile(`(?m)^- `).ReplaceAllString(md, "• ")
|
||||||
|
|
||||||
|
md = regexp.MustCompile(`\[\((\w{6,})\)\]\((https?://[^\s)]+)\)`).ReplaceAllString(md, `(<a href="$2">$1</a>)`)
|
||||||
|
|
||||||
|
md = regexp.MustCompile(`\[(.+?)\]\((https?://[^\s)]+)\)`).ReplaceAllString(md, `<a href="$2">$1</a>`)
|
||||||
|
|
||||||
|
md = strings.ReplaceAll(md, " ", " ")
|
||||||
|
|
||||||
|
return `<blockquote expandable>` + md + `</blockquote>`
|
||||||
|
}()))
|
||||||
|
text := fmt.Sprintf(`发现新版本: %s
|
||||||
|
当前版本: %s
|
||||||
|
|
||||||
|
文件大小: %.2f MB
|
||||||
|
下载链接: %s
|
||||||
|
发布时间: %s
|
||||||
|
|
||||||
|
升级将重启 Bot , 是否升级?`, latest.Version, config.Version,
|
||||||
|
float64(latest.AssetByteSize)/(1024*1024), latest.AssetURL,
|
||||||
|
latest.PublishedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
)
|
||||||
|
ctx.Reply(u, ext.ReplyTextString(text), &ext.ReplyOpts{
|
||||||
|
Markup: &tg.ReplyInlineMarkup{
|
||||||
|
Rows: []tg.KeyboardButtonRow{
|
||||||
|
{
|
||||||
|
Buttons: []tg.KeyboardButtonClass{
|
||||||
|
&tg.KeyboardButtonCallback{
|
||||||
|
Text: "升级",
|
||||||
|
Data: []byte("update"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleUpdateCallback(ctx *ext.Context, u *ext.Update) error {
|
||||||
|
currentV, err := semver.Parse(config.Version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{
|
||||||
|
ID: u.CallbackQuery.GetMsgID(),
|
||||||
|
Message: fmt.Sprintf("正在升级中, 当前版本: %s", config.Version),
|
||||||
|
})
|
||||||
|
latest, err := selfupdate.UpdateSelf(currentV, config.GitRepo)
|
||||||
|
if err != nil {
|
||||||
|
ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{
|
||||||
|
ID: u.CallbackQuery.GetMsgID(),
|
||||||
|
Message: fmt.Sprintf("升级失败: %v", err),
|
||||||
|
})
|
||||||
|
return dispatcher.EndGroups
|
||||||
|
}
|
||||||
|
ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{
|
||||||
|
ID: u.CallbackQuery.GetMsgID(),
|
||||||
|
Message: fmt.Sprintf("已升级至版本 %s\n若 Bot 未自动重启请手动启动", latest.Version),
|
||||||
|
})
|
||||||
|
return errors.New("SAVEANTBOT-RESTART")
|
||||||
|
}
|
||||||
18
cmd/run.go
18
cmd/run.go
@@ -25,7 +25,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Run(cmd *cobra.Command, _ []string) {
|
func Run(cmd *cobra.Command, _ []string) {
|
||||||
ctx := cmd.Context()
|
ctx, cancel := context.WithCancel(cmd.Context())
|
||||||
logger := log.NewWithOptions(os.Stdout, log.Options{
|
logger := log.NewWithOptions(os.Stdout, log.Options{
|
||||||
Level: log.DebugLevel,
|
Level: log.DebugLevel,
|
||||||
ReportTimestamp: true,
|
ReportTimestamp: true,
|
||||||
@@ -34,7 +34,15 @@ func Run(cmd *cobra.Command, _ []string) {
|
|||||||
})
|
})
|
||||||
ctx = log.WithContext(ctx, logger)
|
ctx = log.WithContext(ctx, logger)
|
||||||
|
|
||||||
initAll(ctx)
|
exitChan, err := initAll(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("Failed to initialize", "error", err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-exitChan
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
core.Run(ctx)
|
core.Run(ctx)
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
@@ -43,10 +51,10 @@ func Run(cmd *cobra.Command, _ []string) {
|
|||||||
cleanCache()
|
cleanCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
func initAll(ctx context.Context) {
|
func initAll(ctx context.Context) (<-chan struct{}, error) {
|
||||||
if err := config.Init(ctx); err != nil {
|
if err := config.Init(ctx); err != nil {
|
||||||
fmt.Println("Failed to load config:", err)
|
fmt.Println("Failed to load config:", err)
|
||||||
os.Exit(1)
|
return nil, err
|
||||||
}
|
}
|
||||||
cache.Init()
|
cache.Init()
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
@@ -69,7 +77,7 @@ func initAll(ctx context.Context) {
|
|||||||
logger.Fatalf("User client login failed: %s", err)
|
logger.Fatalf("User client login failed: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bot.Init(ctx)
|
return bot.Init(ctx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanCache() {
|
func cleanCache() {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var upgradeCmd = &cobra.Command{
|
|||||||
Short: "Upgrade saveany-bot to the latest version",
|
Short: "Upgrade saveany-bot to the latest version",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
v := semver.MustParse(config.Version)
|
v := semver.MustParse(config.Version)
|
||||||
latest, err := selfupdate.UpdateSelf(v, "krau/SaveAny-Bot")
|
latest, err := selfupdate.UpdateSelf(v, config.GitRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Binary update failed:", err)
|
fmt.Println("Binary update failed:", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -7,3 +7,7 @@ var (
|
|||||||
BuildTime string = "unknown"
|
BuildTime string = "unknown"
|
||||||
GitCommit string = "unknown"
|
GitCommit string = "unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GitRepo = "krau/SaveAny-Bot"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user