2025-02-20 08:24:49 +00:00
|
|
|
package redirect
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2025-02-20 12:55:54 +00:00
|
|
|
"fonchain-fiee/pkg/service"
|
2025-05-23 02:53:16 +00:00
|
|
|
"github.com/PuerkitoBio/goquery"
|
2025-02-20 08:24:49 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"net/http"
|
2025-05-23 02:53:16 +00:00
|
|
|
"strings"
|
2025-02-20 08:24:49 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2025-02-20 08:38:16 +00:00
|
|
|
// ToRedirectRealUrl 重定向到指定位置
|
2025-02-20 08:24:49 +00:00
|
|
|
func ToRedirectRealUrl(c *gin.Context) {
|
|
|
|
|
|
|
|
realUrl := c.Query("base_redirect_url")
|
|
|
|
if realUrl == "" {
|
|
|
|
service.Error(c, errors.New("not real url"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Redirect(http.StatusMovedPermanently, realUrl)
|
|
|
|
}
|
|
|
|
|
2025-02-20 08:38:16 +00:00
|
|
|
// ToRedirectRealUrlAdnRand 重定向到指定位置
|
2025-02-20 08:24:49 +00:00
|
|
|
func ToRedirectRealUrlAdnRand(c *gin.Context) {
|
|
|
|
|
|
|
|
realUrl := c.Query("base_redirect_url")
|
|
|
|
if realUrl == "" {
|
|
|
|
service.Error(c, errors.New("not real url"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2025-02-20 08:38:16 +00:00
|
|
|
c.Redirect(http.StatusMovedPermanently, realUrl+fmt.Sprintf("?time=%d", time.Now().Unix()))
|
2025-02-20 08:24:49 +00:00
|
|
|
}
|
2025-05-22 12:19:42 +00:00
|
|
|
func ForwardTest(c *gin.Context) {
|
2025-05-23 02:53:16 +00:00
|
|
|
url := "https://stockanalysis.com/quote/otc/MINM/"
|
|
|
|
|
|
|
|
// Create HTTP client with timeout
|
2025-05-22 12:19:42 +00:00
|
|
|
client := &http.Client{
|
|
|
|
Timeout: 10 * time.Second,
|
|
|
|
}
|
|
|
|
|
2025-05-23 02:53:16 +00:00
|
|
|
// Make request
|
|
|
|
resp, err := client.Get(url)
|
2025-05-22 12:19:42 +00:00
|
|
|
if err != nil {
|
2025-05-23 02:53:16 +00:00
|
|
|
sendErrorResponse(c, http.StatusInternalServerError, "请求失败", err.Error())
|
2025-05-22 12:19:42 +00:00
|
|
|
return
|
|
|
|
}
|
2025-05-23 02:53:16 +00:00
|
|
|
defer resp.Body.Close()
|
2025-05-22 12:19:42 +00:00
|
|
|
|
2025-05-23 02:53:16 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
sendErrorResponse(c, http.StatusInternalServerError, "请求失败", fmt.Sprintf("status code: %d", resp.StatusCode))
|
2025-05-22 12:19:42 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2025-05-23 02:53:16 +00:00
|
|
|
// Parse HTML
|
|
|
|
doc, err := goquery.NewDocumentFromReader(resp.Body)
|
2025-05-22 12:19:42 +00:00
|
|
|
if err != nil {
|
2025-05-23 02:53:16 +00:00
|
|
|
sendErrorResponse(c, http.StatusInternalServerError, "解析失败", err.Error())
|
2025-05-22 12:19:42 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2025-05-23 02:53:16 +00:00
|
|
|
var (
|
|
|
|
openValue string
|
|
|
|
volumeValue string
|
|
|
|
daysRangeValue string
|
|
|
|
week52Value string
|
|
|
|
marketCapValue string
|
|
|
|
changeValue []string
|
|
|
|
)
|
|
|
|
type StockData struct {
|
|
|
|
Open string `json:"Open"`
|
|
|
|
Volume string `json:"Volume"`
|
|
|
|
DaysRange string `json:"DaysRange"`
|
|
|
|
Week52Range string `json:"Week52Range"`
|
|
|
|
MarketCap string `json:"MarketCap"`
|
|
|
|
Change []string `json:"change"`
|
|
|
|
}
|
|
|
|
// Get price
|
|
|
|
priceDiv := doc.Find("div.text-4xl.font-bold.transition-colors.duration-300.inline-block").First()
|
|
|
|
price := strings.TrimSpace(priceDiv.Text())
|
|
|
|
|
|
|
|
// Get change
|
|
|
|
changeDiv := priceDiv.NextFiltered("div.font-semibold.inline-block.text-2xl.text-red-vivid")
|
|
|
|
change := strings.TrimSpace(changeDiv.Text())
|
|
|
|
|
|
|
|
if price != "" && change != "" {
|
|
|
|
changeValue = []string{price, change}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find other values in table
|
|
|
|
doc.Find("td").Each(func(i int, s *goquery.Selection) {
|
|
|
|
text := strings.TrimSpace(s.Text())
|
|
|
|
switch text {
|
|
|
|
case "Open":
|
|
|
|
openValue = strings.TrimSpace(s.Next().Text())
|
|
|
|
case "Volume":
|
|
|
|
volumeValue = strings.TrimSpace(s.Next().Text())
|
|
|
|
case "Day's Range":
|
|
|
|
daysRangeValue = strings.TrimSpace(s.Next().Text())
|
|
|
|
case "52-Week Range":
|
|
|
|
week52Value = strings.TrimSpace(s.Next().Text())
|
|
|
|
case "Market Cap":
|
|
|
|
marketCapValue = strings.TrimSpace(s.Next().Text())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Check if all values were found
|
|
|
|
if openValue != "" && volumeValue != "" && daysRangeValue != "" &&
|
|
|
|
week52Value != "" && marketCapValue != "" && len(changeValue) == 2 {
|
|
|
|
c.JSON(http.StatusOK, StockData{
|
|
|
|
Open: openValue,
|
|
|
|
Volume: volumeValue,
|
|
|
|
DaysRange: daysRangeValue,
|
|
|
|
Week52Range: week52Value,
|
|
|
|
MarketCap: marketCapValue,
|
|
|
|
Change: changeValue,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
|
|
"error": "未找到全部数据",
|
|
|
|
"Open": openValue,
|
|
|
|
"Volume": volumeValue,
|
|
|
|
"DaysRange": daysRangeValue,
|
|
|
|
"Week52Range": week52Value,
|
|
|
|
"MarketCap": marketCapValue,
|
|
|
|
"change": changeValue,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func sendErrorResponse(c *gin.Context, statusCode int, errorMsg string, detail string) {
|
|
|
|
c.JSON(statusCode, gin.H{
|
|
|
|
"error": errorMsg,
|
|
|
|
"detail": detail,
|
|
|
|
})
|
2025-05-22 12:19:42 +00:00
|
|
|
}
|