2020-11-23 08:15:19 +00:00
|
|
|
package cwclient
|
2020-11-20 10:47:16 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2020-11-23 10:49:37 +00:00
|
|
|
"os"
|
2020-11-25 08:33:15 +00:00
|
|
|
"strconv"
|
2020-11-20 10:47:16 +00:00
|
|
|
"sync"
|
2020-11-24 11:54:23 +00:00
|
|
|
"time"
|
2020-11-20 10:47:16 +00:00
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2020-11-20 11:15:13 +00:00
|
|
|
"github.com/google/uuid"
|
2020-11-20 10:47:16 +00:00
|
|
|
)
|
|
|
|
|
2020-11-24 07:17:56 +00:00
|
|
|
func init() {
|
|
|
|
log.SetFlags(log.Llongfile | log.LstdFlags)
|
|
|
|
}
|
|
|
|
|
2020-11-24 11:54:23 +00:00
|
|
|
// CallbackContext Callback上下文
|
|
|
|
type CallbackContext struct {
|
|
|
|
TaskID string
|
|
|
|
Content string
|
|
|
|
Error error
|
|
|
|
Carry interface{} // 传递的参数.
|
|
|
|
}
|
|
|
|
|
2020-11-20 10:47:16 +00:00
|
|
|
// Callback 发送代理连接获取内容后的回调函数
|
2020-11-20 11:15:13 +00:00
|
|
|
type Callback struct {
|
|
|
|
label string
|
|
|
|
hash string
|
2020-11-24 11:54:23 +00:00
|
|
|
Do func(cxt *CallbackContext)
|
2020-11-20 11:15:13 +00:00
|
|
|
}
|
2020-11-20 10:47:16 +00:00
|
|
|
|
|
|
|
// Client 客户端
|
|
|
|
type Client struct {
|
|
|
|
chromeProxyAddr string
|
|
|
|
|
2020-11-24 11:54:23 +00:00
|
|
|
carrayCache sync.Map
|
|
|
|
register sync.Map
|
2020-11-20 10:47:16 +00:00
|
|
|
|
|
|
|
host string
|
|
|
|
port string
|
|
|
|
|
|
|
|
server *http.Server
|
|
|
|
listener net.Listener
|
|
|
|
lock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
// Label 区分不同任务类型
|
|
|
|
type Label struct {
|
|
|
|
label string
|
2020-11-23 10:49:37 +00:00
|
|
|
|
2020-11-25 08:33:15 +00:00
|
|
|
conditionJS string
|
|
|
|
retry string
|
|
|
|
waitcapture string
|
|
|
|
configlock sync.Mutex
|
2020-11-23 10:49:37 +00:00
|
|
|
|
|
|
|
cli *Client
|
2020-11-20 10:47:16 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 08:33:15 +00:00
|
|
|
// GetWaitime Get return waitime int
|
|
|
|
func (l *Label) GetWaitime() int {
|
|
|
|
r, _ := strconv.Atoi(l.waitcapture)
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetWaitime Set waitime int
|
|
|
|
func (l *Label) SetWaitime(waitime int) {
|
|
|
|
l.waitcapture = strconv.Itoa(waitime)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRetry Get return retry int
|
|
|
|
func (l *Label) GetRetry() int {
|
|
|
|
r, _ := strconv.Atoi(l.retry)
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRetry Set retry int
|
|
|
|
func (l *Label) SetRetry(retry int) {
|
|
|
|
l.retry = strconv.Itoa(retry)
|
|
|
|
}
|
|
|
|
|
2020-11-20 11:15:13 +00:00
|
|
|
// GetHash 根据label获取hash路径
|
|
|
|
func (l *Label) GetHash(label string) string {
|
|
|
|
if cb, ok := l.cli.register.Load(label); ok {
|
|
|
|
return cb.(Callback).hash
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLabel 根据hash获取路径label
|
|
|
|
func (l *Label) GetLabel(hash string) string {
|
|
|
|
if cb, ok := l.cli.register.Load(hash); ok {
|
|
|
|
return cb.(Callback).label
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-11-24 11:54:23 +00:00
|
|
|
// Open 缓存了Label值. 每次调用少了label传参. carray每次都会给一次请求回调传入参数.
|
|
|
|
func (l *Label) Open(urlstr string, carray interface{}) (bodyRes string, ok bool) {
|
|
|
|
return l.cli.open(l, urlstr, carray)
|
2020-11-23 10:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetContentCondition 设置识别到的内容条件. js代码. 必须是一个函数. 命名可以随意. 返回bool
|
|
|
|
func (l *Label) SetContentCondition(jsScript string) {
|
2020-11-25 08:33:15 +00:00
|
|
|
l.configlock.Lock()
|
|
|
|
defer l.configlock.Unlock()
|
2020-11-23 10:49:37 +00:00
|
|
|
l.conditionJS = jsScript
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetContentConditionFromFile 设置识别到的内容条件. js代码. 从js文件 必须是一个函数. 命名可以随意. 返回bool
|
|
|
|
func (l *Label) SetContentConditionFromFile(jsScriptFile string) {
|
|
|
|
f, err := os.Open(jsScriptFile)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
data, err := ioutil.ReadAll(f)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-11-25 08:33:15 +00:00
|
|
|
l.configlock.Lock()
|
|
|
|
defer l.configlock.Unlock()
|
2020-11-25 04:25:19 +00:00
|
|
|
// log.Println(string(data))
|
2020-11-23 10:49:37 +00:00
|
|
|
l.conditionJS = string(data)
|
2020-11-20 10:47:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPort Get return port string. default random.
|
|
|
|
func (cli *Client) GetPort() string {
|
|
|
|
return cli.port
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPort Set port string. before client call connect method
|
|
|
|
func (cli *Client) SetPort(port string) {
|
|
|
|
cli.port = port
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetHost Get return host string
|
|
|
|
func (cli *Client) GetHost() string {
|
|
|
|
return cli.host
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetHost Set host string. default http://127.0.0.1
|
|
|
|
func (cli *Client) SetHost(host string) {
|
|
|
|
cli.host = host
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register 注册基础信息
|
2020-11-24 11:54:23 +00:00
|
|
|
func (cli *Client) Register(label string, callback func(cxt *CallbackContext)) *Label {
|
2020-11-20 11:15:13 +00:00
|
|
|
cb := Callback{Do: callback, hash: uuid.New().String()}
|
|
|
|
if _, ok := cli.register.Load(label); ok {
|
|
|
|
log.Panic("label: ", label, " is exists")
|
|
|
|
}
|
|
|
|
cli.register.Store(label, cb)
|
|
|
|
cli.register.Store(cb.hash, cb)
|
2020-11-25 08:33:15 +00:00
|
|
|
l := &Label{label: label, cli: cli, waitcapture: "6000", retry: "1"}
|
2020-11-20 10:47:16 +00:00
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnRegister 卸载注册基础信息
|
|
|
|
func (cli *Client) UnRegister(label string) {
|
2020-11-20 11:15:13 +00:00
|
|
|
if cb, ok := cli.register.Load(label); ok {
|
|
|
|
cli.register.Delete(label)
|
|
|
|
cli.register.Delete(cb.(Callback).hash)
|
|
|
|
}
|
2020-11-20 10:47:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Connect 连接初始化回调端口
|
|
|
|
func (cli *Client) Connect() {
|
|
|
|
|
|
|
|
cli.lock.Lock()
|
|
|
|
defer cli.lock.Unlock()
|
|
|
|
|
|
|
|
if cli.server == nil {
|
|
|
|
|
|
|
|
listener, err := net.Listen("tcp", ":0")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
cli.port = fmt.Sprintf("%d", listener.Addr().(*net.TCPAddr).Port)
|
|
|
|
|
|
|
|
router := gin.Default()
|
|
|
|
router.POST("/:label", func(c *gin.Context) {
|
|
|
|
label := c.Param("label")
|
|
|
|
if f, ok := cli.register.Load(label); ok {
|
|
|
|
callback := f.(Callback)
|
|
|
|
if tid, ok := c.GetPostForm("taskid"); ok {
|
|
|
|
content := c.PostForm("content")
|
2020-11-24 07:17:56 +00:00
|
|
|
errorStr := c.PostForm("error")
|
2020-11-24 11:54:23 +00:00
|
|
|
carrayhash := c.PostForm("carrayhash")
|
|
|
|
|
|
|
|
var carray interface{}
|
|
|
|
if icarray, ok := cli.carrayCache.Load(carrayhash); ok {
|
|
|
|
carray = icarray.(*Carray).data
|
|
|
|
}
|
|
|
|
|
2020-11-24 07:17:56 +00:00
|
|
|
var err error = nil
|
|
|
|
if errorStr != "" {
|
|
|
|
err = fmt.Errorf(errorStr)
|
|
|
|
}
|
2020-11-24 11:54:23 +00:00
|
|
|
|
|
|
|
cxt := &CallbackContext{
|
|
|
|
TaskID: tid,
|
|
|
|
Content: content,
|
|
|
|
Error: err,
|
|
|
|
Carry: carray,
|
|
|
|
}
|
|
|
|
callback.Do(cxt)
|
2020-11-20 10:47:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
cli.server = &http.Server{
|
|
|
|
Addr: cli.host + ":" + cli.port,
|
|
|
|
Handler: router,
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
err := cli.server.Serve(listener)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
} else {
|
|
|
|
log.Println("client had connected.")
|
|
|
|
}
|
|
|
|
|
|
|
|
// panic(http.Serve(listener, nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disconnect 断开连接
|
|
|
|
func (cli *Client) Disconnect() {
|
|
|
|
err := cli.server.Shutdown(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:49:37 +00:00
|
|
|
// open 请求完url后 调用不同label注册的回调函数. bodyRes 请求后服务器返回的基础信息. 如果不需要debug一般不需要使用.
|
2020-11-24 11:54:23 +00:00
|
|
|
func (cli *Client) open(label *Label, urlstr string, carray interface{}) (bodyRes string, ok bool) {
|
2020-11-20 10:47:16 +00:00
|
|
|
// urlstr = "https://playerduo.com/api/playerDuo-service-v2/rip113?lang=en&deviceType=browser"
|
|
|
|
|
|
|
|
if cli.server == nil {
|
|
|
|
panic("client is not connect. Client.Connect() ? ")
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:49:37 +00:00
|
|
|
if callback, ok := cli.register.Load(label.label); ok {
|
2020-11-24 11:54:23 +00:00
|
|
|
|
2020-11-20 10:47:16 +00:00
|
|
|
data := url.Values{}
|
|
|
|
data["url"] = []string{urlstr}
|
2020-11-20 11:15:13 +00:00
|
|
|
data["callback"] = []string{cli.host + ":" + cli.port + "/" + callback.(Callback).hash}
|
2020-11-23 10:49:37 +00:00
|
|
|
data["label"] = []string{label.label}
|
|
|
|
|
2020-11-24 11:54:23 +00:00
|
|
|
if carray != nil {
|
|
|
|
carrayhash := uuid.New().String()
|
|
|
|
c := &Carray{hash: carrayhash, data: carray, expire: time.Now().Add(time.Minute * 2)}
|
|
|
|
label.cli.carrayCache.Store(carrayhash, c)
|
|
|
|
data["carrayhash"] = []string{carrayhash}
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:49:37 +00:00
|
|
|
func() {
|
2020-11-25 08:33:15 +00:00
|
|
|
label.configlock.Lock()
|
|
|
|
defer label.configlock.Unlock()
|
2020-11-23 11:40:28 +00:00
|
|
|
data["content_condition"] = []string{label.conditionJS}
|
2020-11-25 08:33:15 +00:00
|
|
|
data["waitcapture"] = []string{label.waitcapture}
|
|
|
|
data["retry"] = []string{label.retry}
|
2020-11-23 10:49:37 +00:00
|
|
|
}()
|
|
|
|
|
2020-11-20 10:47:16 +00:00
|
|
|
resp, err := http.DefaultClient.PostForm(cli.chromeProxyAddr+"/task/put", data)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
bodyRes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
return string(bodyRes), true
|
|
|
|
}
|
|
|
|
|
2020-11-23 10:49:37 +00:00
|
|
|
log.Printf("label: %s is not exists", label.label)
|
2020-11-20 10:47:16 +00:00
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
// New 创建Client并初始化
|
|
|
|
func New(addr string) *Client {
|
|
|
|
cli := &Client{}
|
|
|
|
cli.chromeProxyAddr = addr
|
|
|
|
cli.host = "http://127.0.0.1"
|
|
|
|
return cli
|
|
|
|
}
|