Files
epusdt/src/telegram/handle.go
T
2026-04-14 18:57:38 +08:00

279 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package telegram
import (
"fmt"
"sort"
"strings"
"sync"
"time"
"github.com/assimon/luuu/model/data"
"github.com/assimon/luuu/model/mdb"
"github.com/gookit/goutil/mathutil"
"github.com/gookit/goutil/strutil"
tb "gopkg.in/telebot.v3"
)
const (
ReplaySelectNetwork = "请选择要添加的钱包网络"
ReplayAddWallet = "请发送 %s 网络收款地址"
pendingWalletAddressTTL = 5 * time.Minute
)
type pendingWalletAddressState struct {
RequestedAt time.Time
Network string
}
var pendingWalletAddressUsers sync.Map
func OnTextMessageHandle(c tb.Context) error {
msg := c.Message()
if msg == nil {
return nil
}
sender := c.Sender()
senderID := int64(0)
if sender != nil {
senderID = sender.ID
}
isReplyFlow := msg.ReplyTo != nil && strings.HasPrefix(msg.ReplyTo.Text, "请发送 ")
isPendingFlow := isWalletAddressPending(senderID)
if !isReplyFlow && !isPendingFlow {
return nil
}
if isReplyFlow {
defer bots.Delete(msg.ReplyTo)
}
msgText := strings.TrimSpace(msg.Text)
state, _ := getPendingWalletAddressState(senderID)
if state.Network == "" {
_ = c.Send("请先选择网络,再发送地址。")
return nil
}
var err error
if !isValidAddressByNetwork(state.Network, msgText) {
_ = c.Send(fmt.Sprintf("钱包 [%s] 添加失败:不是合法的 %s 地址", msgText, strings.ToUpper(state.Network)))
return nil
}
storeAddress := normalizeWalletAddressByNetwork(state.Network, msgText)
_, err = data.AddWalletAddressWithNetwork(state.Network, storeAddress)
if err != nil {
return c.Send(err.Error())
}
pendingWalletAddressUsers.Delete(senderID)
_ = c.Send(fmt.Sprintf("钱包 [%s] 添加成功(%s", storeAddress, strings.ToUpper(state.Network)))
return WalletList(c)
}
func WalletList(c tb.Context) error {
wallets, err := data.GetAllWalletAddress()
if err != nil {
return err
}
var btnList [][]tb.InlineButton
for _, wallet := range wallets {
status := "已启用✅"
if wallet.Status == mdb.TokenStatusDisable {
status = "已禁用🚫"
}
net := wallet.Network
if net == "" {
net = mdb.NetworkTron
}
btnInfo := tb.InlineButton{
Unique: wallet.Address,
Text: fmt.Sprintf("[%s] %s [%s]", net, wallet.Address, status),
Data: strutil.MustString(wallet.ID),
}
bots.Handle(&btnInfo, WalletInfo)
btnList = append(btnList, []tb.InlineButton{btnInfo})
}
addBtn := tb.InlineButton{Text: "添加钱包地址", Unique: "AddWallet"}
bots.Handle(&addBtn, func(c tb.Context) error {
chains, err := getEnabledSupportedNetworks()
if err != nil {
return c.Send("读取支持链失败:" + err.Error())
}
if len(chains) == 0 {
return c.Send("当前没有可用链,请先在后台配置 supported-assets。")
}
rows := make([][]tb.InlineButton, 0, len(chains))
for _, network := range chains {
btn := tb.InlineButton{
Text: strings.ToUpper(network),
Unique: "SelectWalletNetwork",
Data: network,
}
bots.Handle(&btn, SelectWalletNetwork)
rows = append(rows, []tb.InlineButton{btn})
}
return c.EditOrSend(ReplaySelectNetwork, &tb.ReplyMarkup{
InlineKeyboard: rows,
})
})
btnList = append(btnList, []tb.InlineButton{addBtn})
return c.EditOrSend("请选择钱包继续操作", &tb.ReplyMarkup{
InlineKeyboard: btnList,
})
}
func SelectWalletNetwork(c tb.Context) error {
network := strings.ToLower(strings.TrimSpace(c.Data()))
if network == "" {
return c.Send("请选择有效网络")
}
if sender := c.Sender(); sender != nil {
pendingWalletAddressUsers.Store(sender.ID, pendingWalletAddressState{
RequestedAt: time.Now(),
Network: network,
})
}
return c.Send(fmt.Sprintf(ReplayAddWallet, strings.ToUpper(network)), &tb.ReplyMarkup{
ForceReply: true,
})
}
func WalletInfo(c tb.Context) error {
id := mathutil.MustUint(c.Data())
tokenInfo, err := data.GetWalletAddressById(id)
if err != nil {
return c.Send(err.Error())
}
enableBtn := tb.InlineButton{
Text: "启用",
Unique: "enableBtn",
Data: c.Data(),
}
disableBtn := tb.InlineButton{
Text: "禁用",
Unique: "disableBtn",
Data: c.Data(),
}
delBtn := tb.InlineButton{
Text: "删除",
Unique: "delBtn",
Data: c.Data(),
}
backBtn := tb.InlineButton{
Text: "返回",
Unique: "WalletList",
}
bots.Handle(&enableBtn, EnableWallet)
bots.Handle(&disableBtn, DisableWallet)
bots.Handle(&delBtn, DelWallet)
bots.Handle(&backBtn, WalletList)
net := tokenInfo.Network
if net == "" {
net = mdb.NetworkTron
}
detail := fmt.Sprintf("网络:%s\n地址:%s", net, tokenInfo.Address)
return c.EditOrReply(detail, &tb.ReplyMarkup{InlineKeyboard: [][]tb.InlineButton{
{
enableBtn,
disableBtn,
delBtn,
},
{
backBtn,
},
}})
}
func EnableWallet(c tb.Context) error {
id := mathutil.MustUint(c.Data())
if id <= 0 {
return c.Send("请求不合法!")
}
err := data.ChangeWalletAddressStatus(id, mdb.TokenStatusEnable)
if err != nil {
return c.Send(err.Error())
}
return WalletList(c)
}
func DisableWallet(c tb.Context) error {
id := mathutil.MustUint(c.Data())
if id <= 0 {
return c.Send("请求不合法!")
}
err := data.ChangeWalletAddressStatus(id, mdb.TokenStatusDisable)
if err != nil {
return c.Send(err.Error())
}
return WalletList(c)
}
func DelWallet(c tb.Context) error {
id := mathutil.MustUint(c.Data())
if id <= 0 {
return c.Send("请求不合法!")
}
err := data.DeleteWalletAddressById(id)
if err != nil {
return c.Send(err.Error())
}
return WalletList(c)
}
func isWalletAddressPending(userID int64) bool {
if userID <= 0 {
return false
}
value, ok := pendingWalletAddressUsers.Load(userID)
if !ok {
return false
}
state, ok := value.(pendingWalletAddressState)
if !ok || time.Since(state.RequestedAt) > pendingWalletAddressTTL {
pendingWalletAddressUsers.Delete(userID)
return false
}
return true
}
func getPendingWalletAddressState(userID int64) (pendingWalletAddressState, bool) {
v, ok := pendingWalletAddressUsers.Load(userID)
if !ok {
return pendingWalletAddressState{}, false
}
state, ok := v.(pendingWalletAddressState)
return state, ok
}
func getEnabledSupportedNetworks() ([]string, error) {
assets, err := data.ListEnabledSupportedAssets()
if err != nil {
return nil, err
}
set := make(map[string]struct{})
for _, a := range assets {
n := strings.ToLower(strings.TrimSpace(a.Network))
if n == "" {
continue
}
set[n] = struct{}{}
}
networks := make([]string, 0, len(set))
for n := range set {
networks = append(networks, n)
}
sort.Strings(networks)
return networks, nil
}