|
@@ -0,0 +1,248 @@
|
|
|
|
+//package front
|
|
|
|
+
|
|
|
|
+//import (
|
|
|
|
+// "fmt"
|
|
|
|
+// "log"
|
|
|
|
+// // "jfw/tools"
|
|
|
|
+// //"log"
|
|
|
|
+// //"math/rand"
|
|
|
|
+// "qfw/util"
|
|
|
|
+// "qfw/util/redis"
|
|
|
|
+// //"strconv"
|
|
|
|
+// "sync"
|
|
|
|
+// "time"
|
|
|
|
+//)
|
|
|
|
+
|
|
|
|
+//var (
|
|
|
|
+// InvalidTime = int64(35 * 60) //定时任务判断二维码失效时间35分钟
|
|
|
|
+// ValidTime = 30 * 60 //前端二维码有效时间30分钟
|
|
|
|
+// QrValid = int64(28 * 86400)
|
|
|
|
+// PoolSize = 100
|
|
|
|
+// RedisList = "mylist"
|
|
|
|
+// QrGCList = make([]*QrGC, PoolSize) //定义回收对象池
|
|
|
|
+//)
|
|
|
|
+
|
|
|
|
+//func init() {
|
|
|
|
+// //1.生成50个线程池
|
|
|
|
+// for i := 0; i < PoolSize; i++ {
|
|
|
|
+// q := &QrGC{make(chan string, 100), map[string]int64{}, &sync.Mutex{}, i}
|
|
|
|
+// go q.PoolGC()
|
|
|
|
+// go q.SetTimeGC()
|
|
|
|
+// QrGCList[i] = q
|
|
|
|
+// }
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////二维码回收对象
|
|
|
|
+//type QrGC struct {
|
|
|
|
+// CodePool chan string
|
|
|
|
+// CodeList map[string]int64
|
|
|
|
+// Lock *sync.Mutex
|
|
|
|
+// Index int
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+//func (q *QrGC) Add(str string, t int64) {
|
|
|
|
+// q.Lock.Lock()
|
|
|
|
+// q.CodeList[str] = t
|
|
|
|
+// q.Lock.Unlock()
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////二维码回收机制,定时回收
|
|
|
|
+//func (q *QrGC) SetTimeGC() {
|
|
|
|
+// for {
|
|
|
|
+// time.Sleep(3 * time.Minute)
|
|
|
|
+// now := time.Now().Unix()
|
|
|
|
+// q.Lock.Lock()
|
|
|
|
+// for k, v := range q.CodeList {
|
|
|
|
+// if now-v > InvalidTime { //失效
|
|
|
|
+// delete(q.CodeList, k)
|
|
|
|
+// //补充逻辑
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// q.Lock.Unlock()
|
|
|
|
+// }
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////二维码回收机制,使用完回收
|
|
|
|
+//func (q *QrGC) PoolGC() {
|
|
|
|
+// for {
|
|
|
|
+// select {
|
|
|
|
+// case code := <-q.CodePool:
|
|
|
|
+// //调用回收逻辑
|
|
|
|
+// q.Lock.Lock()
|
|
|
|
+// delete(q.CodeList, code)
|
|
|
|
+// q.Lock.Unlock()
|
|
|
|
+// //删除redis中的参数,取出二维码的失效时间判断
|
|
|
|
+// //补充逻辑
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////生成二维码串,定义24位串,返回时间,返回回收池索引
|
|
|
|
+//var qrSimpleEncrypt = &util.SimpleEncrypt{"qrcode_jywx2017"}
|
|
|
|
+
|
|
|
|
+////生成二维码代码
|
|
|
|
+//func NewQrCodeStr() (string, int64, int) {
|
|
|
|
+// now := time.Now()
|
|
|
|
+// str := fmt.Sprintf("A%s%d%s", util.GetLetterRandom(4), now.UnixNano()/1000, util.GetLetterRandom(3))
|
|
|
|
+// log.Println(str, "str===", qrSimpleEncrypt.EncodeString(str), qrSimpleEncrypt.Encode2Hex(str))
|
|
|
|
+// str = qrSimpleEncrypt.EncodeString(str)
|
|
|
|
+// return str, now.Unix(), HashVal(str) % PoolSize
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////计算哈希值
|
|
|
|
+//func HashVal(src string) int {
|
|
|
|
+// check := 0
|
|
|
|
+// for i := len(src) / 2; i < len(src); i++ {
|
|
|
|
+// check += int(src[i])
|
|
|
|
+// }
|
|
|
|
+// return check
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////计算二维码
|
|
|
|
+//func ComputeQrCode(str string) int64 {
|
|
|
|
+// str1 := qrSimpleEncrypt.DecodeString(str)
|
|
|
|
+// if len(str1) == 24 {
|
|
|
|
+// return util.Int64All(str1[5:15])
|
|
|
|
+// }
|
|
|
|
+// return 0
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////获取二维码代码
|
|
|
|
+//func GetQRCode() (code string) {
|
|
|
|
+// ret := redis.LPOP("sso", RedisList)
|
|
|
|
+// bnew := false
|
|
|
|
+// res := ""
|
|
|
|
+// if ret != nil {
|
|
|
|
+// res, _ = ret.(string)
|
|
|
|
+// if len(res) != 24 || time.Now().Unix()-ComputeQrCode(res) > QrValid { //过期
|
|
|
|
+// bnew = true
|
|
|
|
+// } else {
|
|
|
|
+// qrgc := QrGCList[HashVal(res)%PoolSize]
|
|
|
|
+// qrgc.Add(res, time.Now().Unix())
|
|
|
|
+// }
|
|
|
|
+// } else {
|
|
|
|
+// bnew = true
|
|
|
|
+// }
|
|
|
|
+// if bnew {
|
|
|
|
+// str, times, index := NewQrCodeStr()
|
|
|
|
+// qrgc := QrGCList[index]
|
|
|
|
+// qrgc.Add(str, times)
|
|
|
|
+// return str
|
|
|
|
+// }
|
|
|
|
+// return res
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+////获取二维码图片
|
|
|
|
+//func GetQRData(code string) (pngdata *[]byte) {
|
|
|
|
+// tmp, err := redis.GetBytes("sso", "qr_"+code)
|
|
|
|
+// if err == nil {
|
|
|
|
+// if tmp == nil {
|
|
|
|
+
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// return nil
|
|
|
|
+//}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+//var QrMap = map[string]*SingleQR{}
|
|
|
|
+//var QrMapLock = &sync.RWMutex{}
|
|
|
|
+
|
|
|
|
+var QrPoolObj = &QRPool{make(chan *SingleQR, 50000), map[string]*SingleQR{}, &sync.RWMutex{}}
|
|
|
|
+
|
|
|
|
+//内存池数据
|
|
|
|
+type QRPool struct {
|
|
|
|
+ Slq chan *SingleQR
|
|
|
|
+ QrMap map[string]*SingleQR
|
|
|
|
+ QrMapLock *sync.RWMutex
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//单个二维码
|
|
|
|
+type SingleQR struct {
|
|
|
|
+ Starttime int64
|
|
|
|
+ Qrbyte *[]byte
|
|
|
|
+ Qrcode string
|
|
|
|
+ Qrchan chan bool
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//手动回收
|
|
|
|
+func ManualGC(qrcode string) {
|
|
|
|
+ QrPoolObj.QrMapLock.RLock()
|
|
|
|
+ pngdata := QrPoolObj.QrMap[qrcode]
|
|
|
|
+ QrPoolObj.QrMapLock.RUnlock()
|
|
|
|
+ //log.Println("手动回收----", len(pngdata.Qrchan))
|
|
|
|
+ if pngdata != nil {
|
|
|
|
+ select {
|
|
|
|
+ case pngdata.Qrchan <- true:
|
|
|
|
+ case <-time.After(10 * time.Millisecond):
|
|
|
|
+ QrPoolObj.QrMapLock.Lock()
|
|
|
|
+ delete(QrPoolObj.QrMap, qrcode)
|
|
|
|
+ QrPoolObj.QrMapLock.Unlock()
|
|
|
|
+ pngdata = nil
|
|
|
|
+ //log.Println("10毫秒")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//自动回收
|
|
|
|
+func (sq *SingleQR) AutoGC() {
|
|
|
|
+ //log.Println("自动回收----", len(sq.Qrchan))
|
|
|
|
+ select {
|
|
|
|
+ case <-time.After(10 * time.Minute):
|
|
|
|
+ case <-sq.Qrchan:
|
|
|
|
+ }
|
|
|
|
+ sq.Starttime = 0
|
|
|
|
+ sq.Qrbyte = nil
|
|
|
|
+ select {
|
|
|
|
+ case <-time.After(2 * time.Second):
|
|
|
|
+ case QrPoolObj.Slq <- sq:
|
|
|
|
+ }
|
|
|
|
+ //log.Println("--自动回收完成--")
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//
|
|
|
|
+func (q *QRPool) GetQRCode() (pngdata *SingleQR) {
|
|
|
|
+ select {
|
|
|
|
+ case pngdata = <-q.Slq:
|
|
|
|
+ //log.Println("-从池中读取id,根据id从redis取得二维码-", pngdata.Qrcode)
|
|
|
|
+ tmp, err := redis.GetBytes("sso", "p_share_"+pngdata.Qrcode)
|
|
|
|
+ if err == nil && tmp != nil && len(*tmp) > 0 {
|
|
|
|
+ pngdata.Qrbyte = tmp
|
|
|
|
+ } else {
|
|
|
|
+ //二维码一个月后过期
|
|
|
|
+ //log.Println("redis中缓存的二维byte过期或被清除")
|
|
|
|
+ pngdata = WXQRData(pngdata.Qrcode)
|
|
|
|
+ }
|
|
|
|
+ case <-time.After(100 * time.Millisecond):
|
|
|
|
+ //log.Println("--从池中取超时后再从微信取二维码--")
|
|
|
|
+ pngdata = WXQRData("")
|
|
|
|
+ }
|
|
|
|
+ if pngdata != nil {
|
|
|
|
+ pngdata.Starttime = time.Now().Unix()
|
|
|
|
+ go pngdata.AutoGC()
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//调微信rpc生成二维码
|
|
|
|
+func WXQRData(shareid string) (pngdata *SingleQR) {
|
|
|
|
+ if shareid == "" {
|
|
|
|
+ shareid = fmt.Sprintf("%s%d", "11"+fmt.Sprintf("%d", time.Now().UnixNano())[7:14], rand.Intn(9))
|
|
|
|
+ }
|
|
|
|
+ id, _ := strconv.Atoi(shareid)
|
|
|
|
+ tools.GetShareQR(uint32(id))
|
|
|
|
+ tmp, err := redis.GetBytes("sso", fmt.Sprintf("p_share_%d", id))
|
|
|
|
+ if err == nil {
|
|
|
|
+ pngdata = &SingleQR{
|
|
|
|
+ Qrbyte: tmp,
|
|
|
|
+ Qrcode: shareid,
|
|
|
|
+ Qrchan: make(chan bool, 1),
|
|
|
|
+ }
|
|
|
|
+ QrPoolObj.QrMapLock.Lock()
|
|
|
|
+ QrPoolObj.QrMap[pngdata.Qrcode] = pngdata
|
|
|
|
+ QrPoolObj.QrMapLock.Unlock()
|
|
|
|
+ } else {
|
|
|
|
+ log.Println("get QR err:", id, err.Error())
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+**/
|