package pdd /* #cgo LDFLAGS: -ldl #include #include #include // 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) } }