Initial commit (code only without large binaries)
This commit is contained in:
31
EdgeAPI/internal/db/models/authority/authority_key_dao.go
Normal file
31
EdgeAPI/internal/db/models/authority/authority_key_dao.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
type AuthorityKeyDAO dbs.DAO
|
||||
|
||||
func NewAuthorityKeyDAO() *AuthorityKeyDAO {
|
||||
return dbs.NewDAO(&AuthorityKeyDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeAuthorityKeys",
|
||||
Model: new(AuthorityKey),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*AuthorityKeyDAO)
|
||||
}
|
||||
|
||||
var SharedAuthorityKeyDAO *AuthorityKeyDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedAuthorityKeyDAO = NewAuthorityKeyDAO()
|
||||
|
||||
// 初始化IsPlus值
|
||||
_, _ = SharedAuthorityKeyDAO.IsPlus(nil)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package authority
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// IsPlus 判断是否为企业版
|
||||
func (this *AuthorityKeyDAO) IsPlus(tx *dbs.Tx) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
363
EdgeAPI/internal/db/models/authority/authority_key_dao_plus.go
Normal file
363
EdgeAPI/internal/db/models/authority/authority_key_dao_plus.go
Normal file
@@ -0,0 +1,363 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package authority
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
plusutils "github.com/TeaOSLab/EdgePlus/pkg/utils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var validateFailures = 0
|
||||
|
||||
const maxValidateFailures = 20
|
||||
|
||||
// 更新Plus数值
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
isPlus, _ := SharedAuthorityKeyDAO.IsPlus(nil)
|
||||
teaconst.IsPlus = isPlus
|
||||
|
||||
var ticker = time.NewTicker(5 * time.Minute)
|
||||
if Tea.IsTesting() {
|
||||
ticker = time.NewTicker(30 * time.Second) // 测试专用
|
||||
}
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
newIsPlus, err := SharedAuthorityKeyDAO.IsPlus(nil)
|
||||
if err != nil {
|
||||
remotelogs.Error("AuthorityKeyDAO", "check isPlus failed: "+err.Error())
|
||||
}
|
||||
|
||||
teaconst.IsPlus = newIsPlus
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// IsPlus 判断是否为商业版
|
||||
func (this *AuthorityKeyDAO) IsPlus(tx *dbs.Tx) (bool, error) {
|
||||
key, err := this.ReadKey(tx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if key == nil || len(key.Value) == 0 {
|
||||
// 通知变更
|
||||
if teaconst.IsPlus {
|
||||
notifyErr := this.NotifyChange(tx, "")
|
||||
if notifyErr != nil {
|
||||
// 这里不阻塞函数继续往下执行
|
||||
remotelogs.Error("PLUS", "notify change failed: "+notifyErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
teaconst.IsPlus = false
|
||||
teaconst.Edition = ""
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
m, err := plusutils.DecodeKey([]byte(key.Value))
|
||||
if err != nil {
|
||||
// 通知变更
|
||||
if teaconst.IsPlus {
|
||||
notifyErr := this.NotifyChange(tx, "")
|
||||
if notifyErr != nil {
|
||||
// 这里不阻塞函数继续往下执行
|
||||
remotelogs.Error("PLUS", "notify change failed: "+notifyErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
teaconst.IsPlus = false
|
||||
teaconst.Edition = ""
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// remotely validation
|
||||
if m.Method == plusutils.MethodRemote {
|
||||
ok, errCode := this.ValidateRemotely(key.Value, key.RequestCode)
|
||||
if ok {
|
||||
validateFailures = 0
|
||||
} else {
|
||||
validateFailures++
|
||||
if len(errCode) > 0 || validateFailures > maxValidateFailures {
|
||||
validateFailures = 0
|
||||
_ = this.ResetKey(nil, false)
|
||||
|
||||
// 通知变更
|
||||
if teaconst.IsPlus {
|
||||
notifyErr := this.NotifyChange(tx, "")
|
||||
if notifyErr != nil {
|
||||
// 这里不阻塞函数继续往下执行
|
||||
remotelogs.Error("PLUS", "notify change failed: "+notifyErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
teaconst.IsPlus = false
|
||||
teaconst.Edition = ""
|
||||
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newIsPlus = m.DayTo >= timeutil.Format("Y-m-d")
|
||||
if newIsPlus {
|
||||
teaconst.Edition = m.Edition
|
||||
|
||||
// 兼容以前授权的版本
|
||||
if len(m.Edition) == 0 {
|
||||
if m.Nodes >= 500 {
|
||||
teaconst.Edition = plusutils.EditionEnt
|
||||
} else if m.Nodes >= 100 {
|
||||
teaconst.Edition = plusutils.EditionPro
|
||||
}
|
||||
}
|
||||
} else {
|
||||
teaconst.Edition = ""
|
||||
}
|
||||
|
||||
if newIsPlus != teaconst.IsPlus {
|
||||
// 通知变更
|
||||
notifyErr := this.NotifyChange(tx, teaconst.Edition)
|
||||
if notifyErr != nil {
|
||||
// 这里不阻塞函数继续往下执行
|
||||
remotelogs.Error("PLUS", "notify change failed: "+notifyErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
teaconst.IsPlus = newIsPlus
|
||||
|
||||
if m.IsValid() {
|
||||
teaconst.MaxNodes = types.Int32(m.Nodes)
|
||||
} else {
|
||||
teaconst.MaxNodes = teaconst.DefaultMaxNodes
|
||||
}
|
||||
|
||||
return teaconst.IsPlus, nil
|
||||
}
|
||||
|
||||
// UpdateKey 设置Key
|
||||
func (this *AuthorityKeyDAO) UpdateKey(tx *dbs.Tx, value string, requestCode string, dayFrom string, dayTo string, hostname string, macAddresses []string, company string) error {
|
||||
one, err := this.Query(tx).
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var op = NewAuthorityKeyOperator()
|
||||
if one != nil {
|
||||
op.Id = one.(*AuthorityKey).Id
|
||||
}
|
||||
op.Value = value
|
||||
op.RequestCode = requestCode
|
||||
op.DayFrom = dayFrom
|
||||
op.DayTo = dayTo
|
||||
op.Hostname = hostname
|
||||
|
||||
if len(macAddresses) == 0 {
|
||||
macAddresses = []string{}
|
||||
}
|
||||
macAddressesJSON, err := json.Marshal(macAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op.MacAddresses = macAddressesJSON
|
||||
op.Company = company
|
||||
op.UpdatedAt = time.Now().Unix()
|
||||
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 激活一下
|
||||
_, err = this.IsPlus(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadKey 读取Key
|
||||
func (this *AuthorityKeyDAO) ReadKey(tx *dbs.Tx) (key *AuthorityKey, err error) {
|
||||
one, err := this.Query(tx).
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if one == nil {
|
||||
return nil, nil
|
||||
}
|
||||
key = one.(*AuthorityKey)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ResetKey 重置Key
|
||||
func (this *AuthorityKeyDAO) ResetKey(tx *dbs.Tx, notifyChange bool) error {
|
||||
_, err := this.Query(tx).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if notifyChange {
|
||||
// 激活一下
|
||||
_, err = this.IsPlus(tx)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActivateRemotely 远程激活
|
||||
func (this *AuthorityKeyDAO) ActivateRemotely(key string, requestCode string) (ok bool, errorCode string) {
|
||||
var hosts = teaconst.AuthorityValidatorHOSTS
|
||||
if len(hosts) == 0 {
|
||||
return false, "HOSTS_NOT_FOUND"
|
||||
}
|
||||
|
||||
var httpClient = utils.NewHTTPClient(30 * time.Second)
|
||||
postDataString, err := plusutils.EncodeMap(maps.Map{
|
||||
"encodedKey": key,
|
||||
"requestCode": requestCode,
|
||||
"timestamp": time.Now().Unix(),
|
||||
})
|
||||
if err != nil {
|
||||
return false, "ENCODE_DATA_FAILED:" + err.Error()
|
||||
}
|
||||
|
||||
for _, host := range hosts {
|
||||
ok, errorCode = this.callRemoteWithHost(httpClient, host+"/api/activate", postDataString)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
if len(errorCode) > 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ValidateRemotely 远程验证
|
||||
func (this *AuthorityKeyDAO) ValidateRemotely(key string, requestCode string) (ok bool, errorCode string) {
|
||||
var hosts = teaconst.AuthorityValidatorHOSTS
|
||||
if len(hosts) == 0 {
|
||||
return false, "HOSTS_NOT_FOUND"
|
||||
}
|
||||
|
||||
var httpClient = utils.NewHTTPClient(30 * time.Second)
|
||||
postDataString, err := plusutils.EncodeMap(maps.Map{
|
||||
"encodedKey": key,
|
||||
"requestCode": requestCode,
|
||||
"timestamp": time.Now().Unix(),
|
||||
})
|
||||
if err != nil {
|
||||
return false, "ENCODE_DATA_FAILED:" + err.Error()
|
||||
}
|
||||
|
||||
for _, host := range hosts {
|
||||
ok, errorCode = this.callRemoteWithHost(httpClient, host+"/api/validate", postDataString)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
if len(errorCode) > 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (this *AuthorityKeyDAO) callRemoteWithHost(httpClient *http.Client, urlString string, postDataString string) (ok bool, errorCode string) {
|
||||
var query = &url.Values{}
|
||||
query.Set("data", postDataString)
|
||||
httpReq, err := http.NewRequest(http.MethodPost, urlString, strings.NewReader(query.Encode()))
|
||||
if err != nil {
|
||||
return false, "CREATE_REQUEST_FAILED"
|
||||
}
|
||||
httpReq.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
|
||||
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
resp, err := httpClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if resp != nil && resp.Body != nil {
|
||||
_ = resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return
|
||||
}
|
||||
|
||||
if resp != nil && resp.Body != nil {
|
||||
respData, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var jsonMap = maps.Map{}
|
||||
err = json.Unmarshal(respData, &jsonMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var code = jsonMap.GetInt("code")
|
||||
if code != 200 {
|
||||
return false, "INVALID_CODE_" + jsonMap.GetString("message")
|
||||
}
|
||||
|
||||
var dataMap = jsonMap.GetMap("data")
|
||||
if dataMap != nil {
|
||||
var info = dataMap.GetString("info")
|
||||
infoMap, err := plusutils.DecodeData([]byte(info))
|
||||
if err != nil {
|
||||
return false, "DECODE_INFO_FAILED"
|
||||
}
|
||||
var timeDelta = time.Now().Unix() - infoMap.GetInt64("timestamp")
|
||||
if timeDelta > 3600 {
|
||||
return false, "INVALID_TIMESTAMP"
|
||||
}
|
||||
if infoMap.GetBool("ok") {
|
||||
return true, ""
|
||||
} else {
|
||||
return false, "FAILED"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// NotifyChange Plus状态变化时调用
|
||||
func (this *AuthorityKeyDAO) NotifyChange(tx *dbs.Tx, edition string) error {
|
||||
// 加载IP库
|
||||
// 注意:现在 Plus 版本也使用 MaxMind,所以统一调用 InitDefault()
|
||||
go func() {
|
||||
var err error
|
||||
// 统一使用 InitDefault(),因为 Plus 版本现在也使用 MaxMind
|
||||
err = iplibrary.InitDefault()
|
||||
if err != nil {
|
||||
remotelogs.Error("IP_LIBRARY", "load ip library failed: "+err.Error())
|
||||
} else {
|
||||
remotelogs.Println("IP_LIBRARY", "IP library reloaded successfully (MaxMind)")
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//go:build plus
|
||||
|
||||
package authority
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAuthorityKeyDAO_UpdateValue(t *testing.T) {
|
||||
err := NewAuthorityKeyDAO().UpdateKey(nil, "12345678", "", "", "", []string{}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestAuthorityKeyDAO_ReadValue(t *testing.T) {
|
||||
value, err := NewAuthorityKeyDAO().ReadKey(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(value)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package authority_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
44
EdgeAPI/internal/db/models/authority/authority_key_model.go
Normal file
44
EdgeAPI/internal/db/models/authority/authority_key_model.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package authority
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
const (
|
||||
AuthorityKeyField_Id dbs.FieldName = "id" // ID
|
||||
AuthorityKeyField_Value dbs.FieldName = "value" // Key值
|
||||
AuthorityKeyField_DayFrom dbs.FieldName = "dayFrom" // 开始日期
|
||||
AuthorityKeyField_DayTo dbs.FieldName = "dayTo" // 结束日期
|
||||
AuthorityKeyField_Hostname dbs.FieldName = "hostname" // Hostname
|
||||
AuthorityKeyField_MacAddresses dbs.FieldName = "macAddresses" // MAC地址
|
||||
AuthorityKeyField_UpdatedAt dbs.FieldName = "updatedAt" // 创建/修改时间
|
||||
AuthorityKeyField_Company dbs.FieldName = "company" // 公司组织
|
||||
AuthorityKeyField_RequestCode dbs.FieldName = "requestCode" // 申请码
|
||||
)
|
||||
|
||||
// AuthorityKey 企业版认证信息
|
||||
type AuthorityKey struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Value string `field:"value"` // Key值
|
||||
DayFrom string `field:"dayFrom"` // 开始日期
|
||||
DayTo string `field:"dayTo"` // 结束日期
|
||||
Hostname string `field:"hostname"` // Hostname
|
||||
MacAddresses dbs.JSON `field:"macAddresses"` // MAC地址
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间
|
||||
Company string `field:"company"` // 公司组织
|
||||
RequestCode string `field:"requestCode"` // 申请码
|
||||
}
|
||||
|
||||
type AuthorityKeyOperator struct {
|
||||
Id any // ID
|
||||
Value any // Key值
|
||||
DayFrom any // 开始日期
|
||||
DayTo any // 结束日期
|
||||
Hostname any // Hostname
|
||||
MacAddresses any // MAC地址
|
||||
UpdatedAt any // 创建/修改时间
|
||||
Company any // 公司组织
|
||||
RequestCode any // 申请码
|
||||
}
|
||||
|
||||
func NewAuthorityKeyOperator() *AuthorityKeyOperator {
|
||||
return &AuthorityKeyOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package authority
|
||||
218
EdgeAPI/internal/db/models/authority/authority_node_dao.go
Normal file
218
EdgeAPI/internal/db/models/authority/authority_node_dao.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthorityNodeStateEnabled = 1 // 已启用
|
||||
AuthorityNodeStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type AuthorityNodeDAO dbs.DAO
|
||||
|
||||
func NewAuthorityNodeDAO() *AuthorityNodeDAO {
|
||||
return dbs.NewDAO(&AuthorityNodeDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeAuthorityNodes",
|
||||
Model: new(AuthorityNode),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*AuthorityNodeDAO)
|
||||
}
|
||||
|
||||
var SharedAuthorityNodeDAO *AuthorityNodeDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedAuthorityNodeDAO = NewAuthorityNodeDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableAuthorityNode 启用条目
|
||||
func (this *AuthorityNodeDAO) EnableAuthorityNode(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", AuthorityNodeStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableAuthorityNode 禁用条目
|
||||
func (this *AuthorityNodeDAO) DisableAuthorityNode(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", AuthorityNodeStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledAuthorityNode 查找启用中的条目
|
||||
func (this *AuthorityNodeDAO) FindEnabledAuthorityNode(tx *dbs.Tx, id int64) (*AuthorityNode, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Attr("state", AuthorityNodeStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*AuthorityNode), err
|
||||
}
|
||||
|
||||
// FindAuthorityNodeName 根据主键查找名称
|
||||
func (this *AuthorityNodeDAO) FindAuthorityNodeName(tx *dbs.Tx, id int64) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// FindAllEnabledAuthorityNodes 列出所有可用认证节点
|
||||
func (this *AuthorityNodeDAO) FindAllEnabledAuthorityNodes(tx *dbs.Tx) (result []*AuthorityNode, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(AuthorityNodeStateEnabled).
|
||||
Desc("order").
|
||||
AscPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// CountAllEnabledAuthorityNodes 计算认证节点数量
|
||||
func (this *AuthorityNodeDAO) CountAllEnabledAuthorityNodes(tx *dbs.Tx) (int64, error) {
|
||||
return this.Query(tx).
|
||||
State(AuthorityNodeStateEnabled).
|
||||
Count()
|
||||
}
|
||||
|
||||
// ListEnabledAuthorityNodes 列出单页的认证节点
|
||||
func (this *AuthorityNodeDAO) ListEnabledAuthorityNodes(tx *dbs.Tx, offset int64, size int64) (result []*AuthorityNode, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(AuthorityNodeStateEnabled).
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Desc("order").
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// CreateAuthorityNode 创建认证节点
|
||||
func (this *AuthorityNodeDAO) CreateAuthorityNode(tx *dbs.Tx, name string, description string, isOn bool) (nodeId int64, err error) {
|
||||
uniqueId, err := this.GenUniqueId(tx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
secret := rands.String(32)
|
||||
err = models.NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleAuthority)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var op = NewAuthorityNodeOperator()
|
||||
op.IsOn = isOn
|
||||
op.UniqueId = uniqueId
|
||||
op.Secret = secret
|
||||
op.Name = name
|
||||
op.Description = description
|
||||
op.State = AuthorityNodeStateEnabled
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return types.Int64(op.Id), nil
|
||||
}
|
||||
|
||||
// UpdateAuthorityNode 修改认证节点
|
||||
func (this *AuthorityNodeDAO) UpdateAuthorityNode(tx *dbs.Tx, nodeId int64, name string, description string, isOn bool) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
|
||||
var op = NewAuthorityNodeOperator()
|
||||
op.Id = nodeId
|
||||
op.Name = name
|
||||
op.Description = description
|
||||
op.IsOn = isOn
|
||||
err := this.Save(tx, op)
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledAuthorityNodeWithUniqueId 根据唯一ID获取节点信息
|
||||
func (this *AuthorityNodeDAO) FindEnabledAuthorityNodeWithUniqueId(tx *dbs.Tx, uniqueId string) (*AuthorityNode, error) {
|
||||
result, err := this.Query(tx).
|
||||
Attr("uniqueId", uniqueId).
|
||||
Attr("state", AuthorityNodeStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*AuthorityNode), err
|
||||
}
|
||||
|
||||
// FindEnabledAuthorityNodeIdWithUniqueId 根据唯一ID获取节点ID
|
||||
func (this *AuthorityNodeDAO) FindEnabledAuthorityNodeIdWithUniqueId(tx *dbs.Tx, uniqueId string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("uniqueId", uniqueId).
|
||||
Attr("state", AuthorityNodeStateEnabled).
|
||||
ResultPk().
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// GenUniqueId 生成唯一ID
|
||||
func (this *AuthorityNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
|
||||
for {
|
||||
uniqueId := rands.HexString(32)
|
||||
ok, err := this.Query(tx).
|
||||
Attr("uniqueId", uniqueId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
return uniqueId, nil
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateNodeStatus 更改节点状态
|
||||
func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
|
||||
if nodeStatus == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeStatusJSON, err := json.Marshal(nodeStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("status", nodeStatusJSON).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// CountAllLowerVersionNodes 计算所有节点中低于某个版本的节点数量
|
||||
func (this *AuthorityNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
State(AuthorityNodeStateEnabled).
|
||||
Attr("isOn", true).
|
||||
Where("status IS NOT NULL").
|
||||
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
|
||||
Param("version", utils.VersionToLong(version)).
|
||||
Count()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
38
EdgeAPI/internal/db/models/authority/authority_node_model.go
Normal file
38
EdgeAPI/internal/db/models/authority/authority_node_model.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package authority
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// AuthorityNode 监控节点
|
||||
type AuthorityNode struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
UniqueId string `field:"uniqueId"` // 唯一ID
|
||||
Secret string `field:"secret"` // 密钥
|
||||
Name string `field:"name"` // 名称
|
||||
Description string `field:"description"` // 描述
|
||||
Order uint32 `field:"order"` // 排序
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
Weight uint32 `field:"weight"` // 权重
|
||||
Status dbs.JSON `field:"status"` // 运行状态
|
||||
}
|
||||
|
||||
type AuthorityNodeOperator struct {
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
UniqueId interface{} // 唯一ID
|
||||
Secret interface{} // 密钥
|
||||
Name interface{} // 名称
|
||||
Description interface{} // 描述
|
||||
Order interface{} // 排序
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
AdminId interface{} // 管理员ID
|
||||
Weight interface{} // 权重
|
||||
Status interface{} // 运行状态
|
||||
}
|
||||
|
||||
func NewAuthorityNodeOperator() *AuthorityNodeOperator {
|
||||
return &AuthorityNodeOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package authority
|
||||
Reference in New Issue
Block a user