feat 抽出coach请求
This commit is contained in:
parent
d4b2d1596c
commit
0653521e73
60
pkg/coach-client/client.go
Normal file
60
pkg/coach-client/client.go
Normal file
@ -0,0 +1,60 @@
|
||||
package coach_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gitea.timerzz.com/kedaya_haitao/common/pkg/proxy"
|
||||
restry_pool "gitea.timerzz.com/kedaya_haitao/common/pkg/restry-pool"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/pkg/errors"
|
||||
proxy2 "github.com/timerzz/proxypool/pkg/proxy"
|
||||
"log/slog"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
pool *proxy.ProxyPool
|
||||
defaultTimeOut time.Duration
|
||||
}
|
||||
|
||||
func NewClient(pool *proxy.ProxyPool) *Client {
|
||||
return &Client{
|
||||
pool: pool,
|
||||
defaultTimeOut: 10 * time.Minute,
|
||||
}
|
||||
}
|
||||
|
||||
func tryRequest(ctx context.Context, urlPath string, respData any, proxyGetter func() proxy2.Proxy) error {
|
||||
for p := proxyGetter(); p != nil; p = proxyGetter() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
|
||||
}
|
||||
_, err := callByProxy(ctx, p, urlPath, respData)
|
||||
if err != nil {
|
||||
slog.Debug(err.Error())
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("未获取到可用的代理")
|
||||
}
|
||||
|
||||
func callByProxy(ctx context.Context, p proxy2.Proxy, urlPath string, result any) (*resty.Response, error) {
|
||||
addr, err := proxy.UrlToMetadata(urlPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subCtx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
conn, err := proxy.ConnFromProxy(subCtx, p, addr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "创建conn失败")
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
var cli = restry_pool.GetRestyClient(conn)
|
||||
defer restry_pool.PutRestyClient(cli)
|
||||
return cli.R().SetResult(result).Get(urlPath)
|
||||
}
|
18
pkg/coach-client/client_test.go
Normal file
18
pkg/coach-client/client_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
package coach_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gitea.timerzz.com/kedaya_haitao/common/pkg/proxy"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
subs := []string{"https://us.timerzz.com:26106/vmess/sub", "https://us.timerzz.com:26106/trojan/sub", "https://us.timerzz.com:26106/ssr/sub"}
|
||||
pool := proxy.NewProxyPool(subs)
|
||||
client := NewClient(pool)
|
||||
resp, err := client.ViewAllBags(context.Background(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(resp)
|
||||
}
|
40
pkg/coach-client/details.go
Normal file
40
pkg/coach-client/details.go
Normal file
@ -0,0 +1,40 @@
|
||||
package coach_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type ProductData struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Brand string `json:"brand"`
|
||||
Inventory Inventory `json:"inventory"`
|
||||
Url string `json:"url"`
|
||||
MasterId string `json:"masterId"`
|
||||
Prices struct {
|
||||
CurrentPrice float64 `json:"currentPrice"`
|
||||
} `json:"prices"`
|
||||
Remark string `json:"-"`
|
||||
}
|
||||
|
||||
type ProductDataResponse struct {
|
||||
ProductData []*ProductData `json:"productsData"`
|
||||
}
|
||||
|
||||
func (c *Client) RequestProductDetail(ctx context.Context, pid string) (data ProductData, err error) {
|
||||
sctx, cancel := context.WithTimeout(ctx, c.defaultTimeOut)
|
||||
defer cancel()
|
||||
var resp ProductDataResponse
|
||||
urlPath := fmt.Sprintf("https://www.coachoutlet.com/api/get-products?ids=%s&includeInventory=false", url.QueryEscape(pid))
|
||||
err = tryRequest(sctx, urlPath, &resp, c.pool.RandomIterator())
|
||||
if len(resp.ProductData) == 0 && err != nil {
|
||||
err = fmt.Errorf("获取详情信息为空")
|
||||
return
|
||||
}
|
||||
if len(resp.ProductData) > 0 {
|
||||
data = *resp.ProductData[0]
|
||||
}
|
||||
return
|
||||
}
|
37
pkg/coach-client/inventory.go
Normal file
37
pkg/coach-client/inventory.go
Normal file
@ -0,0 +1,37 @@
|
||||
package coach_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Inventory struct {
|
||||
Id string `json:"id"`
|
||||
Ats int `json:"ats"`
|
||||
PreOrderable bool `json:"preorderable"`
|
||||
BackOrderable bool `json:"backorderable"`
|
||||
Orderable bool `json:"orderable"`
|
||||
AllocationResetDate time.Time `json:"allocationResetDate,omitempty"`
|
||||
Perpetual bool `json:"perpetual"`
|
||||
StockLevel int `json:"stockLevel"`
|
||||
}
|
||||
|
||||
type InventoryResponse struct {
|
||||
Inventory struct {
|
||||
Status string `json:"status"`
|
||||
InventoryListID string `json:"inventoryListID"`
|
||||
InventoryInfo Inventory `json:"inventoryInfo"`
|
||||
} `json:"inventory"`
|
||||
}
|
||||
|
||||
func (c *Client) RequestInventory(ctx context.Context, pid string) (inv Inventory, err error) {
|
||||
sctx, cancel := context.WithTimeout(ctx, c.defaultTimeOut)
|
||||
defer cancel()
|
||||
var resp InventoryResponse
|
||||
urlPath := fmt.Sprintf("https://www.coachoutlet.com/api/inventory?vgId=%s&includeVariantData=false", url.QueryEscape(pid))
|
||||
err = tryRequest(sctx, urlPath, &resp, c.pool.RandomIterator())
|
||||
inv = resp.Inventory.InventoryInfo
|
||||
return
|
||||
}
|
68
pkg/coach-client/view-all-bags.go
Normal file
68
pkg/coach-client/view-all-bags.go
Normal file
@ -0,0 +1,68 @@
|
||||
package coach_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type PageDataResponse struct {
|
||||
PageData struct {
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
TotalPages int `json:"totalPages"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Products []Product `json:"products"`
|
||||
} `json:"pageData"`
|
||||
}
|
||||
type Product struct {
|
||||
Name string `json:"name"`
|
||||
Colors []Color `json:"colors"`
|
||||
VariantsOnSale []Variant `json:"variantsOnSale"`
|
||||
}
|
||||
|
||||
type Color struct {
|
||||
Id string `json:"id"` //"id": "IMDQC",
|
||||
Text string `json:"text"` //颜色的描述
|
||||
Orderable bool `json:"orderable"`
|
||||
Media Media `json:"media"`
|
||||
Url string `json:"url"` //"/products/eliza-flap-crossbody-bag-in-signature-canvas/CP009-IMDQC.html",
|
||||
VgId string `json:"vgId"` // "vgId": "CP009-IMDQC",
|
||||
MasterId string `json:"masterId"` //"masterId": "CP009"
|
||||
}
|
||||
|
||||
type Media struct {
|
||||
Thumbnail Thumbnail `json:"thumbnail"`
|
||||
}
|
||||
|
||||
type Thumbnail struct {
|
||||
Src string `json:"src"`
|
||||
}
|
||||
|
||||
type Variant struct {
|
||||
Id string `json:"id"`
|
||||
OnSale bool `json:"onSale"`
|
||||
Price Price `json:"price"`
|
||||
}
|
||||
|
||||
type Price struct {
|
||||
Sales Sales `json:"sales"`
|
||||
MarkdownDiscPercent int `json:"markdownDiscPercent"`
|
||||
}
|
||||
|
||||
type Sales struct {
|
||||
Value float64 `json:"value"`
|
||||
Currency string `json:"currency"`
|
||||
Formatted string `json:"formatted"`
|
||||
DecimalPrice string `json:"decimalPrice"`
|
||||
}
|
||||
|
||||
func (c *Client) ViewAllBags(ctx context.Context, page int) (resp PageDataResponse, err error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
sctx, cancel := context.WithTimeout(ctx, c.defaultTimeOut)
|
||||
defer cancel()
|
||||
urlPath := fmt.Sprintf("https://www.coachoutlet.com/api/get-shop/bags/view-all?page=%d", page)
|
||||
err = tryRequest(sctx, urlPath, &resp, c.pool.RandomIterator())
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user