synchronize license every 10 secs

This commit is contained in:
RockYang 2024-04-26 14:35:01 +08:00
parent 74b1b07b31
commit 1966e69460
5 changed files with 113 additions and 31 deletions

View File

@ -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

View File

@ -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 != "" {

View File

@ -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),

View File

@ -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
} }

View File

@ -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: '请输入有效数字'},