[API节点]支持HTTP API

This commit is contained in:
刘祥超
2021-01-01 20:49:09 +08:00
parent f905bb7066
commit b4ab1f0ec8
18 changed files with 667 additions and 80 deletions

View File

@@ -0,0 +1,68 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"time"
)
type APIAccessTokenDAO dbs.DAO
func NewAPIAccessTokenDAO() *APIAccessTokenDAO {
return dbs.NewDAO(&APIAccessTokenDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeAPIAccessTokens",
Model: new(APIAccessToken),
PkName: "id",
},
}).(*APIAccessTokenDAO)
}
var SharedAPIAccessTokenDAO *APIAccessTokenDAO
func init() {
dbs.OnReady(func() {
SharedAPIAccessTokenDAO = NewAPIAccessTokenDAO()
})
}
// 生成AccessToken
func (this *APIAccessTokenDAO) GenerateAccessToken(userId int64) (token string, expiresAt int64, err error) {
// 查询以前的
accessToken, err := this.Query().
Attr("userId", userId).
Find()
if err != nil {
return "", 0, err
}
token = rands.String(128) // TODO 增强安全性,将来使用 base64_encode(encrypt(salt+random)) 算法来代替
expiresAt = time.Now().Unix() + 7200
op := NewAPIAccessTokenOperator()
if accessToken != nil {
op.Id = accessToken.(*APIAccessToken).Id
}
op.UserId = userId
op.Token = token
op.CreatedAt = time.Now().Unix()
op.ExpiredAt = expiresAt
err = this.Save(op)
return
}
// 查找AccessToken
func (this *APIAccessTokenDAO) FindAccessToken(token string) (*APIAccessToken, error) {
one, err := this.Query().
Attr("token", token).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*APIAccessToken), nil
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,22 @@
package models
// API访问令牌
type APIAccessToken struct {
Id uint64 `field:"id"` // ID
UserId uint32 `field:"userId"` // 用户ID
Token string `field:"token"` // 令牌
CreatedAt uint64 `field:"createdAt"` // 创建时间
ExpiredAt uint64 `field:"expiredAt"` // 过期时间
}
type APIAccessTokenOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
Token interface{} // 令牌
CreatedAt interface{} // 创建时间
ExpiredAt interface{} // 过期时间
}
func NewAPIAccessTokenOperator() *APIAccessTokenOperator {
return &APIAccessTokenOperator{}
}

View File

@@ -0,0 +1 @@
package models

View File

@@ -90,7 +90,7 @@ func (this *APINodeDAO) FindAPINodeName(id int64) (string, error) {
}
// 创建API节点
func (this *APINodeDAO) CreateAPINode(name string, description string, httpJSON []byte, httpsJSON []byte, accessAddrsJSON []byte, isOn bool) (nodeId int64, err error) {
func (this *APINodeDAO) CreateAPINode(name string, description string, httpJSON []byte, httpsJSON []byte, restIsOn bool, restHTTPJSON []byte, restHTTPSJSON []byte, accessAddrsJSON []byte, isOn bool) (nodeId int64, err error) {
uniqueId, err := this.genUniqueId()
if err != nil {
return 0, err
@@ -114,6 +114,13 @@ func (this *APINodeDAO) CreateAPINode(name string, description string, httpJSON
if len(httpsJSON) > 0 {
op.Https = httpsJSON
}
op.RestIsOn = restIsOn
if len(restHTTPJSON) > 0 {
op.RestHTTP = restHTTPJSON
}
if len(restHTTPSJSON) > 0 {
op.RestHTTPS = restHTTPSJSON
}
if len(accessAddrsJSON) > 0 {
op.AccessAddrs = accessAddrsJSON
}
@@ -128,7 +135,7 @@ func (this *APINodeDAO) CreateAPINode(name string, description string, httpJSON
}
// 修改API节点
func (this *APINodeDAO) UpdateAPINode(nodeId int64, name string, description string, httpJSON []byte, httpsJSON []byte, accessAddrsJSON []byte, isOn bool) error {
func (this *APINodeDAO) UpdateAPINode(nodeId int64, name string, description string, httpJSON []byte, httpsJSON []byte, restIsOn bool, restHTTPJSON []byte, restHTTPSJSON []byte, accessAddrsJSON []byte, isOn bool) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
}
@@ -142,17 +149,28 @@ func (this *APINodeDAO) UpdateAPINode(nodeId int64, name string, description str
if len(httpJSON) > 0 {
op.Http = httpJSON
} else {
op.Http = "null"
op.Http = "{}"
}
if len(httpsJSON) > 0 {
op.Https = httpsJSON
} else {
op.Https = "null"
op.Https = "{}"
}
op.RestIsOn = restIsOn
if len(restHTTPJSON) > 0 {
op.RestHTTP = restHTTPJSON
} else {
op.RestHTTP = "{}"
}
if len(restHTTPSJSON) > 0 {
op.RestHTTPS = restHTTPSJSON
} else {
op.RestHTTPS = "{}"
}
if len(accessAddrsJSON) > 0 {
op.AccessAddrs = accessAddrsJSON
} else {
op.AccessAddrs = "null"
op.AccessAddrs = "[]"
}
err := this.Save(op)

View File

@@ -11,6 +11,9 @@ type APINode struct {
Description string `field:"description"` // 描述
Http string `field:"http"` // 监听的HTTP配置
Https string `field:"https"` // 监听的HTTPS配置
RestIsOn uint8 `field:"restIsOn"` // 是否开放REST
RestHTTP string `field:"restHTTP"` // REST HTTP配置
RestHTTPS string `field:"restHTTPS"` // REST HTTPS配置
AccessAddrs string `field:"accessAddrs"` // 外部访问地址
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
@@ -30,6 +33,9 @@ type APINodeOperator struct {
Description interface{} // 描述
Http interface{} // 监听的HTTP配置
Https interface{} // 监听的HTTPS配置
RestIsOn interface{} // 是否开放REST
RestHTTP interface{} // REST HTTP配置
RestHTTPS interface{} // REST HTTPS配置
AccessAddrs interface{} // 外部访问地址
Order interface{} // 排序
State interface{} // 状态

View File

@@ -93,3 +93,65 @@ func (this *APINode) DecodeAccessAddrStrings() ([]string, error) {
}
return result, nil
}
// 解析Rest HTTP配置
func (this *APINode) DecodeRestHTTP() (*serverconfigs.HTTPProtocolConfig, error) {
if this.RestIsOn != 1 {
return nil, nil
}
if !IsNotNull(this.RestHTTP) {
return nil, nil
}
config := &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal([]byte(this.RestHTTP), config)
if err != nil {
return nil, err
}
err = config.Init()
if err != nil {
return nil, err
}
return config, nil
}
// 解析HTTPS配置
func (this *APINode) DecodeRestHTTPS() (*serverconfigs.HTTPSProtocolConfig, error) {
if this.RestIsOn != 1 {
return nil, nil
}
if !IsNotNull(this.RestHTTPS) {
return nil, nil
}
config := &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal([]byte(this.RestHTTPS), config)
if err != nil {
return nil, err
}
err = config.Init()
if err != nil {
return nil, err
}
if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(policyId)
if err != nil {
return nil, err
}
if sslPolicy != nil {
config.SSLPolicy = sslPolicy
}
}
}
err = config.Init()
if err != nil {
return nil, err
}
return config, nil
}

View File

@@ -2,11 +2,13 @@ package models
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
timeutil "github.com/iwind/TeaGo/utils/time"
"hash/crc32"
"regexp"
"strconv"
"strings"
"sync"
@@ -46,17 +48,22 @@ func randomAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) {
}
// 检查表格是否存在
func findAccessLogTableName(db *dbs.DB, day string) (string, bool, error) {
func findAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool, err error) {
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
err = errors.New("invalid day '" + day + "', should be YYYYMMDD")
return
}
config, err := db.Config()
if err != nil {
return "", false, err
}
tableName := "edgeHTTPAccessLogs_" + day
tableName = "edgeHTTPAccessLogs_" + day
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
accessLogLocker.RLock()
_, ok := accessLogTableMapping[cacheKey]
_, ok = accessLogTableMapping[cacheKey]
accessLogLocker.RUnlock()
if ok {
return tableName, true, nil

View File

@@ -168,6 +168,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(lastRequestId string, size int64, d
dao := daoWrapper.DAO
tableName, exists, err := findAccessLogTableName(dao.Instance, day)
logs.Println("tableName:", tableName, exists, err) // TODO
if !exists {
// 表格不存在则跳过
return

View File

@@ -109,3 +109,17 @@ func (this *UserAccessKeyDAO) UpdateAccessKeyIsOn(accessKeyId int64, isOn bool)
Update()
return err
}
// 根据UniqueId查找AccessKey
func (this *UserAccessKeyDAO) FindAccessKeyWithUniqueId(uniqueId string) (*UserAccessKey, error) {
one, err := this.Query().
Attr("uniqueId", uniqueId).
Attr("isOn", true).
State(UserAccessKeyStateEnabled).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*UserAccessKey), nil
}