mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	synchronize license every 10 secs
This commit is contained in:
		@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"chatplus/core"
 | 
						"chatplus/core"
 | 
				
			||||||
	"chatplus/core/types"
 | 
						"chatplus/core/types"
 | 
				
			||||||
	"chatplus/handler"
 | 
						"chatplus/handler"
 | 
				
			||||||
 | 
						"chatplus/service"
 | 
				
			||||||
	"chatplus/store/model"
 | 
						"chatplus/store/model"
 | 
				
			||||||
	"chatplus/store/vo"
 | 
						"chatplus/store/vo"
 | 
				
			||||||
	"chatplus/utils"
 | 
						"chatplus/utils"
 | 
				
			||||||
@@ -17,10 +18,11 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type UserHandler struct {
 | 
					type UserHandler struct {
 | 
				
			||||||
	handler.BaseHandler
 | 
						handler.BaseHandler
 | 
				
			||||||
 | 
						licenseService *service.LicenseService
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewUserHandler(app *core.AppServer, db *gorm.DB) *UserHandler {
 | 
					func NewUserHandler(app *core.AppServer, db *gorm.DB, licenseService *service.LicenseService) *UserHandler {
 | 
				
			||||||
	return &UserHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}}
 | 
						return &UserHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}, licenseService: licenseService}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List 用户列表
 | 
					// List 用户列表
 | 
				
			||||||
@@ -75,6 +77,13 @@ func (h *UserHandler) Save(c *gin.Context) {
 | 
				
			|||||||
		resp.ERROR(c, types.InvalidArgs)
 | 
							resp.ERROR(c, types.InvalidArgs)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// 检测最大注册人数
 | 
				
			||||||
 | 
						var totalUser int64
 | 
				
			||||||
 | 
						h.DB.Model(&model.User{}).Count(&totalUser)
 | 
				
			||||||
 | 
						if int(totalUser) >= h.licenseService.GetLicense().UserNum {
 | 
				
			||||||
 | 
							resp.ERROR(c, "当前注册用户数已达上限,请请升级 License")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	var user = model.User{}
 | 
						var user = model.User{}
 | 
				
			||||||
	var res *gorm.DB
 | 
						var res *gorm.DB
 | 
				
			||||||
	var userVo vo.User
 | 
						var userVo vo.User
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package handler
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"chatplus/core"
 | 
						"chatplus/core"
 | 
				
			||||||
	"chatplus/core/types"
 | 
						"chatplus/core/types"
 | 
				
			||||||
 | 
						"chatplus/service"
 | 
				
			||||||
	"chatplus/store/model"
 | 
						"chatplus/store/model"
 | 
				
			||||||
	"chatplus/store/vo"
 | 
						"chatplus/store/vo"
 | 
				
			||||||
	"chatplus/utils"
 | 
						"chatplus/utils"
 | 
				
			||||||
@@ -21,16 +22,23 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type UserHandler struct {
 | 
					type UserHandler struct {
 | 
				
			||||||
	BaseHandler
 | 
						BaseHandler
 | 
				
			||||||
	searcher *xdb.Searcher
 | 
						searcher       *xdb.Searcher
 | 
				
			||||||
	redis    *redis.Client
 | 
						redis          *redis.Client
 | 
				
			||||||
 | 
						licenseService *service.LicenseService
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewUserHandler(
 | 
					func NewUserHandler(
 | 
				
			||||||
	app *core.AppServer,
 | 
						app *core.AppServer,
 | 
				
			||||||
	db *gorm.DB,
 | 
						db *gorm.DB,
 | 
				
			||||||
	searcher *xdb.Searcher,
 | 
						searcher *xdb.Searcher,
 | 
				
			||||||
	client *redis.Client) *UserHandler {
 | 
						client *redis.Client,
 | 
				
			||||||
	return &UserHandler{BaseHandler: BaseHandler{DB: db, App: app}, searcher: searcher, redis: client}
 | 
						licenseService *service.LicenseService) *UserHandler {
 | 
				
			||||||
 | 
						return &UserHandler{
 | 
				
			||||||
 | 
							BaseHandler:    BaseHandler{DB: db, App: app},
 | 
				
			||||||
 | 
							searcher:       searcher,
 | 
				
			||||||
 | 
							redis:          client,
 | 
				
			||||||
 | 
							licenseService: licenseService,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Register user register
 | 
					// Register user register
 | 
				
			||||||
@@ -53,6 +61,14 @@ func (h *UserHandler) Register(c *gin.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 检测最大注册人数
 | 
				
			||||||
 | 
						var totalUser int64
 | 
				
			||||||
 | 
						h.DB.Model(&model.User{}).Count(&totalUser)
 | 
				
			||||||
 | 
						if int(totalUser) >= h.licenseService.GetLicense().UserNum {
 | 
				
			||||||
 | 
							resp.ERROR(c, "当前注册用户数已达上限,请请升级 License")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 检查验证码
 | 
						// 检查验证码
 | 
				
			||||||
	var key string
 | 
						var key string
 | 
				
			||||||
	if data.RegWay == "email" || data.RegWay == "mobile" || data.Code != "" {
 | 
						if data.RegWay == "email" || data.RegWay == "mobile" || data.Code != "" {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,6 +166,9 @@ func main() {
 | 
				
			|||||||
		fx.Provide(service.NewSmtpService),
 | 
							fx.Provide(service.NewSmtpService),
 | 
				
			||||||
		// License 服务
 | 
							// License 服务
 | 
				
			||||||
		fx.Provide(service.NewLicenseService),
 | 
							fx.Provide(service.NewLicenseService),
 | 
				
			||||||
 | 
							fx.Invoke(func(licenseService *service.LicenseService) {
 | 
				
			||||||
 | 
								licenseService.SyncLicense()
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 微信机器人服务
 | 
							// 微信机器人服务
 | 
				
			||||||
		fx.Provide(wx.NewWeChatBot),
 | 
							fx.Provide(wx.NewWeChatBot),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,11 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LicenseService struct {
 | 
					type LicenseService struct {
 | 
				
			||||||
	config types.ApiConfig
 | 
						config       types.ApiConfig
 | 
				
			||||||
	levelDB *store.LevelDB
 | 
						levelDB      *store.LevelDB
 | 
				
			||||||
	license types.License
 | 
						license      types.License
 | 
				
			||||||
	machineId string
 | 
						urlWhiteList []string
 | 
				
			||||||
 | 
						machineId    string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * LicenseService {
 | 
					func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * LicenseService {
 | 
				
			||||||
@@ -28,25 +29,27 @@ func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * License
 | 
				
			|||||||
		machineId = info.HostID
 | 
							machineId = info.HostID
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &LicenseService{
 | 
						return &LicenseService{
 | 
				
			||||||
		config: server.Config.ApiConfig,
 | 
							config:    server.Config.ApiConfig,
 | 
				
			||||||
		levelDB: levelDB,
 | 
							levelDB:   levelDB,
 | 
				
			||||||
		license: license,
 | 
							license:   license,
 | 
				
			||||||
		machineId: machineId,
 | 
							machineId: machineId,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type License struct {
 | 
				
			||||||
 | 
						Name      string `json:"name"`
 | 
				
			||||||
 | 
						Value     string `json:"license"`
 | 
				
			||||||
 | 
						Mid       string `json:"mid"`
 | 
				
			||||||
 | 
						ExpiredAt int64  `json:"expired_at"`
 | 
				
			||||||
 | 
						UserNum   int    `json:"user_num"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ActiveLicense 激活 License
 | 
					// ActiveLicense 激活 License
 | 
				
			||||||
func (s *LicenseService) ActiveLicense(license string, machineId string) error {
 | 
					func (s *LicenseService) ActiveLicense(license string, machineId string) error {
 | 
				
			||||||
	var res struct {
 | 
						var res struct {
 | 
				
			||||||
		Code    types.BizCode `json:"code"`
 | 
							Code    types.BizCode `json:"code"`
 | 
				
			||||||
		Message string        `json:"message"`
 | 
							Message string        `json:"message"`
 | 
				
			||||||
		Data    struct {
 | 
							Data    License       `json:"data"`
 | 
				
			||||||
			Name      string `json:"name"`
 | 
					 | 
				
			||||||
			License   string `json:"license"`
 | 
					 | 
				
			||||||
			Mid       string `json:"mid"`
 | 
					 | 
				
			||||||
			ExpiredAt int64  `json:"expired_at"`
 | 
					 | 
				
			||||||
			UserNum   int    `json:"user_num"`
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/active")
 | 
						apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/active")
 | 
				
			||||||
	response, err := req.C().R().
 | 
						response, err := req.C().R().
 | 
				
			||||||
@@ -75,10 +78,54 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("保存许可证书失败:%v", err)
 | 
							return fmt.Errorf("保存许可证书失败:%v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SyncLicense 定期同步 License
 | 
				
			||||||
 | 
					func (s *LicenseService) SyncLicense() {
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							for {
 | 
				
			||||||
 | 
								var res struct {
 | 
				
			||||||
 | 
									Code    types.BizCode `json:"code"`
 | 
				
			||||||
 | 
									Message string        `json:"message"`
 | 
				
			||||||
 | 
									Data    struct {
 | 
				
			||||||
 | 
										License License  `json:"license"`
 | 
				
			||||||
 | 
										Urls    []string `json:"urls"`
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/check")
 | 
				
			||||||
 | 
								response, err := req.C().R().
 | 
				
			||||||
 | 
									SetBody(map[string]string{"license": s.license.Key, "machine_id": s.machineId}).
 | 
				
			||||||
 | 
									SetSuccessResult(&res).Post(apiURL)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									logger.Errorf("发送激活请求失败: %v", err)
 | 
				
			||||||
 | 
									goto next
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if response.IsErrorState() {
 | 
				
			||||||
 | 
									logger.Errorf("激活失败:%v", response.Status)
 | 
				
			||||||
 | 
									goto next
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if res.Code != types.Success {
 | 
				
			||||||
 | 
									logger.Errorf("激活失败:%v", res.Message)
 | 
				
			||||||
 | 
									s.license.IsActive = false
 | 
				
			||||||
 | 
									goto next
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								s.license = types.License{
 | 
				
			||||||
 | 
									Key:       res.Data.License.Value,
 | 
				
			||||||
 | 
									MachineId: res.Data.License.Mid,
 | 
				
			||||||
 | 
									UserNum:   res.Data.License.UserNum,
 | 
				
			||||||
 | 
									ExpiredAt: res.Data.License.ExpiredAt,
 | 
				
			||||||
 | 
									IsActive:  true,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								s.urlWhiteList = res.Data.Urls
 | 
				
			||||||
 | 
								logger.Debugf("同步 License 成功:%v\n%v", s.license, s.urlWhiteList)
 | 
				
			||||||
 | 
							next:
 | 
				
			||||||
 | 
								time.Sleep(time.Second * 10)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetLicense 获取许可信息
 | 
					// GetLicense 获取许可信息
 | 
				
			||||||
func (s *LicenseService) GetLicense() types.License {
 | 
					func (s *LicenseService) GetLicense() types.License {
 | 
				
			||||||
	return s.license
 | 
						return s.license
 | 
				
			||||||
@@ -98,12 +145,10 @@ func (s *LicenseService) IsValidApiURL(uri string) error {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !strings.HasPrefix(uri, "https://gpt.bemore.lol") &&
 | 
						for _, v := range s.urlWhiteList {
 | 
				
			||||||
		!strings.HasPrefix(uri, "https://api.openai.com") &&
 | 
							if strings.HasPrefix(uri, v) {
 | 
				
			||||||
		!strings.HasPrefix(uri, "http://cdn.chat-plus.net") &&
 | 
								return nil
 | 
				
			||||||
		!strings.HasPrefix(uri, "https://api.chat-plus.net") {
 | 
							}
 | 
				
			||||||
		return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。",uri)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。", uri)
 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -73,7 +73,7 @@
 | 
				
			|||||||
          <el-input v-model="user.username" autocomplete="off"/>
 | 
					          <el-input v-model="user.username" autocomplete="off"/>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item v-if="add" label="密码:" prop="password">
 | 
					        <el-form-item v-if="add" label="密码:" prop="password">
 | 
				
			||||||
          <el-input v-model="user.password" autocomplete="off"/>
 | 
					          <el-input v-model="user.password" autocomplete="off" placeholder="8-16位"/>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item label="剩余算力:" prop="power">
 | 
					        <el-form-item label="剩余算力:" prop="power">
 | 
				
			||||||
          <el-input v-model.number="user.power" autocomplete="off" placeholder="0"/>
 | 
					          <el-input v-model.number="user.power" autocomplete="off" placeholder="0"/>
 | 
				
			||||||
@@ -186,8 +186,17 @@ const models = ref([])
 | 
				
			|||||||
const showUserEditDialog = ref(false)
 | 
					const showUserEditDialog = ref(false)
 | 
				
			||||||
const showResetPassDialog = ref(false)
 | 
					const showResetPassDialog = ref(false)
 | 
				
			||||||
const rules = reactive({
 | 
					const rules = reactive({
 | 
				
			||||||
  username: [{required: true, message: '请输入账号', trigger: 'change',}],
 | 
					  username: [{required: true, message: '请输入账号', trigger: 'blur',}],
 | 
				
			||||||
  password: [{required: true, message: '请输入密码', trigger: 'change',}],
 | 
					  password: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					      validator: (rule, value) => {
 | 
				
			||||||
 | 
					        return !(value.length > 16 || value.length < 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }, message: '密码必须为8-16',
 | 
				
			||||||
 | 
					      trigger: 'blur'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  calls: [
 | 
					  calls: [
 | 
				
			||||||
    {required: true, message: '请输入提问次数'},
 | 
					    {required: true, message: '请输入提问次数'},
 | 
				
			||||||
    {type: 'number', message: '请输入有效数字'},
 | 
					    {type: 'number', message: '请输入有效数字'},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user