Files
thuanle a36eb7aad0 perf: run token price source lookups in parallel
Fetch alpha, futures, and spot sources concurrently in token lookup flow to reduce end-to-end response latency while preserving independent source behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 18:26:33 +07:00

147 lines
3.2 KiB
Go

package commands
import (
"strings"
"sync"
"gopkg.in/telebot.v3"
"me.thuanle/bbot/internal/configs/tele"
"me.thuanle/bbot/internal/data"
"me.thuanle/bbot/internal/services/tele/chat"
"me.thuanle/bbot/internal/services/tele/view"
)
type buildRichTokenMessageArgs struct {
Token string
HasSpot bool
SpotPrice float64
HasFuture bool
FuturePrice float64
FundingRate float64
FundingTimeMs int64
HasAlpha bool
AlphaPrice float64
HasAlpha24h bool
Alpha24h float64
HasMarginAPR bool
MarginAPRPercent float64
}
func buildRichTokenMessageInput(a buildRichTokenMessageArgs) view.RichTokenMessageInput {
return view.RichTokenMessageInput{
Token: a.Token,
HasSpot: a.HasSpot,
SpotPrice: a.SpotPrice,
HasFuture: a.HasFuture,
FuturePrice: a.FuturePrice,
FundingRate: a.FundingRate,
FundingTimeMs: a.FundingTimeMs,
HasAlpha: a.HasAlpha,
AlphaPrice: a.AlphaPrice,
HasAlpha24h: a.HasAlpha24h,
Alpha24hChange: a.Alpha24h,
HasMarginAPR: a.HasMarginAPR,
MarginAPRPercent: a.MarginAPRPercent,
}
}
func showStickerMode(context telebot.Context, token string) {
token = strings.ToUpper(token)
stickerIdx, ok := tele.Token2StickerIdxMap[token]
if !ok {
return
}
stickers, err := context.Bot().StickerSet(tele.StickerSet)
if err == nil && stickers != nil {
_ = context.Reply(&stickers.Stickers[stickerIdx])
}
}
func collectRichTokenData(token string) buildRichTokenMessageArgs {
a := buildRichTokenMessageArgs{Token: token}
marginRates := data.Market.GetMarginInterestRates()
a.MarginAPRPercent = marginRates[token] * 365 * 100
a.HasMarginAPR = marginRates[token] != 0
futureSymbol := token + "USDT"
spotSymbol := token + "USDT"
var (
wg sync.WaitGroup
mu sync.Mutex
)
wg.Add(3)
go func() {
defer wg.Done()
if alphaToken, ok := data.Market.GetAlphaToken(token); ok {
alpha24h := alphaToken.GetPercentChange24h()
alphaPrice := alphaToken.GetPrice()
if p, ok := data.Market.GetAlphaPrice(token + "USDT"); ok {
alphaPrice = p
}
mu.Lock()
a.HasAlpha = true
a.HasAlpha24h = true
a.Alpha24h = alpha24h
a.AlphaPrice = alphaPrice
mu.Unlock()
}
}()
go func() {
defer wg.Done()
if data.Market.IsFuturesPair(futureSymbol) {
if fp, fr, ft, ok := data.Market.GetFuturePrice(futureSymbol); ok {
mu.Lock()
a.HasFuture = true
a.FuturePrice = fp
a.FundingRate = fr
a.FundingTimeMs = ft
mu.Unlock()
}
}
}()
go func() {
defer wg.Done()
if data.Market.IsSpotPair(spotSymbol) {
if sp, ok := data.Market.GetSpotPrice(spotSymbol); ok {
mu.Lock()
a.HasSpot = true
a.SpotPrice = sp
mu.Unlock()
}
}
}()
wg.Wait()
return a
}
func OnTokenInfoByToken(context telebot.Context, token string) error {
token = strings.ToUpper(token)
showStickerMode(context, token)
args := collectRichTokenData(token)
if !args.HasSpot && !args.HasFuture && !args.HasAlpha {
return nil
}
msg := view.RenderRichTokenMessage(buildRichTokenMessageInput(args))
_ = chat.ReplyMessage(context, msg)
return nil
}
func OnTokenInfo(context telebot.Context) error {
text := strings.ToLower(context.Text())
return OnTokenInfoByToken(context, text)
}