1、sms取消号码
This commit is contained in:
		| @ -392,6 +392,13 @@ func (e MemberProxy) GetIpList(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if req.Lang == "zh" { | ||||
| 		for i, v := range data { | ||||
| 			data[i].City = v.CityZh | ||||
| 			data[i].Country = v.CountryZh | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	e.OK(data, "success") | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -319,7 +319,7 @@ func (e SmsPhone) WeakUp(c *gin.Context) { | ||||
| 	e.OK(nil, "唤醒长效号码成功") | ||||
| } | ||||
|  | ||||
| // cancelWeakUp 取消号码 | ||||
| // cancelWeakUp 删除号码 | ||||
| func (e SmsPhone) DeleteMyNumber(c *gin.Context) { | ||||
| 	req := dto.DeleteMyNumberReq{} | ||||
| 	s := service.SmsPhone{} | ||||
| @ -350,3 +350,30 @@ func (e SmsPhone) DeleteMyNumber(c *gin.Context) { | ||||
|  | ||||
| 	e.OK(nil, "取消号码成功") | ||||
| } | ||||
|  | ||||
| // 取消号码 | ||||
| func (e SmsPhone) CancelNumber(c *gin.Context) { | ||||
| 	req := dto.SmsPhoneCancelNumberReq{} | ||||
| 	s := service.SmsPhone{} | ||||
| 	err := e.MakeContext(c). | ||||
| 		MakeOrm(). | ||||
| 		Bind(&req). | ||||
| 		MakeService(&s.Service). | ||||
| 		Errors | ||||
| 	if err != nil { | ||||
| 		e.Logger.Error(err) | ||||
| 		e.Error(500, err, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	userId := user.GetUserId(c) | ||||
|  | ||||
| 	code := s.CancelNumber(&req, userId) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		e.Error(code, nil, statuscode.GetMsg(code, "zh")) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	e.OK(nil, "取消号码成功") | ||||
| } | ||||
|  | ||||
| @ -3,23 +3,27 @@ package models | ||||
| import ( | ||||
| 	"go-admin/common/models" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/shopspring/decimal" | ||||
| ) | ||||
|  | ||||
| type SmsPhone struct { | ||||
| 	models.Model | ||||
|  | ||||
| 	UserId          int        `json:"userId" gorm:"type:bigint;comment:用户Id"` | ||||
| 	Service         string     `json:"service" gorm:"type:varchar(50);comment:sms 服务"` | ||||
| 	ServiceCode     string     `json:"serviceCode" gorm:"type:varchar(30);comment:服务code"` | ||||
| 	Type            int        `json:"type" gorm:"type:tinyint;comment:类型 0-短效 1-长效"` | ||||
| 	Period          int        `json:"period" gorm:"type:int;comment:时长(月)"` | ||||
| 	Phone           string     `json:"phone" gorm:"type:varchar(30);comment:号码"` | ||||
| 	ActivationId    int        `json:"activationId" gorm:"type:int;comment:激活码id"` | ||||
| 	NewActivationId int        `json:"newActivationId" gorm:"type:int;comment:新激活码id 每次获取验证码会刷新"` | ||||
| 	MessageId       int        `json:"messageId" gorm:"type:int;comment:短信模板id"` | ||||
| 	Code            string     `json:"code" gorm:"type:varchar(10);comment:验证码"` | ||||
| 	Status          int        `json:"status" gorm:"type:tinyint;comment:状态 1-等待验证码 2-已获取"` | ||||
| 	ExpireTime      *time.Time `json:"expireTime" gorm:"type:datetime;comment:过期时间"` | ||||
| 	UserId          int             `json:"userId" gorm:"type:bigint;comment:用户Id"` | ||||
| 	Service         string          `json:"service" gorm:"type:varchar(50);comment:sms 服务"` | ||||
| 	ServiceCode     string          `json:"serviceCode" gorm:"type:varchar(30);comment:服务code"` | ||||
| 	Type            int             `json:"type" gorm:"type:tinyint;comment:类型 0-短效 1-长效"` | ||||
| 	Period          int             `json:"period" gorm:"type:int;comment:时长(月)"` | ||||
| 	Phone           string          `json:"phone" gorm:"type:varchar(30);comment:号码"` | ||||
| 	ActivationId    int             `json:"activationId" gorm:"type:int;comment:激活码id"` | ||||
| 	NewActivationId int             `json:"newActivationId" gorm:"type:int;comment:新激活码id 每次获取验证码会刷新"` | ||||
| 	MessageId       int             `json:"messageId" gorm:"type:int;comment:短信模板id"` | ||||
| 	Code            string          `json:"code" gorm:"type:varchar(10);comment:验证码"` | ||||
| 	Status          int             `json:"status" gorm:"type:tinyint;comment:状态 1-等待验证码 2-已获取"` | ||||
| 	ExpireTime      *time.Time      `json:"expireTime" gorm:"type:datetime;comment:过期时间"` | ||||
| 	Actived         int             `json:"actived" gorm:"type:tinyint;comment:是否激活(长期租赁如果第一次没接收到验证码 则不会激活号码) 1-未激活 2-已激活 3-已失效"` | ||||
| 	Price           decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"` | ||||
| 	models.ModelTime | ||||
| 	models.ControlBy | ||||
| } | ||||
|  | ||||
| @ -1,22 +1,21 @@ | ||||
| package models | ||||
|  | ||||
| import ( | ||||
|  | ||||
| 	"go-admin/common/models" | ||||
|  | ||||
| ) | ||||
|  | ||||
| type SmsServices struct { | ||||
|     models.Model | ||||
|      | ||||
|     Name string `json:"name" gorm:"type:varchar(255);comment:服务名称"`  | ||||
|     Code string `json:"code" gorm:"type:varchar(50);comment:编码"`  | ||||
|     models.ModelTime | ||||
|     models.ControlBy | ||||
| 	models.Model | ||||
|  | ||||
| 	Name              string `json:"name" gorm:"type:varchar(255);comment:服务名称"` | ||||
| 	Code              string `json:"code" gorm:"type:varchar(50);comment:编码"` | ||||
| 	ExpirationMinutes int    `json:"expirationMinutes" gorm:"type:int;comment:过期时间(分钟)"` | ||||
| 	models.ModelTime | ||||
| 	models.ControlBy | ||||
| } | ||||
|  | ||||
| func (SmsServices) TableName() string { | ||||
|     return "sms_services" | ||||
| 	return "sms_services" | ||||
| } | ||||
|  | ||||
| func (e *SmsServices) Generate() models.ActiveRecord { | ||||
| @ -26,4 +25,4 @@ func (e *SmsServices) Generate() models.ActiveRecord { | ||||
|  | ||||
| func (e *SmsServices) GetId() interface{} { | ||||
| 	return e.Id | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -24,6 +24,7 @@ func registerSmsPhoneRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl | ||||
| 		r1.GET("list", api.GetMyPage)                              // 获取自己的号码列表 | ||||
| 		r1.POST("weakUp", api.WeakUp)                              // 新增号码 | ||||
| 		r1.DELETE("my-number", api.DeleteMyNumber)                 // 删除自己的号码 | ||||
| 		r1.PUT("cancel", api.CancelNumber)                         //取消号码 | ||||
| 	} | ||||
|  | ||||
| 	r := v1.Group("/sms-phone").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) | ||||
|  | ||||
| @ -66,7 +66,7 @@ func (e *CliProxyService) GetTrafficInfo() ([]dto.CliProxyTraffics, error) { | ||||
|  | ||||
| // 提取长效ip | ||||
| func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal.Decimal, error) { | ||||
| 	api := "/v2/static/use" | ||||
| 	api := "/api/static/buy" | ||||
|  | ||||
| 	balanceService := MemberBalance{Service: e.Service} | ||||
| 	balance := balanceService.GetBalance(userId) | ||||
| @ -91,10 +91,10 @@ func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal. | ||||
| 		return balance, errors.New("余额不足") | ||||
| 	} | ||||
|  | ||||
| 	token, err := e.GetToken() | ||||
| 	key, err := e.GetKey() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取token失败 %v", err) | ||||
| 		e.Log.Errorf("获取key失败 %v", err) | ||||
| 		return balance, err | ||||
| 	} | ||||
|  | ||||
| @ -103,13 +103,12 @@ func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal. | ||||
| 	form.Set("day", strconv.Itoa(day)) | ||||
| 	form.Set("id", strconv.Itoa(req.Id)) | ||||
| 	form.Set("code", req.Code) | ||||
| 	form.Set("lang", "en") | ||||
| 	form.Set("token", token) | ||||
| 	form.Set("lang", "zh") | ||||
| 	form.Set("key", key) | ||||
|  | ||||
| 	body := strings.NewReader(form.Encode()) | ||||
|  | ||||
| 	useTime := time.Now().Format("01-02 15") | ||||
| 	resp := dto.CliProxyResultResp[interface{}]{} | ||||
| 	resp := dto.CliProxyResultResp[dto.CliProxyBuyResp]{} | ||||
| 	client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, nil) | ||||
| 	err = client.PostWithContentType(api, body, "application/x-www-form-urlencoded;charset=UTF-8", nil, &resp) | ||||
|  | ||||
| @ -120,22 +119,14 @@ func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal. | ||||
|  | ||||
| 	if resp.Code != 0 { | ||||
| 		if resp.Code == 300 { | ||||
| 			e.resetToken() | ||||
| 			return e.UseIp(req, userId) | ||||
| 			e.Log.Errorf("key 失效 code:%d", resp.Code) | ||||
| 			return balance, errors.New("key 失效") | ||||
| 		} | ||||
|  | ||||
| 		e.Log.Errorf("请求失败 params:%v err: %v", req, resp.Msg) | ||||
| 		return balance, errors.New(resp.Msg) | ||||
| 	} | ||||
|  | ||||
| 	//查询获取到的ip | ||||
| 	userList, err := e.GetUserIpList(1, 10, req.Lang, req.Code) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取用户ip列表失败 %v", err) | ||||
| 		return balance, err | ||||
| 	} | ||||
|  | ||||
| 	memberProxy := models.MemberProxy{} | ||||
| 	memberProxy.Area = req.Code | ||||
| 	memberProxy.Day = day | ||||
| @ -143,40 +134,28 @@ func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal. | ||||
| 	memberProxy.Type = 1 | ||||
| 	memberProxy.UserId = userId | ||||
| 	memberProxy.Status = 1 | ||||
| 	memberProxy.State = resp.Data.City | ||||
| 	memberProxy.Ip = resp.Data.Ip | ||||
| 	memberProxy.Port = strconv.Itoa(resp.Data.Port) | ||||
| 	memberProxy.Password = resp.Data.Password | ||||
| 	memberProxy.UserName = resp.Data.UserName | ||||
| 	memberProxy.Expired = time.Unix(int64(resp.Data.Expired), 0) | ||||
|  | ||||
| 	var count int64 | ||||
|  | ||||
| 	for _, v := range userList.List { | ||||
| 		//用提取时间来区分 | ||||
| 		if strings.Contains(v.UseTime, useTime) && v.Code == req.Code { | ||||
| 			err := e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 				if err1 := tx.Model(&models.MemberProxy{}).Where("ip =?", v.IP).Count(&count).Error; err1 != nil { | ||||
| 					return err1 | ||||
| 				} | ||||
|  | ||||
| 				if count > 0 { | ||||
| 					return errors.New("该ip已被使用") | ||||
| 				} | ||||
|  | ||||
| 				if err1 := tx.Exec("UPDATE member_balance SET balance = balance - ? WHERE user_id =?", price, userId).Error; err1 != nil { | ||||
| 					return err1 | ||||
| 				} | ||||
|  | ||||
| 				memberProxy.Ip = v.IP | ||||
| 				memberProxy.StaticId = v.ID | ||||
| 				memberProxy.Port = strconv.Itoa(v.Port) | ||||
| 				memberProxy.Password = v.Password | ||||
| 				memberProxy.State = v.City | ||||
| 				memberProxy.UserName = v.Username | ||||
| 				memberProxy.Expired, err = time.Parse("2006-01-02 15:04", v.Expired) | ||||
|  | ||||
| 				return tx.Create(&memberProxy).Error | ||||
| 			}) | ||||
|  | ||||
| 			if err == nil { | ||||
| 				return balance.Sub(price), nil | ||||
| 			} | ||||
| 	err = e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 		if err1 := tx.Exec("UPDATE member_balance SET balance = balance - ? WHERE user_id =?", price, userId).Error; err1 != nil { | ||||
| 			e.Log.Errorf("扣款失败 %v", err1) | ||||
| 			return err1 | ||||
| 		} | ||||
|  | ||||
| 		if err1 := tx.Create(&memberProxy).Error; err1 != nil { | ||||
| 			e.Log.Errorf("创建ip记录失败 %v", err1) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("创建ip记录失败 %v", err) | ||||
| 		return balance, err | ||||
| 	} | ||||
|  | ||||
| 	return balance, nil | ||||
| @ -184,11 +163,11 @@ func (e *CliProxyService) UseIp(req *dto.CliProxyIPUseReq, userId int) (decimal. | ||||
|  | ||||
| // 获取长效ip列表 | ||||
| func (e *CliProxyService) GetIps(req *dto.CliProxyIPListGetReq, userId int) ([]dto.CliProxyStaticListResp, error) { | ||||
| 	api := "/v1/static/list" | ||||
| 	token, err := e.GetToken() | ||||
| 	api := "/api/static/list" | ||||
| 	key, err := e.GetKey() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取token失败 %v", err) | ||||
| 		e.Log.Errorf("获取key失败 %v", err) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -208,7 +187,7 @@ func (e *CliProxyService) GetIps(req *dto.CliProxyIPListGetReq, userId int) ([]d | ||||
| 	writer := multipart.NewWriter(&buf) | ||||
| 	// 添加字段 | ||||
| 	_ = writer.WriteField("lang", req.Lang) | ||||
| 	_ = writer.WriteField("token", token) | ||||
| 	_ = writer.WriteField("key", key) | ||||
| 	_ = writer.WriteField("code", configResp.ConfigValue) | ||||
|  | ||||
| 	writer.Close() | ||||
| @ -224,8 +203,10 @@ func (e *CliProxyService) GetIps(req *dto.CliProxyIPListGetReq, userId int) ([]d | ||||
|  | ||||
| 	if resp.Code == 0 { | ||||
| 		if resp.Code == 300 { | ||||
| 			e.resetToken() | ||||
| 			return e.GetIps(req, userId) | ||||
| 			// e.resetToken() | ||||
| 			// return e.GetIps(req, userId) | ||||
| 			e.Log.Errorf("key 失效 code:%d", resp.Code) | ||||
| 			return nil, errors.New("key 失效") | ||||
| 		} | ||||
| 		return resp.Data, nil | ||||
| 	} else { | ||||
| @ -235,12 +216,12 @@ func (e *CliProxyService) GetIps(req *dto.CliProxyIPListGetReq, userId int) ([]d | ||||
|  | ||||
| // 获取总的用户ip列表 | ||||
| func (e *CliProxyService) GetUserIpList(page int, limit int, lang, code string) (dto.CliProxyUserListResp, error) { | ||||
| 	api := "/v2/static/useList" | ||||
| 	token, err := e.GetToken() | ||||
| 	api := "/api/static/useList" | ||||
| 	key, err := e.GetKey() | ||||
| 	respList := dto.CliProxyUserListResp{} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取token失败 %v", err) | ||||
| 		e.Log.Errorf("获取key失败 %v", err) | ||||
| 		return respList, err | ||||
| 	} | ||||
|  | ||||
| @ -248,7 +229,7 @@ func (e *CliProxyService) GetUserIpList(page int, limit int, lang, code string) | ||||
| 	writer := multipart.NewWriter(&buf) | ||||
| 	// 添加字段 | ||||
| 	_ = writer.WriteField("lang", lang) | ||||
| 	_ = writer.WriteField("token", token) | ||||
| 	_ = writer.WriteField("key", key) | ||||
| 	_ = writer.WriteField("code", code) | ||||
| 	_ = writer.WriteField("page", strconv.Itoa(page)) | ||||
| 	_ = writer.WriteField("limit", strconv.Itoa(limit)) | ||||
| @ -268,25 +249,19 @@ func (e *CliProxyService) GetUserIpList(page int, limit int, lang, code string) | ||||
| 	return resp.Data, nil | ||||
| } | ||||
|  | ||||
| // 获取token | ||||
| func (e *CliProxyService) GetToken() (string, error) { | ||||
| 	val, _ := redishelper.DefaultRedis.GetString(rediskey.CliProxyTokenPrefix) | ||||
|  | ||||
| 	if val != "" { | ||||
| 		resp := dto.CliProxySigninResp{} | ||||
| 		sonic.UnmarshalString(val, &resp) | ||||
|  | ||||
| 		if resp.Token != "" { | ||||
| 			return resp.Token, nil | ||||
| 		} | ||||
| // 获取私钥 | ||||
| func (e *CliProxyService) GetKey() (string, error) { | ||||
| 	sysConfigService := SysConfig{Service: e.Service} | ||||
| 	configResp := dto.GetSysConfigByKEYForServiceResp{} | ||||
| 	if err := sysConfigService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "cli_proxy_key"}, &configResp); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := e.resetToken() | ||||
| 	if err != nil { | ||||
| 		return resp.Token, err | ||||
| 	if configResp.ConfigValue == "" { | ||||
| 		return "", errors.New("未配置私钥") | ||||
| 	} | ||||
|  | ||||
| 	return resp.Token, nil | ||||
| 	return configResp.ConfigValue, nil | ||||
| } | ||||
|  | ||||
| // 获取线路 | ||||
| @ -296,10 +271,10 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR | ||||
| 	client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) | ||||
| 	resp := dto.CliProxyResultResp[[]dto.CliProxyTrafficServerResp]{} | ||||
|  | ||||
| 	token, err := e.GetToken() | ||||
| 	key, err := e.GetKey() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("获取token失败 %v", err) | ||||
| 		e.Log.Errorf("获取key失败 %v", err) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -307,7 +282,7 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR | ||||
| 	writer := multipart.NewWriter(&buf) | ||||
| 	// 添加字段 | ||||
| 	_ = writer.WriteField("lang", "en") | ||||
| 	_ = writer.WriteField("token", token) | ||||
| 	_ = writer.WriteField("key", key) | ||||
|  | ||||
| 	writer.Close() | ||||
|  | ||||
| @ -320,8 +295,10 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR | ||||
|  | ||||
| 	if resp.Code == 0 { | ||||
| 		if resp.Code == 300 { | ||||
| 			e.resetToken() | ||||
| 			return e.GetTrafficServer(req) | ||||
| 			// e.resetToken() | ||||
| 			// return e.GetTrafficServer(req) | ||||
| 			e.Log.Errorf("key 失效 code:%d", resp.Code) | ||||
| 			return nil, errors.New("key 失效") | ||||
| 		} | ||||
| 		return resp.Data, nil | ||||
| 	} else { | ||||
| @ -329,64 +306,64 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 充值token | ||||
| func (e *CliProxyService) resetToken() (dto.CliProxySigninResp, error) { | ||||
| 	configService := SysConfig{} | ||||
| 	configService.Orm = e.Orm | ||||
| 	configService.Log = e.Log | ||||
| 	configReq := dto.SysConfigByKeyReq{ | ||||
| 		ConfigKey: "proxy_dash_email", | ||||
| 	} | ||||
| 	configResp := dto.GetSysConfigByKEYForServiceResp{} | ||||
| 	passwordConfigReq := dto.SysConfigByKeyReq{ | ||||
| 		ConfigKey: "proxy_dash_password", | ||||
| 	} | ||||
| 	passwordConfigResp := dto.GetSysConfigByKEYForServiceResp{} | ||||
| 	if err := configService.GetWithKey(&configReq, &configResp); err != nil { | ||||
| 		return dto.CliProxySigninResp{}, err | ||||
| 	} | ||||
| 	if err := configService.GetWithKey(&passwordConfigReq, &passwordConfigResp); err != nil { | ||||
| 		return dto.CliProxySigninResp{}, err | ||||
| 	} | ||||
| // // 充值token | ||||
| // func (e *CliProxyService) resetToken() (dto.CliProxySigninResp, error) { | ||||
| // 	configService := SysConfig{} | ||||
| // 	configService.Orm = e.Orm | ||||
| // 	configService.Log = e.Log | ||||
| // 	configReq := dto.SysConfigByKeyReq{ | ||||
| // 		ConfigKey: "proxy_dash_email", | ||||
| // 	} | ||||
| // 	configResp := dto.GetSysConfigByKEYForServiceResp{} | ||||
| // 	passwordConfigReq := dto.SysConfigByKeyReq{ | ||||
| // 		ConfigKey: "proxy_dash_password", | ||||
| // 	} | ||||
| // 	passwordConfigResp := dto.GetSysConfigByKEYForServiceResp{} | ||||
| // 	if err := configService.GetWithKey(&configReq, &configResp); err != nil { | ||||
| // 		return dto.CliProxySigninResp{}, err | ||||
| // 	} | ||||
| // 	if err := configService.GetWithKey(&passwordConfigReq, &passwordConfigResp); err != nil { | ||||
| // 		return dto.CliProxySigninResp{}, err | ||||
| // 	} | ||||
|  | ||||
| 	resp := dto.CliProxyResultResp[dto.CliProxySigninResp]{} | ||||
| 	api := "/v1/signin" | ||||
| 	headers, _ := GetHeaders() | ||||
| 	client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) | ||||
| // 	resp := dto.CliProxyResultResp[dto.CliProxySigninResp]{} | ||||
| // 	api := "/v1/signin" | ||||
| // 	headers, _ := GetHeaders() | ||||
| // 	client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) | ||||
|  | ||||
| 	var buf bytes.Buffer | ||||
| 	writer := multipart.NewWriter(&buf) | ||||
| 	// 添加字段 | ||||
| 	_ = writer.WriteField("lang", "en") | ||||
| 	_ = writer.WriteField("email", configResp.ConfigValue) | ||||
| 	_ = writer.WriteField("pwd", passwordConfigResp.ConfigValue) | ||||
| // 	var buf bytes.Buffer | ||||
| // 	writer := multipart.NewWriter(&buf) | ||||
| // 	// 添加字段 | ||||
| // 	_ = writer.WriteField("lang", "en") | ||||
| // 	_ = writer.WriteField("email", configResp.ConfigValue) | ||||
| // 	_ = writer.WriteField("pwd", passwordConfigResp.ConfigValue) | ||||
|  | ||||
| 	writer.Close() | ||||
| // 	writer.Close() | ||||
|  | ||||
| 	contentType := writer.FormDataContentType() | ||||
| 	err := client.PostWithContentType(api, &buf, contentType, nil, &resp) | ||||
| // 	contentType := writer.FormDataContentType() | ||||
| // 	err := client.PostWithContentType(api, &buf, contentType, nil, &resp) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return dto.CliProxySigninResp{}, err | ||||
| 	} | ||||
| // 	if err != nil { | ||||
| // 		return dto.CliProxySigninResp{}, err | ||||
| // 	} | ||||
|  | ||||
| 	if resp.Code != 0 || resp.Data.Token == "" { | ||||
| 		return dto.CliProxySigninResp{}, errors.New(resp.Msg) | ||||
| 	} | ||||
| // 	if resp.Code != 0 || resp.Data.Token == "" { | ||||
| // 		return dto.CliProxySigninResp{}, errors.New(resp.Msg) | ||||
| // 	} | ||||
|  | ||||
| 	val, err := sonic.MarshalString(resp.Data) | ||||
| // 	val, err := sonic.MarshalString(resp.Data) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return dto.CliProxySigninResp{}, err | ||||
| 	} | ||||
| // 	if err != nil { | ||||
| // 		return dto.CliProxySigninResp{}, err | ||||
| // 	} | ||||
|  | ||||
| 	if val != "" { | ||||
| 		if err := redishelper.DefaultRedis.SetString(rediskey.CliProxyTokenPrefix, val); err != nil { | ||||
| 			return dto.CliProxySigninResp{}, err | ||||
| 		} | ||||
| 	} | ||||
| 	return resp.Data, nil | ||||
| } | ||||
| // 	if val != "" { | ||||
| // 		if err := redishelper.DefaultRedis.SetString(rediskey.CliProxyTokenPrefix, val); err != nil { | ||||
| // 			return dto.CliProxySigninResp{}, err | ||||
| // 		} | ||||
| // 	} | ||||
| // 	return resp.Data, nil | ||||
| // } | ||||
|  | ||||
| // 获取自定义header | ||||
| func GetHeaders() (map[string]string, error) { | ||||
|  | ||||
							
								
								
									
										57
									
								
								app/admin/service/cliproxy_server_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/admin/service/cliproxy_server_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| package service | ||||
|  | ||||
| import ( | ||||
| 	"go-admin/app/admin/models" | ||||
| 	"go-admin/app/admin/service/dto" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
|  | ||||
| func TestCliProxyServer(t *testing.T) { | ||||
| 	initSetting() | ||||
| 	val := `{"code":0,"data":{"ip":"38.75.201.117","port":443,"days":30,"username":"H18LP70091","password":"QjFZCG6k","country":"United States","city":"Seattle","expired":1756022300},"msg":"success"}` | ||||
| 	resp := dto.CliProxyResultResp[dto.CliProxyBuyResp]{} | ||||
| 	sonic.UnmarshalString(val, &resp) | ||||
|  | ||||
| 	if resp.Code == 0 { | ||||
| 		memberProxy := models.MemberProxy{} | ||||
| 		memberProxy.Area = "US" | ||||
| 		memberProxy.Day = 30 | ||||
| 		memberProxy.StaticId = 10000 | ||||
| 		memberProxy.Type = 1 | ||||
| 		memberProxy.UserId = 1 | ||||
| 		memberProxy.Status = 1 | ||||
| 		memberProxy.State = resp.Data.City | ||||
| 		memberProxy.Ip = resp.Data.Ip | ||||
| 		memberProxy.Port = strconv.Itoa(resp.Data.Port) | ||||
| 		memberProxy.Password = resp.Data.Password | ||||
| 		memberProxy.UserName = resp.Data.UserName | ||||
| 		memberProxy.Expired = time.Unix(int64(resp.Data.Expired), 0) | ||||
|  | ||||
| 		db := sdk.Runtime.GetDbByKey("default") | ||||
| 		err := db.Transaction(func(tx *gorm.DB) error { | ||||
| 			if err1 := tx.Exec("UPDATE member_balance SET balance = balance - ? WHERE user_id =?", 5.7, 1).Error; err1 != nil { | ||||
| 				logger.Errorf("扣款失败 %v", err1) | ||||
| 				return err1 | ||||
| 			} | ||||
|  | ||||
| 			if err1 := tx.Create(&memberProxy).Error; err1 != nil { | ||||
| 				logger.Errorf("创建ip记录失败 %v", err1) | ||||
| 			} | ||||
| 			return nil | ||||
| 		}) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			logger.Errorf("创建ip记录失败 %v", err) | ||||
|  | ||||
| 			t.Fail() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @ -43,6 +43,16 @@ type CliProxyResultResp[T any] struct { | ||||
| 	Msg  string `json:"msg"` | ||||
| } | ||||
|  | ||||
| type CliProxyBuyResp struct { | ||||
| 	Ip       string `json:"ip"` | ||||
| 	Port     int    `json:"port"` | ||||
| 	Days     int    `json:"days"` | ||||
| 	UserName string `json:"username"` | ||||
| 	Password string `json:"password"` | ||||
| 	City     string `json:"city"` | ||||
| 	Expired  int    `json:"expired" comment:"过期时间 秒 unix"` | ||||
| } | ||||
|  | ||||
| type CliProxySigninResp struct { | ||||
| 	Token   string          `json:"token"` | ||||
| 	Balance decimal.Decimal `json:"balance"` | ||||
| @ -50,11 +60,13 @@ type CliProxySigninResp struct { | ||||
|  | ||||
| // 长效ip列表响应 | ||||
| type CliProxyStaticListResp struct { | ||||
| 	City    string `json:"city"` | ||||
| 	Code    string `json:"code"` | ||||
| 	Country string `json:"country"` | ||||
| 	Id      int    `json:"id"` | ||||
| 	Ip      string `json:"ip"` | ||||
| 	City      string `json:"city"` | ||||
| 	CityZh    string `json:"city_zh"` | ||||
| 	Code      string `json:"code"` | ||||
| 	Country   string `json:"country"` | ||||
| 	CountryZh string `json:"country_zh"` | ||||
| 	Id        int    `json:"id"` | ||||
| 	Ip        string `json:"ip"` | ||||
| } | ||||
|  | ||||
| type CliProxyUserListResp struct { | ||||
|  | ||||
| @ -163,3 +163,7 @@ func (s *DeleteMyNumberReq) Validate() error { | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type SmsPhoneCancelNumberReq struct { | ||||
| 	Id int `json:"id" comment:"短信号码id"` | ||||
| } | ||||
|  | ||||
| @ -24,8 +24,46 @@ type SmsPhone struct { | ||||
| 	service.Service | ||||
| } | ||||
|  | ||||
| // 取消等待 | ||||
| func (e *SmsPhone) CancelNumber(req *dto.SmsPhoneCancelNumberReq, userId int) int { | ||||
| 	var data models.SmsPhone | ||||
| 	if err := e.Orm.Model(data).Where("id =? and user_id= ?", req.Id, userId).First(&data).Error; err != nil { | ||||
| 		e.Log.Errorf("获取短信号码失败, %s", err) | ||||
| 		return statuscode.SmsNotExisted | ||||
| 	} | ||||
|  | ||||
| 	if data.Actived == 1 { | ||||
| 		code := e.CancelRental(data.NewActivationId) | ||||
|  | ||||
| 		if code == statuscode.Success { | ||||
| 			err := e.Orm.Transaction(func(tx *gorm.DB) error { | ||||
| 				if err1 := e.Orm.Model(data).Updates(map[string]interface{}{"status": 3, "code": "", "actived": "3"}).Error; err1 != nil { | ||||
| 					e.Log.Errorf("更新短信号码失败, %s", err1) | ||||
| 					return err1 | ||||
| 				} | ||||
|  | ||||
| 				if err1 := tx.Exec("UPDATE member_balance SET balance = balance +? WHERE user_id =?", data.Price, userId).Error; err1 != nil { | ||||
| 					e.Log.Errorf("更新余额失败, %s", err1) | ||||
| 					return err1 | ||||
| 				} | ||||
|  | ||||
| 				return nil | ||||
| 			}) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				e.Log.Errorf("取消租赁后修改失败, %s", err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			e.Log.Errorf("取消租赁失败, %s", code) | ||||
| 			return code | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return statuscode.Success | ||||
| } | ||||
|  | ||||
| // 删除断信号码 | ||||
| func (e SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int { | ||||
| func (e *SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int { | ||||
| 	var data models.SmsPhone | ||||
|  | ||||
| 	if err := e.Orm.Model(data).Where("id =? and user_id= ?", req.Id, userId).First(&data).Error; err != nil { | ||||
| @ -33,7 +71,7 @@ func (e SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int { | ||||
| 		return statuscode.AccountExisted | ||||
| 	} | ||||
|  | ||||
| 	if data.ExpireTime != nil && data.ExpireTime.After(time.Now()) && data.Type == 1 { | ||||
| 	if data.ExpireTime != nil && data.ExpireTime.After(time.Now()) && data.Type == 1 && data.Actived == 2 { | ||||
| 		return statuscode.SmsNotExpired | ||||
| 	} | ||||
|  | ||||
| @ -52,7 +90,7 @@ func (e SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int { | ||||
| } | ||||
|  | ||||
| // 唤醒长效号码 | ||||
| func (e SmsPhone) WeakUp(req *dto.WeakUpReq, userId int) int { | ||||
| func (e *SmsPhone) WeakUp(req *dto.WeakUpReq, userId int) int { | ||||
| 	smsPhone := models.SmsPhone{} | ||||
| 	if err := e.Orm.Model(smsPhone).Where("activation_id =? and user_id= ?", req.ActivationId, userId).First(&smsPhone).Error; err != nil { | ||||
| 		e.Log.Errorf("获取短信号码失败, %s", err) | ||||
| @ -84,7 +122,7 @@ func (e SmsPhone) WeakUp(req *dto.WeakUpReq, userId int) int { | ||||
| } | ||||
|  | ||||
| // 分页查询自己的号码列表 | ||||
| func (e SmsPhone) GetMyPage(req *dto.SmsPhoneGetPageReq, userId int, phone *[]models.SmsPhone, count *int64) int { | ||||
| func (e *SmsPhone) GetMyPage(req *dto.SmsPhoneGetPageReq, userId int, phone *[]models.SmsPhone, count *int64) int { | ||||
| 	var data models.SmsPhone | ||||
|  | ||||
| 	if err := e.Orm.Model(data).Where("user_id =? and type =?", userId, req.Type).Scopes( | ||||
| @ -102,7 +140,7 @@ func (e SmsPhone) GetMyPage(req *dto.SmsPhoneGetPageReq, userId int, phone *[]mo | ||||
| } | ||||
|  | ||||
| // 租赁号码 | ||||
| func (e SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, int) { | ||||
| func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, int) { | ||||
| 	config := dto.GetSysConfigByKEYForServiceResp{} | ||||
| 	configReq := dto.SysConfigByKeyReq{} | ||||
| 	configService := SysConfig{Service: e.Service} | ||||
| @ -166,10 +204,15 @@ func (e SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, | ||||
| 	smsPhone.ActivationId = activationId | ||||
| 	smsPhone.MessageId = activationId | ||||
| 	smsPhone.NewActivationId = activationId | ||||
| 	smsPhone.Actived = 1 | ||||
|  | ||||
| 	smsPhone.Price = price | ||||
| 	if req.Type == 1 { | ||||
| 		now = now.AddDate(0, req.Period, 0) | ||||
| 		smsPhone.ExpireTime = &now | ||||
| 	} else { | ||||
| 		now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes)) | ||||
| 		smsPhone.ExpireTime = &now | ||||
| 	} | ||||
|  | ||||
| 	smsPhone.Status = 1 | ||||
| @ -179,28 +222,13 @@ func (e SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, | ||||
| 		return decimal.Zero, statuscode.ServerError | ||||
| 	} | ||||
|  | ||||
| 	// if req.Type == 0 { | ||||
| 	// 	smsReceiveLog := models.SmsReceiveLog{ | ||||
| 	// 		UserId:      userId, | ||||
| 	// 		MessageId:   activationId, | ||||
| 	// 		Service:     serviceItem.Name, | ||||
| 	// 		ServiceCode: serviceItem.Code, | ||||
| 	// 		Phone:       phone, | ||||
| 	// 		Status:      1, | ||||
| 	// 	} | ||||
| 	// 	if err := e.Orm.Save(&smsReceiveLog).Error; err != nil { | ||||
| 	// 		e.Log.Errorf("保存短信接收日志失败", err) | ||||
| 	// 		return decimal.Zero, statuscode.ServerError | ||||
| 	// 	} | ||||
| 	// if req.Type == 1 { | ||||
| 	// 	//保存长效号码 | ||||
| 	// 	// if code := e.KeepLongTerm(smsPhone.ActivationId); code != statuscode.Success { | ||||
| 	// 	// 	return decimal.Zero, code | ||||
| 	// 	// } | ||||
| 	// } | ||||
|  | ||||
| 	if req.Type == 1 { | ||||
| 		//保存长效号码 | ||||
| 		if code := e.KeepLongTerm(smsPhone.ActivationId); code != statuscode.Success { | ||||
| 			return decimal.Zero, code | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := e.Orm.Exec("UPDATE member_balance SET balance = balance -? WHERE user_id =?", price, userId).Error; err != nil { | ||||
| 		e.Log.Errorf("更新余额失败", err) | ||||
| 		return decimal.Zero, statuscode.ServerError | ||||
| @ -353,7 +381,7 @@ func (e *SmsPhone) SyncCodes() error { | ||||
| 	for _, item := range phones { | ||||
| 		code, codeStatus := e.GetCodeForApi(item.ActivationId) | ||||
| 		mapData := make(map[string]interface{}) | ||||
| 		remark := "" | ||||
| 		logMapData := make(map[string]interface{}) | ||||
|  | ||||
| 		if codeStatus == statuscode.SmsWaitCode { | ||||
| 			continue | ||||
| @ -361,10 +389,24 @@ func (e *SmsPhone) SyncCodes() error { | ||||
| 			mapData["code"] = code | ||||
| 			mapData["status"] = 2 | ||||
|  | ||||
| 			if item.Actived == 1 { | ||||
| 				mapData["actived"] = 2 | ||||
| 			} | ||||
|  | ||||
| 			logMapData["code"] = code | ||||
| 			logMapData["status"] = 2 | ||||
|  | ||||
| 		} else if codeStatus == statuscode.SmsNoActivation || codeStatus == statuscode.SmsCancel { | ||||
| 			mapData["code"] = code | ||||
| 			mapData["status"] = 3 | ||||
| 			remark = statuscode.GetMsg(codeStatus, "zh") | ||||
|  | ||||
| 			if item.Actived == 1 { | ||||
| 				mapData["actived"] = 3 | ||||
| 			} | ||||
|  | ||||
| 			logMapData["code"] = code | ||||
| 			logMapData["status"] = 3 | ||||
| 			logMapData["remark"] = statuscode.GetMsg(codeStatus, "zh") | ||||
| 		} else { | ||||
| 			continue | ||||
| 		} | ||||
| @ -374,11 +416,7 @@ func (e *SmsPhone) SyncCodes() error { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if remark != "" { | ||||
| 			mapData["remark"] = remark | ||||
| 		} | ||||
|  | ||||
| 		if err := e.Orm.Model(models.SmsReceiveLog{}).Where("message_id =?", item.MessageId).Updates(mapData).Error; err != nil { | ||||
| 		if err := e.Orm.Model(models.SmsReceiveLog{}).Where("message_id =?", item.MessageId).Updates(logMapData).Error; err != nil { | ||||
| 			e.Log.Errorf("同步短信接收日志失败:%s", err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| @ -489,8 +527,33 @@ func (e *SmsPhone) KeepLongTerm(activationId int) int { | ||||
| 		e.Log.Errorf("租赁请求失败 %s", content) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	return statuscode.Success | ||||
| // 取消租赁 | ||||
| func (e *SmsPhone) CancelRental(activationId int) int { | ||||
| 	key, code := GetApiKey(e) | ||||
|  | ||||
| 	if code != statuscode.Success { | ||||
| 		e.Log.Errorf("租赁api请求失败 %s") | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
|  | ||||
| 	url := fmt.Sprintf("?api_key=%s&action=setStatus&id=%d&status=8", key.ConfigValue, activationId) | ||||
| 	client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil) | ||||
| 	bytes, err := client.GetRaw(url, nil) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("租赁请求失败 %s", err.Error()) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| 	content := string(bytes) | ||||
|  | ||||
| 	if content == "ACCESS_CANCEL" { | ||||
| 		return statuscode.Success | ||||
| 	} else { | ||||
| 		e.Log.Errorf("租赁请求失败 %s", content) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetPage 获取SmsPhone列表 | ||||
|  | ||||
| @ -26,7 +26,7 @@ func (e SmsReceiveLog) WebHook(req *dto.SmsReceiveWebHookReq) error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if err := e.Orm.Model(&phoneLog).Where("new_activation_id =?", req.ActivationID).Updates(map[string]interface{}{"status": "2", "code": req.Code, "message_id": req.MessageID}).Error; err != nil { | ||||
| 	if err := e.Orm.Model(&phoneLog).Where("new_activation_id =?", req.ActivationID).Updates(map[string]interface{}{"status": "2", "code": req.Code, "message_id": req.MessageID, "actived": 2}).Error; err != nil { | ||||
| 		e.Log.Errorf("webhook 修改phone code失败:%s \r\n", err) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @ -75,6 +75,14 @@ func (e *SysConfig) Update(c *dto.SysConfigControl) error { | ||||
| 		return errors.New("无权更新该数据") | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	// if c.ConfigKey == "proxy_dash_email" || c.ConfigKey == "proxy_dash_password" { | ||||
| 	// 	e.Log.Info("更新了邮箱或密码,刷新token") | ||||
| 	// 	proxyService := CliProxyService{Service: e.Service} | ||||
| 	// 	if _, err := proxyService.resetToken(); err != nil { | ||||
| 	// 		e.Log.Errorf("修改配置重置token失败:%s", err) | ||||
| 	// 	} | ||||
| 	// } | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										44
									
								
								utils/utility/safe_go_helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								utils/utility/safe_go_helper.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| package utility | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"runtime" | ||||
| 	"runtime/debug" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| ) | ||||
|  | ||||
| // SafeGo 安全地启动一个 goroutine,捕获 panic | ||||
| func SafeGo(fn func()) { | ||||
| 	go func() { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				// 记录 Goroutine ID、panic 信息和堆栈 | ||||
| 				logger.Error(fmt.Sprintf("Recovered from panic in Goroutine %s: %v\nStack Trace:\n%s", GetGoroutineID(), r, string(debug.Stack()))) | ||||
| 			} | ||||
| 		}() | ||||
| 		fn() | ||||
| 	}() | ||||
| } | ||||
|  | ||||
| // 获取 Goroutine ID | ||||
| func GetGoroutineID() string { | ||||
| 	buf := make([]byte, 64) | ||||
| 	n := runtime.Stack(buf, false) | ||||
| 	stack := string(buf[:n]) | ||||
| 	// 提取 Goroutine ID | ||||
| 	id := strings.Split(stack, " ")[1] | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| func SafeGoParam[T any](fn func(T), param T) { | ||||
| 	go func() { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				logger.Error(fmt.Sprintf(" SafeGoParam Recovered from panic in Goroutine %s: %v\nStack Trace:\n%s", GetGoroutineID(), r, string(debug.Stack()))) | ||||
| 			} | ||||
| 		}() | ||||
| 		fn(param) // 执行传入的函数 | ||||
| 	}() | ||||
| } | ||||
		Reference in New Issue
	
	Block a user