|
@@ -0,0 +1,318 @@
|
|
|
+//人工识别验证码
|
|
|
+package weixin
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "math/rand"
|
|
|
+ util "mfw/util"
|
|
|
+ "net/http"
|
|
|
+ "net/rpc"
|
|
|
+ "os"
|
|
|
+ qfwutil "qfw/util"
|
|
|
+ qrpc "qfw/util/rpc"
|
|
|
+ wf "qfw/weixinconfig"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ status_rest = 0 //闲时,没有任务
|
|
|
+ status_working = 1 //进入工作状态
|
|
|
+ status_waitReply = 2 //收到验证码,等待回复
|
|
|
+)
|
|
|
+
|
|
|
+var workLock = new(sync.Mutex)
|
|
|
+var waitWorks []map[string]interface{} //待识别的验证码[{msgId:"",from:"",img:""}]
|
|
|
+var workers []map[string]interface{} //工作的人集合[{openId:"",status:""}]
|
|
|
+var workering = make(map[string][]string) //工作的人{openId:[msgid,from]}
|
|
|
+var client *util.Client
|
|
|
+
|
|
|
+//
|
|
|
+type DistinguishWork struct {
|
|
|
+}
|
|
|
+
|
|
|
+func initDgWork() {
|
|
|
+ client, _ = util.StartClient(processevent, wf.SysConfig.Msgserver, []int{util.SERVICE_DISTINGUISH}, 20)
|
|
|
+ client.ResetMyName("识别验证码")
|
|
|
+}
|
|
|
+func processevent(p *util.Packet) {
|
|
|
+ event := int(p.Event)
|
|
|
+ switch event {
|
|
|
+ case util.SERVICE_DISTINGUISH:
|
|
|
+ //写数据
|
|
|
+ if ret := make(map[string]interface{}); json.Unmarshal(p.GetBusinessData(), &ret) == nil {
|
|
|
+ flag, _ := ret["flag"].(bool)
|
|
|
+ if flag {
|
|
|
+ imgTmp, err := json.Marshal(ret["img"])
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var img []byte
|
|
|
+ err = json.Unmarshal(imgTmp, &img)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ obj := map[string]interface{}{
|
|
|
+ "from": p.From,
|
|
|
+ "msgId": p.Msgid,
|
|
|
+ "img": img,
|
|
|
+ }
|
|
|
+ if len(workers) == 0 {
|
|
|
+ waitWorks = append(waitWorks, obj)
|
|
|
+ } else {
|
|
|
+ toWork(obj)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ overtime(p.Msgid)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//开始工作,记录工作人的相关数
|
|
|
+func (a *DistinguishWork) Start(openId string) {
|
|
|
+ if client == nil {
|
|
|
+ initDgWork()
|
|
|
+ }
|
|
|
+ for _, v := range workers {
|
|
|
+ if v["openId"] == openId {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ workers = append(workers, map[string]interface{}{"openId": openId, "status": status_rest})
|
|
|
+ toWork(nil)
|
|
|
+}
|
|
|
+
|
|
|
+//结束工作,删除工作人
|
|
|
+func (a *DistinguishWork) End(openId string) {
|
|
|
+ deleteWorker(openId)
|
|
|
+ for k, v := range workers {
|
|
|
+ if v["openId"] == openId {
|
|
|
+ workers = append(workers[:k], workers[k+1:]...)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//判断该人是否是工作模式
|
|
|
+func (a *DistinguishWork) IsWorking(openId string) bool {
|
|
|
+ for _, v := range workers {
|
|
|
+ if v["openId"] == openId {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+//判断该人是否在等待回复
|
|
|
+func (a *DistinguishWork) IsWaitReply(openId string) bool {
|
|
|
+ for _, v := range workers {
|
|
|
+ if v["openId"] == openId {
|
|
|
+ return v["status"] == status_waitReply
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+//超时处理,删除该任务
|
|
|
+func overtime(msgId string) {
|
|
|
+ for k, v := range waitWorks {
|
|
|
+ if v["msgId"] == msgId {
|
|
|
+ waitWorks = append(waitWorks[:k], waitWorks[k+1:]...)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//回复验证码
|
|
|
+func (a *DistinguishWork) Reply(openId, content string) {
|
|
|
+ obj := workering[openId]
|
|
|
+ if obj == nil || len(obj) < 2 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ tmp := make(map[string]interface{})
|
|
|
+ tmp["content"] = content
|
|
|
+ tmp["msgId"] = obj[0]
|
|
|
+ client.WriteObj(obj[1], obj[0], util.EVENT_RECIVE_CALLBACK, util.SENDTO_TYPE_P2P, tmp)
|
|
|
+ deleteWorker(openId)
|
|
|
+ updateWorker(openId, status_rest)
|
|
|
+ toWork(nil)
|
|
|
+}
|
|
|
+
|
|
|
+//删除工作的人
|
|
|
+func deleteWorker(openId string) {
|
|
|
+ delete(workering, openId)
|
|
|
+}
|
|
|
+
|
|
|
+//进行一个任务
|
|
|
+func toWork(o map[string]interface{}) {
|
|
|
+ openId, obj, err := worked(o)
|
|
|
+ if err == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //如果任务在执行过程中出现异常,把该任务放入等待队列中,修改这个人的状态为空闲
|
|
|
+ obj["status"] = "-1"
|
|
|
+ waitWorks = append(waitWorks, obj)
|
|
|
+ deleteWorker(openId)
|
|
|
+ updateWorker(openId, status_rest)
|
|
|
+}
|
|
|
+
|
|
|
+func worked(o map[string]interface{}) (string, map[string]interface{}, error) {
|
|
|
+ openId, obj := getWorker(o)
|
|
|
+ if openId == "" { //没有闲人
|
|
|
+ return openId, obj, nil
|
|
|
+ }
|
|
|
+ from := obj["from"].(string)
|
|
|
+ msgId := obj["msgId"].(string)
|
|
|
+ img := obj["img"].([]byte)
|
|
|
+ //生成验证码图片
|
|
|
+ name, err := createImg(msgId, img)
|
|
|
+ if name == "" || err != nil {
|
|
|
+ log.Println("生成验证码图片出错:", err)
|
|
|
+ return openId, obj, err
|
|
|
+ }
|
|
|
+ workering[openId] = []string{msgId, from}
|
|
|
+ //发送验证码图片
|
|
|
+ var itm qrpc.ImgTextMsg
|
|
|
+ itm.ToUser = openId
|
|
|
+
|
|
|
+ var als qrpc.Articles
|
|
|
+ als.Title = wf.SysConfig.DistinguishWork["title"]
|
|
|
+ als.Description = wf.SysConfig.DistinguishWork["description"]
|
|
|
+ als.Url = wf.SysConfig.Qmxcdn + "/upload/spider/" + name
|
|
|
+ als.Picurl = wf.SysConfig.Qmxcdn + "/upload/spider/" + name
|
|
|
+
|
|
|
+ itm.News.Articles = append(itm.News.Articles, als)
|
|
|
+
|
|
|
+ var e error
|
|
|
+ qfwutil.Try(func() {
|
|
|
+ client, err := rpc.DialHTTP("tcp", wf.SysConfig.Rpcserver)
|
|
|
+ defer client.Close()
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err.Error())
|
|
|
+ e = err
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var repl qrpc.RpcResult
|
|
|
+ err = client.Call("WeiXinRpc.SendImgTextMsg", itm, &repl)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err.Error())
|
|
|
+ e = err
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ updateWorker(openId, status_waitReply)
|
|
|
+ }
|
|
|
+ }, func(e interface{}) {})
|
|
|
+ return openId, obj, e
|
|
|
+}
|
|
|
+
|
|
|
+//修改这个人的状态为等待回复
|
|
|
+func updateWorker(openId string, status int) {
|
|
|
+ for _, v := range workers {
|
|
|
+ if v["openId"] == openId {
|
|
|
+ v["status"] = status
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//获取一个可以工作的人
|
|
|
+func getWorker(obj map[string]interface{}) (openId string, object map[string]interface{}) {
|
|
|
+ workLock.Lock()
|
|
|
+ defer workLock.Unlock()
|
|
|
+ if len(workers) == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if obj == nil && len(waitWorks) == 0 { //接下来没有任务了
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //随机获取
|
|
|
+ var tmp []int
|
|
|
+ for k, v := range workers {
|
|
|
+ if v["status"] == status_rest {
|
|
|
+ tmp = append(tmp, k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tmp_length := len(tmp)
|
|
|
+ if tmp_length == 0 { //都在忙,没有闲人
|
|
|
+ waitWorks = append(waitWorks, obj)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ tmp_index := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(tmp_length)
|
|
|
+ workers_index := tmp[tmp_index]
|
|
|
+ workers[workers_index]["status"] = status_working
|
|
|
+ openId = workers[workers_index]["openId"].(string)
|
|
|
+ if len(waitWorks) > 0 {
|
|
|
+ object = waitWorks[0]
|
|
|
+ //删除第一个
|
|
|
+ waitWorks = waitWorks[1:]
|
|
|
+ } else if obj != nil { //没有待执行的任务
|
|
|
+ object = obj
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//获取一个要识别的任务
|
|
|
+func createImg(msgId string, img []byte) (string, error) {
|
|
|
+ name := msgId + "-" + fmt.Sprint(time.Now().Unix()) + ".jpg"
|
|
|
+ path := wf.SysConfig.Imgpath + "/upload/spider"
|
|
|
+ fs, err := os.Open(path)
|
|
|
+ if err != nil && os.MkdirAll(path, 0700) != nil {
|
|
|
+ log.Println("创建文件夹出错:", err)
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ defer fs.Close()
|
|
|
+ file, err := os.Create(path + "/" + name)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("创建验证码图片出错:", err)
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ log.Println(img)
|
|
|
+ _, err = file.Write(img)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("写入验证码图片出错:", err)
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ defer file.Close()
|
|
|
+ return name, nil
|
|
|
+}
|
|
|
+func Monitor(w http.ResponseWriter, r *http.Request) {
|
|
|
+ var h_p, h_w, h_wa string
|
|
|
+ for _, v := range workers {
|
|
|
+ h_p += fmt.Sprint(v) + "<br>"
|
|
|
+ }
|
|
|
+ for k, v := range workering {
|
|
|
+ h_w += fmt.Sprint(k) + ":" + fmt.Sprint(v) + "<br>"
|
|
|
+ }
|
|
|
+ for _, v := range waitWorks {
|
|
|
+ delete(v, "img")
|
|
|
+ h_wa += fmt.Sprint(v) + "<br>"
|
|
|
+ }
|
|
|
+ if h_p == "" {
|
|
|
+ h_p = "无"
|
|
|
+ }
|
|
|
+ if h_w == "" {
|
|
|
+ h_w = "无"
|
|
|
+ }
|
|
|
+ if h_wa == "" {
|
|
|
+ h_wa = "无"
|
|
|
+ }
|
|
|
+ html := `<!DOCTYPE HTML>
|
|
|
+<HTML>
|
|
|
+ <HEAD>
|
|
|
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
|
|
|
+ </HEAD>
|
|
|
+ <BODY>
|
|
|
+<button style='padding: 5px 10px;margin-right: 15px;' onclick="document.getElementById('person').style.display='block';document.getElementById('waitwork').style.display='none';document.getElementById('working').style.display='none';">工作的人</button>
|
|
|
+<button style='padding: 5px 10px;margin-right: 15px;' onclick="document.getElementById('person').style.display='none';document.getElementById('working').style.display='block';document.getElementById('waitwork').style.display='none';">工作中</button>
|
|
|
+<button style='padding: 5px 10px;' onclick="document.getElementById('person').style.display='none';document.getElementById('working').style.display='none';document.getElementById('waitwork').style.display='block';">等待工作</button>
|
|
|
+<br><br>
|
|
|
+<div id="person" style='display: none;'>` + h_p + `</div>
|
|
|
+<div id="working" style='display: none;'>` + h_w + `</div>
|
|
|
+<div id="waitwork" style='display: none;'>` + h_wa + `</div>
|
|
|
+ </BODY>
|
|
|
+</HTML>`
|
|
|
+ w.Write([]byte(html))
|
|
|
+}
|