123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- package service
- import (
- "bytes"
- "context"
- "encoding/hex"
- "fmt"
- "image/jpeg"
- "image/png"
- "math/rand"
- "strings"
- "sync"
- "time"
- "go-common/library/ecode"
- uuid "github.com/satori/go.uuid"
- )
- const (
- _captchaURL = "%s/x/v1/captcha/get?bid=%s&token=%s"
- )
- // Token use bid, get a token.
- func (s *Service) Token(c context.Context, bid string) (url string, token string, err error) {
- token = hex.EncodeToString(uuid.NewV4().Bytes())
- business := s.LookUp(bid)
- if err = s.dao.AddTokenCache(c, token, int32(time.Duration(business.TTL)/time.Second)); err != nil {
- return
- }
- url = fmt.Sprintf(_captchaURL, s.conf.Captcha.OuterHost, bid, token)
- return
- }
- // CaptchaImg get a captcha by token,bid.
- func (s *Service) CaptchaImg(c context.Context, token, bid string) (img []byte, err error) {
- code, img, ttl := s.randomCaptcha(bid)
- realCode, _, err := s.dao.CaptchaCache(c, token)
- if err != nil {
- return
- }
- if realCode == "" {
- err = ecode.CaptchaTokenExpired
- return
- }
- err = s.dao.UpdateTokenCache(c, token, code, ttl)
- return
- }
- // VerifyCaptcha verify captcha by token and code.
- func (s *Service) VerifyCaptcha(c context.Context, token, code string) (err error) {
- var (
- realCode string
- isInit bool
- )
- if realCode, isInit, err = s.dao.CaptchaCache(c, token); err != nil {
- return
- }
- if realCode == "" {
- err = ecode.CaptchaCodeNotFound
- return
- }
- if isInit {
- err = ecode.CaptchaNotCreate
- return
- }
- if ok := strings.ToLower(realCode) == strings.ToLower(code); ok {
- s.cacheCh.Save(func() {
- s.dao.DelCaptchaCache(context.Background(), token)
- })
- } else {
- err = ecode.CaptchaErr
- }
- return
- }
- func (s *Service) initGenerater(waiter *sync.WaitGroup, bid string, lenStart, lenEnd, width, length int) {
- s.generater(bid, lenStart, lenEnd, width, length)
- waiter.Done()
- }
- func (s *Service) generater(bid string, lenStart, lenEnd, width, length int) {
- images := make(map[string][]byte, s.conf.Captcha.Capacity)
- codes := make([]string, 0, s.conf.Captcha.Capacity)
- for i := 0; i < s.conf.Captcha.Capacity; i++ {
- img, code := s.captcha.createImage(lenStart, lenEnd, width, length, TypeALL)
- var b bytes.Buffer
- switch s.conf.Captcha.Ext {
- case "png":
- png.Encode(&b, img)
- case "jpeg":
- jpeg.Encode(&b, img, &jpeg.Options{Quality: 100})
- default:
- jpeg.Encode(&b, img, &jpeg.Options{Quality: 100})
- }
- images[code] = b.Bytes()
- codes = append(codes, code)
- }
- s.lock.Lock()
- s.mImage[bid] = images
- s.mCode[bid] = codes
- s.lock.Unlock()
- }
- func (s *Service) randomCaptcha(bid string) (code string, img []byte, ttl int32) {
- business := s.LookUp(bid)
- ttl = int32(time.Duration(business.TTL) / time.Second)
- rnd := rand.Intn(s.conf.Captcha.Capacity)
- code = s.mCode[business.BusinessID][rnd]
- img = s.mImage[business.BusinessID][code]
- return
- }
|