geekai/api/service/license_service.go
2024-04-26 14:35:01 +08:00

154 lines
3.8 KiB
Go

package service
import (
"chatplus/core"
"chatplus/core/types"
"chatplus/store"
"errors"
"fmt"
"github.com/imroc/req/v3"
"github.com/shirou/gopsutil/host"
"strings"
"time"
)
type LicenseService struct {
config types.ApiConfig
levelDB *store.LevelDB
license types.License
urlWhiteList []string
machineId string
}
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * LicenseService {
var license types.License
var machineId string
_ = levelDB.Get(types.LicenseKey, &license)
info, err := host.Info()
if err == nil {
machineId = info.HostID
}
return &LicenseService{
config: server.Config.ApiConfig,
levelDB: levelDB,
license: license,
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
func (s *LicenseService) ActiveLicense(license string, machineId string) error {
var res struct {
Code types.BizCode `json:"code"`
Message string `json:"message"`
Data License `json:"data"`
}
apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/active")
response, err := req.C().R().
SetBody(map[string]string{"license": license, "machine_id": machineId}).
SetSuccessResult(&res).Post(apiURL)
if err != nil {
return fmt.Errorf("发送激活请求失败: %v", err)
}
if response.IsErrorState() {
return fmt.Errorf( "发送激活请求失败:%v", response.Status)
}
if res.Code != types.Success {
return fmt.Errorf("激活失败:%v", res.Message)
}
s.license = types.License{
Key: license,
MachineId: machineId,
UserNum: res.Data.UserNum,
ExpiredAt: res.Data.ExpiredAt,
IsActive: true,
}
err = s.levelDB.Put(types.LicenseKey, s.license)
if err != nil {
return fmt.Errorf("保存许可证书失败:%v", err)
}
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 获取许可信息
func (s *LicenseService) GetLicense() types.License {
return s.license
}
// IsValidApiURL 判断是否合法的中转 URL
func (s *LicenseService) IsValidApiURL(uri string) error {
// 获得许可授权的直接放行
if s.license.IsActive {
if s.license.MachineId != s.machineId {
return errors.New("系统使用了盗版的许可证书")
}
if time.Now().Unix() > s.license.ExpiredAt {
return errors.New("系统许可证书已经过期")
}
return nil
}
for _, v := range s.urlWhiteList {
if strings.HasPrefix(uri, v) {
return nil
}
}
return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。", uri)
}