wenlng/go-captcha

在使用过程中,莫名其妙的会卡死,后面再请求就始终无法生成验证码了,增加了重试机制

Closed this issue · 1 comments

func initSlideBasic(isReTry bool) (slideBasicCapt slide.Captcha, err error) {
	builder := slide.NewBuilder(
		//slide.WithGenGraphNumber(2),
		slide.WithEnableGraphVerticalRandom(true),
	)
	if isReTry {
		builder.Clear()
		builder = slide.NewBuilder(
			//slide.WithGenGraphNumber(2),
			slide.WithEnableGraphVerticalRandom(true),
		)
	}

	log.Info("initSlideBasic builder success")

	// background images
	imgs, err := images.GetImages()
	if err != nil {
		log.Errorf("images.GetImages err:%+v", err)
		return nil, err
	}
	log.Info("images.GetImages success")

	graphs, err := tiles.GetTiles()
	if err != nil {
		log.Errorf("tiles.GetTiles err:%+v", err)
		return nil, err
	}
	log.Info("tiles.GetTiles success")

	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for i := 0; i < len(graphs); i++ {
		graph := graphs[i]
		newGraphs = append(newGraphs, &slide.GraphImage{
			OverlayImage: graph.OverlayImage,
			MaskImage:    graph.MaskImage,
			ShadowImage:  graph.ShadowImage,
		})
	}
	log.Info("newGraphs success")

	// set resources
	builder.SetResources(
		slide.WithGraphImages(newGraphs),
		slide.WithBackgrounds(imgs),
	)

	slideBasicCapt = builder.Make()
	log.Info("builder.Make success")

	return slideBasicCapt, nil
}

// GenerateSlideBasic generate slide basic
func GenerateSlideBasic(ctx *fiber.Ctx, retryNum int) (resp map[string]interface{}, err error) {
	l := log.WithContext(ctx.Context())
	l.Info("service pkg GenerateSlideBasic")
	resp = make(map[string]interface{})
	ch := make(chan map[string]interface{}, 1)
	isRetry := false
	if retryNum > 0 {
		isRetry = true
	}
	if retryNum > 3 {
		return nil, errors.New("GenerateSlideBasic failed")
	}
	go func() {
		slideBasicCapt, err := initSlideBasic(isRetry)
		if err != nil {
			l.Errorf("initSlideBasic err:%+v", err)
			return
		}
		l.Info("initSlideBasic success")

		captData, err := slideBasicCapt.Generate()
		if err != nil {
			l.Errorf("slideRegionCapt.Generate err:%+v", err)
			return
		}
		l.Info("slideRegionCapt.Generate success")

		blockData := captData.GetData()
		if blockData == nil {
			l.Error("GenerateSlideCaptcha failed")
			return
		}
		l.Info("captData.GetData success")

		var masterImageBase64, tileImageBase64 string
		masterImageBase64 = captData.GetMasterImage().ToBase64()
		if err != nil {
			l.Errorf("captData.GetMasterImage().ToBase64 err:%+v", err)
			return
		}
		l.Info("captData.GetMasterImage().ToBase64 success")

		tileImageBase64 = captData.GetTileImage().ToBase64()
		if err != nil {
			l.Errorf("captData.GetTileImage().ToBase64 err:%+v", err)
			return
		}
		l.Info("captData.GetTileImage().ToBase64 success")

		dotsByte, _ := json.Marshal(blockData)
		key := helper.StringToMD5(string(dotsByte))
		WriteCache(key, dotsByte)
		l.Info("WriteCache success")

		resp = map[string]interface{}{
			"code":         0,
			"captcha_key":  key,
			"image_base64": masterImageBase64,
			"tile_base64":  tileImageBase64,
			"tile_width":   blockData.Width,
			"tile_height":  blockData.Height,
			"tile_x":       blockData.TileX,
			"tile_y":       blockData.TileY,
		}
		bt, _ := json.Marshal(resp)
		l.Infof("GenerateSlideBasicCaptcha success:%s", string(bt))

		ch <- resp
	}()

	select {
	case resp = <-ch:
		return resp, err
	case <-time.After(2 * time.Second):
		_, err = GenerateSlideBasic(ctx, retryNum+1)
		if err != nil {
			l.Errorf("GenerateSlideBasic timeout num:%d err:%+v", retryNum+1, err)
			return nil, err
		}
		return nil, errors.New("GenerateSlideBasicCaptcha timeout")

	}
}

哈喽,请参考如下你的代码修改:

var slideBasicCapt slide.Captcha

// 此处建议在 init() 或者在程序 main 启动时创建实例
func initSlideBasic() (slideBasicCapt slide.Captcha, err error) {
	builder := slide.NewBuilder(
		slide.WithEnableGraphVerticalRandom(true),
	)

	imgs, err := images.GetImages()
	if err != nil {
		log.Errorf("images.GetImages err:%+v", err)
		return err
	}
	graphs, err := tiles.GetTiles()
	if err != nil {
		log.Errorf("tiles.GetTiles err:%+v", err)
		return err
	}

	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for i := 0; i < len(graphs); i++ {
		graph := graphs[i]
		newGraphs = append(newGraphs, &slide.GraphImage{
			OverlayImage: graph.OverlayImage,
			MaskImage:    graph.MaskImage,
			ShadowImage:  graph.ShadowImage,
		})
	}

	builder.SetResources(
		slide.WithGraphImages(newGraphs),
		slide.WithBackgrounds(imgs),
	)

	slideBasicCapt = builder.Make()
	return nil
}

func init() {
	err := initSlideBasic()
	if err != nil {
		log.Println(">>>> init slide err: ", err)
	}
}

// GenerateImpl 生成实现
func GenerateImpl() (map[string]interface{}, error) {
	captData, err := slideBasicCapt.Generate()
	if err != nil {
		l.Errorf("slideRegionCapt.Generate err:%+v", err)
		return nil, err
	}

	blockData := captData.GetData()
	if blockData == nil {
		l.Error("GenerateSlideCaptcha failed")
		return nil, err
	}

	var masterImageBase64, tileImageBase64 string
	masterImageBase64 = captData.GetMasterImage().ToBase64()
	if err != nil {
		l.Errorf("captData.GetMasterImage().ToBase64 err:%+v", err)
		return nil, err
	}

	tileImageBase64 = captData.GetTileImage().ToBase64()
	if err != nil {
		l.Errorf("captData.GetTileImage().ToBase64 err:%+v", err)
		return nil, err
	}

	dotsByte, _ := json.Marshal(blockData)
	key := helper.StringToMD5(string(dotsByte))
	// 此处 WriteCache 建议写入 Redis 等中间件
	WriteCache(key, dotsByte)
	fmt.Printf("WriteCache success")

	resp := map[string]interface{}{
		"code":         0,
		"captcha_key":  key,
		"image_base64": masterImageBase64,
		"tile_base64":  tileImageBase64,
		"tile_width":   blockData.Width,
		"tile_height":  blockData.Height,
		"tile_x":       blockData.TileX,
		"tile_y":       blockData.TileY,
	}

	return resp, nil
}

// GenerateSlideBasic generate slide basic
func GenerateSlideBasic(ctx *fiber.Ctx, retryNum int) (resp map[string]interface{}, err error) {
	fmt.Printf("service pkg GenerateSlideBasic")
	resp = make(map[string]interface{})
	//ch := make(chan map[string]interface{}, 1)

	// 因为你使用的是 fiber 框架,每个进来的请求已经是一个新的协程处理,此处的协程可以省略
	//go func() {
	//	resp, err = GenerateImpl(retryNum)
	//	bt, _ := json.Marshal(resp)
	//	fmt.Printf("GenerateSlideBasicCaptcha success:%s", string(bt))
	//	ch <- resp
	//}()
	//select {
	//case resp = <-ch:
	//	return resp, err
	//}

	resp, err = GenerateImpl()
	for err != nil {
		if retryNum == 0 {
			break
		}
		retryNum--
		resp, err = GenerateImpl()
	}

	return
}