package common import ( "bytes" "context" "crypto/tls" "errors" "git.listensoft.net/tool/jspkit/common/lxhttp" "git.listensoft.net/tool/jspkit/common/models" "git.listensoft.net/tool/jspkit/common/variable" "git.listensoft.net/tool/jspkit/logger" "git.listensoft.net/tool/jspkit/taxerr" "github.com/go-kratos/kratos/v2/log" "github.com/go-rod/rod" "github.com/google/uuid" "go.uber.org/zap" "io" "mime/multipart" "net/http" "os" "strings" "time" ) var ExcelServiceUrl = `http://47.105.103.181:4000/excel` // 新版解析excel服务 var InfoCscsts bool = false var ComInfo = models.CompanyInfo{} const ( ClickTimeOut = 5 * time.Second LoadTimeout = 20 * time.Second ) // 手机号锁 time 锁定多长时间 传-1解锁 func AddTelLockerX2(tel string, secend string) { c := lxhttp.NewHttpClient() bytes, _ := lxhttp.Get(c, variable.TaxTaskURL+"/api/v1/saveTelLock?tel="+tel+"&time="+secend) logger.Info("TelLock: " + string(bytes) + secend + "s") } func AddTelLockerX2Req(tel string, secend string, reqs string) { c := lxhttp.NewHttpClient() uri := variable.TaxTaskURL + "/api/v1/saveTelLock?tel=" + tel + "&time=" + secend if reqs != "" { uri += "&reqNos=" + reqs } bytes, _ := lxhttp.Get(c, uri) logger.Info(tel + " TelLock: " + string(bytes) + " " + secend + "s") } func HandleError(ctx context.Context, err error) error { if err == nil { return nil } uuid := "" _ = rod.Try(func() { if ctx != nil { uuid = ctx.Value(variable.UUID).(string) } }) var usererr *taxerr.UserErr var taxerr2 *taxerr.SystemErr if errors.As(err, &taxerr2) { logger.Info(uuid, " ", taxerr2.Error()) if !strings.Contains(taxerr2.Error(), "[异常]:") { return errors.New("[异常]:" + taxerr2.Error()) } else { return errors.New(taxerr2.Error()) } } else if errors.As(err, &usererr) { logger.Info(uuid, " ", usererr.Error()) if !strings.Contains(usererr.Error(), "[错误]:") { return errors.New("[错误]:" + usererr.Error()) } else { return errors.New(usererr.Error()) } } else if err != nil { log.Error(uuid, " ", err.Error()) return taxerr.NewWebStuckTitle(true) } return nil } // url 路径 filename 文件的上传参数 func PostFile(url string, files map[string]string, ext map[string]string) ([]byte, error) { res := []byte{} //创建一个模拟的form中的一个选项,这个form项现在是空的 bodyBuf := &bytes.Buffer{} bodyWriter := multipart.NewWriter(bodyBuf) for k, v := range files { //打开文件句柄操作 file, err := os.Open(v) if err != nil { //zaplog.LoggerS.Info("error opening file") return res, err } defer file.Close() //相当于现在还没选择文件, form项里选择文件的选项 fileWriter, err := bodyWriter.CreateFormFile(k, file.Name()) if err != nil { //zaplog.LoggerS.Info("error writing to buffer") return res, err } //iocopy 这里相当于选择了文件,将文件放到form中 _, err = io.Copy(fileWriter, file) if err != nil { return res, err } } //获取上传文件的类型,multipart/form-data; boundary=... contentType := bodyWriter.FormDataContentType() //上传的其他参数 for key, val := range ext { _ = bodyWriter.WriteField(key, val) } //这个很关键,必须这样写关闭,不能使用defer关闭,不然会导致错误 bodyWriter.Close() // 忽略证书 c := http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, Timeout: time.Second * 60, } c.CloseIdleConnections() //发送post请求到服务端 resp, err := c.Post(url, contentType, bodyBuf) if err != nil { return res, err } defer resp.Body.Close() return io.ReadAll(resp.Body) } func GetBaseUrl(p *rod.Page) string { URL := p.MustInfo().URL baseUrl := "https://" + URL[8:][:strings.Index(URL[8:], "/")] return baseUrl } func GetUUid() string { // 创建新的UUID newID := uuid.New().String() return strings.ReplaceAll(newID, "-", "") } // 拦截请求 for 代理 func PageHijackReqForProxy(b *rod.Page, pattern string, ch chan []byte, c *http.Client) *rod.HijackRouter { router := b.HijackRequests() router.MustAdd(pattern, func(ctx *rod.Hijack) { rod.Try(func() { err := ctx.LoadResponse(c, true) if err != nil { return } ch <- []byte(ctx.Response.Body()) time.Sleep(time.Second * 5) select { case <-ch: break } }) }) go router.Run() return router } // 拦截请求 func BrowserHijackReq(b *rod.Browser, pattern string, ch chan []byte) *rod.HijackRouter { router := b.HijackRequests() router.MustAdd(pattern, func(ctx *rod.Hijack) { rod.Try(func() { ctx.MustLoadResponse() ch <- []byte(ctx.Response.Body()) time.Sleep(time.Second * 5) select { case <-ch: break } }) }) go router.Run() return router } // DeleteTpassCookie 失效当前cookie func DeleteTpassCookie(info models.CompanyInfo) { //江西新版登录和旧版的tpass,分开来存储,防止新版登录的公司拿到旧版登录的tapss tsessionKey := info.Tel if !strings.Contains(tsessionKey, "_"+info.Area) { tsessionKey += "_" + info.Area } if strings.Contains(info.Dlfs, "代理") { tsessionKey += "Agent" } if (info.Area == "jiangxi" || info.Area == "heilongjiang" || info.Area == "guizhou" || info.Area == "chongqing") && info.Dlfs != "新版登录" { tsessionKey += "Other" } tsessionKey += "_tpass" client := lxhttp.NewHttpClient() body := map[string]string{ "tsessionKey": tsessionKey, "pwd": info.Zzrmm, } logger.Info("req", zap.Any("body", body)) bys, err := lxhttp.POSTJson(client, variable.SessionKeepURL+"/api/v1/session/TSession/delete", body, map[string]string{}) if err != nil { logger.Error(err.Error()) } logger.Info("删除key:" + tsessionKey + "结果: " + string(bys)) } type SessionInfo struct { URL string //页面URL API接口地址 Selector string //选择器 API返回结果路径 SelectorValue string //每个选择器对应的值 API对应的企业值 Cookies string //cookies Area variable.Area Api bool ApiURL string ApiMethod string ApiParam string ApiHeader map[string]string Valid int //新版登录的cookie是否可用,仅获取时赋值 }