daShangDao_centerBook/util/pdd/pdd.go
2026-02-28 14:27:33 +08:00

193 lines
5.4 KiB
Go
Raw Permalink 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 pdd
/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
// C包装函数用于调用动态加载的函数
static void* get_func(void* handle, const char* name) {
return dlsym(handle, name);
}
// 包装PddGoodsOuterCatMappingGet函数
static char* call_PddGoodsOuterCatMappingGet(void* func, const char* clientId, const char* clientSecret,
const char* accessToken, const char* outerCatId, const char* outerCatName, const char* outerGoodsName) {
typedef char* (*FuncType)(const char*, const char*, const char*, const char*, const char*, const char*);
return ((FuncType)func)(clientId, clientSecret, accessToken, outerCatId, outerCatName, outerGoodsName);
}
// 包装FreeCString函数
static void call_FreeCString(void* func, char* str) {
typedef void (*FuncType)(char*);
if (func != NULL && str != NULL) {
((FuncType)func)(str);
}
}
*/
import "C"
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"unsafe"
)
// PddResponse 定义完整的响应结构(包含成功和失败两种情况)
type PddResponse struct {
SuccessResponse *PddCategoryMappingResponse `json:"outer_cat_mapping_get_response,omitempty"`
ErrorResponse *PddErrorResponse `json:"error_response,omitempty"`
}
// PddCategoryMappingResponse 定义拼多多API响应结构根据文档规范
type PddCategoryMappingResponse struct {
CatID1 int64 `json:"cat_id1"` // 一级类目ID
CatID2 int64 `json:"cat_id2"` // 二级类目ID
CatID3 int64 `json:"cat_id3"` // 三级类目ID
CatID4 int64 `json:"cat_id4"` // 四级类目ID
RequestID string `json:"request_id"` // 请求ID
}
type PddSO struct {
handle unsafe.Pointer // 动态库句柄
pddGoodsOuterCatMappingGet unsafe.Pointer // 类目预测函数指针
freeCString unsafe.Pointer // 释放C字符串函数指针
}
type PddErrorResponse struct {
ErrorCode int64 `json:"error_code"` // 错误码
ErrorMsg string `json:"error_msg"` // 错误信息
SubCode *string `json:"sub_code"` // 子错误码
SubMsg string `json:"sub_msg"` // 子错误信息
RequestID string `json:"request_id"` // 请求ID
}
var (
instance *PddSO
once sync.Once
)
// GetPddInstance 获取拼多多客户端单例实例
func GetPddInstance() (*PddSO, error) {
var initErr error
once.Do(func() {
instance, initErr = InitPddSO()
})
return instance, initErr
}
// InitPddSO 初始化pddSO
func InitPddSO() (*PddSO, error) {
soPath := filepath.Join("so", "pdd.so")
if _, err := os.Stat(soPath); os.IsNotExist(err) {
return nil, fmt.Errorf("pdd SO 不存在: %s", soPath)
}
// 加载动态库
soPathC := C.CString(soPath)
defer C.free(unsafe.Pointer(soPathC))
handle := C.dlopen(soPathC, C.RTLD_LAZY)
if handle == nil {
errMsg := C.GoString(C.dlerror())
return nil, fmt.Errorf("加载pdd SO 失败: %s", errMsg)
}
// 获取函数指针
// 获取函数指针
getFunc := func(name string) (unsafe.Pointer, error) {
funcPtr := C.get_func(handle, C.CString(name))
if funcPtr == nil {
C.dlclose(handle)
return nil, fmt.Errorf("找不到函数 %s", name)
}
return funcPtr, nil
}
pddFunc, err := getFunc("PddGoodsOuterCatMappingGet")
if err != nil {
return nil, err
}
freeFunc, err := getFunc("FreeCString")
if err != nil {
return nil, err
}
return &PddSO{
handle: handle,
pddGoodsOuterCatMappingGet: pddFunc,
freeCString: freeFunc,
}, nil
}
// PddGoodsOuterCatMappingGet 类目检测
func (m *PddSO) PddGoodsOuterCatMappingGet(clientId, clientSecret, accessToken,
outerCatId, outerCatName, outerGoodsName string) (string, error) {
// 使用闭包简化C字符串管理
toCStr := func(s string) (*C.char, func()) {
cStr := C.CString(s)
return cStr, func() { C.free(unsafe.Pointer(cStr)) }
}
clientIdC, cleanup1 := toCStr(clientId)
defer cleanup1()
clientSecretC, cleanup2 := toCStr(clientSecret)
defer cleanup2()
accessTokenC, cleanup3 := toCStr(accessToken)
defer cleanup3()
outerCatIdC, cleanup4 := toCStr(outerCatId)
defer cleanup4()
outerCatNameC, cleanup5 := toCStr(outerCatName)
defer cleanup5()
outerGoodsNameC, cleanup6 := toCStr(outerGoodsName)
defer cleanup6()
result := C.call_PddGoodsOuterCatMappingGet(
m.pddGoodsOuterCatMappingGet,
clientIdC, clientSecretC, accessTokenC,
outerCatIdC, outerCatNameC, outerGoodsNameC,
)
if result == nil {
return "", fmt.Errorf("调用PddGoodsOuterCatMappingGet失败")
}
defer C.call_FreeCString(m.freeCString, result)
return m.parseCategoryMappingResponse(C.GoString(result))
}
// parseCategoryMappingResponse 解析类目映射API响应
func (m *PddSO) parseCategoryMappingResponse(result string) (string, error) {
var apiResponse PddResponse
if err := json.Unmarshal([]byte(result), &apiResponse); err != nil {
return "", fmt.Errorf("JSON解析失败: %v, 原始数据: %s", err, result)
}
// 判断是成功响应还是错误响应
switch {
case apiResponse.ErrorResponse != nil:
errorResp := apiResponse.ErrorResponse
return "", fmt.Errorf("API调用失败 - 错误码: %d, 错误信息: %s",
errorResp.ErrorCode, errorResp.ErrorMsg)
case apiResponse.SuccessResponse != nil:
successResp := apiResponse.SuccessResponse
return fmt.Sprintf("%d/%d/%d",
successResp.CatID1,
successResp.CatID2,
successResp.CatID3), nil
default:
return "", fmt.Errorf("未知的响应格式: %s", result)
}
}