feat: 增加详细日志, 覆盖所有接口和核心业务逻辑
This commit is contained in:
parent
2c90c95b55
commit
05bec7f1d0
@ -3,6 +3,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
@ -14,9 +15,12 @@ var DB *sql.DB
|
|||||||
func InitDB(dbPath string) error {
|
func InitDB(dbPath string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
log.Printf("[DB] 初始化数据库: path=%s", dbPath)
|
||||||
|
|
||||||
// 确保数据库目录存在
|
// 确保数据库目录存在
|
||||||
dir := "./data"
|
dir := "./data"
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
log.Printf("[DB] 数据库目录不存在, 创建: %s", dir)
|
||||||
os.MkdirAll(dir, 0755)
|
os.MkdirAll(dir, 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +36,7 @@ func InitDB(dbPath string) error {
|
|||||||
return fmt.Errorf("创建表失败: %w", err)
|
return fmt.Errorf("创建表失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[DB] 数据库初始化完成")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,13 +28,19 @@ func NewConfigHandler(configPath string) *ConfigHandler {
|
|||||||
// GetConfigPrice 获取配置
|
// GetConfigPrice 获取配置
|
||||||
// 先读 yaml(Port/TimerInterval/APIRateLimit/CallbackURL),再用数据库值覆盖价格字段
|
// 先读 yaml(Port/TimerInterval/APIRateLimit/CallbackURL),再用数据库值覆盖价格字段
|
||||||
func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[GetConfigPrice] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
defer h.mu.Unlock()
|
defer h.mu.Unlock()
|
||||||
|
|
||||||
// 1. 加载yaml配置
|
// 1. 加载yaml配置
|
||||||
cfg, err := config.Load(h.configPath)
|
cfg, err := config.Load(h.configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[GetConfigPrice] 读取配置失败: %s", err.Error())
|
log.Printf("[GetConfigPrice] 读取配置失败: %s, 来源IP: %s", err.Error(), clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"读取配置失败: %s"}`, err.Error())))
|
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"读取配置失败: %s"}`, err.Error())))
|
||||||
return
|
return
|
||||||
@ -56,6 +62,9 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 同步全局配置
|
// 同步全局配置
|
||||||
config.SetGlobal(cfg)
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
log.Printf("[GetConfigPrice] 返回配置: port=%s, new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
|
||||||
|
cfg.Port, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"code": 200,
|
"code": 200,
|
||||||
@ -70,6 +79,12 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (h *ConfigHandler) SetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
func (h *ConfigHandler) SetConfigPrice(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseMultipartForm(32 << 20)
|
r.ParseMultipartForm(32 << 20)
|
||||||
|
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[SetConfigPrice] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
defer h.mu.Unlock()
|
defer h.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,15 @@ func NewGoodsHandler(goodsService *service.GoodsService) *GoodsHandler {
|
|||||||
|
|
||||||
// QueryGoods 查询商品接口
|
// QueryGoods 查询商品接口
|
||||||
func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
|
func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[QueryGoods] 收到请求, 来源IP: %s, Method: %s", clientIP, r.Method)
|
||||||
|
|
||||||
// 只支持POST请求
|
// 只支持POST请求
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
|
log.Printf("[QueryGoods] 方法不允许: %s, 来源IP: %s", r.Method, clientIP)
|
||||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -34,8 +41,7 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 读取原始body用于调试
|
// 读取原始body用于调试
|
||||||
bodyBytes, _ := io.ReadAll(r.Body)
|
bodyBytes, _ := io.ReadAll(r.Body)
|
||||||
bodyStr := string(bodyBytes)
|
bodyStr := string(bodyBytes)
|
||||||
log.Printf("收到原始请求 Body: [%s]", bodyStr)
|
log.Printf("[QueryGoods] 原始请求 Body: [%s], Content-Type: [%s]", bodyStr, r.Header.Get("Content-Type"))
|
||||||
log.Printf("Content-Type: [%s]", r.Header.Get("Content-Type"))
|
|
||||||
|
|
||||||
// 重新创建body供ParseForm使用
|
// 重新创建body供ParseForm使用
|
||||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||||
@ -44,33 +50,43 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err := r.ParseMultipartForm(32 << 20); err != nil {
|
if err := r.ParseMultipartForm(32 << 20); err != nil {
|
||||||
// 尝试纯表单解析
|
// 尝试纯表单解析
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
log.Printf("ParseForm 失败: %v", err)
|
log.Printf("[QueryGoods] 参数解析失败: %v, 来源IP: %s", err, clientIP)
|
||||||
http.Error(w, "Invalid request form", http.StatusBadRequest)
|
http.Error(w, "Invalid request form", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试日志
|
isbn := r.FormValue("isbn")
|
||||||
log.Printf("解析结果 - isbn: [%s], book_name: [%s], author: [%s], publishing: [%s], out_id: [%s], quality: [%s], query_index: [%s], user_id: [%s], placeholder_down_price: [%s], min_shipping_fee: [%s], min_price: [%s] ",
|
bookName := r.FormValue("book_name")
|
||||||
r.FormValue("isbn"), r.FormValue("book_name"), r.FormValue("author"), r.FormValue("publishing"),
|
author := r.FormValue("author")
|
||||||
r.FormValue("out_id"), r.FormValue("quality"),
|
publishing := r.FormValue("publishing")
|
||||||
r.FormValue("query_index"), r.FormValue("user_id"), r.FormValue("placeholder_down_price"), r.FormValue("min_shipping_fee"), r.FormValue("min_price"))
|
outID := r.FormValue("out_id")
|
||||||
|
quality := r.FormValue("quality")
|
||||||
|
queryIndex := r.FormValue("query_index")
|
||||||
|
userID := r.FormValue("user_id")
|
||||||
|
placeholderDownPrice := r.FormValue("placeholder_down_price")
|
||||||
|
minShippingFee := r.FormValue("min_shipping_fee")
|
||||||
|
minPrice := r.FormValue("min_price")
|
||||||
|
|
||||||
|
log.Printf("[QueryGoods] 解析参数完成 - isbn=[%s], book_name=[%s], author=[%s], publishing=[%s], out_id=[%s], quality=[%s], query_index=[%s], user_id=[%s], placeholder_down_price=[%s], min_shipping_fee=[%s], min_price=[%s]",
|
||||||
|
isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice)
|
||||||
|
|
||||||
var req service.QueryRequest
|
var req service.QueryRequest
|
||||||
req.ISBN = r.FormValue("isbn")
|
req.ISBN = isbn
|
||||||
req.BookName = r.FormValue("book_name")
|
req.BookName = bookName
|
||||||
req.Author = r.FormValue("author")
|
req.Author = author
|
||||||
req.Publishing = r.FormValue("publishing")
|
req.Publishing = publishing
|
||||||
req.OutID = r.FormValue("out_id")
|
req.OutID = outID
|
||||||
req.Quality = r.FormValue("quality")
|
req.Quality = quality
|
||||||
req.QueryIndex, _ = strconv.Atoi(r.FormValue("query_index"))
|
req.QueryIndex, _ = strconv.Atoi(queryIndex)
|
||||||
req.UserID = r.FormValue("user_id")
|
req.UserID = userID
|
||||||
req.PlaceholderDownPrice, _ = strconv.ParseFloat(r.FormValue("placeholder_down_price"), 64)
|
req.PlaceholderDownPrice, _ = strconv.ParseFloat(placeholderDownPrice, 64)
|
||||||
req.MinShippingFee, _ = strconv.ParseFloat(r.FormValue("min_shipping_fee"), 64)
|
req.MinShippingFee, _ = strconv.ParseFloat(minShippingFee, 64)
|
||||||
req.MinPrice, _ = strconv.ParseFloat(r.FormValue("min_price"), 64)
|
req.MinPrice, _ = strconv.ParseFloat(minPrice, 64)
|
||||||
|
|
||||||
// 调用服务层
|
// 调用服务层
|
||||||
resp := h.goodsService.QueryGoods(&req)
|
resp := h.goodsService.QueryGoods(&req)
|
||||||
|
log.Printf("[QueryGoods] 处理完成, ID=%d, Code=%d, Message=%s", resp.ID, resp.Code, resp.Message)
|
||||||
|
|
||||||
// 返回响应
|
// 返回响应
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|||||||
@ -3,10 +3,12 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/parnurzeal/gorequest"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/parnurzeal/gorequest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KfzHandler Kfz处理器
|
// KfzHandler Kfz处理器
|
||||||
@ -20,31 +22,43 @@ func NewKfzHandler() *KfzHandler {
|
|||||||
|
|
||||||
// KfzLogin 登录孔网并返回用户信息
|
// KfzLogin 登录孔网并返回用户信息
|
||||||
func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
|
func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[KfzLogin] 收到登录请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
r.ParseMultipartForm(32 << 20)
|
r.ParseMultipartForm(32 << 20)
|
||||||
username := r.PostForm.Get("username")
|
username := r.PostForm.Get("username")
|
||||||
password := r.PostForm.Get("password")
|
password := r.PostForm.Get("password")
|
||||||
|
|
||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
|
log.Printf("[KfzLogin] username或password为空, 来源IP: %s", clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"code":500,"message":"username和password不能为空"}`))
|
w.Write([]byte(`{"code":500,"message":"username和password不能为空"}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[KfzLogin] 开始登录孔网, username=%s, 来源IP: %s", username, clientIP)
|
||||||
token, err := outKfzLogin(username, password)
|
token, err := outKfzLogin(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[KfzLogin] 孔网登录失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
|
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("[KfzLogin] 孔网登录成功: username=%s, token=%s..., 来源IP: %s", username, token[:min(len(token), 10)], clientIP)
|
||||||
|
|
||||||
userInfo, err := outKfzGetUserInfo(token)
|
userInfo, err := outKfzGetUserInfo(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[KfzLogin] 获取用户信息失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
|
w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo.Token = token
|
userInfo.Token = token
|
||||||
|
log.Printf("[KfzLogin] 登录成功: username=%s, userId=%d, nickname=%s, 来源IP: %s", username, userInfo.UserID, userInfo.Nickname, clientIP)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
@ -54,6 +68,13 @@ func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 孔网登录
|
* 孔网登录
|
||||||
* param username[string] 孔网用户名
|
* param username[string] 孔网用户名
|
||||||
|
|||||||
@ -36,22 +36,27 @@ type TokenInput struct {
|
|||||||
|
|
||||||
// BatchAddTokens 批量添加Token(JSON数组: [{"username":"","token":""},...])
|
// BatchAddTokens 批量添加Token(JSON数组: [{"username":"","token":""},...])
|
||||||
func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
|
func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputs []TokenInput
|
var inputs []TokenInput
|
||||||
if err := json.NewDecoder(r.Body).Decode(&inputs); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&inputs); err != nil {
|
||||||
log.Printf("BatchAddTokens - decode error: %v", err)
|
log.Printf("[Token/BatchAdd] 请求体解析失败: %v, 来源IP: %s", err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "invalid request body"})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "invalid request body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("BatchAddTokens - received %d tokens", len(inputs))
|
log.Printf("[Token/BatchAdd] 收到请求, 来源IP: %s, token数量: %d", clientIP, len(inputs))
|
||||||
|
|
||||||
if len(inputs) == 0 {
|
if len(inputs) == 0 {
|
||||||
|
log.Printf("[Token/BatchAdd] 空数组, 来源IP: %s", clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "empty array"})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "empty array"})
|
||||||
return
|
return
|
||||||
@ -59,21 +64,25 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// 逐条插入
|
// 逐条插入
|
||||||
var failed []TokenInput
|
var failed []TokenInput
|
||||||
for _, input := range inputs {
|
for i, input := range inputs {
|
||||||
if input.Username == "" || input.Token == "" {
|
if input.Username == "" || input.Token == "" {
|
||||||
|
log.Printf("[Token/BatchAdd] 第%d条数据不完整(username或token为空), 跳过", i+1)
|
||||||
failed = append(failed, input)
|
failed = append(failed, input)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := h.tokenRepo.Insert(input.Username, input.Token, true)
|
id, err := h.tokenRepo.Insert(input.Username, input.Token, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("BatchAddTokens - insert error: %v", err)
|
log.Printf("[Token/BatchAdd] 第%d条插入失败: username=%s, 错误=%v", i+1, input.Username, err)
|
||||||
failed = append(failed, input)
|
failed = append(failed, input)
|
||||||
|
} else {
|
||||||
|
log.Printf("[Token/BatchAdd] 第%d条插入成功: id=%d, username=%s", i+1, id, input.Username)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
if len(failed) > 0 {
|
if len(failed) > 0 {
|
||||||
|
log.Printf("[Token/BatchAdd] 部分成功: 成功%d条, 失败%d条, 来源IP: %s", len(inputs)-len(failed), len(failed), clientIP)
|
||||||
json.NewEncoder(w).Encode(TokenResponse{
|
json.NewEncoder(w).Encode(TokenResponse{
|
||||||
Code: 207,
|
Code: 207,
|
||||||
Message: "partial success",
|
Message: "partial success",
|
||||||
@ -82,31 +91,44 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/BatchAdd] 全部成功: %d条, 来源IP: %s", len(inputs), clientIP)
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllTokens 查询所有Token
|
// GetAllTokens 查询所有Token
|
||||||
func (h *TokenHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) {
|
func (h *TokenHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[Token/GetAll] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := h.tokenRepo.GetAll()
|
records, err := h.tokenRepo.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/GetAll] 查询失败: %v, 来源IP: %s", err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/GetAll] 查询成功: 共%d条记录, 来源IP: %s", len(records), clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteToken 删除Token
|
// DeleteToken 删除Token
|
||||||
func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) {
|
func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[Token/Delete] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,25 +144,33 @@ func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/Delete] 参数id无效: %s, 来源IP: %s", idStr, clientIP)
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
http.Error(w, "invalid id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.tokenRepo.Delete(id)
|
err = h.tokenRepo.Delete(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/Delete] 删除失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/Delete] 删除成功: id=%d, 来源IP: %s", id, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateToken 修改Token
|
// UpdateToken 修改Token
|
||||||
func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
|
func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[Token/Update] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +185,7 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/Update] 参数id无效: %s, 来源IP: %s", idStr, clientIP)
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
http.Error(w, "invalid id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -164,31 +195,41 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) {
|
|||||||
isEnable = false
|
isEnable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/Update] 更新: id=%d, username=%s, is_enable=%v, 来源IP: %s", id, username, isEnable, clientIP)
|
||||||
err = h.tokenRepo.Update(id, username, token, isEnable)
|
err = h.tokenRepo.Update(id, username, token, isEnable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/Update] 更新失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/Update] 更新成功: id=%d, 来源IP: %s", id, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEnabledTokens 获取所有启用的Token
|
// GetEnabledTokens 获取所有启用的Token
|
||||||
func (h *TokenHandler) GetEnabledTokens(w http.ResponseWriter, r *http.Request) {
|
func (h *TokenHandler) GetEnabledTokens(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIP := r.RemoteAddr
|
||||||
|
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||||
|
clientIP = forwarded
|
||||||
|
}
|
||||||
|
log.Printf("[Token/GetEnabled] 收到请求, 来源IP: %s", clientIP)
|
||||||
|
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := h.tokenRepo.GetEnabledTokens()
|
records, err := h.tokenRepo.GetEnabledTokens()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Token/GetEnabled] 查询失败: %v, 来源IP: %s", err, clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Token/GetEnabled] 查询成功: 共%d条启用token, 来源IP: %s", len(records), clientIP)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
|
json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"kfz-goods-pricing/internal/database"
|
"kfz-goods-pricing/internal/database"
|
||||||
)
|
)
|
||||||
@ -26,11 +27,15 @@ func GetKfzConfig() (*KfzConfig, error) {
|
|||||||
).Scan(&cfg.ID, &cfg.NewPrice, &cfg.PlaceholderDownPrice, &cfg.MinShippingFee, &cfg.MinPrice, &cfg.QueryIndex)
|
).Scan(&cfg.ID, &cfg.NewPrice, &cfg.PlaceholderDownPrice, &cfg.MinShippingFee, &cfg.MinPrice, &cfg.QueryIndex)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
log.Printf("[Repo/Config] kfz_config表无数据")
|
||||||
return nil, nil // 无数据
|
return nil, nil // 无数据
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Config] 查询kfz_config失败: %v", err)
|
||||||
return nil, fmt.Errorf("查询kfz_config失败: %w", err)
|
return nil, fmt.Errorf("查询kfz_config失败: %w", err)
|
||||||
}
|
}
|
||||||
|
log.Printf("[Repo/Config] 查询成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
|
||||||
|
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +45,7 @@ func SaveKfzConfig(cfg *KfzConfig) error {
|
|||||||
var count int
|
var count int
|
||||||
err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_config").Scan(&count)
|
err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_config").Scan(&count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Config] 查询kfz_config数量失败: %v", err)
|
||||||
return fmt.Errorf("查询kfz_config失败: %w", err)
|
return fmt.Errorf("查询kfz_config失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,16 +55,22 @@ func SaveKfzConfig(cfg *KfzConfig) error {
|
|||||||
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
|
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Config] 插入配置失败: %v", err)
|
||||||
return fmt.Errorf("插入kfz_config失败: %w", err)
|
return fmt.Errorf("插入kfz_config失败: %w", err)
|
||||||
}
|
}
|
||||||
|
log.Printf("[Repo/Config] 插入配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
|
||||||
|
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
|
||||||
} else {
|
} else {
|
||||||
_, err = database.DB.Exec(
|
_, err = database.DB.Exec(
|
||||||
`UPDATE kfz_config SET new_price=?, placeholder_down_price=?, min_shipping_fee=?, min_price=?, query_index=? WHERE id=1`,
|
`UPDATE kfz_config SET new_price=?, placeholder_down_price=?, min_shipping_fee=?, min_price=?, query_index=? WHERE id=1`,
|
||||||
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
|
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Config] 更新配置失败: %v", err)
|
||||||
return fmt.Errorf("更新kfz_config失败: %w", err)
|
return fmt.Errorf("更新kfz_config失败: %w", err)
|
||||||
}
|
}
|
||||||
|
log.Printf("[Repo/Config] 更新配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
|
||||||
|
cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"kfz-goods-pricing/internal/database"
|
"kfz-goods-pricing/internal/database"
|
||||||
)
|
)
|
||||||
@ -40,14 +41,17 @@ func (r *GoodsRepository) Insert(isbn, bookName, author, publishing, outID, qual
|
|||||||
|
|
||||||
result, err := database.DB.Exec(query, isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice)
|
result, err := database.DB.Exec(query, isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Goods] 插入记录失败: isbn=%s, out_id=%s, 错误=%v", isbn, outID, err)
|
||||||
return 0, fmt.Errorf("插入记录失败: %w", err)
|
return 0, fmt.Errorf("插入记录失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := result.LastInsertId()
|
id, err := result.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Goods] 获取自增ID失败: %v", err)
|
||||||
return 0, fmt.Errorf("获取自增ID失败: %w", err)
|
return 0, fmt.Errorf("获取自增ID失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Repo/Goods] 插入成功: id=%d, isbn=%s, out_id=%s, min_price=%.2f", id, isbn, outID, minPrice)
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,16 +61,23 @@ func (r *GoodsRepository) UpdatePrice(id int64, price, shippingFee, finalPrice f
|
|||||||
|
|
||||||
_, err := database.DB.Exec(query, price, shippingFee, finalPrice, id)
|
_, err := database.DB.Exec(query, price, shippingFee, finalPrice, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Goods] 更新价格失败: id=%d, 错误=%v", id, err)
|
||||||
return fmt.Errorf("更新价格失败: %w", err)
|
return fmt.Errorf("更新价格失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Repo/Goods] 更新价格成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", id, price, shippingFee, finalPrice)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkFailed 标记查询失败,fail_count+1,更新updated_at
|
// MarkFailed 标记查询失败,fail_count+1,更新updated_at
|
||||||
func (r *GoodsRepository) MarkFailed(id int64) {
|
func (r *GoodsRepository) MarkFailed(id int64) {
|
||||||
query := `UPDATE goods_pricing SET fail_count = fail_count + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
|
query := `UPDATE goods_pricing SET fail_count = fail_count + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
|
||||||
database.DB.Exec(query, id)
|
_, err := database.DB.Exec(query, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[Repo/Goods] 标记失败: id=%d, 错误=%v", id, err)
|
||||||
|
} else {
|
||||||
|
log.Printf("[Repo/Goods] 标记失败成功: id=%d", id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByID 根据ID查询记录
|
// GetByID 根据ID查询记录
|
||||||
@ -144,6 +155,7 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) {
|
|||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
log.Printf("[Repo/Goods] 查询待处理记录失败: %v", err)
|
||||||
return nil, fmt.Errorf("查询记录失败: %w", err)
|
return nil, fmt.Errorf("查询记录失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,5 +178,6 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) {
|
|||||||
record.MinPrice = minPrice.Float64
|
record.MinPrice = minPrice.Float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[Repo/Goods] 查询到待处理记录: id=%d, isbn=%s, book_name=%s, fail_count=%d", record.ID, record.ISBN, record.BookName, record.FailCount)
|
||||||
return &record, nil
|
return &record, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ type QueryResponse struct {
|
|||||||
// QueryGoods 查询商品信息
|
// QueryGoods 查询商品信息
|
||||||
func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse {
|
func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse {
|
||||||
if req.ISBN == "0" {
|
if req.ISBN == "0" {
|
||||||
|
log.Printf("[QueryGoods] ISBN为0, 跳过处理")
|
||||||
return &QueryResponse{
|
return &QueryResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
Message: "success",
|
Message: "success",
|
||||||
@ -76,12 +77,15 @@ func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse {
|
|||||||
// 插入入参记录到数据库
|
// 插入入参记录到数据库
|
||||||
id, err := s.goodsRepository.Insert(req.ISBN, req.BookName, req.Author, req.Publishing, req.OutID, req.Quality, req.UserID, req.QueryIndex, req.PlaceholderDownPrice, req.MinShippingFee, req.MinPrice)
|
id, err := s.goodsRepository.Insert(req.ISBN, req.BookName, req.Author, req.Publishing, req.OutID, req.Quality, req.UserID, req.QueryIndex, req.PlaceholderDownPrice, req.MinShippingFee, req.MinPrice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[QueryGoods] 保存记录失败: isbn=%s, out_id=%s, user_id=%s, 错误=%v", req.ISBN, req.OutID, req.UserID, err)
|
||||||
return &QueryResponse{
|
return &QueryResponse{
|
||||||
Code: 500,
|
Code: 500,
|
||||||
Message: fmt.Sprintf("保存记录失败: %v", err),
|
Message: fmt.Sprintf("保存记录失败: %v", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[QueryGoods] 记录保存成功: id=%d, isbn=%s, book_name=%s, out_id=%s, user_id=%s", id, req.ISBN, req.BookName, req.OutID, req.UserID)
|
||||||
|
|
||||||
return &QueryResponse{
|
return &QueryResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
Message: "success",
|
Message: "success",
|
||||||
@ -135,6 +139,7 @@ func (s *GoodsService) sendCallback(outID, userID string, price, shippingFee flo
|
|||||||
|
|
||||||
// StartTimerScheduler 启动定时器
|
// StartTimerScheduler 启动定时器
|
||||||
func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
|
func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
|
||||||
|
log.Printf("[TimerScheduler] 定时器启动, 间隔=%d秒", intervalSeconds)
|
||||||
ticker := time.NewTicker(time.Duration(intervalSeconds) * time.Second)
|
ticker := time.NewTicker(time.Duration(intervalSeconds) * time.Second)
|
||||||
go func() {
|
go func() {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
@ -145,23 +150,29 @@ func (s *GoodsService) StartTimerScheduler(intervalSeconds int) {
|
|||||||
|
|
||||||
// syncGoodsPricing 定时同步商品价格
|
// syncGoodsPricing 定时同步商品价格
|
||||||
func (s *GoodsService) syncGoodsPricing() {
|
func (s *GoodsService) syncGoodsPricing() {
|
||||||
//cfg := config.GetGlobal()
|
log.Printf("[syncGoodsPricing] ===== 开始执行定时同步任务 =====")
|
||||||
|
|
||||||
// 查询数据库数据
|
// 查询数据库数据
|
||||||
kfzConfig, err := repository.GetKfzConfig()
|
kfzConfig, err := repository.GetKfzConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("获取config数据库数据失败: %v", err)
|
log.Printf("[syncGoodsPricing] 获取config数据库数据失败: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("[syncGoodsPricing] 全局配置: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d",
|
||||||
|
kfzConfig.NewPrice, kfzConfig.PlaceholderDownPrice, kfzConfig.MinShippingFee, kfzConfig.MinPrice, kfzConfig.QueryIndex)
|
||||||
|
|
||||||
// 查询一条记录,按fail_count升序、updated_at倒序
|
// 查询一条记录,按fail_count升序、updated_at倒序
|
||||||
record, err := s.goodsRepository.GetAllOrderByUpdatedAt()
|
record, err := s.goodsRepository.GetAllOrderByUpdatedAt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("定时任务查询失败: %v", err)
|
log.Printf("[syncGoodsPricing] 查询待处理记录失败: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if record == nil {
|
if record == nil {
|
||||||
|
log.Printf("[syncGoodsPricing] 没有待处理的记录, 跳过本次同步")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("[syncGoodsPricing] 获取到待处理记录: id=%d, isbn=%s, book_name=%s, out_id=%s, fail_count=%d",
|
||||||
|
record.ID, record.ISBN, record.BookName, record.OutID, record.FailCount)
|
||||||
|
|
||||||
// 限流等待
|
// 限流等待
|
||||||
s.rateLimitWait()
|
s.rateLimitWait()
|
||||||
@ -172,33 +183,45 @@ func (s *GoodsService) syncGoodsPricing() {
|
|||||||
var finalPrice float64
|
var finalPrice float64
|
||||||
|
|
||||||
// 查询孔网数据
|
// 查询孔网数据
|
||||||
|
log.Printf("[syncGoodsPricing] 开始查询孔网数据: id=%d, isbn=%s, book_name=%s", record.ID, record.ISBN, record.BookName)
|
||||||
bookInfo, err := s.outGetAllGoods(record.ISBN, record.BookName, record.Author, record.Publishing, record.Quality, record.QueryIndex)
|
bookInfo, err := s.outGetAllGoods(record.ISBN, record.BookName, record.Author, record.Publishing, record.Quality, record.QueryIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("[syncGoodsPricing] 查询孔网失败: id=%d, 错误=%v", record.ID, err)
|
||||||
if kfzConfig.NewPrice == 0 {
|
if kfzConfig.NewPrice == 0 {
|
||||||
s.goodsRepository.MarkFailed(record.ID)
|
s.goodsRepository.MarkFailed(record.ID)
|
||||||
log.Printf("定时任务[%d]查询孔网失败(fail_count=%d): %v", record.ID, record.FailCount+1, err)
|
log.Printf("[syncGoodsPricing] 标记失败: id=%d, fail_count=%d, new_price=0不启用兜底", record.ID, record.FailCount+1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
finalPrice = kfzConfig.NewPrice
|
finalPrice = kfzConfig.NewPrice
|
||||||
|
log.Printf("[syncGoodsPricing] 查询失败, 启用兜底价格: finalPrice=%.2f (new_price)", finalPrice)
|
||||||
} else {
|
} else {
|
||||||
// 查询成功,更新价格
|
// 查询成功,更新价格
|
||||||
price, _ = strconv.ParseFloat(bookInfo.Price, 64)
|
price, _ = strconv.ParseFloat(bookInfo.Price, 64)
|
||||||
shippingFee, _ = strconv.ParseFloat(bookInfo.ShippingFee, 64)
|
shippingFee, _ = strconv.ParseFloat(bookInfo.ShippingFee, 64)
|
||||||
totalPrice := price + shippingFee
|
totalPrice := price + shippingFee
|
||||||
|
log.Printf("[syncGoodsPricing] 孔网数据: id=%d, price=%.2f, shipping_fee=%.2f, total=%.2f", record.ID, price, shippingFee, totalPrice)
|
||||||
|
log.Printf("[syncGoodsPricing] 计算参数: placeholder_down_price=%.2f, min_shipping_fee=%.2f, kfzConfig.min_price=%.2f",
|
||||||
|
record.PlaceholderDownPrice, record.MinShippingFee, kfzConfig.MinPrice)
|
||||||
|
|
||||||
finalPrice = totalPrice - record.PlaceholderDownPrice - record.MinShippingFee
|
finalPrice = totalPrice - record.PlaceholderDownPrice - record.MinShippingFee
|
||||||
|
log.Printf("[syncGoodsPricing] 减去占位降价和运费后: finalPrice=%.2f", finalPrice)
|
||||||
|
|
||||||
if finalPrice < kfzConfig.MinPrice {
|
if finalPrice < kfzConfig.MinPrice {
|
||||||
|
log.Printf("[syncGoodsPricing] 价格低于最低书价, 使用最低书价: %.2f -> %.2f", finalPrice, kfzConfig.MinPrice)
|
||||||
finalPrice = kfzConfig.MinPrice
|
finalPrice = kfzConfig.MinPrice
|
||||||
}
|
}
|
||||||
// 保留两位小数
|
// 保留两位小数
|
||||||
|
beforeRound := finalPrice
|
||||||
finalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", finalPrice), 64)
|
finalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", finalPrice), 64)
|
||||||
|
log.Printf("[syncGoodsPricing] 最终价格取两位小数: %.2f -> %.2f", beforeRound, finalPrice)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.goodsRepository.UpdatePrice(record.ID, price, shippingFee, finalPrice); err != nil {
|
if err := s.goodsRepository.UpdatePrice(record.ID, price, shippingFee, finalPrice); err != nil {
|
||||||
log.Printf("定时任务[%d]更新价格失败: %v", record.ID, err)
|
log.Printf("[syncGoodsPricing] 更新价格失败: id=%d, 错误=%v", record.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("定时任务[%d]更新成功: price=%.2f, shipping_fee=%.2f", record.ID, price, shippingFee)
|
log.Printf("[syncGoodsPricing] 更新成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", record.ID, price, shippingFee, finalPrice)
|
||||||
|
|
||||||
// 调用回调
|
// 调用回调
|
||||||
s.sendCallback(record.OutID, record.UserID, finalPrice, record.MinShippingFee, kfzConfig.MinPrice)
|
s.sendCallback(record.OutID, record.UserID, finalPrice, record.MinShippingFee, kfzConfig.MinPrice)
|
||||||
@ -211,8 +234,10 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
// 从数据库获取启用的token列表
|
// 从数据库获取启用的token列表
|
||||||
tokens, err := s.tokenRepository.GetEnabledTokens()
|
tokens, err := s.tokenRepository.GetEnabledTokens()
|
||||||
if err != nil || len(tokens) == 0 {
|
if err != nil || len(tokens) == 0 {
|
||||||
|
log.Printf("[outGetAllGoods] 没有可用的token, 查询终止")
|
||||||
return nil, fmt.Errorf("没有可用的token")
|
return nil, fmt.Errorf("没有可用的token")
|
||||||
}
|
}
|
||||||
|
log.Printf("[outGetAllGoods] 可用token数量: %d", len(tokens))
|
||||||
|
|
||||||
// 轮询选择token
|
// 轮询选择token
|
||||||
s.tokenMu.Lock()
|
s.tokenMu.Lock()
|
||||||
@ -222,8 +247,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
s.tokenMu.Unlock()
|
s.tokenMu.Unlock()
|
||||||
|
|
||||||
token := tokens[currentIdx].Token
|
token := tokens[currentIdx].Token
|
||||||
|
log.Printf("[outGetAllGoods] 使用token索引: %d/%d, username=%s", currentIdx, len(tokens), tokens[currentIdx].Username)
|
||||||
|
|
||||||
//kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&quaSelect=2"
|
|
||||||
kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2"
|
kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2"
|
||||||
|
|
||||||
// 整理查询参数-加上排序
|
// 整理查询参数-加上排序
|
||||||
@ -260,6 +285,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
// 加入查询参数
|
// 加入查询参数
|
||||||
kfzUrl = kfzUrl + "&actionPath=" + actionPath
|
kfzUrl = kfzUrl + "&actionPath=" + actionPath
|
||||||
|
|
||||||
|
log.Printf("[outGetAllGoods] 请求孔网URL: %s", kfzUrl)
|
||||||
|
|
||||||
// 创建HTTP客户端
|
// 创建HTTP客户端
|
||||||
requestSpt := gorequest.New()
|
requestSpt := gorequest.New()
|
||||||
|
|
||||||
@ -267,7 +294,6 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
if s.proxy != "" {
|
if s.proxy != "" {
|
||||||
requestSpt.Proxy(s.proxy)
|
requestSpt.Proxy(s.proxy)
|
||||||
}
|
}
|
||||||
fmt.Println("请求地址:", kfzUrl)
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl).
|
respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl).
|
||||||
Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)).
|
Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)).
|
||||||
@ -280,16 +306,16 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
|
|
||||||
// 错误处理
|
// 错误处理
|
||||||
if len(errsSpt) > 0 {
|
if len(errsSpt) > 0 {
|
||||||
|
log.Printf("[outGetAllGoods] 孔网请求失败: %v", errsSpt)
|
||||||
return nil, fmt.Errorf("请求失败: %v", errsSpt)
|
return nil, fmt.Errorf("请求失败: %v", errsSpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查HTTP状态码
|
// 检查HTTP状态码
|
||||||
if respSpt.StatusCode != http.StatusOK {
|
if respSpt.StatusCode != http.StatusOK {
|
||||||
|
log.Printf("[outGetAllGoods] 孔网HTTP错误: %s", respSpt.Status)
|
||||||
return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status)
|
return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("响应数据:", bodySpt)
|
|
||||||
|
|
||||||
// 解析响应
|
// 解析响应
|
||||||
var apiSptResp struct {
|
var apiSptResp struct {
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
@ -318,16 +344,19 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
|
|
||||||
// 解析JSON
|
// 解析JSON
|
||||||
if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil {
|
if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil {
|
||||||
|
log.Printf("[outGetAllGoods] 解析孔网响应JSON失败: %v", err)
|
||||||
return nil, fmt.Errorf("解析JSON失败: %w", err)
|
return nil, fmt.Errorf("解析JSON失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiSptResp.Status != 1 {
|
if apiSptResp.Status != 1 {
|
||||||
|
log.Printf("[outGetAllGoods] 孔网API返回错误: message=%s, errType=%s", apiSptResp.Message, apiSptResp.ErrType)
|
||||||
return nil, fmt.Errorf("错误信息: %v,状态码: %s", apiSptResp.Message, apiSptResp.ErrType)
|
return nil, fmt.Errorf("错误信息: %v,状态码: %s", apiSptResp.Message, apiSptResp.ErrType)
|
||||||
}
|
}
|
||||||
|
|
||||||
bookInfo := &model.BookInfo{}
|
bookInfo := &model.BookInfo{}
|
||||||
|
|
||||||
if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 {
|
if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 {
|
||||||
|
log.Printf("[outGetAllGoods] 孔网搜索成功: 总共%d条结果, query_index=%d", apiSptResp.Data.ItemResponse.Total, queryIndex)
|
||||||
if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) {
|
if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) {
|
||||||
goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1]
|
goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1]
|
||||||
bookInfo.BookName = goodsInfo.Title
|
bookInfo.BookName = goodsInfo.Title
|
||||||
@ -339,6 +368,7 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
for _, shipping := range goodsInfo.Postage.ShippingList {
|
for _, shipping := range goodsInfo.Postage.ShippingList {
|
||||||
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
|
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
|
||||||
}
|
}
|
||||||
|
log.Printf("[outGetAllGoods] 取第%d条结果: title=%s, price=%s, shipping=%s", queryIndex, bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee)
|
||||||
} else {
|
} else {
|
||||||
goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1]
|
goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1]
|
||||||
bookInfo.BookName = goodsInfo.Title
|
bookInfo.BookName = goodsInfo.Title
|
||||||
@ -350,9 +380,11 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin
|
|||||||
for _, shipping := range goodsInfo.Postage.ShippingList {
|
for _, shipping := range goodsInfo.Postage.ShippingList {
|
||||||
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
|
bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee)
|
||||||
}
|
}
|
||||||
|
log.Printf("[outGetAllGoods] query_index无效, 取最后一条: title=%s, price=%s, shipping=%s", bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee)
|
||||||
}
|
}
|
||||||
return bookInfo, nil
|
return bookInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[outGetAllGoods] 孔网搜索无结果: total=%d", apiSptResp.Data.ItemResponse.Total)
|
||||||
return nil, fmt.Errorf("查询失败,没有数据!")
|
return nil, fmt.Errorf("查询失败,没有数据!")
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user