chromeworker_client/client.go

238 lines
5.3 KiB
Go

package cwclient
import (
"context"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"sync"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func init() {
log.SetFlags(log.Llongfile | log.LstdFlags)
}
// Callback 发送代理连接获取内容后的回调函数
type Callback struct {
label string
hash string
Do func(tid, content string, err error)
}
// Client 客户端
type Client struct {
chromeProxyAddr string
register sync.Map
host string
port string
server *http.Server
listener net.Listener
lock sync.Mutex
}
// Label 区分不同任务类型
type Label struct {
label string
conditionJS string
conditionlock sync.Mutex
cli *Client
}
// 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 ""
}
// Open 缓存了Label值. 每次调用少了label传参
func (l *Label) Open(urlstr string) (bodyRes string, ok bool) {
return l.cli.open(l, urlstr)
}
// SetContentCondition 设置识别到的内容条件. js代码. 必须是一个函数. 命名可以随意. 返回bool
func (l *Label) SetContentCondition(jsScript string) {
l.conditionlock.Lock()
defer l.conditionlock.Unlock()
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)
}
l.conditionlock.Lock()
defer l.conditionlock.Unlock()
log.Println(string(data))
l.conditionJS = string(data)
}
// 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 注册基础信息
func (cli *Client) Register(label string, callback func(tid, content string, err error)) *Label {
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)
l := &Label{label: label, cli: cli}
return l
}
// UnRegister 卸载注册基础信息
func (cli *Client) UnRegister(label string) {
if cb, ok := cli.register.Load(label); ok {
cli.register.Delete(label)
cli.register.Delete(cb.(Callback).hash)
}
}
// 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")
errorStr := c.PostForm("error")
var err error = nil
if errorStr != "" {
err = fmt.Errorf(errorStr)
}
callback.Do(tid, content, err)
}
}
})
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)
}
}
// open 请求完url后 调用不同label注册的回调函数. bodyRes 请求后服务器返回的基础信息. 如果不需要debug一般不需要使用.
func (cli *Client) open(label *Label, urlstr string) (bodyRes string, ok bool) {
// urlstr = "https://playerduo.com/api/playerDuo-service-v2/rip113?lang=en&deviceType=browser"
if cli.server == nil {
panic("client is not connect. Client.Connect() ? ")
}
if callback, ok := cli.register.Load(label.label); ok {
data := url.Values{}
data["url"] = []string{urlstr}
data["callback"] = []string{cli.host + ":" + cli.port + "/" + callback.(Callback).hash}
data["label"] = []string{label.label}
func() {
label.conditionlock.Lock()
defer label.conditionlock.Unlock()
data["content_condition"] = []string{label.conditionJS}
}()
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
}
log.Printf("label: %s is not exists", label.label)
return "", false
}
// New 创建Client并初始化
func New(addr string) *Client {
cli := &Client{}
cli.chromeProxyAddr = addr
cli.host = "http://127.0.0.1"
return cli
}