504 lines
16 KiB
Go
504 lines
16 KiB
Go
package main
|
|
|
|
///*
|
|
//#cgo linux LDFLAGS: -ldl
|
|
//#cgo windows LDFLAGS: -lkernel32
|
|
//
|
|
//#include <stdlib.h>
|
|
//
|
|
//#ifdef _WIN32
|
|
//#include <windows.h>
|
|
//static void* dlopen(const char* filename, int flags) {
|
|
// return (void*)LoadLibraryA(filename);
|
|
//}
|
|
//static void dlclose(void* handle) {
|
|
// FreeLibrary((HMODULE)handle);
|
|
//}
|
|
//static void* dlsym(void* handle, const char* name) {
|
|
// return (void*)GetProcAddress((HMODULE)handle, name);
|
|
//}
|
|
//static const char* dlerror() {
|
|
// static char buf[256];
|
|
// FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
// NULL, GetLastError(), 0, buf, sizeof(buf), NULL);
|
|
// return buf;
|
|
//}
|
|
//#define RTLD_LAZY 0
|
|
//#else
|
|
//#include <dlfcn.h>
|
|
//#endif
|
|
//*/
|
|
//import "C"
|
|
//import (
|
|
// "encoding/json"
|
|
// "fmt"
|
|
// "log"
|
|
// "net/http"
|
|
// "os"
|
|
// "path/filepath"
|
|
// "runtime"
|
|
// "unsafe"
|
|
//)
|
|
//
|
|
//// 配置结构
|
|
//type Configs struct {
|
|
// App struct {
|
|
// MaxRetryTimes int `json:"max_retry_times"`
|
|
// RateLimitDelay int `json:"rate_limit_delay"`
|
|
// Size int `json:"size"`
|
|
// DefaultUserAgent string `json:"default_user_agent"`
|
|
// } `json:"app"`
|
|
//
|
|
// API struct {
|
|
// LoginURL string `json:"login_url"`
|
|
// BookSearchURL string `json:"book_search_url"`
|
|
// ProductSearchURL string `json:"product_search_url"`
|
|
// } `json:"api"`
|
|
//
|
|
// Proxy struct {
|
|
// Servers string `json:"servers"`
|
|
// Username string `json:"username"`
|
|
// Password string `json:"password"`
|
|
// TailMachineCode string `json:"tail_machine_code"`
|
|
// TailCardKey string `json:"tail_card_key"`
|
|
// ProxyFilePath string `json:"proxy_file_path"`
|
|
// } `json:"proxy"`
|
|
//}
|
|
//
|
|
//// API响应结构
|
|
//type APIResponseSO struct {
|
|
// Success bool `json:"success"`
|
|
// Message string `json:"message,omitempty"`
|
|
// GoodsNum string `json:"goods_num,omitempty"`
|
|
// PNum string `json:"pnum,omitempty"`
|
|
// Data interface{} `json:"data,omitempty"`
|
|
// Error string `json:"error,omitempty"`
|
|
//}
|
|
//
|
|
//// APIResp 简化的响应结构体
|
|
//type APIRespSO struct {
|
|
// Success bool `json:"success"`
|
|
// Message string `json:"message"`
|
|
// Data interface{} `json:"data,omitempty"`
|
|
//}
|
|
//
|
|
//type SOManager struct {
|
|
// handle unsafe.Pointer
|
|
//}
|
|
//
|
|
//func NewSOManager(soPath string) (*SOManager, error) {
|
|
// // 根据平台调整库文件扩展名
|
|
// if runtime.GOOS == "windows" {
|
|
// soPath = changeExtensionToDLL(soPath)
|
|
// }
|
|
// // 使用 dlopen 加载 .so 文件
|
|
// cSoPath := C.CString(soPath)
|
|
// defer C.free(unsafe.Pointer(cSoPath))
|
|
//
|
|
// handle := C.dlopen(cSoPath, C.RTLD_LAZY)
|
|
// if handle == nil {
|
|
// return nil, fmt.Errorf("加载SO文件失败: %s", C.GoString(C.dlerror()))
|
|
// }
|
|
//
|
|
// return &SOManager{handle: handle}, nil
|
|
//}
|
|
//
|
|
//func (m *SOManager) Close() {
|
|
// if m.handle != nil {
|
|
// C.dlclose(m.handle)
|
|
// }
|
|
//}
|
|
//
|
|
//func changeExtensionToDLL(path string) string {
|
|
// ext := filepath.Ext(path)
|
|
// if ext == ".so" {
|
|
// return path[:len(path)-len(ext)] + ".dll"
|
|
// }
|
|
// return path
|
|
//}
|
|
//
|
|
//// 获取函数指针
|
|
//func (m *SOManager) getFunction(funcName string) (unsafe.Pointer, error) {
|
|
// cFuncName := C.CString(funcName)
|
|
// defer C.free(unsafe.Pointer(cFuncName))
|
|
//
|
|
// symbol := C.dlsym(m.handle, cFuncName)
|
|
// if symbol == nil {
|
|
// return nil, fmt.Errorf("找不到函数 %s: %s", funcName, C.GoString(C.dlerror()))
|
|
// }
|
|
// return symbol, nil
|
|
//}
|
|
//
|
|
//// 初始化
|
|
//func (m *SOManager) Initialize(configJSON string) (string, error) {
|
|
// function, err := m.getFunction("Initialize")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char) *C.char)(unsafe.Pointer(&function))
|
|
// configJSONC := C.CString(configJSON)
|
|
// defer C.free(unsafe.Pointer(configJSONC))
|
|
// result := (*funcPtr)(configJSONC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 登录
|
|
//func (m *SOManager) OutLogin(username, password string) (string, error) {
|
|
// function, err := m.getFunction("OutLogin")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// usernameC := C.CString(username)
|
|
// passwordC := C.CString(password)
|
|
// defer C.free(unsafe.Pointer(usernameC))
|
|
// defer C.free(unsafe.Pointer(passwordC))
|
|
// result := (*funcPtr)(usernameC, passwordC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取用户信息
|
|
//func (m *SOManager) OutGetUserMsg(token string) (string, error) {
|
|
// function, err := m.getFunction("OutGetUserMsg")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// result := (*funcPtr)(tokenC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取商品模版
|
|
//func (m *SOManager) OutGetGoodsTplMsg(token, itemId, proxy string) (string, error) {
|
|
// function, err := m.getFunction("OutGetGoodsTplMsg")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// itemIdC := C.CString(itemId)
|
|
// proxyC := C.CString(proxy)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(itemIdC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(tokenC, itemIdC, proxyC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取商品列表-已登的店铺
|
|
//func (m *SOManager) OutGetGoodsListMsgFromSelfShop(token string, proxy string,
|
|
// itemSn string, priceMin string, priceMax string, startCreateTime int,
|
|
// endCreateTime int, requestType string, isItemSnEqual int, page int, size int) (string, error) {
|
|
// function, err := m.getFunction("OutGetGoodsListMsgFromSelfShop")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, *C.char, *C.char, *C.char, C.int, C.int, *C.char, C.int, C.int, C.int) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// proxyC := C.CString(proxy)
|
|
// itemSnC := C.CString(itemSn)
|
|
// priceMinC := C.CString(priceMin)
|
|
// priceMaxC := C.CString(priceMax)
|
|
// startCreateTimeC := C.int(startCreateTime)
|
|
// endCreateTimeC := C.int(endCreateTime)
|
|
// requestTypeC := C.CString(requestType)
|
|
// isItemSnEqualC := C.int(isItemSnEqual)
|
|
// pageC := C.int(page)
|
|
// sizeC := C.int(size)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// defer C.free(unsafe.Pointer(itemSnC))
|
|
// defer C.free(unsafe.Pointer(priceMinC))
|
|
// defer C.free(unsafe.Pointer(priceMaxC))
|
|
// defer C.free(unsafe.Pointer(requestTypeC))
|
|
// result := (*funcPtr)(tokenC, proxyC, itemSnC, priceMinC, priceMaxC, startCreateTimeC,
|
|
// endCreateTimeC, requestTypeC, isItemSnEqualC, pageC, sizeC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 删除商品-已登的店铺
|
|
//func (m *SOManager) OutDelGoodsFromSelfShop(token, itemId, proxy string) (string, error) {
|
|
// function, err := m.getFunction("OutDelGoodsFromSelfShop")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// itemIdC := C.CString(itemId)
|
|
// proxyC := C.CString(proxy)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(itemIdC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(tokenC, itemIdC, proxyC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 新增商品
|
|
//func (m *SOManager) OutAddGoods(token, proxy, formData string) (string, error) {
|
|
// function, err := m.getFunction("OutAddGoods")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// proxyC := C.CString(proxy)
|
|
// formDataC := C.CString(formData)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// defer C.free(unsafe.Pointer(formDataC))
|
|
// result := (*funcPtr)(tokenC, proxyC, formDataC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取图片URL(官图和拍图)带有店铺过滤
|
|
//func (m *SOManager) OutGetImageFilterShopId(token string, isbn string, shopId int, proxy string, isLiveImage int, isReturnMsg int) (string, error) {
|
|
// function, err := m.getFunction("OutGetImageFilterShopId")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, C.int, *C.char, C.int, C.int) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// isbnC := C.CString(isbn)
|
|
// shopIdC := C.int(shopId)
|
|
// proxyC := C.CString(proxy)
|
|
// isLiveImageC := C.int(isLiveImage)
|
|
// isReturnMsgC := C.int(isReturnMsg)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(isbnC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(tokenC, isbnC, shopIdC, proxyC, isLiveImageC, isReturnMsgC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取商品图片
|
|
//func (m *SOManager) OutGetImageByIsbn(token string, isbn string, proxy string, isLiveImage int, isReturnMsg int) (string, error) {
|
|
// function, err := m.getFunction("OutGetImageByIsbn")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char, *C.char, C.int, C.int) *C.char)(unsafe.Pointer(&function))
|
|
// tokenC := C.CString(token)
|
|
// isbnC := C.CString(isbn)
|
|
// proxyC := C.CString(proxy)
|
|
// isLiveImageC := C.int(isLiveImage)
|
|
// isReturnMsgC := C.int(isReturnMsg)
|
|
// defer C.free(unsafe.Pointer(tokenC))
|
|
// defer C.free(unsafe.Pointer(isbnC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(tokenC, isbnC, proxyC, isLiveImageC, isReturnMsgC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取商品列表通过店铺ID
|
|
//func (m *SOManager) OutGetGoodsListMsgByShopId(shopId int, proxy string, retPrice int, isImage int, sortType string,
|
|
// sort string, priceMin float32, priceMax float32, pageNum, returnNum int) (string, error) {
|
|
// function, err := m.getFunction("OutGetGoodsListMsgByShopId")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(C.int, *C.char, C.int, C.int, *C.char, *C.char, C.double, C.double, C.int, C.int) *C.char)(unsafe.Pointer(&function))
|
|
// shopIdC := C.int(shopId)
|
|
// proxyC := C.CString(proxy)
|
|
// retPriceC := C.int(retPrice)
|
|
// isImageC := C.int(isImage)
|
|
// sortTypeC := C.CString(sortType)
|
|
// sortC := C.CString(sort)
|
|
// priceMinC := C.double(priceMin)
|
|
// priceMaxC := C.double(priceMax)
|
|
// pageNumC := C.int(pageNum)
|
|
// returnNumC := C.int(returnNum)
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// defer C.free(unsafe.Pointer(sortTypeC))
|
|
// defer C.free(unsafe.Pointer(sortC))
|
|
// result := (*funcPtr)(shopIdC, proxyC, retPriceC, isImageC, sortTypeC, sortC, priceMinC, priceMaxC, pageNumC, returnNumC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取商品信息通过商品详情链接
|
|
//func (m *SOManager) OutGetGoodsMsgByDetailUrl(detailUrl, proxy string) (string, error) {
|
|
// function, err := m.getFunction("OutGetGoodsMsgByDetailUrl")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(*C.char, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// detailUrlC := C.CString(detailUrl)
|
|
// proxyC := C.CString(proxy)
|
|
// defer C.free(unsafe.Pointer(detailUrlC))
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(detailUrlC, proxyC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 获取销量榜商品列表
|
|
//func (m *SOManager) OutGetTopGoodsListMsg(catId int, proxy string) (string, error) {
|
|
// function, err := m.getFunction("OutGetTopGoodsListMsg")
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// funcPtr := (*func(C.int, *C.char) *C.char)(unsafe.Pointer(&function))
|
|
// catIdC := C.int(catId)
|
|
// proxyC := C.CString(proxy)
|
|
// defer C.free(unsafe.Pointer(proxyC))
|
|
// result := (*funcPtr)(catIdC, proxyC)
|
|
// defer C.free(unsafe.Pointer(result))
|
|
// return C.GoString(result), nil
|
|
//}
|
|
//
|
|
//// 创建默认配置
|
|
//func createDefaultConfig() Configs {
|
|
// var configs Configs
|
|
// // App配置
|
|
// configs.App.MaxRetryTimes = 3
|
|
// configs.App.RateLimitDelay = 1000
|
|
// configs.App.Size = 10
|
|
// configs.App.DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
// // API配置
|
|
// configs.API.LoginURL = "https://login.kongfz.com/Pc/Login/account"
|
|
// configs.API.BookSearchURL = "https://search.kongfz.com/pc-gw/search-web/client/pc/bookLib/keyword/list"
|
|
// configs.API.ProductSearchURL = "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list"
|
|
// // 代理配置
|
|
// configs.Proxy.Servers = "http-dynamic.xiaoxiangdaili.com,http-dynamic-S02.xiaoxiangdaili.com,http-dynamic-S03.xiaoxiangdaili.com,http-dynamic-S04.xiaoxiangdaili.com"
|
|
// configs.Proxy.Username = "1297757178467602432"
|
|
// configs.Proxy.Password = "QgQBvP7f"
|
|
// configs.Proxy.TailMachineCode = "b7bf22a237ec692f13fcc2c43ee63252"
|
|
// configs.Proxy.TailCardKey = "DL_20_YK_1920acb2129844c2aabade3896560a9b"
|
|
// configs.Proxy.ProxyFilePath = "so/proxyConfig.so"
|
|
// return configs
|
|
//}
|
|
//
|
|
//// 获取当前可执行文件所在目录
|
|
//func getExecutableDir() string {
|
|
// exePath, err := os.Executable()
|
|
// if err != nil {
|
|
// return "."
|
|
// }
|
|
// return filepath.Dir(exePath)
|
|
//}
|
|
//
|
|
//func main() {
|
|
// fmt.Println("ccc")
|
|
// http.HandleFunc("/api/kfzShopBookInfo", handleGetKFZShopBookInfo)
|
|
//
|
|
// port := "8080"
|
|
// log.Printf("🚀 服务器启动在端口 %s", port)
|
|
// if err := http.ListenAndServe(":"+port, nil); err != nil {
|
|
// log.Fatalf("服务器启动失败: %v", err)
|
|
// }
|
|
//}
|
|
//
|
|
//func handleGetKFZShopBookInfo(w http.ResponseWriter, r *http.Request) {
|
|
// // 设置响应头
|
|
// w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
//
|
|
// // 只支持GET请求
|
|
// if r.Method != http.MethodGet {
|
|
// sendErrorResponse(w, http.StatusMethodNotAllowed, "只支持GET方法")
|
|
// return
|
|
// }
|
|
// soPath := filepath.Join("so", "kongfz.so")
|
|
// if _, err := os.Stat(soPath); os.IsNotExist(err) {
|
|
// log.Printf("❌ SO文件不存在: %s", soPath)
|
|
// sendErrorResponse(w, http.StatusInternalServerError,
|
|
// fmt.Sprintf("SO文件不存在: %s", soPath))
|
|
// return
|
|
// }
|
|
// // 加载SO
|
|
// manager, err := NewSOManager(soPath)
|
|
// if err != nil {
|
|
// log.Printf("初始化SO管理器失败: %v", err)
|
|
// sendErrorResponse(w, http.StatusInternalServerError, "初始化SO管理器失败")
|
|
// return
|
|
// }
|
|
// defer manager.Close()
|
|
// log.Println("✅ SO加载成功")
|
|
// // 使用默认配置初始化
|
|
// config := createDefaultConfig()
|
|
// configJSON, err := json.Marshal(config)
|
|
// if err != nil {
|
|
// log.Printf("序列化配置失败: %v", err)
|
|
// sendErrorResponse(w, http.StatusInternalServerError, "序列化配置失败")
|
|
// return
|
|
// }
|
|
// result, err := manager.Initialize(string(configJSON))
|
|
// if err != nil {
|
|
// log.Printf("初始化失败: %v", err)
|
|
// sendErrorResponse(w, http.StatusInternalServerError, "初始化失败")
|
|
// return
|
|
// }
|
|
// var initResp APIResponseSO
|
|
// if err := json.Unmarshal([]byte(result), &initResp); err != nil {
|
|
// log.Printf("解析初始化响应失败: %v", err)
|
|
// sendErrorResponse(w, http.StatusInternalServerError, "解析初始化响应失败")
|
|
// return
|
|
// }
|
|
// if !initResp.Success {
|
|
// log.Printf("初始化失败: %s", initResp.Message)
|
|
// sendErrorResponse(w, http.StatusInternalServerError, "初始化失败: "+initResp.Message)
|
|
// return
|
|
// }
|
|
// log.Println("✅ SO初始化成功")
|
|
//
|
|
// // 登录示例
|
|
// user, err := manager.OutLogin("18904056801", "Long6166@@")
|
|
// if err != nil {
|
|
// log.Printf("登录失败: %v", err)
|
|
// } else {
|
|
// log.Printf("登录结果: %s", user)
|
|
// }
|
|
//
|
|
// // 解析token
|
|
// var data APIResponseSO
|
|
// if err := json.Unmarshal([]byte(user), &data); err != nil {
|
|
// log.Printf("解析登录响应失败: %v", err)
|
|
// } else {
|
|
// var token string
|
|
// if dataMap, ok := data.Data.(map[string]interface{}); ok {
|
|
// if tk, exists := dataMap["token"]; exists {
|
|
// token = tk.(string)
|
|
// log.Printf("获取到Token: %s", token)
|
|
//
|
|
// // 使用token获取用户信息
|
|
// msg, err := manager.OutGetUserMsg(token)
|
|
// if err != nil {
|
|
// log.Printf("获取用户信息失败: %v", err)
|
|
// } else {
|
|
// log.Printf("用户信息: %s", msg)
|
|
// }
|
|
// } else {
|
|
// log.Println("Token 不存在")
|
|
// }
|
|
// } else {
|
|
// log.Println("Data 格式不正确")
|
|
// }
|
|
// }
|
|
// // 返回成功响应
|
|
// response := APIRespSO{
|
|
// Success: true,
|
|
// Message: "SO调用成功",
|
|
// }
|
|
// json.NewEncoder(w).Encode(response)
|
|
//}
|
|
//
|
|
//// 发送错误响应
|
|
//func sendErrorResponse(w http.ResponseWriter, statusCode int, message string) {
|
|
// response := APIRespSO{
|
|
// Success: false,
|
|
// Message: message,
|
|
// }
|
|
// w.WriteHeader(statusCode)
|
|
// json.NewEncoder(w).Encode(response)
|
|
//}
|