mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2026-05-22 03:15:17 +08:00
[API节点]支持HTTP API
This commit is contained in:
68
internal/db/models/api_access_token_dao.go
Normal file
68
internal/db/models/api_access_token_dao.go
Normal 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
|
||||
}
|
||||
5
internal/db/models/api_access_token_dao_test.go
Normal file
5
internal/db/models/api_access_token_dao_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
22
internal/db/models/api_access_token_model.go
Normal file
22
internal/db/models/api_access_token_model.go
Normal 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{}
|
||||
}
|
||||
1
internal/db/models/api_access_token_model_ext.go
Normal file
1
internal/db/models/api_access_token_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -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)
|
||||
|
||||
@@ -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{} // 状态
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user