Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6143f08cf2 | ||
|
|
73a5814fd6 | ||
|
|
448152d5c2 | ||
|
|
eedb3fb338 | ||
|
|
06f6f68f3a | ||
|
|
903e524e80 | ||
|
|
fa6b4fcaee | ||
|
|
67cc8e515f | ||
|
|
fa29817920 | ||
|
|
794c3bc132 | ||
|
|
9e481d31ac | ||
|
|
4ebc03af75 | ||
|
|
80e2face67 | ||
|
|
815a5187d5 | ||
|
|
1d7bc42fba | ||
|
|
1eb9cca793 | ||
|
|
8766f5b1a9 | ||
|
|
823e42626d | ||
|
|
c5308cf41c | ||
|
|
3053157c6e | ||
|
|
d1ba141c65 | ||
|
|
034ababead | ||
|
|
f5450e37be | ||
|
|
549fca93e6 | ||
|
|
efa0f33256 | ||
|
|
977a12843c | ||
|
|
6de2834a8c | ||
|
|
51f91e1603 | ||
|
|
d27b7c8fa1 | ||
|
|
c5098c66af | ||
|
|
c2635b0d04 | ||
|
|
41a1a6a2e5 | ||
|
|
e437117e69 | ||
|
|
fdc8f78229 | ||
|
|
2f78d76a1a | ||
|
|
742f2f0216 | ||
|
|
89a606329f | ||
|
|
3bba79d14c | ||
|
|
9f9787e30f | ||
|
|
529016d4d5 | ||
|
|
63942bfb08 | ||
|
|
f4e4f32f9c | ||
|
|
0a3c740502 | ||
|
|
9a3438e066 | ||
|
|
814b82e1b6 | ||
|
|
89cfd175cd | ||
|
|
860816719e | ||
|
|
caa936f0ac | ||
|
|
97836a89eb |
75
.golangci.yaml
Normal file
75
.golangci.yaml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# https://golangci-lint.run/usage/configuration/
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- ifshort
|
||||||
|
- exhaustivestruct
|
||||||
|
- golint
|
||||||
|
- nosnakecase
|
||||||
|
- scopelint
|
||||||
|
- varcheck
|
||||||
|
- structcheck
|
||||||
|
- interfacer
|
||||||
|
- maligned
|
||||||
|
- deadcode
|
||||||
|
- dogsled
|
||||||
|
- wrapcheck
|
||||||
|
- wastedassign
|
||||||
|
- varnamelen
|
||||||
|
- testpackage
|
||||||
|
- thelper
|
||||||
|
- nilerr
|
||||||
|
- sqlclosecheck
|
||||||
|
- paralleltest
|
||||||
|
- nonamedreturns
|
||||||
|
- nlreturn
|
||||||
|
- nakedret
|
||||||
|
- ireturn
|
||||||
|
- interfacebloat
|
||||||
|
- gosmopolitan
|
||||||
|
- gomnd
|
||||||
|
- goerr113
|
||||||
|
- gochecknoglobals
|
||||||
|
- exhaustruct
|
||||||
|
- errorlint
|
||||||
|
- depguard
|
||||||
|
- exhaustive
|
||||||
|
- containedctx
|
||||||
|
- wsl
|
||||||
|
- cyclop
|
||||||
|
- dupword
|
||||||
|
- errchkjson
|
||||||
|
- contextcheck
|
||||||
|
- tagalign
|
||||||
|
- dupl
|
||||||
|
- forbidigo
|
||||||
|
- funlen
|
||||||
|
- goconst
|
||||||
|
- godox
|
||||||
|
- gosec
|
||||||
|
- lll
|
||||||
|
- nestif
|
||||||
|
- revive
|
||||||
|
- unparam
|
||||||
|
- stylecheck
|
||||||
|
- gocritic
|
||||||
|
- gofumpt
|
||||||
|
- gomoddirectives
|
||||||
|
- godot
|
||||||
|
- gofmt
|
||||||
|
- gocognit
|
||||||
|
- mirror
|
||||||
|
- gocyclo
|
||||||
|
- gochecknoinits
|
||||||
|
- gci
|
||||||
|
- maintidx
|
||||||
|
- prealloc
|
||||||
|
- goimports
|
||||||
|
- errname
|
||||||
|
- musttag
|
||||||
|
- forcetypeassert
|
||||||
|
- whitespace
|
||||||
|
- noctx
|
||||||
|
- tagliatelle
|
||||||
|
- nilnil
|
||||||
@@ -12,5 +12,5 @@ dbs:
|
|||||||
|
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled" ]
|
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled", "enableHTTP2", "retry50X" ]
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,9 @@ func TestGenerate_EAB(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
myUser.Registration = reg
|
myUser.Registration = reg
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
request := certificate.ObtainRequest{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
@@ -45,7 +46,7 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||||||
if !wasDeleted {
|
if !wasDeleted {
|
||||||
records, err := this.raw.QueryRecords(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
|
records, err := this.raw.QueryRecords(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query DNS record failed: " + err.Error())
|
return fmt.Errorf("query DNS record failed: %w", err)
|
||||||
}
|
}
|
||||||
for _, record := range records {
|
for _, record := range records {
|
||||||
err = this.raw.DeleteRecord(this.dnsDomain, record)
|
err = this.raw.DeleteRecord(this.dnsDomain, record)
|
||||||
@@ -67,7 +68,7 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||||||
Route: this.raw.DefaultRoute(),
|
Route: this.raw.DefaultRoute(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create DNS record failed: " + err.Error())
|
return fmt.Errorf("create DNS record failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
@@ -92,26 +93,26 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
|
|||||||
// 注册用户
|
// 注册用户
|
||||||
var resource = this.task.User.GetRegistration()
|
var resource = this.task.User.GetRegistration()
|
||||||
if resource != nil {
|
if resource != nil {
|
||||||
resource, err = client.Registration.QueryRegistration()
|
_, err = client.Registration.QueryRegistration()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if this.task.Provider.RequireEAB {
|
if this.task.Provider.RequireEAB {
|
||||||
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
TermsOfServiceAgreed: true,
|
TermsOfServiceAgreed: true,
|
||||||
Kid: this.task.Account.EABKid,
|
Kid: this.task.Account.EABKid,
|
||||||
HmacEncoded: this.task.Account.EABKey,
|
HmacEncoded: this.task.Account.EABKey,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.New("register user failed: " + err.Error())
|
return nil, nil, fmt.Errorf("register user failed: %w", err)
|
||||||
}
|
}
|
||||||
err = this.task.User.Register(resource)
|
err = this.task.User.Register(resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -134,7 +135,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
|
|||||||
}
|
}
|
||||||
certResource, err := client.Certificate.Obtain(request)
|
certResource, err := client.Certificate.Obtain(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.New("obtain cert failed: " + err.Error())
|
return nil, nil, fmt.Errorf("obtain cert failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return certResource.Certificate, certResource.PrivateKey, nil
|
return certResource.Certificate, certResource.PrivateKey, nil
|
||||||
@@ -165,26 +166,26 @@ func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
|
|||||||
// 注册用户
|
// 注册用户
|
||||||
var resource = this.task.User.GetRegistration()
|
var resource = this.task.User.GetRegistration()
|
||||||
if resource != nil {
|
if resource != nil {
|
||||||
resource, err = client.Registration.QueryRegistration()
|
_, err = client.Registration.QueryRegistration()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if this.task.Provider.RequireEAB {
|
if this.task.Provider.RequireEAB {
|
||||||
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
TermsOfServiceAgreed: true,
|
TermsOfServiceAgreed: true,
|
||||||
Kid: this.task.Account.EABKid,
|
Kid: this.task.Account.EABKid,
|
||||||
HmacEncoded: this.task.Account.EABKey,
|
HmacEncoded: this.task.Account.EABKey,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.New("register user failed: " + err.Error())
|
return nil, nil, fmt.Errorf("register user failed: %w", err)
|
||||||
}
|
}
|
||||||
err = this.task.User.Register(resource)
|
err = this.task.User.Register(resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package apps
|
package apps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
@@ -9,8 +10,10 @@ import (
|
|||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -184,13 +187,16 @@ func (this *AppCmd) runStart() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(os.Args[0])
|
var cmd = exec.Command(this.exe())
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(this.product+" start failed:", err.Error())
|
fmt.Println(this.product+" start failed:", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create symbolic links
|
||||||
|
_ = this.createSymLinks()
|
||||||
|
|
||||||
fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid)
|
fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,3 +243,58 @@ func (this *AppCmd) getPID() int {
|
|||||||
}
|
}
|
||||||
return maps.NewMap(reply.Params).GetInt("pid")
|
return maps.NewMap(reply.Params).GetInt("pid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *AppCmd) exe() string {
|
||||||
|
var exe, _ = os.Executable()
|
||||||
|
if len(exe) == 0 {
|
||||||
|
exe = os.Args[0]
|
||||||
|
}
|
||||||
|
return exe
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建软链接
|
||||||
|
func (this *AppCmd) createSymLinks() error {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var exe, _ = os.Executable()
|
||||||
|
if len(exe) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorList = []string{}
|
||||||
|
|
||||||
|
// bin
|
||||||
|
{
|
||||||
|
var target = "/usr/bin/" + teaconst.ProcessName
|
||||||
|
old, _ := filepath.EvalSymlinks(target)
|
||||||
|
if old != exe {
|
||||||
|
_ = os.Remove(target)
|
||||||
|
err := os.Symlink(exe, target)
|
||||||
|
if err != nil {
|
||||||
|
errorList = append(errorList, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// log
|
||||||
|
{
|
||||||
|
var realPath = filepath.Dir(filepath.Dir(exe)) + "/logs/run.log"
|
||||||
|
var target = "/var/log/" + teaconst.ProcessName + ".log"
|
||||||
|
old, _ := filepath.EvalSymlinks(target)
|
||||||
|
if old != realPath {
|
||||||
|
_ = os.Remove(target)
|
||||||
|
err := os.Symlink(realPath, target)
|
||||||
|
if err != nil {
|
||||||
|
errorList = append(errorList, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errorList) > 0 {
|
||||||
|
return errors.New(strings.Join(errorList, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "1.2.2"
|
Version = "1.2.9"
|
||||||
|
|
||||||
ProductName = "Edge API"
|
ProductName = "Edge API"
|
||||||
ProcessName = "edge-api"
|
ProcessName = "edge-api"
|
||||||
@@ -18,7 +18,7 @@ const (
|
|||||||
|
|
||||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||||
|
|
||||||
NodeVersion = "1.2.2"
|
NodeVersion = "1.2.9"
|
||||||
|
|
||||||
// SQLVersion SQL版本号
|
// SQLVersion SQL版本号
|
||||||
SQLVersion = "11"
|
SQLVersion = "11"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package acme
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
acmeutils "github.com/TeaOSLab/EdgeAPI/internal/acme"
|
acmeutils "github.com/TeaOSLab/EdgeAPI/internal/acme"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
@@ -434,7 +435,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
|
|||||||
CertData: certData,
|
CertData: certData,
|
||||||
KeyData: keyData,
|
KeyData: keyData,
|
||||||
}
|
}
|
||||||
err = sslConfig.Init(nil)
|
err = sslConfig.Init(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error()
|
errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
@@ -37,7 +38,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -153,7 +154,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,11 +61,12 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
|
|||||||
"error": "",
|
"error": "",
|
||||||
"version": time.Now().UnixNano(),
|
"version": time.Now().UnixNano(),
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"updatedAt": time.Now().Unix(),
|
"updatedAt": time.Now().Unix(),
|
||||||
"isDone": false,
|
"isDone": false,
|
||||||
"isOk": false,
|
"isOk": false,
|
||||||
"error": "",
|
"error": "",
|
||||||
"version": time.Now().UnixNano(),
|
"version": time.Now().UnixNano(),
|
||||||
|
"countFails": 0,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -108,7 +109,7 @@ func (this *DNSTaskDAO) CreateDomainTask(tx *dbs.Tx, domainId int64, taskType DN
|
|||||||
// FindAllDoingTasks 查找所有正在执行的任务
|
// FindAllDoingTasks 查找所有正在执行的任务
|
||||||
func (this *DNSTaskDAO) FindAllDoingTasks(tx *dbs.Tx) (result []*DNSTask, err error) {
|
func (this *DNSTaskDAO) FindAllDoingTasks(tx *dbs.Tx) (result []*DNSTask, err error) {
|
||||||
_, err = this.Query(tx).
|
_, err = this.Query(tx).
|
||||||
Attr("isDone", 0).
|
Where("(isDone=0 OR (isDone=1 AND isOk=0 AND countFails<3))"). // 3 = retry times
|
||||||
Asc("version").
|
Asc("version").
|
||||||
AscPk().
|
AscPk().
|
||||||
Slice(&result).
|
Slice(&result).
|
||||||
@@ -171,6 +172,7 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
|
|||||||
op.IsDone = true
|
op.IsDone = true
|
||||||
op.Error = err
|
op.Error = err
|
||||||
op.IsOk = false
|
op.IsOk = false
|
||||||
|
op.CountFails = dbs.SQL("countFails+1")
|
||||||
return this.Save(tx, op)
|
return this.Save(tx, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +199,7 @@ func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64, taskVersion
|
|||||||
op.Id = taskId
|
op.Id = taskId
|
||||||
op.IsDone = true
|
op.IsDone = true
|
||||||
op.IsOk = true
|
op.IsOk = true
|
||||||
|
op.CountFails = 0
|
||||||
op.Error = ""
|
op.Error = ""
|
||||||
return this.Save(tx, op)
|
return this.Save(tx, op)
|
||||||
}
|
}
|
||||||
@@ -219,6 +222,7 @@ func (this *DNSTaskDAO) UpdateClusterDNSTasksDone(tx *dbs.Tx, clusterId int64, m
|
|||||||
Set("isDone", true).
|
Set("isDone", true).
|
||||||
Set("isOk", true).
|
Set("isOk", true).
|
||||||
Set("error", "").
|
Set("error", "").
|
||||||
|
Set("countFails", 0).
|
||||||
UpdateQuickly()
|
UpdateQuickly()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
DNSTaskField_Id dbs.FieldName = "id" // ID
|
||||||
|
DNSTaskField_ClusterId dbs.FieldName = "clusterId" // 集群ID
|
||||||
|
DNSTaskField_ServerId dbs.FieldName = "serverId" // 服务ID
|
||||||
|
DNSTaskField_NodeId dbs.FieldName = "nodeId" // 节点ID
|
||||||
|
DNSTaskField_DomainId dbs.FieldName = "domainId" // 域名ID
|
||||||
|
DNSTaskField_RecordName dbs.FieldName = "recordName" // 记录名
|
||||||
|
DNSTaskField_Type dbs.FieldName = "type" // 任务类型
|
||||||
|
DNSTaskField_UpdatedAt dbs.FieldName = "updatedAt" // 更新时间
|
||||||
|
DNSTaskField_IsDone dbs.FieldName = "isDone" // 是否已完成
|
||||||
|
DNSTaskField_IsOk dbs.FieldName = "isOk" // 是否成功
|
||||||
|
DNSTaskField_Error dbs.FieldName = "error" // 错误信息
|
||||||
|
DNSTaskField_Version dbs.FieldName = "version" // 版本
|
||||||
|
DNSTaskField_CountFails dbs.FieldName = "countFails" // 尝试失败次数
|
||||||
|
)
|
||||||
|
|
||||||
// DNSTask DNS更新任务
|
// DNSTask DNS更新任务
|
||||||
type DNSTask struct {
|
type DNSTask struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
@@ -14,6 +32,7 @@ type DNSTask struct {
|
|||||||
IsOk bool `field:"isOk"` // 是否成功
|
IsOk bool `field:"isOk"` // 是否成功
|
||||||
Error string `field:"error"` // 错误信息
|
Error string `field:"error"` // 错误信息
|
||||||
Version uint64 `field:"version"` // 版本
|
Version uint64 `field:"version"` // 版本
|
||||||
|
CountFails uint32 `field:"countFails"` // 尝试失败次数
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSTaskOperator struct {
|
type DNSTaskOperator struct {
|
||||||
@@ -29,6 +48,7 @@ type DNSTaskOperator struct {
|
|||||||
IsOk any // 是否成功
|
IsOk any // 是否成功
|
||||||
Error any // 错误信息
|
Error any // 错误信息
|
||||||
Version any // 版本
|
Version any // 版本
|
||||||
|
CountFails any // 尝试失败次数
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDNSTaskOperator() *DNSTaskOperator {
|
func NewDNSTaskOperator() *DNSTaskOperator {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package dnsutils
|
package dnsutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||||
@@ -217,7 +218,7 @@ func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) {
|
|||||||
}
|
}
|
||||||
paramsMap, err := provider.DecodeAPIParams()
|
paramsMap, err := provider.DecodeAPIParams()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("decode provider params failed: " + err.Error())
|
return "", fmt.Errorf("decode provider params failed: %w", err)
|
||||||
}
|
}
|
||||||
var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
|
||||||
if dnsProvider == nil {
|
if dnsProvider == nil {
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ Loop:
|
|||||||
|
|
||||||
// CreateHTTPAccessLog 写入单条访问日志
|
// CreateHTTPAccessLog 写入单条访问日志
|
||||||
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
|
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
|
||||||
var day = ""
|
var day string
|
||||||
// 注意:如果你修改了 TimeISO8601 的逻辑,这里也需要同步修改
|
// 注意:如果你修改了 TimeISO8601 的逻辑,这里也需要同步修改
|
||||||
if len(accessLog.TimeISO8601) > 10 {
|
if len(accessLog.TimeISO8601) > 10 {
|
||||||
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
|
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func (this *HTTPAccessLogManager) FindTableNames(db *dbs.DB, day string) ([]stri
|
|||||||
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
||||||
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("query table names error: " + err.Error())
|
return nil, fmt.Errorf("query table names error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var columnName = columnNames[0]
|
var columnName = columnNames[0]
|
||||||
@@ -88,7 +88,7 @@ func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAcc
|
|||||||
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
||||||
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("query table names error: " + err.Error())
|
return nil, fmt.Errorf("query table names error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var columnName = columnNames[0]
|
var columnName = columnNames[0]
|
||||||
@@ -373,7 +373,7 @@ func (this *HTTPAccessLogManager) findTableWithoutCache(db *dbs.DB, day string,
|
|||||||
var lastInt64Id = types.Int64(lastId)
|
var lastInt64Id = types.Int64(lastId)
|
||||||
if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable {
|
if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable {
|
||||||
// create next partial table
|
// create next partial table
|
||||||
var nextTableName = ""
|
var nextTableName string
|
||||||
if accessLogTableMainReg.MatchString(lastTableName) {
|
if accessLogTableMainReg.MatchString(lastTableName) {
|
||||||
nextTableName = prefix + "_0001"
|
nextTableName = prefix + "_0001"
|
||||||
} else if accessLogTablePartialReg.MatchString(lastTableName) {
|
} else if accessLogTablePartialReg.MatchString(lastTableName) {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateCachePolicy 创建缓存策略
|
// CreateCachePolicy 创建缓存策略
|
||||||
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
|
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool, fetchTimeoutJSON []byte) (int64, error) {
|
||||||
var op = NewHTTPCachePolicyOperator()
|
var op = NewHTTPCachePolicyOperator()
|
||||||
op.State = HTTPCachePolicyStateEnabled
|
op.State = HTTPCachePolicyStateEnabled
|
||||||
op.IsOn = isOn
|
op.IsOn = isOn
|
||||||
@@ -114,6 +114,10 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
|
|||||||
}
|
}
|
||||||
op.SyncCompressionCache = syncCompressionCache
|
op.SyncCompressionCache = syncCompressionCache
|
||||||
|
|
||||||
|
if len(fetchTimeoutJSON) > 0 {
|
||||||
|
op.FetchTimeout = fetchTimeoutJSON
|
||||||
|
}
|
||||||
|
|
||||||
// 默认的缓存条件
|
// 默认的缓存条件
|
||||||
cacheRef := &serverconfigs.HTTPCacheRef{
|
cacheRef := &serverconfigs.HTTPCacheRef{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
@@ -183,7 +187,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
|
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -191,7 +195,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCachePolicy 修改缓存策略
|
// UpdateCachePolicy 修改缓存策略
|
||||||
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error {
|
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool, fetchTimeoutJSON []byte) error {
|
||||||
if policyId <= 0 {
|
if policyId <= 0 {
|
||||||
return errors.New("invalid policyId")
|
return errors.New("invalid policyId")
|
||||||
}
|
}
|
||||||
@@ -212,6 +216,9 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
|
|||||||
op.Options = storageOptionsJSON
|
op.Options = storageOptionsJSON
|
||||||
}
|
}
|
||||||
op.SyncCompressionCache = syncCompressionCache
|
op.SyncCompressionCache = syncCompressionCache
|
||||||
|
if len(fetchTimeoutJSON) > 0 {
|
||||||
|
op.FetchTimeout = fetchTimeoutJSON
|
||||||
|
}
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -237,7 +244,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
if policy == nil {
|
if policy == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
config := &serverconfigs.HTTPCachePolicy{}
|
var config = &serverconfigs.HTTPCachePolicy{}
|
||||||
config.Id = int64(policy.Id)
|
config.Id = int64(policy.Id)
|
||||||
config.IsOn = policy.IsOn
|
config.IsOn = policy.IsOn
|
||||||
config.Name = policy.Name
|
config.Name = policy.Name
|
||||||
@@ -246,7 +253,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
|
|
||||||
// capacity
|
// capacity
|
||||||
if IsNotNull(policy.Capacity) {
|
if IsNotNull(policy.Capacity) {
|
||||||
capacityConfig := &shared.SizeCapacity{}
|
var capacityConfig = &shared.SizeCapacity{}
|
||||||
err = json.Unmarshal(policy.Capacity, capacityConfig)
|
err = json.Unmarshal(policy.Capacity, capacityConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -256,7 +263,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
|
|
||||||
// max size
|
// max size
|
||||||
if IsNotNull(policy.MaxSize) {
|
if IsNotNull(policy.MaxSize) {
|
||||||
maxSizeConfig := &shared.SizeCapacity{}
|
var maxSizeConfig = &shared.SizeCapacity{}
|
||||||
err = json.Unmarshal(policy.MaxSize, maxSizeConfig)
|
err = json.Unmarshal(policy.MaxSize, maxSizeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -268,7 +275,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
|
|
||||||
// options
|
// options
|
||||||
if IsNotNull(policy.Options) {
|
if IsNotNull(policy.Options) {
|
||||||
m := map[string]interface{}{}
|
var m = map[string]any{}
|
||||||
err = json.Unmarshal(policy.Options, &m)
|
err = json.Unmarshal(policy.Options, &m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err)
|
return nil, errors.Wrap(err)
|
||||||
@@ -278,7 +285,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
|
|
||||||
// refs
|
// refs
|
||||||
if IsNotNull(policy.Refs) {
|
if IsNotNull(policy.Refs) {
|
||||||
refs := []*serverconfigs.HTTPCacheRef{}
|
var refs = []*serverconfigs.HTTPCacheRef{}
|
||||||
err = json.Unmarshal(policy.Refs, &refs)
|
err = json.Unmarshal(policy.Refs, &refs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -286,6 +293,16 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
|||||||
config.CacheRefs = refs
|
config.CacheRefs = refs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetch timeout
|
||||||
|
if IsNotNull(policy.FetchTimeout) {
|
||||||
|
var timeoutDuration = &shared.TimeDuration{}
|
||||||
|
err = json.Unmarshal(policy.FetchTimeout, timeoutDuration)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.FetchTimeout = timeoutDuration
|
||||||
|
}
|
||||||
|
|
||||||
if cacheMap != nil {
|
if cacheMap != nil {
|
||||||
cacheMap.Put(cacheKey, config)
|
cacheMap.Put(cacheKey, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,26 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
HTTPCachePolicyField_Id dbs.FieldName = "id" // ID
|
||||||
|
HTTPCachePolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
|
||||||
|
HTTPCachePolicyField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
HTTPCachePolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
|
||||||
|
HTTPCachePolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
HTTPCachePolicyField_Name dbs.FieldName = "name" // 名称
|
||||||
|
HTTPCachePolicyField_Capacity dbs.FieldName = "capacity" // 容量数据
|
||||||
|
HTTPCachePolicyField_MaxKeys dbs.FieldName = "maxKeys" // 最多Key值
|
||||||
|
HTTPCachePolicyField_MaxSize dbs.FieldName = "maxSize" // 最大缓存内容尺寸
|
||||||
|
HTTPCachePolicyField_Type dbs.FieldName = "type" // 存储类型
|
||||||
|
HTTPCachePolicyField_Options dbs.FieldName = "options" // 存储选项
|
||||||
|
HTTPCachePolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
HTTPCachePolicyField_State dbs.FieldName = "state" // 状态
|
||||||
|
HTTPCachePolicyField_Description dbs.FieldName = "description" // 描述
|
||||||
|
HTTPCachePolicyField_Refs dbs.FieldName = "refs" // 默认的缓存设置
|
||||||
|
HTTPCachePolicyField_SyncCompressionCache dbs.FieldName = "syncCompressionCache" // 是否同步写入压缩缓存
|
||||||
|
HTTPCachePolicyField_FetchTimeout dbs.FieldName = "fetchTimeout" // 预热超时时间
|
||||||
|
)
|
||||||
|
|
||||||
// HTTPCachePolicy HTTP缓存策略
|
// HTTPCachePolicy HTTP缓存策略
|
||||||
type HTTPCachePolicy struct {
|
type HTTPCachePolicy struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
@@ -20,25 +40,27 @@ type HTTPCachePolicy struct {
|
|||||||
Description string `field:"description"` // 描述
|
Description string `field:"description"` // 描述
|
||||||
Refs dbs.JSON `field:"refs"` // 默认的缓存设置
|
Refs dbs.JSON `field:"refs"` // 默认的缓存设置
|
||||||
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
|
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
|
||||||
|
FetchTimeout dbs.JSON `field:"fetchTimeout"` // 预热超时时间
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPCachePolicyOperator struct {
|
type HTTPCachePolicyOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId any // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId any // 用户ID
|
||||||
TemplateId interface{} // 模版ID
|
TemplateId any // 模版ID
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
Name interface{} // 名称
|
Name any // 名称
|
||||||
Capacity interface{} // 容量数据
|
Capacity any // 容量数据
|
||||||
MaxKeys interface{} // 最多Key值
|
MaxKeys any // 最多Key值
|
||||||
MaxSize interface{} // 最大缓存内容尺寸
|
MaxSize any // 最大缓存内容尺寸
|
||||||
Type interface{} // 存储类型
|
Type any // 存储类型
|
||||||
Options interface{} // 存储选项
|
Options any // 存储选项
|
||||||
CreatedAt interface{} // 创建时间
|
CreatedAt any // 创建时间
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
Description interface{} // 描述
|
Description any // 描述
|
||||||
Refs interface{} // 默认的缓存设置
|
Refs any // 默认的缓存设置
|
||||||
SyncCompressionCache interface{} // 是否同步写入压缩缓存
|
SyncCompressionCache any // 是否同步写入压缩缓存
|
||||||
|
FetchTimeout any // 预热超时时间
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {
|
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {
|
||||||
|
|||||||
@@ -172,16 +172,18 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
|
|||||||
// 初始化
|
// 初始化
|
||||||
var groupCodes = []string{}
|
var groupCodes = []string{}
|
||||||
|
|
||||||
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
|
var templatePolicy = firewallconfigs.HTTPFirewallTemplate()
|
||||||
for _, group := range templatePolicy.AllRuleGroups() {
|
for _, group := range templatePolicy.AllRuleGroups() {
|
||||||
groupCodes = append(groupCodes, group.Code)
|
if group.IsOn {
|
||||||
|
groupCodes = append(groupCodes, group.Code)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||||
var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
|
var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
|
||||||
if templatePolicy.Inbound != nil {
|
if templatePolicy.Inbound != nil {
|
||||||
for _, group := range templatePolicy.Inbound.Groups {
|
for _, group := range templatePolicy.Inbound.Groups {
|
||||||
isOn := lists.ContainsString(groupCodes, group.Code)
|
var isOn = lists.ContainsString(groupCodes, group.Code)
|
||||||
group.IsOn = isOn
|
group.IsOn = isOn
|
||||||
|
|
||||||
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
|
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
|
||||||
@@ -196,7 +198,7 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
|
|||||||
}
|
}
|
||||||
if templatePolicy.Outbound != nil {
|
if templatePolicy.Outbound != nil {
|
||||||
for _, group := range templatePolicy.Outbound.Groups {
|
for _, group := range templatePolicy.Outbound.Groups {
|
||||||
isOn := lists.ContainsString(groupCodes, group.Code)
|
var isOn = lists.ContainsString(groupCodes, group.Code)
|
||||||
group.IsOn = isOn
|
group.IsOn = isOn
|
||||||
|
|
||||||
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
|
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
|
||||||
@@ -290,7 +292,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
|
|||||||
mode firewallconfigs.FirewallMode,
|
mode firewallconfigs.FirewallMode,
|
||||||
useLocalFirewall bool,
|
useLocalFirewall bool,
|
||||||
synFloodConfig *firewallconfigs.SYNFloodConfig,
|
synFloodConfig *firewallconfigs.SYNFloodConfig,
|
||||||
logConfig *firewallconfigs.HTTPFirewallPolicyLogConfig) error {
|
logConfig *firewallconfigs.HTTPFirewallPolicyLogConfig,
|
||||||
|
maxRequestBodySize int64,
|
||||||
|
denyCountryHTML string,
|
||||||
|
denyProvinceHTML string) error {
|
||||||
if policyId <= 0 {
|
if policyId <= 0 {
|
||||||
return errors.New("invalid policyId")
|
return errors.New("invalid policyId")
|
||||||
}
|
}
|
||||||
@@ -338,6 +343,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
op.UseLocalFirewall = useLocalFirewall
|
op.UseLocalFirewall = useLocalFirewall
|
||||||
|
op.MaxRequestBodySize = maxRequestBodySize
|
||||||
|
op.DenyCountryHTML = denyCountryHTML
|
||||||
|
op.DenyProvinceHTML = denyProvinceHTML
|
||||||
|
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -390,7 +399,7 @@ func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, clust
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ComposeFirewallPolicy 组合策略配置
|
// ComposeFirewallPolicy 组合策略配置
|
||||||
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*firewallconfigs.HTTPFirewallPolicy, error) {
|
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64, forNode bool, cacheMap *utils.CacheMap) (*firewallconfigs.HTTPFirewallPolicy, error) {
|
||||||
if cacheMap == nil {
|
if cacheMap == nil {
|
||||||
cacheMap = utils.NewCacheMap()
|
cacheMap = utils.NewCacheMap()
|
||||||
}
|
}
|
||||||
@@ -414,6 +423,9 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
|||||||
config.Name = policy.Name
|
config.Name = policy.Name
|
||||||
config.Description = policy.Description
|
config.Description = policy.Description
|
||||||
config.UseLocalFirewall = policy.UseLocalFirewall == 1
|
config.UseLocalFirewall = policy.UseLocalFirewall == 1
|
||||||
|
config.MaxRequestBodySize = int64(policy.MaxRequestBodySize)
|
||||||
|
config.DenyCountryHTML = policy.DenyCountryHTML
|
||||||
|
config.DenyProvinceHTML = policy.DenyProvinceHTML
|
||||||
|
|
||||||
if len(policy.Mode) == 0 {
|
if len(policy.Mode) == 0 {
|
||||||
policy.Mode = firewallconfigs.FirewallModeDefend
|
policy.Mode = firewallconfigs.FirewallModeDefend
|
||||||
@@ -421,18 +433,18 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
|||||||
config.Mode = policy.Mode
|
config.Mode = policy.Mode
|
||||||
|
|
||||||
// Inbound
|
// Inbound
|
||||||
inbound := &firewallconfigs.HTTPFirewallInboundConfig{}
|
var inbound = &firewallconfigs.HTTPFirewallInboundConfig{}
|
||||||
if IsNotNull(policy.Inbound) {
|
if IsNotNull(policy.Inbound) {
|
||||||
err = json.Unmarshal(policy.Inbound, inbound)
|
err = json.Unmarshal(policy.Inbound, inbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(inbound.GroupRefs) > 0 {
|
if len(inbound.GroupRefs) > 0 {
|
||||||
resultGroupRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
|
var resultGroupRefs = []*firewallconfigs.HTTPFirewallRuleGroupRef{}
|
||||||
resultGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
var resultGroups = []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||||
|
|
||||||
for _, groupRef := range inbound.GroupRefs {
|
for _, groupRef := range inbound.GroupRefs {
|
||||||
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId)
|
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId, forNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -449,18 +461,18 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
|||||||
config.Inbound = inbound
|
config.Inbound = inbound
|
||||||
|
|
||||||
// Outbound
|
// Outbound
|
||||||
outbound := &firewallconfigs.HTTPFirewallOutboundConfig{}
|
var outbound = &firewallconfigs.HTTPFirewallOutboundConfig{}
|
||||||
if IsNotNull(policy.Outbound) {
|
if IsNotNull(policy.Outbound) {
|
||||||
err = json.Unmarshal(policy.Outbound, outbound)
|
err = json.Unmarshal(policy.Outbound, outbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(outbound.GroupRefs) > 0 {
|
if len(outbound.GroupRefs) > 0 {
|
||||||
resultGroupRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
|
var resultGroupRefs = []*firewallconfigs.HTTPFirewallRuleGroupRef{}
|
||||||
resultGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
|
var resultGroups = []*firewallconfigs.HTTPFirewallRuleGroup{}
|
||||||
|
|
||||||
for _, groupRef := range outbound.GroupRefs {
|
for _, groupRef := range outbound.GroupRefs {
|
||||||
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId)
|
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId, forNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,49 +2,80 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
HTTPFirewallPolicyField_Id dbs.FieldName = "id" // ID
|
||||||
|
HTTPFirewallPolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
|
||||||
|
HTTPFirewallPolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
|
||||||
|
HTTPFirewallPolicyField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
HTTPFirewallPolicyField_ServerId dbs.FieldName = "serverId" // 服务ID
|
||||||
|
HTTPFirewallPolicyField_GroupId dbs.FieldName = "groupId" // 服务分组ID
|
||||||
|
HTTPFirewallPolicyField_State dbs.FieldName = "state" // 状态
|
||||||
|
HTTPFirewallPolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
HTTPFirewallPolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
HTTPFirewallPolicyField_Name dbs.FieldName = "name" // 名称
|
||||||
|
HTTPFirewallPolicyField_Description dbs.FieldName = "description" // 描述
|
||||||
|
HTTPFirewallPolicyField_Inbound dbs.FieldName = "inbound" // 入站规则
|
||||||
|
HTTPFirewallPolicyField_Outbound dbs.FieldName = "outbound" // 出站规则
|
||||||
|
HTTPFirewallPolicyField_BlockOptions dbs.FieldName = "blockOptions" // BLOCK选项
|
||||||
|
HTTPFirewallPolicyField_CaptchaOptions dbs.FieldName = "captchaOptions" // 验证码选项
|
||||||
|
HTTPFirewallPolicyField_Mode dbs.FieldName = "mode" // 模式
|
||||||
|
HTTPFirewallPolicyField_UseLocalFirewall dbs.FieldName = "useLocalFirewall" // 是否自动使用本地防火墙
|
||||||
|
HTTPFirewallPolicyField_SynFlood dbs.FieldName = "synFlood" // SynFlood防御设置
|
||||||
|
HTTPFirewallPolicyField_Log dbs.FieldName = "log" // 日志配置
|
||||||
|
HTTPFirewallPolicyField_MaxRequestBodySize dbs.FieldName = "maxRequestBodySize" // 可以检查的最大请求内容尺寸
|
||||||
|
HTTPFirewallPolicyField_DenyCountryHTML dbs.FieldName = "denyCountryHTML" // 区域封禁提示
|
||||||
|
HTTPFirewallPolicyField_DenyProvinceHTML dbs.FieldName = "denyProvinceHTML" // 省份封禁提示
|
||||||
|
)
|
||||||
|
|
||||||
// HTTPFirewallPolicy HTTP防火墙
|
// HTTPFirewallPolicy HTTP防火墙
|
||||||
type HTTPFirewallPolicy struct {
|
type HTTPFirewallPolicy struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||||
UserId uint32 `field:"userId"` // 用户ID
|
UserId uint32 `field:"userId"` // 用户ID
|
||||||
ServerId uint32 `field:"serverId"` // 服务ID
|
ServerId uint32 `field:"serverId"` // 服务ID
|
||||||
GroupId uint32 `field:"groupId"` // 服务分组ID
|
GroupId uint32 `field:"groupId"` // 服务分组ID
|
||||||
State uint8 `field:"state"` // 状态
|
State uint8 `field:"state"` // 状态
|
||||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||||
IsOn bool `field:"isOn"` // 是否启用
|
IsOn bool `field:"isOn"` // 是否启用
|
||||||
Name string `field:"name"` // 名称
|
Name string `field:"name"` // 名称
|
||||||
Description string `field:"description"` // 描述
|
Description string `field:"description"` // 描述
|
||||||
Inbound dbs.JSON `field:"inbound"` // 入站规则
|
Inbound dbs.JSON `field:"inbound"` // 入站规则
|
||||||
Outbound dbs.JSON `field:"outbound"` // 出站规则
|
Outbound dbs.JSON `field:"outbound"` // 出站规则
|
||||||
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
|
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
|
||||||
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
|
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
|
||||||
Mode string `field:"mode"` // 模式
|
Mode string `field:"mode"` // 模式
|
||||||
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
|
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
|
||||||
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
|
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
|
||||||
Log dbs.JSON `field:"log"` // 日志配置
|
Log dbs.JSON `field:"log"` // 日志配置
|
||||||
|
MaxRequestBodySize uint32 `field:"maxRequestBodySize"` // 可以检查的最大请求内容尺寸
|
||||||
|
DenyCountryHTML string `field:"denyCountryHTML"` // 区域封禁提示
|
||||||
|
DenyProvinceHTML string `field:"denyProvinceHTML"` // 省份封禁提示
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPFirewallPolicyOperator struct {
|
type HTTPFirewallPolicyOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
TemplateId interface{} // 模版ID
|
TemplateId any // 模版ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId any // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId any // 用户ID
|
||||||
ServerId interface{} // 服务ID
|
ServerId any // 服务ID
|
||||||
GroupId interface{} // 服务分组ID
|
GroupId any // 服务分组ID
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
CreatedAt interface{} // 创建时间
|
CreatedAt any // 创建时间
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
Name interface{} // 名称
|
Name any // 名称
|
||||||
Description interface{} // 描述
|
Description any // 描述
|
||||||
Inbound interface{} // 入站规则
|
Inbound any // 入站规则
|
||||||
Outbound interface{} // 出站规则
|
Outbound any // 出站规则
|
||||||
BlockOptions interface{} // BLOCK选项
|
BlockOptions any // BLOCK选项
|
||||||
CaptchaOptions interface{} // 验证码选项
|
CaptchaOptions any // 验证码选项
|
||||||
Mode interface{} // 模式
|
Mode any // 模式
|
||||||
UseLocalFirewall interface{} // 是否自动使用本地防火墙
|
UseLocalFirewall any // 是否自动使用本地防火墙
|
||||||
SynFlood interface{} // SynFlood防御设置
|
SynFlood any // SynFlood防御设置
|
||||||
Log interface{} // 日志配置
|
Log any // 日志配置
|
||||||
|
MaxRequestBodySize any // 可以检查的最大请求内容尺寸
|
||||||
|
DenyCountryHTML any // 区域封禁提示
|
||||||
|
DenyProvinceHTML any // 省份封禁提示
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator {
|
func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (this *HTTPFirewallRuleGroupDAO) FindHTTPFirewallRuleGroupName(tx *dbs.Tx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ComposeFirewallRuleGroup 组合配置
|
// ComposeFirewallRuleGroup 组合配置
|
||||||
func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, groupId int64) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
|
func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, groupId int64, forNode bool) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
|
||||||
group, err := this.FindEnabledHTTPFirewallRuleGroup(tx, groupId)
|
group, err := this.FindEnabledHTTPFirewallRuleGroup(tx, groupId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -89,7 +89,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
|
|||||||
if group == nil {
|
if group == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
config := &firewallconfigs.HTTPFirewallRuleGroup{}
|
var config = &firewallconfigs.HTTPFirewallRuleGroup{}
|
||||||
config.Id = int64(group.Id)
|
config.Id = int64(group.Id)
|
||||||
config.IsOn = group.IsOn
|
config.IsOn = group.IsOn
|
||||||
config.Name = group.Name
|
config.Name = group.Name
|
||||||
@@ -98,7 +98,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
|
|||||||
config.IsTemplate = group.IsTemplate
|
config.IsTemplate = group.IsTemplate
|
||||||
|
|
||||||
if IsNotNull(group.Sets) {
|
if IsNotNull(group.Sets) {
|
||||||
setRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
|
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
|
||||||
err = json.Unmarshal(group.Sets, &setRefs)
|
err = json.Unmarshal(group.Sets, &setRefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -108,7 +108,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if setConfig != nil {
|
if setConfig != nil && (!forNode || setConfig.IsOn) {
|
||||||
config.SetRefs = append(config.SetRefs, setRef)
|
config.SetRefs = append(config.SetRefs, setRef)
|
||||||
config.Sets = append(config.Sets, setConfig)
|
config.Sets = append(config.Sets, setConfig)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
|
|||||||
if set == nil {
|
if set == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
config := &firewallconfigs.HTTPFirewallRuleSet{}
|
var config = &firewallconfigs.HTTPFirewallRuleSet{}
|
||||||
config.Id = int64(set.Id)
|
config.Id = int64(set.Id)
|
||||||
config.IsOn = set.IsOn
|
config.IsOn = set.IsOn
|
||||||
config.Name = set.Name
|
config.Name = set.Name
|
||||||
@@ -102,7 +102,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
|
|||||||
config.IgnoreLocal = set.IgnoreLocal == 1
|
config.IgnoreLocal = set.IgnoreLocal == 1
|
||||||
|
|
||||||
if IsNotNull(set.Rules) {
|
if IsNotNull(set.Rules) {
|
||||||
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{}
|
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
|
||||||
err = json.Unmarshal(set.Rules, &ruleRefs)
|
err = json.Unmarshal(set.Rules, &ruleRefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -128,6 +128,22 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
|
|||||||
config.Actions = actionConfigs
|
config.Actions = actionConfigs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查各个选项
|
||||||
|
for _, actionConfig := range actionConfigs {
|
||||||
|
if actionConfig.Code == firewallconfigs.HTTPFirewallActionRecordIP { // 记录IP动作
|
||||||
|
if actionConfig.Options != nil {
|
||||||
|
var ipListId = actionConfig.Options.GetInt64("ipListId")
|
||||||
|
exists, err := SharedIPListDAO.ExistsEnabledIPList(tx, ipListId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
actionConfig.Options["ipListIsDeleted"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +228,28 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, r
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledRuleSetIdsWithIPListId 根据IP名单ID查找对应动作的WAF规则集
|
||||||
|
func (this *HTTPFirewallRuleSetDAO) FindAllEnabledRuleSetIdsWithIPListId(tx *dbs.Tx, ipListId int64) (setIds []int64, err error) {
|
||||||
|
ones, err := this.Query(tx).
|
||||||
|
State(HTTPFirewallRuleStateEnabled).
|
||||||
|
Where("JSON_CONTAINS(actions, :jsonQuery)").
|
||||||
|
Param("jsonQuery", maps.Map{
|
||||||
|
"code": firewallconfigs.HTTPFirewallActionRecordIP,
|
||||||
|
"options": maps.Map{
|
||||||
|
"ipListId": ipListId,
|
||||||
|
},
|
||||||
|
}.AsJSON()).
|
||||||
|
ResultPk().
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, one := range ones {
|
||||||
|
setIds = append(setIds, int64(one.(*HTTPFirewallRuleSet).Id))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// CheckUserRuleSet 检查用户
|
// CheckUserRuleSet 检查用户
|
||||||
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
|
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
|
||||||
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)
|
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
|
|||||||
|
|
||||||
// root
|
// root
|
||||||
if IsNotNull(web.Root) {
|
if IsNotNull(web.Root) {
|
||||||
var rootConfig = &serverconfigs.HTTPRootConfig{}
|
var rootConfig = serverconfigs.NewHTTPRootConfig()
|
||||||
err = json.Unmarshal(web.Root, rootConfig)
|
err = json.Unmarshal(web.Root, rootConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -301,7 +301,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
|
|||||||
|
|
||||||
// 自定义防火墙设置
|
// 自定义防火墙设置
|
||||||
if firewallRef.FirewallPolicyId > 0 {
|
if firewallRef.FirewallPolicyId > 0 {
|
||||||
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap)
|
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, forNode, cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -519,6 +519,14 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
|
|||||||
}
|
}
|
||||||
if this.shouldCompose(isLocationOrGroup, forNode, ccConfig.IsPrior, ccConfig.IsOn) {
|
if this.shouldCompose(isLocationOrGroup, forNode, ccConfig.IsPrior, ccConfig.IsOn) {
|
||||||
config.CC = ccConfig
|
config.CC = ccConfig
|
||||||
|
|
||||||
|
if forNode {
|
||||||
|
for index, threshold := range ccConfig.Thresholds {
|
||||||
|
if index < len(serverconfigs.DefaultHTTPCCThresholds) {
|
||||||
|
threshold.MergeIfEmpty(serverconfigs.DefaultHTTPCCThresholds[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,6 +576,7 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
|
|||||||
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
|
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Value: "${rawRemoteAddr}",
|
Value: "${rawRemoteAddr}",
|
||||||
|
Type: serverconfigs.HTTPRemoteAddrTypeDefault,
|
||||||
}
|
}
|
||||||
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
|
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"math"
|
"math"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -498,7 +499,11 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, ke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(keyword) > 0 {
|
if len(keyword) > 0 {
|
||||||
query.Like("ipFrom", dbutils.QuoteLike(keyword))
|
if net.ParseIP(keyword) != nil { // 是一个IP地址
|
||||||
|
query.Attr("ipFrom", keyword)
|
||||||
|
} else {
|
||||||
|
query.Like("ipFrom", dbutils.QuoteLike(keyword))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(ip) > 0 {
|
if len(ip) > 0 {
|
||||||
query.Attr("ipFrom", ip)
|
query.Attr("ipFrom", ip)
|
||||||
@@ -540,7 +545,11 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, key
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(keyword) > 0 {
|
if len(keyword) > 0 {
|
||||||
query.Like("ipFrom", dbutils.QuoteLike(keyword))
|
if net.ParseIP(keyword) != nil { // 是一个IP地址
|
||||||
|
query.Attr("ipFrom", keyword)
|
||||||
|
} else {
|
||||||
|
query.Like("ipFrom", dbutils.QuoteLike(keyword))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(ip) > 0 {
|
if len(ip) > 0 {
|
||||||
query.Attr("ipFrom", ip)
|
query.Attr("ipFrom", ip)
|
||||||
@@ -665,6 +674,9 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx)
|
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
for _, clusterId := range clusterIds {
|
for _, clusterId := range clusterIds {
|
||||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeIPItemChanged)
|
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeIPItemChanged)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package models
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||||
@@ -299,7 +300,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
var libraryFile = one.(*IPLibraryFile)
|
var libraryFile = one.(*IPLibraryFile)
|
||||||
template, err := iplibrary.NewTemplate(libraryFile.Template)
|
template, err := iplibrary.NewTemplate(libraryFile.Template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create template from '" + libraryFile.Template + "' failed: " + err.Error())
|
return fmt.Errorf("create template from '%s' failed: %w", libraryFile.Template, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileId = int64(libraryFile.FileId)
|
var fileId = int64(libraryFile.FileId)
|
||||||
@@ -314,17 +315,17 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
|
||||||
}
|
}
|
||||||
} else if !stat.IsDir() {
|
} else if !stat.IsDir() {
|
||||||
_ = os.Remove(dir)
|
_ = os.Remove(dir)
|
||||||
|
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,7 +429,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
|
|
||||||
err = writer.WriteMeta()
|
err = writer.WriteMeta()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("write meta failed: " + err.Error())
|
return fmt.Errorf("write meta failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
|
chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
|
||||||
@@ -503,7 +504,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
|
|
||||||
err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
|
err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("write failed: " + err.Error())
|
return fmt.Errorf("write failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -536,7 +537,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
// 将生成的内容写入到文件
|
// 将生成的内容写入到文件
|
||||||
stat, err = os.Stat(filePath)
|
stat, err = os.Stat(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("stat generated file failed: " + err.Error())
|
return fmt.Errorf("stat generated file failed: %w", err)
|
||||||
}
|
}
|
||||||
generatedFileId, err := SharedFileDAO.CreateFile(tx, 0, 0, "ipLibraryFile", "", libraryCode+".db", stat.Size(), "", false)
|
generatedFileId, err := SharedFileDAO.CreateFile(tx, 0, 0, "ipLibraryFile", "", libraryCode+".db", stat.Size(), "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -545,7 +546,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
|
|||||||
|
|
||||||
fp, err := os.Open(filePath)
|
fp, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("open generated file failed: " + err.Error())
|
return fmt.Errorf("open generated file failed: %w", err)
|
||||||
}
|
}
|
||||||
var buf = make([]byte, 256*1024)
|
var buf = make([]byte, 256*1024)
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -61,12 +62,16 @@ func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DisableIPList 禁用条目
|
// DisableIPList 禁用条目
|
||||||
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, id int64) error {
|
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, listId int64) error {
|
||||||
_, err := this.Query(tx).
|
_, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(listId).
|
||||||
Set("state", IPListStateDisabled).
|
Set("state", IPListStateDisabled).
|
||||||
Update()
|
Update()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.NotifyUpdate(tx, listId, NodeTaskTypeIPListDeleted+"@"+string(maps.Map{"listId": listId}.AsJSON()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindEnabledIPList 查找启用中的条目
|
// FindEnabledIPList 查找启用中的条目
|
||||||
@@ -258,11 +263,35 @@ func (this *IPListDAO) ExistsEnabledIPList(tx *dbs.Tx, listId int64) (bool, erro
|
|||||||
|
|
||||||
// NotifyUpdate 通知更新
|
// NotifyUpdate 通知更新
|
||||||
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
|
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
|
||||||
|
// WAF策略中的
|
||||||
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
|
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resultClusterIds := []int64{}
|
|
||||||
|
// 规则集动作中使用此名单的策略
|
||||||
|
ruleSetIds, err := SharedHTTPFirewallRuleSetDAO.FindAllEnabledRuleSetIdsWithIPListId(tx, listId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, ruleSetId := range ruleSetIds {
|
||||||
|
ruleGroupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, ruleSetId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ruleGroupId > 0 {
|
||||||
|
policyId, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdWithRuleGroupId(tx, ruleGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if policyId > 0 && !lists.ContainsInt64(httpFirewallPolicyIds, policyId) {
|
||||||
|
httpFirewallPolicyIds = append(httpFirewallPolicyIds, policyId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找集群
|
||||||
|
var resultClusterIds = []int64{}
|
||||||
for _, policyId := range httpFirewallPolicyIds {
|
for _, policyId := range httpFirewallPolicyIds {
|
||||||
// 集群
|
// 集群
|
||||||
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId)
|
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -27,7 +28,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
|
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
|
||||||
if err == ErrNotFound {
|
if err != nil && errors.Is(err, ErrNotFound) {
|
||||||
t.Log("not found")
|
t.Log("not found")
|
||||||
} else {
|
} else {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -36,7 +37,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
|
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
|
||||||
if err == ErrNotFound {
|
if err != nil && errors.Is(err, ErrNotFound) {
|
||||||
t.Log("not found")
|
t.Log("not found")
|
||||||
} else {
|
} else {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -45,7 +46,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
|
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
|
||||||
if err == ErrNotFound {
|
if err != nil && errors.Is(err, ErrNotFound) {
|
||||||
t.Log("not found")
|
t.Log("not found")
|
||||||
} else {
|
} else {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -53,6 +54,17 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIPListDAO_NotifyUpdate(t *testing.T) {
|
||||||
|
dbs.NotifyReady()
|
||||||
|
|
||||||
|
var dao = NewIPListDAO()
|
||||||
|
var tx *dbs.Tx
|
||||||
|
err := dao.NotifyUpdate(tx, 104, NodeTaskTypeIPListDeleted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
|
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
|
||||||
runtime.GOMAXPROCS(1)
|
runtime.GOMAXPROCS(1)
|
||||||
|
|
||||||
@@ -65,4 +77,3 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
|
|||||||
_, _ = dao.IncreaseVersion(tx)
|
_, _ = dao.IncreaseVersion(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -647,10 +647,10 @@ func (this *NodeClusterDAO) FindClusterTOAConfig(tx *dbs.Tx, clusterId int64, ca
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !IsNotNull([]byte(toa)) {
|
if !IsNotNull([]byte(toa)) {
|
||||||
return nodeconfigs.DefaultTOAConfig(), nil
|
return nodeconfigs.NewTOAConfig(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &nodeconfigs.TOAConfig{}
|
var config = nodeconfigs.NewTOAConfig()
|
||||||
err = json.Unmarshal([]byte(toa), config)
|
err = json.Unmarshal([]byte(toa), config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -675,7 +675,7 @@ func (this *NodeClusterDAO) UpdateClusterTOA(tx *dbs.Tx, clusterId int64, toaJSO
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return this.NotifyUpdate(tx, clusterId)
|
return this.NotifyTOAUpdate(tx, clusterId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量
|
// CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量
|
||||||
@@ -1454,12 +1454,13 @@ func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId in
|
|||||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
|
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyTOAUpdate 通知TOA变化
|
||||||
|
func (this *NodeClusterDAO) NotifyTOAUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||||
|
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeTOAChanged)
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyDNSUpdate 通知DNS更新
|
// NotifyDNSUpdate 通知DNS更新
|
||||||
// TODO 更新新的DNS解析记录的同时,需要删除老的DNS解析记录
|
// TODO 更新新的DNS解析记录的同时,需要删除老的DNS解析记录
|
||||||
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {
|
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||||
err := dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
|
return dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1039,9 +1039,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, clusterServer := range clusterServers {
|
servers = append(servers, clusterServers...)
|
||||||
servers = append(servers, clusterServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
@@ -1063,7 +1061,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
// TODO 根据用户的不同读取不同的全局设置
|
// TODO 根据用户的不同读取不同的全局设置
|
||||||
var settingCacheKey = "SharedSysSettingDAO:" + systemconfigs.SettingCodeServerGlobalConfig
|
var settingCacheKey = "SharedSysSettingDAO:" + systemconfigs.SettingCodeServerGlobalConfig
|
||||||
settingJSONCache, ok := cacheMap.Get(settingCacheKey)
|
settingJSONCache, ok := cacheMap.Get(settingCacheKey)
|
||||||
var settingJSON = []byte{}
|
var settingJSON []byte
|
||||||
if ok {
|
if ok {
|
||||||
settingJSON = settingJSONCache.([]byte)
|
settingJSON = settingJSONCache.([]byte)
|
||||||
} else {
|
} else {
|
||||||
@@ -1089,6 +1087,9 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
config.HTTPCCPolicies = map[int64]*nodeconfigs.HTTPCCPolicy{}
|
config.HTTPCCPolicies = map[int64]*nodeconfigs.HTTPCCPolicy{}
|
||||||
config.HTTP3Policies = map[int64]*nodeconfigs.HTTP3Policy{}
|
config.HTTP3Policies = map[int64]*nodeconfigs.HTTP3Policy{}
|
||||||
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
|
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
|
||||||
|
|
||||||
|
var cachePolicyIds = []int64{}
|
||||||
|
|
||||||
var allowIPMaps = map[string]bool{}
|
var allowIPMaps = map[string]bool{}
|
||||||
for _, clusterId := range clusterIds {
|
for _, clusterId := range clusterIds {
|
||||||
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
|
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
|
||||||
@@ -1116,7 +1117,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
// 防火墙
|
// 防火墙
|
||||||
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
|
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
|
||||||
if httpFirewallPolicyId > 0 {
|
if httpFirewallPolicyId > 0 {
|
||||||
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap)
|
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, true, cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1128,12 +1129,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
// 缓存策略
|
// 缓存策略
|
||||||
var httpCachePolicyId = int64(nodeCluster.CachePolicyId)
|
var httpCachePolicyId = int64(nodeCluster.CachePolicyId)
|
||||||
if httpCachePolicyId > 0 {
|
if httpCachePolicyId > 0 {
|
||||||
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
|
if !lists.ContainsInt64(cachePolicyIds, httpCachePolicyId) {
|
||||||
if err != nil {
|
cachePolicyIds = append(cachePolicyIds, httpCachePolicyId)
|
||||||
return nil, err
|
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
|
||||||
}
|
if err != nil {
|
||||||
if cachePolicy != nil {
|
return nil, err
|
||||||
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
|
}
|
||||||
|
if cachePolicy != nil {
|
||||||
|
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2118,7 +2122,7 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
|
|||||||
var secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(node.UniqueId+"@"+node.Secret)))
|
var secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(node.UniqueId+"@"+node.Secret)))
|
||||||
|
|
||||||
for _, clusterId := range node.AllClusterIds() {
|
for _, clusterId := range node.AllClusterIds() {
|
||||||
parentNodeConfigs, _ := result[clusterId]
|
var parentNodeConfigs = result[clusterId]
|
||||||
parentNodeConfigs = append(parentNodeConfigs, &nodeconfigs.ParentNodeConfig{
|
parentNodeConfigs = append(parentNodeConfigs, &nodeconfigs.ParentNodeConfig{
|
||||||
Id: int64(node.Id),
|
Id: int64(node.Id),
|
||||||
Addrs: addrStrings,
|
Addrs: addrStrings,
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
domainRoutes, _ := routes[dnsDomainId]
|
var domainRoutes = routes[dnsDomainId]
|
||||||
|
|
||||||
if len(domainRoutes) > 0 {
|
if len(domainRoutes) > 0 {
|
||||||
sort.Strings(domainRoutes)
|
sort.Strings(domainRoutes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ const (
|
|||||||
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
|
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
|
||||||
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
|
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
|
||||||
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
|
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
|
||||||
|
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
|
||||||
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
|
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
|
||||||
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
|
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
|
||||||
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
|
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
|
||||||
@@ -29,6 +31,7 @@ const (
|
|||||||
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
|
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
|
||||||
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
|
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
|
||||||
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
|
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
|
||||||
|
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
|
||||||
|
|
||||||
// NS相关
|
// NS相关
|
||||||
|
|
||||||
@@ -234,7 +237,7 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAllNodeTasks 删除所有节点相关任务
|
// DeleteAllNodeTasks 删除所有节点相关任务
|
||||||
func (this *NodeTaskDAO)DeleteAllNodeTasks(tx *dbs.Tx) error {
|
func (this *NodeTaskDAO) DeleteAllNodeTasks(tx *dbs.Tx) error {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
DeleteQuickly()
|
DeleteQuickly()
|
||||||
}
|
}
|
||||||
@@ -264,6 +267,23 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
|
|||||||
|
|
||||||
// UpdateNodeTaskDone 修改节点任务的完成状态
|
// UpdateNodeTaskDone 修改节点任务的完成状态
|
||||||
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error {
|
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error {
|
||||||
|
if isOk {
|
||||||
|
// 特殊任务删除
|
||||||
|
taskType, err := this.Query(tx).
|
||||||
|
Pk(taskId).
|
||||||
|
Result("type").
|
||||||
|
FindStringCol("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(taskType, NodeTaskTypeIPListDeleted+"@") {
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(taskId).
|
||||||
|
DeleteQuickly()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他任务标记为完成
|
||||||
var query = this.Query(tx).
|
var query = this.Query(tx).
|
||||||
Pk(taskId)
|
Pk(taskId)
|
||||||
if !isOk {
|
if !isOk {
|
||||||
@@ -273,8 +293,9 @@ func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool,
|
|||||||
}
|
}
|
||||||
query.Set("version", version)
|
query.Set("version", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := query.
|
_, err := query.
|
||||||
Set("isDone", 1).
|
Set("isDone", true).
|
||||||
Set("isOk", isOk).
|
Set("isOk", isOk).
|
||||||
Set("error", errorMessage).
|
Set("error", errorMessage).
|
||||||
Update()
|
Update()
|
||||||
|
|||||||
@@ -54,3 +54,12 @@ func TestNodeTaskDAO_FindDoingNodeTasks(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNodeTaskDAO_UpdateNodeTaskDone(t *testing.T) {
|
||||||
|
var tx *dbs.Tx
|
||||||
|
var dao = models.NewNodeTaskDAO()
|
||||||
|
err := dao.UpdateNodeTaskDone(tx, 1741, true, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,15 +61,28 @@ func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindEnabledPlan 查找启用中的条目
|
// FindEnabledPlan 查找启用中的条目
|
||||||
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, id int64) (*Plan, error) {
|
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, planId int64, cacheMap *utils.CacheMap) (*Plan, error) {
|
||||||
|
var cacheKey = this.Table + ":FindEnabledPlan:" + types.String(planId)
|
||||||
|
if cacheMap != nil {
|
||||||
|
cache, _ := cacheMap.Get(cacheKey)
|
||||||
|
if cache != nil {
|
||||||
|
return cache.(*Plan), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result, err := this.Query(tx).
|
result, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(planId).
|
||||||
Attr("state", PlanStateEnabled).
|
Attr("state", PlanStateEnabled).
|
||||||
Find()
|
Find()
|
||||||
if result == nil {
|
if result == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return result.(*Plan), err
|
|
||||||
|
if cacheMap != nil {
|
||||||
|
cacheMap.Put(cacheKey, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.(*Plan), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindPlanName 根据主键查找名称
|
// FindPlanName 根据主键查找名称
|
||||||
|
|||||||
6
internal/db/models/plan_dao_test.go
Normal file
6
internal/db/models/plan_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
@@ -2,39 +2,71 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
PlanField_Id dbs.FieldName = "id" // ID
|
||||||
|
PlanField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
PlanField_Name dbs.FieldName = "name" // 套餐名
|
||||||
|
PlanField_ClusterId dbs.FieldName = "clusterId" // 集群ID
|
||||||
|
PlanField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
|
||||||
|
PlanField_Features dbs.FieldName = "features" // 允许的功能
|
||||||
|
PlanField_TrafficPrice dbs.FieldName = "trafficPrice" // 流量价格设定
|
||||||
|
PlanField_BandwidthPrice dbs.FieldName = "bandwidthPrice" // 带宽价格
|
||||||
|
PlanField_MonthlyPrice dbs.FieldName = "monthlyPrice" // 月付
|
||||||
|
PlanField_SeasonallyPrice dbs.FieldName = "seasonallyPrice" // 季付
|
||||||
|
PlanField_YearlyPrice dbs.FieldName = "yearlyPrice" // 年付
|
||||||
|
PlanField_PriceType dbs.FieldName = "priceType" // 价格类型
|
||||||
|
PlanField_Order dbs.FieldName = "order" // 排序
|
||||||
|
PlanField_State dbs.FieldName = "state" // 状态
|
||||||
|
PlanField_TotalServers dbs.FieldName = "totalServers" // 可以绑定的网站数量
|
||||||
|
PlanField_TotalServerNamesPerServer dbs.FieldName = "totalServerNamesPerServer" // 每个网站可以绑定的域名数量
|
||||||
|
PlanField_TotalServerNames dbs.FieldName = "totalServerNames" // 总域名数量
|
||||||
|
PlanField_MonthlyRequests dbs.FieldName = "monthlyRequests" // 每月访问量额度
|
||||||
|
PlanField_DailyRequests dbs.FieldName = "dailyRequests" // 每日访问量额度
|
||||||
|
)
|
||||||
|
|
||||||
// Plan 用户套餐
|
// Plan 用户套餐
|
||||||
type Plan struct {
|
type Plan struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
IsOn bool `field:"isOn"` // 是否启用
|
IsOn bool `field:"isOn"` // 是否启用
|
||||||
Name string `field:"name"` // 套餐名
|
Name string `field:"name"` // 套餐名
|
||||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
|
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
|
||||||
Features dbs.JSON `field:"features"` // 允许的功能
|
Features dbs.JSON `field:"features"` // 允许的功能
|
||||||
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
|
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
|
||||||
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
|
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
|
||||||
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
|
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
|
||||||
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
|
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
|
||||||
YearlyPrice float64 `field:"yearlyPrice"` // 年付
|
YearlyPrice float64 `field:"yearlyPrice"` // 年付
|
||||||
PriceType string `field:"priceType"` // 价格类型
|
PriceType string `field:"priceType"` // 价格类型
|
||||||
Order uint32 `field:"order"` // 排序
|
Order uint32 `field:"order"` // 排序
|
||||||
State uint8 `field:"state"` // 状态
|
State uint8 `field:"state"` // 状态
|
||||||
|
TotalServers uint32 `field:"totalServers"` // 可以绑定的网站数量
|
||||||
|
TotalServerNamesPerServer uint32 `field:"totalServerNamesPerServer"` // 每个网站可以绑定的域名数量
|
||||||
|
TotalServerNames uint32 `field:"totalServerNames"` // 总域名数量
|
||||||
|
MonthlyRequests uint64 `field:"monthlyRequests"` // 每月访问量额度
|
||||||
|
DailyRequests uint64 `field:"dailyRequests"` // 每日访问量额度
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlanOperator struct {
|
type PlanOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
Name interface{} // 套餐名
|
Name any // 套餐名
|
||||||
ClusterId interface{} // 集群ID
|
ClusterId any // 集群ID
|
||||||
TrafficLimit interface{} // 流量限制
|
TrafficLimit any // 流量限制
|
||||||
Features interface{} // 允许的功能
|
Features any // 允许的功能
|
||||||
TrafficPrice interface{} // 流量价格设定
|
TrafficPrice any // 流量价格设定
|
||||||
BandwidthPrice interface{} // 带宽价格
|
BandwidthPrice any // 带宽价格
|
||||||
MonthlyPrice interface{} // 月付
|
MonthlyPrice any // 月付
|
||||||
SeasonallyPrice interface{} // 季付
|
SeasonallyPrice any // 季付
|
||||||
YearlyPrice interface{} // 年付
|
YearlyPrice any // 年付
|
||||||
PriceType interface{} // 价格类型
|
PriceType any // 价格类型
|
||||||
Order interface{} // 排序
|
Order any // 排序
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
|
TotalServers any // 可以绑定的网站数量
|
||||||
|
TotalServerNamesPerServer any // 每个网站可以绑定的域名数量
|
||||||
|
TotalServerNames any // 总域名数量
|
||||||
|
MonthlyRequests any // 每月访问量额度
|
||||||
|
DailyRequests any // 每日访问量额度
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlanOperator() *PlanOperator {
|
func NewPlanOperator() *PlanOperator {
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
|
|||||||
pinyinResult = append(pinyinResult, strings.Join(piece, " "))
|
pinyinResult = append(pinyinResult, strings.Join(piece, " "))
|
||||||
}
|
}
|
||||||
pinyinJSON, err := json.Marshal([]string{strings.Join(pinyinResult, " ")})
|
pinyinJSON, err := json.Marshal([]string{strings.Join(pinyinResult, " ")})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
op.Pinyin = pinyinJSON
|
op.Pinyin = pinyinJSON
|
||||||
|
|
||||||
codes := []string{name}
|
codes := []string{name}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = &serverconfigs.ReverseProxyConfig{}
|
var config = serverconfigs.NewReverseProxyConfig()
|
||||||
config.Id = int64(reverseProxy.Id)
|
config.Id = int64(reverseProxy.Id)
|
||||||
config.IsOn = reverseProxy.IsOn
|
config.IsOn = reverseProxy.IsOn
|
||||||
config.RequestHostType = types.Int8(reverseProxy.RequestHostType)
|
config.RequestHostType = types.Int8(reverseProxy.RequestHostType)
|
||||||
@@ -109,6 +109,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
|
|||||||
config.StripPrefix = reverseProxy.StripPrefix
|
config.StripPrefix = reverseProxy.StripPrefix
|
||||||
config.AutoFlush = reverseProxy.AutoFlush == 1
|
config.AutoFlush = reverseProxy.AutoFlush == 1
|
||||||
config.FollowRedirects = reverseProxy.FollowRedirects == 1
|
config.FollowRedirects = reverseProxy.FollowRedirects == 1
|
||||||
|
config.Retry50X = reverseProxy.Retry50X
|
||||||
|
|
||||||
var schedulingConfig = &serverconfigs.SchedulingConfig{}
|
var schedulingConfig = &serverconfigs.SchedulingConfig{}
|
||||||
if IsNotNull(reverseProxy.Scheduling) {
|
if IsNotNull(reverseProxy.Scheduling) {
|
||||||
@@ -218,6 +219,7 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
|
|||||||
op.AdminId = adminId
|
op.AdminId = adminId
|
||||||
op.UserId = userId
|
op.UserId = userId
|
||||||
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
|
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
|
||||||
|
op.Retry50X = true
|
||||||
|
|
||||||
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
|
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
|
||||||
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
|
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
|
||||||
@@ -425,7 +427,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
|||||||
maxConns int32,
|
maxConns int32,
|
||||||
maxIdleConns int32,
|
maxIdleConns int32,
|
||||||
proxyProtocolJSON []byte,
|
proxyProtocolJSON []byte,
|
||||||
followRedirects bool) error {
|
followRedirects bool,
|
||||||
|
retry50X bool) error {
|
||||||
if reverseProxyId <= 0 {
|
if reverseProxyId <= 0 {
|
||||||
return errors.New("invalid reverseProxyId")
|
return errors.New("invalid reverseProxyId")
|
||||||
}
|
}
|
||||||
@@ -490,6 +493,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
|||||||
op.ProxyProtocol = proxyProtocolJSON
|
op.ProxyProtocol = proxyProtocolJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
op.Retry50X = retry50X
|
||||||
|
|
||||||
err = this.Save(tx, op)
|
err = this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -2,6 +2,34 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
ReverseProxyField_Id dbs.FieldName = "id" // ID
|
||||||
|
ReverseProxyField_AdminId dbs.FieldName = "adminId" // 管理员ID
|
||||||
|
ReverseProxyField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
ReverseProxyField_TemplateId dbs.FieldName = "templateId" // 模版ID
|
||||||
|
ReverseProxyField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
ReverseProxyField_Scheduling dbs.FieldName = "scheduling" // 调度算法
|
||||||
|
ReverseProxyField_PrimaryOrigins dbs.FieldName = "primaryOrigins" // 主要源站
|
||||||
|
ReverseProxyField_BackupOrigins dbs.FieldName = "backupOrigins" // 备用源站
|
||||||
|
ReverseProxyField_StripPrefix dbs.FieldName = "stripPrefix" // 去除URL前缀
|
||||||
|
ReverseProxyField_RequestHostType dbs.FieldName = "requestHostType" // 请求Host类型
|
||||||
|
ReverseProxyField_RequestHost dbs.FieldName = "requestHost" // 请求Host
|
||||||
|
ReverseProxyField_RequestHostExcludingPort dbs.FieldName = "requestHostExcludingPort" // 移除请求Host中的域名
|
||||||
|
ReverseProxyField_RequestURI dbs.FieldName = "requestURI" // 请求URI
|
||||||
|
ReverseProxyField_AutoFlush dbs.FieldName = "autoFlush" // 是否自动刷新缓冲区
|
||||||
|
ReverseProxyField_AddHeaders dbs.FieldName = "addHeaders" // 自动添加的Header列表
|
||||||
|
ReverseProxyField_State dbs.FieldName = "state" // 状态
|
||||||
|
ReverseProxyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
ReverseProxyField_ConnTimeout dbs.FieldName = "connTimeout" // 连接超时时间
|
||||||
|
ReverseProxyField_ReadTimeout dbs.FieldName = "readTimeout" // 读取超时时间
|
||||||
|
ReverseProxyField_IdleTimeout dbs.FieldName = "idleTimeout" // 空闲超时时间
|
||||||
|
ReverseProxyField_MaxConns dbs.FieldName = "maxConns" // 最大并发连接数
|
||||||
|
ReverseProxyField_MaxIdleConns dbs.FieldName = "maxIdleConns" // 最大空闲连接数
|
||||||
|
ReverseProxyField_ProxyProtocol dbs.FieldName = "proxyProtocol" // Proxy Protocol配置
|
||||||
|
ReverseProxyField_FollowRedirects dbs.FieldName = "followRedirects" // 回源跟随
|
||||||
|
ReverseProxyField_Retry50X dbs.FieldName = "retry50X" // 启用50X重试
|
||||||
|
)
|
||||||
|
|
||||||
// ReverseProxy 反向代理配置
|
// ReverseProxy 反向代理配置
|
||||||
type ReverseProxy struct {
|
type ReverseProxy struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
@@ -28,33 +56,35 @@ type ReverseProxy struct {
|
|||||||
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
|
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
|
||||||
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
|
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
|
||||||
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
|
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
|
||||||
|
Retry50X bool `field:"retry50X"` // 启用50X重试
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReverseProxyOperator struct {
|
type ReverseProxyOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId any // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId any // 用户ID
|
||||||
TemplateId interface{} // 模版ID
|
TemplateId any // 模版ID
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
Scheduling interface{} // 调度算法
|
Scheduling any // 调度算法
|
||||||
PrimaryOrigins interface{} // 主要源站
|
PrimaryOrigins any // 主要源站
|
||||||
BackupOrigins interface{} // 备用源站
|
BackupOrigins any // 备用源站
|
||||||
StripPrefix interface{} // 去除URL前缀
|
StripPrefix any // 去除URL前缀
|
||||||
RequestHostType interface{} // 请求Host类型
|
RequestHostType any // 请求Host类型
|
||||||
RequestHost interface{} // 请求Host
|
RequestHost any // 请求Host
|
||||||
RequestHostExcludingPort interface{} // 移除请求Host中的域名
|
RequestHostExcludingPort any // 移除请求Host中的域名
|
||||||
RequestURI interface{} // 请求URI
|
RequestURI any // 请求URI
|
||||||
AutoFlush interface{} // 是否自动刷新缓冲区
|
AutoFlush any // 是否自动刷新缓冲区
|
||||||
AddHeaders interface{} // 自动添加的Header列表
|
AddHeaders any // 自动添加的Header列表
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
CreatedAt interface{} // 创建时间
|
CreatedAt any // 创建时间
|
||||||
ConnTimeout interface{} // 连接超时时间
|
ConnTimeout any // 连接超时时间
|
||||||
ReadTimeout interface{} // 读取超时时间
|
ReadTimeout any // 读取超时时间
|
||||||
IdleTimeout interface{} // 空闲超时时间
|
IdleTimeout any // 空闲超时时间
|
||||||
MaxConns interface{} // 最大并发连接数
|
MaxConns any // 最大并发连接数
|
||||||
MaxIdleConns interface{} // 最大空闲连接数
|
MaxIdleConns any // 最大空闲连接数
|
||||||
ProxyProtocol interface{} // Proxy Protocol配置
|
ProxyProtocol any // Proxy Protocol配置
|
||||||
FollowRedirects interface{} // 回源跟随
|
FollowRedirects any // 回源跟随
|
||||||
|
Retry50X any // 启用50X重试
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReverseProxyOperator() *ReverseProxyOperator {
|
func NewReverseProxyOperator() *ReverseProxyOperator {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
type ServerBandwidthStatDAO dbs.DAO
|
type ServerBandwidthStatDAO dbs.DAO
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ServerBandwidthStatTablePartials = 20 // 分表数量
|
ServerBandwidthStatTablePartitions = 20 // 分表数量
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -63,15 +63,15 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServerBandwidth 写入数据
|
// UpdateServerBandwidth 写入数据
|
||||||
// 暂时不使用region区分
|
// 现在不需要把 userPlanId 加入到数据表unique key中,因为只会影响5分钟统计,影响非常有限
|
||||||
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, day string, timeAt string, bytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
|
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, userPlanId int64, day string, timeAt string, bandwidthBytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
|
||||||
if serverId <= 0 {
|
if serverId <= 0 {
|
||||||
return errors.New("invalid server id '" + types.String(serverId) + "'")
|
return errors.New("invalid server id '" + types.String(serverId) + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Table(this.partialTable(serverId)).
|
Table(this.partialTable(serverId)).
|
||||||
Param("bytes", bytes).
|
Param("bytes", bandwidthBytes).
|
||||||
Param("totalBytes", totalBytes).
|
Param("totalBytes", totalBytes).
|
||||||
Param("cachedBytes", cachedBytes).
|
Param("cachedBytes", cachedBytes).
|
||||||
Param("attackBytes", attackBytes).
|
Param("attackBytes", attackBytes).
|
||||||
@@ -84,7 +84,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
|
|||||||
"regionId": regionId,
|
"regionId": regionId,
|
||||||
"day": day,
|
"day": day,
|
||||||
"timeAt": timeAt,
|
"timeAt": timeAt,
|
||||||
"bytes": bytes,
|
"bytes": bandwidthBytes,
|
||||||
"totalBytes": totalBytes,
|
"totalBytes": totalBytes,
|
||||||
"avgBytes": totalBytes / 300,
|
"avgBytes": totalBytes / 300,
|
||||||
"cachedBytes": cachedBytes,
|
"cachedBytes": cachedBytes,
|
||||||
@@ -92,6 +92,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
|
|||||||
"countRequests": countRequests,
|
"countRequests": countRequests,
|
||||||
"countCachedRequests": countCachedRequests,
|
"countCachedRequests": countCachedRequests,
|
||||||
"countAttackRequests": countAttackRequests,
|
"countAttackRequests": countAttackRequests,
|
||||||
|
"userPlanId": userPlanId,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"bytes": dbs.SQL("bytes+:bytes"),
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前,所以这里不用担心先后顺序的问题
|
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前,所以这里不用担心先后顺序的问题
|
||||||
@@ -379,14 +380,18 @@ func (this *ServerBandwidthStatDAO) FindAllServerStatsWithMonth(tx *dbs.Tx, serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindMonthlyPercentile 获取某月内百分位
|
// FindMonthlyPercentile 获取某月内百分位
|
||||||
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool) (result int64, err error) {
|
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool, noPlan bool, minSamples int) (result int64, err error) {
|
||||||
if percentile <= 0 {
|
if percentile <= 0 {
|
||||||
percentile = 95
|
percentile = 95
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是100%以上,则快速返回
|
// 如果是100%以上,则快速返回
|
||||||
if percentile >= 100 {
|
if percentile >= 100 {
|
||||||
result, err = this.Query(tx).
|
var query = this.Query(tx)
|
||||||
|
if noPlan {
|
||||||
|
query.Attr("userPlanId", 0)
|
||||||
|
}
|
||||||
|
result, err = query.
|
||||||
Table(this.partialTable(serverId)).
|
Table(this.partialTable(serverId)).
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
Result(this.bytesField(useAvg)).
|
Result(this.bytesField(useAvg)).
|
||||||
@@ -398,7 +403,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 总数量
|
// 总数量
|
||||||
total, err := this.Query(tx).
|
var totalQuery = this.Query(tx)
|
||||||
|
if noPlan {
|
||||||
|
totalQuery.Attr("userPlanId", 0)
|
||||||
|
}
|
||||||
|
total, err := totalQuery.
|
||||||
Table(this.partialTable(serverId)).
|
Table(this.partialTable(serverId)).
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
Between("day", month+"01", month+"31").
|
Between("day", month+"01", month+"31").
|
||||||
@@ -406,7 +415,7 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if total == 0 || total < int64(minSamples) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +426,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询 nth 位置
|
// 查询 nth 位置
|
||||||
result, err = this.Query(tx).
|
var query = this.Query(tx)
|
||||||
|
if noPlan {
|
||||||
|
query.Attr("userPlanId", 0)
|
||||||
|
}
|
||||||
|
result, err = query.
|
||||||
Table(this.partialTable(serverId)).
|
Table(this.partialTable(serverId)).
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
Result(this.bytesField(useAvg)).
|
Result(this.bytesField(useAvg)).
|
||||||
@@ -745,6 +758,74 @@ func (this *ServerBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, reg
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SumMonthlyBytes 统计某个网站单月总流量
|
||||||
|
func (this *ServerBandwidthStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, month string, noPlan bool) (int64, error) {
|
||||||
|
if !regexputils.YYYYMM.MatchString(month) {
|
||||||
|
return 0, errors.New("invalid month '" + month + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容以往版本
|
||||||
|
hasFullData, err := this.HasFullData(tx, serverId, month)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if !hasFullData {
|
||||||
|
return SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = this.Query(tx)
|
||||||
|
if noPlan {
|
||||||
|
query.Attr("userPlanId", 0)
|
||||||
|
}
|
||||||
|
return query.
|
||||||
|
Table(this.partialTable(serverId)).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
Attr("serverId", serverId).
|
||||||
|
SumInt64("totalBytes", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SumServerMonthlyWithRegion 根据服务计算某月合计
|
||||||
|
// month 格式为YYYYMM
|
||||||
|
func (this *ServerBandwidthStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId int64, regionId int64, month string, noPlan bool) (int64, error) {
|
||||||
|
var query = this.Query(tx)
|
||||||
|
query.Table(this.partialTable(serverId))
|
||||||
|
if regionId > 0 {
|
||||||
|
query.Attr("regionId", regionId)
|
||||||
|
}
|
||||||
|
if noPlan {
|
||||||
|
query.Attr("userPlanId", 0)
|
||||||
|
}
|
||||||
|
return query.Between("day", month+"01", month+"31").
|
||||||
|
Attr("serverId", serverId).
|
||||||
|
SumInt64("totalBytes", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindDistinctServerIdsWithoutPlanAtPartition 查找没有绑定套餐的有流量网站
|
||||||
|
func (this *ServerBandwidthStatDAO) FindDistinctServerIdsWithoutPlanAtPartition(tx *dbs.Tx, partitionIndex int, month string) (serverIds []int64, err error) {
|
||||||
|
ones, err := this.Query(tx).
|
||||||
|
Table(this.partialTable(int64(partitionIndex))).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
Attr("userPlanId", 0). // 没有绑定套餐
|
||||||
|
Result("DISTINCT serverId").
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, one := range ones {
|
||||||
|
var serverId = int64(one.(*ServerBandwidthStat).ServerId)
|
||||||
|
if serverId <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
serverIds = append(serverIds, serverId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountPartitions 查看分区数量
|
||||||
|
func (this *ServerBandwidthStatDAO) CountPartitions() int {
|
||||||
|
return ServerBandwidthStatTablePartitions
|
||||||
|
}
|
||||||
|
|
||||||
// CleanDays 清理过期数据
|
// CleanDays 清理过期数据
|
||||||
func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
|
func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
|
||||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
|
||||||
@@ -777,9 +858,9 @@ func (this *ServerBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int
|
|||||||
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
|
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
|
||||||
var locker = &sync.Mutex{}
|
var locker = &sync.Mutex{}
|
||||||
var wg = sync.WaitGroup{}
|
var wg = sync.WaitGroup{}
|
||||||
wg.Add(ServerBandwidthStatTablePartials)
|
wg.Add(ServerBandwidthStatTablePartitions)
|
||||||
var resultErr error
|
var resultErr error
|
||||||
for i := 0; i < ServerBandwidthStatTablePartials; i++ {
|
for i := 0; i < ServerBandwidthStatTablePartitions; i++ {
|
||||||
var table = this.partialTable(int64(i))
|
var table = this.partialTable(int64(i))
|
||||||
go func(table string) {
|
go func(table string) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@@ -796,7 +877,7 @@ func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.M
|
|||||||
|
|
||||||
// 获取分区表
|
// 获取分区表
|
||||||
func (this *ServerBandwidthStatDAO) partialTable(serverId int64) string {
|
func (this *ServerBandwidthStatDAO) partialTable(serverId int64) string {
|
||||||
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartials))
|
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartitions))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取字节字段
|
// 获取字节字段
|
||||||
@@ -844,6 +925,11 @@ func (this *ServerBandwidthStatDAO) fixServerStats(stats []*ServerBandwidthStat,
|
|||||||
// HasFullData 检查一个月是否完整数据
|
// HasFullData 检查一个月是否完整数据
|
||||||
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
|
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
|
||||||
func (this *ServerBandwidthStatDAO) HasFullData(tx *dbs.Tx, serverId int64, month string) (bool, error) {
|
func (this *ServerBandwidthStatDAO) HasFullData(tx *dbs.Tx, serverId int64, month string) (bool, error) {
|
||||||
|
// 最迟在2024年完成过渡
|
||||||
|
if time.Now().Year() >= 2024 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
var monthKey = month + "@" + types.String(serverId)
|
var monthKey = month + "@" + types.String(serverId)
|
||||||
|
|
||||||
if !regexputils.YYYYMM.MatchString(month) {
|
if !regexputils.YYYYMM.MatchString(month) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
|
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
|
||||||
var dao = models.NewServerBandwidthStatDAO()
|
var dao = models.NewServerBandwidthStatDAO()
|
||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
|
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200)))
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200)))
|
||||||
var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
|
var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
|
||||||
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
|
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,10 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
|
|||||||
func TestServerBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
|
func TestServerBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
|
||||||
var dao = models.NewServerBandwidthStatDAO()
|
var dao = models.NewServerBandwidthStatDAO()
|
||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false))
|
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false, false, 0))
|
||||||
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true))
|
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 0))
|
||||||
|
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 100))
|
||||||
|
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, true, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerBandwidthStatDAO_FindAllServerStatsWithMonth(t *testing.T) {
|
func TestServerBandwidthStatDAO_FindAllServerStatsWithMonth(t *testing.T) {
|
||||||
@@ -114,3 +116,32 @@ func TestServerBandwidthStatDAO_FindBandwidthStatsBetweenDays(t *testing.T) {
|
|||||||
t.Log(stat.Day, stat.TimeAt, "bytes:", stat.Bytes, "bits:", stat.Bits)
|
t.Log(stat.Day, stat.TimeAt, "bytes:", stat.Bytes, "bits:", stat.Bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerBandwidthStatDAO_SumServerMonthlyWithRegion(t *testing.T) {
|
||||||
|
var dao = models.NewServerBandwidthStatDAO()
|
||||||
|
var tx *dbs.Tx
|
||||||
|
{
|
||||||
|
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("with plan:", totalBytes)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("without plan:", totalBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerBandwidthStatDAO_SumMonthlyBytes(t *testing.T) {
|
||||||
|
var dao = models.NewServerBandwidthStatDAO()
|
||||||
|
var tx *dbs.Tx
|
||||||
|
totalBytes, err := dao.SumMonthlyBytes(tx, 23, timeutil.Format("Ym"), false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("total bytes:", totalBytes)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServerBandwidthStatField_Id dbs.FieldName = "id" // ID
|
||||||
|
ServerBandwidthStatField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
ServerBandwidthStatField_ServerId dbs.FieldName = "serverId" // 服务ID
|
||||||
|
ServerBandwidthStatField_RegionId dbs.FieldName = "regionId" // 区域ID
|
||||||
|
ServerBandwidthStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
|
||||||
|
ServerBandwidthStatField_Day dbs.FieldName = "day" // 日期YYYYMMDD
|
||||||
|
ServerBandwidthStatField_TimeAt dbs.FieldName = "timeAt" // 时间点HHMM
|
||||||
|
ServerBandwidthStatField_Bytes dbs.FieldName = "bytes" // 带宽字节
|
||||||
|
ServerBandwidthStatField_AvgBytes dbs.FieldName = "avgBytes" // 平均流量
|
||||||
|
ServerBandwidthStatField_CachedBytes dbs.FieldName = "cachedBytes" // 缓存的流量
|
||||||
|
ServerBandwidthStatField_AttackBytes dbs.FieldName = "attackBytes" // 攻击流量
|
||||||
|
ServerBandwidthStatField_CountRequests dbs.FieldName = "countRequests" // 请求数
|
||||||
|
ServerBandwidthStatField_CountCachedRequests dbs.FieldName = "countCachedRequests" // 缓存的请求数
|
||||||
|
ServerBandwidthStatField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 攻击请求数
|
||||||
|
ServerBandwidthStatField_TotalBytes dbs.FieldName = "totalBytes" // 总流量
|
||||||
|
)
|
||||||
|
|
||||||
// ServerBandwidthStat 服务峰值带宽统计
|
// ServerBandwidthStat 服务峰值带宽统计
|
||||||
type ServerBandwidthStat struct {
|
type ServerBandwidthStat struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
UserId uint64 `field:"userId"` // 用户ID
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
ServerId uint64 `field:"serverId"` // 服务ID
|
ServerId uint64 `field:"serverId"` // 服务ID
|
||||||
RegionId uint32 `field:"regionId"` // 区域ID
|
RegionId uint32 `field:"regionId"` // 区域ID
|
||||||
|
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
|
||||||
Day string `field:"day"` // 日期YYYYMMDD
|
Day string `field:"day"` // 日期YYYYMMDD
|
||||||
TimeAt string `field:"timeAt"` // 时间点HHMM
|
TimeAt string `field:"timeAt"` // 时间点HHMM
|
||||||
Bytes uint64 `field:"bytes"` // 带宽字节
|
Bytes uint64 `field:"bytes"` // 带宽字节
|
||||||
@@ -23,6 +44,7 @@ type ServerBandwidthStatOperator struct {
|
|||||||
UserId any // 用户ID
|
UserId any // 用户ID
|
||||||
ServerId any // 服务ID
|
ServerId any // 服务ID
|
||||||
RegionId any // 区域ID
|
RegionId any // 区域ID
|
||||||
|
UserPlanId any // 用户套餐ID
|
||||||
Day any // 日期YYYYMMDD
|
Day any // 日期YYYYMMDD
|
||||||
TimeAt any // 时间点HHMM
|
TimeAt any // 时间点HHMM
|
||||||
Bytes any // 带宽字节
|
Bytes any // 带宽字节
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
|
|||||||
|
|
||||||
// 更新流量限制状态
|
// 更新流量限制状态
|
||||||
if stat.CheckTrafficLimiting {
|
if stat.CheckTrafficLimiting {
|
||||||
trafficLimitConfig, err := SharedServerDAO.CalculateServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
|
trafficLimitConfig, err := SharedServerDAO.FindServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = SharedServerDAO.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
|
err = SharedServerDAO.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -140,6 +140,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SumCurrentDailyStat 查找当前时刻的数据统计
|
// SumCurrentDailyStat 查找当前时刻的数据统计
|
||||||
func (this *ServerDailyStatDAO) SumCurrentDailyStat(tx *dbs.Tx, serverId int64) (*ServerDailyStat, error) {
|
func (this *ServerDailyStatDAO) SumCurrentDailyStat(tx *dbs.Tx, serverId int64) (*ServerDailyStat, error) {
|
||||||
var day = timeutil.Format("Ymd")
|
var day = timeutil.Format("Ymd")
|
||||||
@@ -164,7 +165,7 @@ func (this *ServerDailyStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId
|
|||||||
if regionId > 0 {
|
if regionId > 0 {
|
||||||
query.Attr("regionId", regionId)
|
query.Attr("regionId", regionId)
|
||||||
}
|
}
|
||||||
return query.Between("day", month+"01", month+"32").
|
return query.Between("day", month+"01", month+"31").
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
SumInt64("bytes", 0)
|
SumInt64("bytes", 0)
|
||||||
}
|
}
|
||||||
@@ -178,7 +179,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyWithoutPlan(tx *dbs.Tx, userId int
|
|||||||
}
|
}
|
||||||
return query.
|
return query.
|
||||||
Attr("planId", 0).
|
Attr("planId", 0).
|
||||||
Between("day", month+"01", month+"32").
|
Between("day", month+"01", month+"31").
|
||||||
Attr("userId", userId).
|
Attr("userId", userId).
|
||||||
SumInt64("bytes", 0)
|
SumInt64("bytes", 0)
|
||||||
}
|
}
|
||||||
@@ -190,7 +191,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, reg
|
|||||||
if regionId > 0 {
|
if regionId > 0 {
|
||||||
query.Attr("regionId", regionId)
|
query.Attr("regionId", regionId)
|
||||||
}
|
}
|
||||||
max, err := query.Between("day", month+"01", month+"32").
|
max, err := query.Between("day", month+"01", month+"31").
|
||||||
Attr("userId", userId).
|
Attr("userId", userId).
|
||||||
Max("bytes", 0)
|
Max("bytes", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -644,7 +645,7 @@ func (this *ServerDailyStatDAO) FindStatsBetweenDays(tx *dbs.Tx, userId int64, s
|
|||||||
// month YYYYMM
|
// month YYYYMM
|
||||||
func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month string) (result []*ServerDailyStat, err error) {
|
func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month string) (result []*ServerDailyStat, err error) {
|
||||||
_, err = this.Query(tx).
|
_, err = this.Query(tx).
|
||||||
Between("day", month+"01", month+"32").
|
Between("day", month+"01", month+"31").
|
||||||
Gt("planId", 0).
|
Gt("planId", 0).
|
||||||
Slice(&result).
|
Slice(&result).
|
||||||
FindAll()
|
FindAll()
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package models
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
@@ -782,7 +784,7 @@ func (this *ServerDAO) CountAllEnabledServers(tx *dbs.Tx) (int64, error) {
|
|||||||
// 参数:
|
// 参数:
|
||||||
//
|
//
|
||||||
// groupId 分组ID,如果为-1,则搜索没有分组的服务
|
// groupId 分组ID,如果为-1,则搜索没有分组的服务
|
||||||
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string) (int64, error) {
|
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string, userPlanId int64) (int64, error) {
|
||||||
query := this.Query(tx).
|
query := this.Query(tx).
|
||||||
State(ServerStateEnabled)
|
State(ServerStateEnabled)
|
||||||
if groupId > 0 {
|
if groupId > 0 {
|
||||||
@@ -829,6 +831,10 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
|
|||||||
query.Where("(" + strings.Join(protocolConds, " OR ") + ")")
|
query.Where("(" + strings.Join(protocolConds, " OR ") + ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userPlanId > 0 {
|
||||||
|
query.Attr("userPlanId", userPlanId)
|
||||||
|
}
|
||||||
|
|
||||||
return query.Count()
|
return query.Count()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1316,12 +1322,13 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 套餐是否依然有效
|
// 套餐是否依然有效
|
||||||
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
|
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if plan != nil {
|
if plan != nil {
|
||||||
config.UserPlan = &serverconfigs.UserPlanConfig{
|
config.UserPlan = &serverconfigs.UserPlanConfig{
|
||||||
|
Id: int64(userPlan.Id),
|
||||||
DayTo: userPlan.DayTo,
|
DayTo: userPlan.DayTo,
|
||||||
Plan: &serverconfigs.PlanConfig{
|
Plan: &serverconfigs.PlanConfig{
|
||||||
Id: int64(plan.Id),
|
Id: int64(plan.Id),
|
||||||
@@ -1341,16 +1348,14 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TrafficLimit != nil && config.TrafficLimit.IsOn && !config.TrafficLimit.IsEmpty() {
|
if len(server.TrafficLimitStatus) > 0 {
|
||||||
if len(server.TrafficLimitStatus) > 0 {
|
var status = &serverconfigs.TrafficLimitStatus{}
|
||||||
var status = &serverconfigs.TrafficLimitStatus{}
|
err := json.Unmarshal(server.TrafficLimitStatus, status)
|
||||||
err := json.Unmarshal(server.TrafficLimitStatus, status)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
if status.IsValid() {
|
||||||
if status.IsValid() {
|
config.TrafficLimitStatus = status
|
||||||
config.TrafficLimitStatus = status
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1794,6 +1799,7 @@ func (this *ServerDAO) FindServerUserId(tx *dbs.Tx, serverId int64) (userId int6
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindServerUserPlanId 查找服务的套餐ID
|
// FindServerUserPlanId 查找服务的套餐ID
|
||||||
|
// TODO 需要缓存
|
||||||
func (this *ServerDAO) FindServerUserPlanId(tx *dbs.Tx, serverId int64) (userPlanId int64, err error) {
|
func (this *ServerDAO) FindServerUserPlanId(tx *dbs.Tx, serverId int64) (userPlanId int64, err error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Pk(serverId).
|
Pk(serverId).
|
||||||
@@ -2306,94 +2312,17 @@ func (this *ServerDAO) FindServerTrafficLimitConfig(tx *dbs.Tx, serverId int64,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var limit = &serverconfigs.TrafficLimitConfig{}
|
|
||||||
if serverOne == nil {
|
|
||||||
return limit, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var trafficLimit = serverOne.(*Server).TrafficLimit
|
|
||||||
|
|
||||||
if len(trafficLimit) > 0 {
|
|
||||||
err = json.Unmarshal([]byte(trafficLimit), limit)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cacheMap != nil {
|
|
||||||
cacheMap.Put(cacheKey, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return limit, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CalculateServerTrafficLimitConfig 计算服务的流量限制
|
|
||||||
// TODO 优化性能
|
|
||||||
func (this *ServerDAO) CalculateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64, cacheMap *utils.CacheMap) (*serverconfigs.TrafficLimitConfig, error) {
|
|
||||||
if cacheMap == nil {
|
|
||||||
cacheMap = utils.NewCacheMap()
|
|
||||||
}
|
|
||||||
var cacheKey = this.Table + ":FindServerTrafficLimitConfig:" + types.String(serverId)
|
|
||||||
result, ok := cacheMap.Get(cacheKey)
|
|
||||||
if ok {
|
|
||||||
return result.(*serverconfigs.TrafficLimitConfig), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
serverOne, err := this.Query(tx).
|
|
||||||
Pk(serverId).
|
|
||||||
Result("trafficLimit", "userPlanId").
|
|
||||||
Find()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var limitConfig = &serverconfigs.TrafficLimitConfig{}
|
var limitConfig = &serverconfigs.TrafficLimitConfig{}
|
||||||
if serverOne == nil {
|
if serverOne == nil {
|
||||||
return limitConfig, nil
|
return limitConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var trafficLimit = serverOne.(*Server).TrafficLimit
|
var trafficLimitJSON = serverOne.(*Server).TrafficLimit
|
||||||
var userPlanId = int64(serverOne.(*Server).UserPlanId)
|
|
||||||
|
|
||||||
if len(trafficLimit) == 0 {
|
if len(trafficLimitJSON) > 0 {
|
||||||
if userPlanId > 0 {
|
err = json.Unmarshal(trafficLimitJSON, limitConfig)
|
||||||
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if userPlan != nil {
|
|
||||||
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if planLimit != nil {
|
|
||||||
return planLimit, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return limitConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(trafficLimit, limitConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !limitConfig.IsOn {
|
|
||||||
if userPlanId > 0 {
|
|
||||||
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if userPlan != nil {
|
|
||||||
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if planLimit != nil {
|
|
||||||
return planLimit, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2423,11 +2352,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新状态
|
// 更新状态
|
||||||
return this.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
|
return this.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServerTrafficLimitStatus 修改服务的流量限制状态
|
// RenewServerTrafficLimitStatus 根据限流配置更新网站的流量限制状态
|
||||||
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
|
func (this *ServerDAO) RenewServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
|
||||||
if !trafficLimitConfig.IsOn {
|
if !trafficLimitConfig.IsOn {
|
||||||
if isUpdatingConfig {
|
if isUpdatingConfig {
|
||||||
return this.NotifyUpdate(tx, serverId)
|
return this.NotifyUpdate(tx, serverId)
|
||||||
@@ -2464,9 +2393,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
|
|||||||
var untilDay = ""
|
var untilDay = ""
|
||||||
|
|
||||||
// daily
|
// daily
|
||||||
|
var dateType = ""
|
||||||
if trafficLimitConfig.DailyBytes() > 0 {
|
if trafficLimitConfig.DailyBytes() > 0 {
|
||||||
if server.TrafficDay == timeutil.Format("Ymd") && server.TotalDailyTraffic >= float64(trafficLimitConfig.DailyBytes())/(1<<30) {
|
if server.TrafficDay == timeutil.Format("Ymd") && server.TotalDailyTraffic >= float64(trafficLimitConfig.DailyBytes())/(1<<30) {
|
||||||
untilDay = timeutil.Format("Ymd")
|
untilDay = timeutil.Format("Ymd")
|
||||||
|
dateType = "day"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2474,6 +2405,7 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
|
|||||||
if server.TrafficMonth == timeutil.Format("Ym") && trafficLimitConfig.MonthlyBytes() > 0 {
|
if server.TrafficMonth == timeutil.Format("Ym") && trafficLimitConfig.MonthlyBytes() > 0 {
|
||||||
if server.TotalMonthlyTraffic >= float64(trafficLimitConfig.MonthlyBytes())/(1<<30) {
|
if server.TotalMonthlyTraffic >= float64(trafficLimitConfig.MonthlyBytes())/(1<<30) {
|
||||||
untilDay = timeutil.Format("Ym32")
|
untilDay = timeutil.Format("Ym32")
|
||||||
|
dateType = "month"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2481,12 +2413,17 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
|
|||||||
if trafficLimitConfig.TotalBytes() > 0 {
|
if trafficLimitConfig.TotalBytes() > 0 {
|
||||||
if server.TotalTraffic >= float64(trafficLimitConfig.TotalBytes())/(1<<30) {
|
if server.TotalTraffic >= float64(trafficLimitConfig.TotalBytes())/(1<<30) {
|
||||||
untilDay = "30000101"
|
untilDay = "30000101"
|
||||||
|
dateType = "total"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isChanged = oldStatus.UntilDay != untilDay
|
var isChanged = oldStatus.UntilDay != untilDay
|
||||||
if isChanged {
|
if isChanged {
|
||||||
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{UntilDay: untilDay})
|
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{
|
||||||
|
UntilDay: untilDay,
|
||||||
|
DateType: dateType,
|
||||||
|
TargetType: serverconfigs.TrafficLimitTargetTraffic,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2507,6 +2444,91 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateServerTrafficLimitStatus 修改网站的流量限制状态
|
||||||
|
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, serverId int64, day string, planId int64, dateType string, targetType string) error {
|
||||||
|
if !regexputils.YYYYMMDD.MatchString(day) {
|
||||||
|
return errors.New("invalid 'day' format")
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup old status
|
||||||
|
statusJSON, err := this.Query(tx).
|
||||||
|
Pk(serverId).
|
||||||
|
Result(ServerField_TrafficLimitStatus).
|
||||||
|
FindJSONCol()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsNotNull(statusJSON) {
|
||||||
|
var oldStatus = &serverconfigs.TrafficLimitStatus{}
|
||||||
|
err = json.Unmarshal(statusJSON, oldStatus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(oldStatus.UntilDay) > 0 && oldStatus.UntilDay >= day /** 如果已经限制,且比当前日期长,则无需重复 **/ {
|
||||||
|
// no need to change
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = &serverconfigs.TrafficLimitStatus{
|
||||||
|
UntilDay: day,
|
||||||
|
PlanId: planId,
|
||||||
|
DateType: dateType,
|
||||||
|
TargetType: targetType,
|
||||||
|
}
|
||||||
|
statusJSON, err = json.Marshal(status)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = this.Query(tx).
|
||||||
|
Pk(serverId).
|
||||||
|
Set(ServerField_TrafficLimitStatus, statusJSON).
|
||||||
|
UpdateQuickly()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return this.NotifyUpdate(tx, serverId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateServersTrafficLimitStatusWithUserPlanId 修改某个套餐下的网站的流量限制状态
|
||||||
|
func (this *ServerDAO) UpdateServersTrafficLimitStatusWithUserPlanId(tx *dbs.Tx, userPlanId int64, day string, planId int64, dateType string, targetType serverconfigs.TrafficLimitTarget) error {
|
||||||
|
if userPlanId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
servers, err := this.Query(tx).
|
||||||
|
State(ServerStateEnabled).
|
||||||
|
Attr("userPlanId", userPlanId).
|
||||||
|
ResultPk().
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, server := range servers {
|
||||||
|
var serverId = int64(server.(*Server).Id)
|
||||||
|
err = this.UpdateServerTrafficLimitStatus(tx, serverId, day, planId, dateType, targetType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetServersTrafficLimitStatusWithPlanId 重置网站限流状态
|
||||||
|
func (this *ServerDAO) ResetServersTrafficLimitStatusWithPlanId(tx *dbs.Tx, planId int64) error {
|
||||||
|
return this.Query(tx).
|
||||||
|
Where("JSON_EXTRACT(trafficLimitStatus, '$.planId')=:planId").
|
||||||
|
Param("planId", planId).
|
||||||
|
Set("trafficLimitStatus", dbs.SQL("NULL")).
|
||||||
|
UpdateQuickly()
|
||||||
|
}
|
||||||
|
|
||||||
// IncreaseServerTotalTraffic 增加服务的总流量
|
// IncreaseServerTotalTraffic 增加服务的总流量
|
||||||
func (this *ServerDAO) IncreaseServerTotalTraffic(tx *dbs.Tx, serverId int64, bytes int64) error {
|
func (this *ServerDAO) IncreaseServerTotalTraffic(tx *dbs.Tx, serverId int64, bytes int64) error {
|
||||||
if serverId <= 0 {
|
if serverId <= 0 {
|
||||||
@@ -2548,17 +2570,16 @@ func (this *ServerDAO) FindEnabledServerIdWithUserPlanId(tx *dbs.Tx, userPlanId
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindEnabledServerWithUserPlanId 查找使用某个套餐的服务
|
// FindEnabledServersWithUserPlanId 查找使用某个套餐的网站
|
||||||
func (this *ServerDAO) FindEnabledServerWithUserPlanId(tx *dbs.Tx, userPlanId int64) (*Server, error) {
|
func (this *ServerDAO) FindEnabledServersWithUserPlanId(tx *dbs.Tx, userPlanId int64) (result []*Server, err error) {
|
||||||
one, err := this.Query(tx).
|
_, err = this.Query(tx).
|
||||||
State(ServerStateEnabled).
|
State(ServerStateEnabled).
|
||||||
Attr("userPlanId", userPlanId).
|
Attr("userPlanId", userPlanId).
|
||||||
Result("id", "name", "serverNames", "type").
|
Result("id", "name", "serverNames", "type").
|
||||||
Find()
|
AscPk().
|
||||||
if err != nil || one == nil {
|
Slice(&result).
|
||||||
return nil, err
|
FindAll()
|
||||||
}
|
return
|
||||||
return one.(*Server), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServersClusterIdWithPlanId 修改套餐所在集群
|
// UpdateServersClusterIdWithPlanId 修改套餐所在集群
|
||||||
@@ -2643,7 +2664,7 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
|
|||||||
return errors.New("can not find user plan with id '" + types.String(userPlanId) + "'")
|
return errors.New("can not find user plan with id '" + types.String(userPlanId) + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
|
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2881,6 +2902,89 @@ func (this *ServerDAO) FindEnabledServersWithIds(tx *dbs.Tx, serverIds []int64)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountAllServerNamesWithUserId 计算某个用户下的所有域名数
|
||||||
|
func (this *ServerDAO) CountAllServerNamesWithUserId(tx *dbs.Tx, userId int64, userPlanId int64) (int64, error) {
|
||||||
|
if userId <= 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = this.Query(tx).
|
||||||
|
Attr("userId", userId).
|
||||||
|
State(ServerStateEnabled).
|
||||||
|
Where("JSON_TYPE(plainServerNames)='ARRAY'")
|
||||||
|
if userPlanId > 0 {
|
||||||
|
query.Attr("userPlanId", userPlanId)
|
||||||
|
}
|
||||||
|
return query.
|
||||||
|
SumInt64("JSON_LENGTH(plainServerNames)", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountServerNames 计算某个网站下的所有域名数
|
||||||
|
func (this *ServerDAO) CountServerNames(tx *dbs.Tx, serverId int64) (int64, error) {
|
||||||
|
if serverId <= 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Query(tx).
|
||||||
|
Result("JSON_LENGTH(plainServerNames)").
|
||||||
|
Pk(serverId).
|
||||||
|
State(ServerStateEnabled).
|
||||||
|
Where("JSON_TYPE(plainServerNames)='ARRAY'").
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckServerPlanQuota 检查网站套餐限制
|
||||||
|
func (this *ServerDAO) CheckServerPlanQuota(tx *dbs.Tx, serverId int64, countServerNames int) error {
|
||||||
|
if serverId <= 0 {
|
||||||
|
return errors.New("invalid 'serverId'")
|
||||||
|
}
|
||||||
|
if countServerNames <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userPlanId, err := this.FindServerUserPlanId(tx, serverId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if userPlanId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if userPlan == nil {
|
||||||
|
return fmt.Errorf("invalid user plan with id %q", types.String(userPlanId))
|
||||||
|
}
|
||||||
|
if userPlan.IsExpired() {
|
||||||
|
return errors.New("the user plan has been expired")
|
||||||
|
}
|
||||||
|
if userPlan.UserId == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if plan == nil {
|
||||||
|
return fmt.Errorf("invalid plan with id %q", types.String(userPlan.PlanId))
|
||||||
|
}
|
||||||
|
if plan.TotalServerNames > 0 {
|
||||||
|
totalServerNames, err := this.CountAllServerNamesWithUserId(tx, int64(userPlan.UserId), userPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if totalServerNames+int64(countServerNames) > int64(plan.TotalServerNames) {
|
||||||
|
return errors.New("server names over plan quota")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if plan.TotalServerNamesPerServer > 0 {
|
||||||
|
if countServerNames > types.Int(plan.TotalServerNamesPerServer) {
|
||||||
|
return errors.New("server names per server over plan quota")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdate 同步服务所在的集群
|
// NotifyUpdate 同步服务所在的集群
|
||||||
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
|
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
|
||||||
if serverId <= 0 {
|
if serverId <= 0 {
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ func TestServerDAO_FindEnabledServerWithDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
|
func TestServerDAO_RenewServerTrafficLimitStatus(t *testing.T) {
|
||||||
dbs.NotifyReady()
|
dbs.NotifyReady()
|
||||||
|
|
||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
@@ -250,7 +250,7 @@ func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||||
}()
|
}()
|
||||||
err := models.NewServerDAO().UpdateServerTrafficLimitStatus(tx, &serverconfigs.TrafficLimitConfig{
|
err := models.NewServerDAO().RenewServerTrafficLimitStatus(tx, &serverconfigs.TrafficLimitConfig{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
DailySize: &shared.SizeCapacity{Count: 1, Unit: "mb"},
|
DailySize: &shared.SizeCapacity{Count: 1, Unit: "mb"},
|
||||||
MonthlySize: &shared.SizeCapacity{Count: 10, Unit: "mb"},
|
MonthlySize: &shared.SizeCapacity{Count: 10, Unit: "mb"},
|
||||||
@@ -263,40 +263,15 @@ func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
|
|||||||
t.Log("ok")
|
t.Log("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerDAO_CalculateServerTrafficLimitConfig(t *testing.T) {
|
func TestServerDAO_UpdateServerTrafficLimitStatus(t *testing.T) {
|
||||||
dbs.NotifyReady()
|
dbs.NotifyReady()
|
||||||
|
|
||||||
|
var dao = models.NewServerDAO()
|
||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
before := time.Now()
|
err := dao.UpdateServerTrafficLimitStatus(tx, 23, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 20)), 14, "day", "traffic")
|
||||||
defer func() {
|
|
||||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
|
||||||
}()
|
|
||||||
|
|
||||||
var cacheMap = utils.NewCacheMap()
|
|
||||||
config, err := models.SharedServerDAO.CalculateServerTrafficLimitConfig(tx, 23, cacheMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
logs.PrintAsJSON(config, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServerDAO_CalculateServerTrafficLimitConfig_Cache(t *testing.T) {
|
|
||||||
dbs.NotifyReady()
|
|
||||||
|
|
||||||
var tx *dbs.Tx
|
|
||||||
before := time.Now()
|
|
||||||
defer func() {
|
|
||||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
|
||||||
}()
|
|
||||||
|
|
||||||
var cacheMap = utils.NewCacheMap()
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
config, err := models.SharedServerDAO.CalculateServerTrafficLimitConfig(tx, 23, cacheMap)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
_ = config
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerDAO_FindBytes(t *testing.T) {
|
func TestServerDAO_FindBytes(t *testing.T) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
@@ -78,7 +79,7 @@ func (this *Server) DecodeHTTPSPorts() (ports []int) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,7 @@ func (this *Server) DecodeTLSPorts() (ports []int) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ func (this *SSLCertDAO) buildDomainSearchingQuery(query *dbs.Query, domains []st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检测 JSON_OVERLAPS() 函数是否可用
|
// 检测 JSON_OVERLAPS() 函数是否可用
|
||||||
var canJSONOverlaps = false
|
var canJSONOverlaps bool
|
||||||
_, funcErr := this.Instance.FindCol(0, "SELECT JSON_OVERLAPS('[1]', '[1]')")
|
_, funcErr := this.Instance.FindCol(0, "SELECT JSON_OVERLAPS('[1]', '[1]')")
|
||||||
canJSONOverlaps = funcErr == nil
|
canJSONOverlaps = funcErr == nil
|
||||||
if canJSONOverlaps {
|
if canJSONOverlaps {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func TestServerDomainHourlyStatDAO_FindTopDomainStats(t *testing.T) {
|
|||||||
|
|
||||||
func TestServerDomainHourlyStatDAO_Clean(t *testing.T) {
|
func TestServerDomainHourlyStatDAO_Clean(t *testing.T) {
|
||||||
var dao = NewServerDomainHourlyStatDAO()
|
var dao = NewServerDomainHourlyStatDAO()
|
||||||
err := dao.Clean(nil, 10)
|
err := dao.CleanDays(nil, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/zero"
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
@@ -14,10 +13,6 @@ import (
|
|||||||
|
|
||||||
type SysLockerDAO dbs.DAO
|
type SysLockerDAO dbs.DAO
|
||||||
|
|
||||||
// concurrent transactions control
|
|
||||||
// 考虑到存在多个API节点的可能性,容量不能太大,也不能使用mutex
|
|
||||||
var sysLockerConcurrentLimiter = make(chan zero.Zero, 8)
|
|
||||||
|
|
||||||
func NewSysLockerDAO() *SysLockerDAO {
|
func NewSysLockerDAO() *SysLockerDAO {
|
||||||
return dbs.NewDAO(&SysLockerDAO{
|
return dbs.NewDAO(&SysLockerDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -71,7 +66,7 @@ func (this *SysLockerDAO) Lock(tx *dbs.Tx, key string, timeout int64) (ok bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果已经有锁
|
// 如果已经有锁
|
||||||
locker := one.(*SysLocker)
|
var locker = one.(*SysLocker)
|
||||||
if time.Now().Unix() <= int64(locker.TimeoutAt) {
|
if time.Now().Unix() <= int64(locker.TimeoutAt) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@@ -102,7 +97,7 @@ func (this *SysLockerDAO) Lock(tx *dbs.Tx, key string, timeout int64) (ok bool,
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if types.Int64(version) != int64(locker.Version)+1 {
|
if types.Int64(version) > int64(locker.Version)+1 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +114,10 @@ func (this *SysLockerDAO) Unlock(tx *dbs.Tx, key string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sysLockerStep = 8
|
||||||
|
|
||||||
|
var increment = NewSysLockerIncrement(sysLockerStep)
|
||||||
|
|
||||||
// Increase 增加版本号
|
// Increase 增加版本号
|
||||||
func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (int64, error) {
|
func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (int64, error) {
|
||||||
// validate key
|
// validate key
|
||||||
@@ -130,10 +129,22 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
|
|||||||
var result int64
|
var result int64
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
sysLockerConcurrentLimiter <- zero.Zero{} // push
|
{
|
||||||
defer func() {
|
colValue, err := this.Query(tx).
|
||||||
<-sysLockerConcurrentLimiter // pop
|
Result("version").
|
||||||
}()
|
Attr("key", key).
|
||||||
|
FindInt64Col(0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var lastVersion = types.Int64(colValue)
|
||||||
|
if lastVersion <= increment.MaxValue(key) {
|
||||||
|
value, ok := increment.Pop(key)
|
||||||
|
if ok {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = this.Instance.RunTx(func(tx *dbs.Tx) error {
|
err = this.Instance.RunTx(func(tx *dbs.Tx) error {
|
||||||
result, err = this.Increase(tx, key, defaultValue)
|
result, err = this.Increase(tx, key, defaultValue)
|
||||||
@@ -146,16 +157,20 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// combine statements to make increasing faster
|
// combine statements to make increasing faster
|
||||||
colValue, err := tx.FindCol(0, "INSERT INTO `"+this.Table+"` (`key`, `version`) VALUES ('"+key+"', "+types.String(defaultValue)+") ON DUPLICATE KEY UPDATE `version`=`version`+1; SELECT `version` FROM `"+this.Table+"` WHERE `key`='"+key+"'")
|
colValue, err := tx.FindCol(0, "INSERT INTO `"+this.Table+"` (`key`, `version`) VALUES ('"+key+"', "+types.String(defaultValue+sysLockerStep)+") ON DUPLICATE KEY UPDATE `version`=`version`+"+types.String(sysLockerStep)+"; SELECT `version` FROM `"+this.Table+"` WHERE `key`='"+key+"'")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if CheckSQLErrCode(err, 1064 /** syntax error **/) {
|
if CheckSQLErrCode(err, 1064 /** syntax error **/) {
|
||||||
// continue to use seperated query
|
// continue to use separated query
|
||||||
err = nil
|
err = nil
|
||||||
} else {
|
} else {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return types.Int64(colValue), nil
|
var maxVersion = types.Int64(colValue)
|
||||||
|
var minVersion = maxVersion - sysLockerStep + 1
|
||||||
|
increment.Push(key, minVersion+1, maxVersion)
|
||||||
|
|
||||||
|
return minVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = this.Query(tx).
|
err = this.Query(tx).
|
||||||
|
|||||||
@@ -43,12 +43,54 @@ func TestSysLocker_Increase_SQL(t *testing.T) {
|
|||||||
t.Log("after:", v)
|
t.Log("after:", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSysLocker_Increase_New_Key(t *testing.T) {
|
||||||
|
var key = "KEY" + types.String(time.Now().Unix())
|
||||||
|
|
||||||
|
var dao = NewSysLockerDAO()
|
||||||
|
value, err := dao.Read(nil, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("before:", value)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
v, err := dao.Increase(nil, key, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Log("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log("after:", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSysLocker_Increase_Cache(t *testing.T) {
|
||||||
|
var dao = NewSysLockerDAO()
|
||||||
|
for i := 0; i < 11; i++ {
|
||||||
|
v, err := dao.Increase(nil, "hello", 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Log("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log("hello", i, "after:", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 11; i++ {
|
||||||
|
v, err := dao.Increase(nil, "hello2", 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Log("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log("hello2", i, "after:", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSysLocker_Increase(t *testing.T) {
|
func TestSysLocker_Increase(t *testing.T) {
|
||||||
dbs.NotifyReady()
|
dbs.NotifyReady()
|
||||||
|
|
||||||
|
var dao = NewSysLockerDAO()
|
||||||
|
dao.Instance.Raw().SetMaxOpenConns(64)
|
||||||
|
|
||||||
var count = 1000
|
var count = 1000
|
||||||
|
|
||||||
var dao = NewSysLockerDAO()
|
|
||||||
value, err := dao.Read(nil, "hello")
|
value, err := dao.Read(nil, "hello")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -133,6 +175,8 @@ func TestSysLocker_Increase_Performance(t *testing.T) {
|
|||||||
|
|
||||||
func BenchmarkSysLockerDAO_Increase(b *testing.B) {
|
func BenchmarkSysLockerDAO_Increase(b *testing.B) {
|
||||||
var dao = NewSysLockerDAO()
|
var dao = NewSysLockerDAO()
|
||||||
|
dao.Instance.Raw().SetMaxOpenConns(64)
|
||||||
|
|
||||||
_, _ = dao.Increase(nil, "hello", 0)
|
_, _ = dao.Increase(nil, "hello", 0)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|||||||
110
internal/db/models/sys_locker_increment.go
Normal file
110
internal/db/models/sys_locker_increment.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SysLockerIncrementItem struct {
|
||||||
|
size int
|
||||||
|
c chan int64
|
||||||
|
maxValue int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSysLockerIncrementItem(size int) *SysLockerIncrementItem {
|
||||||
|
if size <= 0 {
|
||||||
|
size = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SysLockerIncrementItem{
|
||||||
|
size: size,
|
||||||
|
c: make(chan int64, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrementItem) Pop() (result int64, ok bool) {
|
||||||
|
select {
|
||||||
|
case v := <-this.c:
|
||||||
|
result = v
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrementItem) Push(value int64) {
|
||||||
|
if this.maxValue < value {
|
||||||
|
this.maxValue = value
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case this.c <- value:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrementItem) Reset() {
|
||||||
|
close(this.c)
|
||||||
|
this.c = make(chan int64, this.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrementItem) MaxValue() int64 {
|
||||||
|
return this.maxValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type SysLockerIncrement struct {
|
||||||
|
itemMap map[string]*SysLockerIncrementItem // key => item
|
||||||
|
size int
|
||||||
|
locker sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSysLockerIncrement(size int) *SysLockerIncrement {
|
||||||
|
if size <= 0 {
|
||||||
|
size = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SysLockerIncrement{
|
||||||
|
itemMap: map[string]*SysLockerIncrementItem{},
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrement) Pop(key string) (result int64, ok bool) {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
item, itemOk := this.itemMap[key]
|
||||||
|
if itemOk {
|
||||||
|
result, ok = item.Pop()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrement) Push(key string, minValue int64, maxValue int64) {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
item, itemOk := this.itemMap[key]
|
||||||
|
if itemOk {
|
||||||
|
item.Reset()
|
||||||
|
} else {
|
||||||
|
item = NewSysLockerIncrementItem(this.size)
|
||||||
|
this.itemMap[key] = item
|
||||||
|
}
|
||||||
|
for i := minValue; i <= maxValue; i++ {
|
||||||
|
item.Push(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SysLockerIncrement) MaxValue(key string) int64 {
|
||||||
|
this.locker.RLock()
|
||||||
|
defer this.locker.RUnlock()
|
||||||
|
|
||||||
|
item, itemOk := this.itemMap[key]
|
||||||
|
if itemOk {
|
||||||
|
return item.MaxValue()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
23
internal/db/models/sys_locker_increment_test.go
Normal file
23
internal/db/models/sys_locker_increment_test.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewSysLockerIncrement(t *testing.T) {
|
||||||
|
var increment = models.NewSysLockerIncrement(10)
|
||||||
|
increment.Push("key", 1, 10)
|
||||||
|
t.Log(increment.MaxValue("key"))
|
||||||
|
for i := 0; i < 11; i++ {
|
||||||
|
result, value := increment.Pop("key")
|
||||||
|
t.Log(i, "=>", result, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 11; i++ {
|
||||||
|
result, value := increment.Pop("key1")
|
||||||
|
t.Log(i, "=>", result, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -522,16 +522,6 @@ func (this *UserBandwidthStatDAO) sumBytesField(useAvg bool) string {
|
|||||||
return "SUM(bytes) AS bytes"
|
return "SUM(bytes) AS bytes"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UserBandwidthStatDAO) fixUserStat(stat *UserBandwidthStat, useAvg bool) *UserBandwidthStat {
|
|
||||||
if stat == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if useAvg {
|
|
||||||
stat.Bytes = stat.AvgBytes
|
|
||||||
}
|
|
||||||
return stat
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasFullData 检查一个月是否完整数据
|
// HasFullData 检查一个月是否完整数据
|
||||||
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
|
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
|
||||||
func (this *UserBandwidthStatDAO) HasFullData(tx *dbs.Tx, userId int64, month string) (bool, error) {
|
func (this *UserBandwidthStatDAO) HasFullData(tx *dbs.Tx, userId int64, month string) (bool, error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
@@ -36,7 +37,7 @@ func (this *UserNode) DecodeHTTPS(cacheMap *utils.CacheMap) (*serverconfigs.HTTP
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -54,7 +55,7 @@ func (this *UserNode) DecodeHTTPS(cacheMap *utils.CacheMap) (*serverconfigs.HTTP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Init(nil)
|
err = config.Init(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
239
internal/db/models/user_plan_bandwidth_stat_dao.go
Normal file
239
internal/db/models/user_plan_bandwidth_stat_dao.go
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserPlanBandwidthStatDAO dbs.DAO
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserPlanBandwidthStatTablePartitions = 20 // 分表数量
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||||
|
goman.New(func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedUserPlanBandwidthStatDAO.CleanDefaultDays(nil, 100)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("SharedUserPlanBandwidthStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserPlanBandwidthStatDAO() *UserPlanBandwidthStatDAO {
|
||||||
|
return dbs.NewDAO(&UserPlanBandwidthStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserPlanBandwidthStats",
|
||||||
|
Model: new(UserPlanBandwidthStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserPlanBandwidthStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserPlanBandwidthStatDAO *UserPlanBandwidthStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserPlanBandwidthStatDAO = NewUserPlanBandwidthStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserPlanBandwidth 写入数据
|
||||||
|
// 暂时不使用region区分
|
||||||
|
func (this *UserPlanBandwidthStatDAO) UpdateUserPlanBandwidth(tx *dbs.Tx, userId int64, userPlanId int64, regionId int64, day string, timeAt string, bandwidthBytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
|
||||||
|
if userId <= 0 || userPlanId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Query(tx).
|
||||||
|
Table(this.partialTable(userPlanId)).
|
||||||
|
Param("bytes", bandwidthBytes).
|
||||||
|
Param("totalBytes", totalBytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("attackBytes", attackBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
|
Param("countAttackRequests", countAttackRequests).
|
||||||
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"userId": userId,
|
||||||
|
"userPlanId": userPlanId,
|
||||||
|
"regionId": regionId,
|
||||||
|
"day": day,
|
||||||
|
"timeAt": timeAt,
|
||||||
|
"bytes": bandwidthBytes,
|
||||||
|
"totalBytes": totalBytes,
|
||||||
|
"avgBytes": totalBytes / 300,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"attackBytes": attackBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
|
"countAttackRequests": countAttackRequests,
|
||||||
|
}, maps.Map{
|
||||||
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前,所以这里不用担心先后顺序的问题
|
||||||
|
"totalBytes": dbs.SQL("totalBytes+:totalBytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"attackBytes": dbs.SQL("attackBytes+:attackBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
|
"countAttackRequests": dbs.SQL("countAttackRequests+:countAttackRequests"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMonthlyPercentile 获取某月内百分位
|
||||||
|
func (this *UserPlanBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, userPlanId int64, month string, percentile int, useAvg bool) (result int64, err error) {
|
||||||
|
if percentile <= 0 {
|
||||||
|
percentile = 95
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是100%以上,则快速返回
|
||||||
|
if percentile >= 100 {
|
||||||
|
result, err = this.Query(tx).
|
||||||
|
Table(this.partialTable(userPlanId)).
|
||||||
|
Attr("userPlanId", userPlanId).
|
||||||
|
Result(this.sumBytesField(useAvg)).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
Group("day").
|
||||||
|
Group("timeAt").
|
||||||
|
Desc("bytes").
|
||||||
|
Limit(1).
|
||||||
|
FindInt64Col(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总数量
|
||||||
|
total, err := this.Query(tx).
|
||||||
|
Table(this.partialTable(userPlanId)).
|
||||||
|
Attr("userPlanId", userPlanId).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
CountAttr("DISTINCT day, timeAt")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if total == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset int64
|
||||||
|
|
||||||
|
if total > 1 {
|
||||||
|
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 nth 位置
|
||||||
|
result, err = this.Query(tx).
|
||||||
|
Table(this.partialTable(userPlanId)).
|
||||||
|
Attr("userPlanId", userPlanId).
|
||||||
|
Result(this.sumBytesField(useAvg)).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
Group("day").
|
||||||
|
Group("timeAt").
|
||||||
|
Desc("bytes").
|
||||||
|
Offset(offset).
|
||||||
|
Limit(1).
|
||||||
|
FindInt64Col(0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SumMonthlyBytes 读取单月总流量
|
||||||
|
func (this *UserPlanBandwidthStatDAO) SumMonthlyBytes(tx *dbs.Tx, userPlanId int64, month string) (int64, error) {
|
||||||
|
if !regexputils.YYYYMM.MatchString(month) {
|
||||||
|
return 0, errors.New("invalid ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Query(tx).
|
||||||
|
Table(this.partialTable(userPlanId)).
|
||||||
|
Attr("userPlanId", userPlanId).
|
||||||
|
Between("day", month+"01", month+"31").
|
||||||
|
SumInt64("totalBytes", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanDefaultDays 清理过期数据
|
||||||
|
func (this *UserPlanBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
|
||||||
|
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if databaseConfig != nil && databaseConfig.UserPlanBandwidthStat.Clean.Days > 0 {
|
||||||
|
defaultDays = databaseConfig.UserPlanBandwidthStat.Clean.Days
|
||||||
|
}
|
||||||
|
if defaultDays <= 0 {
|
||||||
|
defaultDays = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.CleanDays(tx, defaultDays)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanDays 清理过期数据
|
||||||
|
func (this *UserPlanBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
|
||||||
|
return this.runBatch(func(table string, locker *sync.Mutex) error {
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Table(table).
|
||||||
|
Lt("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字节字段
|
||||||
|
func (this *UserPlanBandwidthStatDAO) bytesField(useAvg bool) string {
|
||||||
|
if useAvg {
|
||||||
|
return "avgBytes AS bytes"
|
||||||
|
}
|
||||||
|
return "bytes"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UserPlanBandwidthStatDAO) sumBytesField(useAvg bool) string {
|
||||||
|
if useAvg {
|
||||||
|
return "SUM(avgBytes) AS bytes"
|
||||||
|
}
|
||||||
|
return "SUM(bytes) AS bytes"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量执行
|
||||||
|
func (this *UserPlanBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
|
||||||
|
var locker = &sync.Mutex{}
|
||||||
|
var wg = sync.WaitGroup{}
|
||||||
|
wg.Add(UserPlanBandwidthStatTablePartitions)
|
||||||
|
var resultErr error
|
||||||
|
for i := 0; i < UserPlanBandwidthStatTablePartitions; i++ {
|
||||||
|
var table = this.partialTable(int64(i))
|
||||||
|
go func(table string) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
err := f(table, locker)
|
||||||
|
if err != nil {
|
||||||
|
resultErr = err
|
||||||
|
}
|
||||||
|
}(table)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return resultErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取分区表
|
||||||
|
func (this *UserPlanBandwidthStatDAO) partialTable(userPlanId int64) string {
|
||||||
|
return this.Table + "_" + types.String(userPlanId%int64(UserPlanBandwidthStatTablePartitions))
|
||||||
|
}
|
||||||
39
internal/db/models/user_plan_bandwidth_stat_dao_test.go
Normal file
39
internal/db/models/user_plan_bandwidth_stat_dao_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserPlanBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
|
||||||
|
var dao = models.NewUserPlanBandwidthStatDAO()
|
||||||
|
var tx *dbs.Tx
|
||||||
|
|
||||||
|
{
|
||||||
|
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 100, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("result bytes0:", resultBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 95, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("result bytes1:", resultBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
resultBytes, err := dao.FindMonthlyPercentile(tx, 20, timeutil.Format("Ym"), 95, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("result bytes2:", resultBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
59
internal/db/models/user_plan_bandwidth_stat_model.go
Normal file
59
internal/db/models/user_plan_bandwidth_stat_model.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserPlanBandwidthStatField_Id dbs.FieldName = "id" // ID
|
||||||
|
UserPlanBandwidthStatField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
UserPlanBandwidthStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
|
||||||
|
UserPlanBandwidthStatField_Day dbs.FieldName = "day" // 日期YYYYMMDD
|
||||||
|
UserPlanBandwidthStatField_TimeAt dbs.FieldName = "timeAt" // 时间点HHII
|
||||||
|
UserPlanBandwidthStatField_Bytes dbs.FieldName = "bytes" // 带宽
|
||||||
|
UserPlanBandwidthStatField_RegionId dbs.FieldName = "regionId" // 区域ID
|
||||||
|
UserPlanBandwidthStatField_TotalBytes dbs.FieldName = "totalBytes" // 总流量
|
||||||
|
UserPlanBandwidthStatField_AvgBytes dbs.FieldName = "avgBytes" // 平均流量
|
||||||
|
UserPlanBandwidthStatField_CachedBytes dbs.FieldName = "cachedBytes" // 缓存的流量
|
||||||
|
UserPlanBandwidthStatField_AttackBytes dbs.FieldName = "attackBytes" // 攻击流量
|
||||||
|
UserPlanBandwidthStatField_CountRequests dbs.FieldName = "countRequests" // 请求数
|
||||||
|
UserPlanBandwidthStatField_CountCachedRequests dbs.FieldName = "countCachedRequests" // 缓存的请求数
|
||||||
|
UserPlanBandwidthStatField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 攻击请求数
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserPlanBandwidthStat 用户套餐带宽峰值
|
||||||
|
type UserPlanBandwidthStat struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
|
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
|
||||||
|
Day string `field:"day"` // 日期YYYYMMDD
|
||||||
|
TimeAt string `field:"timeAt"` // 时间点HHII
|
||||||
|
Bytes uint64 `field:"bytes"` // 带宽
|
||||||
|
RegionId uint32 `field:"regionId"` // 区域ID
|
||||||
|
TotalBytes uint64 `field:"totalBytes"` // 总流量
|
||||||
|
AvgBytes uint64 `field:"avgBytes"` // 平均流量
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存的流量
|
||||||
|
AttackBytes uint64 `field:"attackBytes"` // 攻击流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
||||||
|
CountAttackRequests uint64 `field:"countAttackRequests"` // 攻击请求数
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserPlanBandwidthStatOperator struct {
|
||||||
|
Id any // ID
|
||||||
|
UserId any // 用户ID
|
||||||
|
UserPlanId any // 用户套餐ID
|
||||||
|
Day any // 日期YYYYMMDD
|
||||||
|
TimeAt any // 时间点HHII
|
||||||
|
Bytes any // 带宽
|
||||||
|
RegionId any // 区域ID
|
||||||
|
TotalBytes any // 总流量
|
||||||
|
AvgBytes any // 平均流量
|
||||||
|
CachedBytes any // 缓存的流量
|
||||||
|
AttackBytes any // 攻击流量
|
||||||
|
CountRequests any // 请求数
|
||||||
|
CountCachedRequests any // 缓存的请求数
|
||||||
|
CountAttackRequests any // 攻击请求数
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserPlanBandwidthStatOperator() *UserPlanBandwidthStatOperator {
|
||||||
|
return &UserPlanBandwidthStatOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/user_plan_bandwidth_stat_model_ext.go
Normal file
1
internal/db/models/user_plan_bandwidth_stat_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
@@ -1 +1,8 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
|
||||||
|
// IsExpired 判断套餐是否过期
|
||||||
|
func (this *UserPlan) IsExpired() bool {
|
||||||
|
return len(this.DayTo) == 0 || this.DayTo < timeutil.Format("Y-m-d")
|
||||||
|
}
|
||||||
|
|||||||
28
internal/db/models/user_plan_stat_dao.go
Normal file
28
internal/db/models/user_plan_stat_dao.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserPlanStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserPlanStatDAO() *UserPlanStatDAO {
|
||||||
|
return dbs.NewDAO(&UserPlanStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserPlanStats",
|
||||||
|
Model: new(UserPlanStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserPlanStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserPlanStatDAO *UserPlanStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserPlanStatDAO = NewUserPlanStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
10
internal/db/models/user_plan_stat_dao_community.go
Normal file
10
internal/db/models/user_plan_stat_dao_community.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
func (this *UserPlanStatDAO) IncreaseUserPlanStat(tx *dbs.Tx, userPlanId int64, trafficBytes int64, countRequests int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
6
internal/db/models/user_plan_stat_dao_test.go
Normal file
6
internal/db/models/user_plan_stat_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
38
internal/db/models/user_plan_stat_model.go
Normal file
38
internal/db/models/user_plan_stat_model.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserPlanStatField_Id dbs.FieldName = "id" // ID
|
||||||
|
UserPlanStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
|
||||||
|
UserPlanStatField_Date dbs.FieldName = "date" // 日期:YYYYMMDD或YYYYMM
|
||||||
|
UserPlanStatField_DateType dbs.FieldName = "dateType" // 日期类型:day|month
|
||||||
|
UserPlanStatField_TrafficBytes dbs.FieldName = "trafficBytes" // 流量
|
||||||
|
UserPlanStatField_CountRequests dbs.FieldName = "countRequests" // 总请求数
|
||||||
|
UserPlanStatField_IsProcessed dbs.FieldName = "isProcessed" // 是否已处理
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserPlanStat 用户套餐统计
|
||||||
|
type UserPlanStat struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
|
||||||
|
Date string `field:"date"` // 日期:YYYYMMDD或YYYYMM
|
||||||
|
DateType string `field:"dateType"` // 日期类型:day|month
|
||||||
|
TrafficBytes uint64 `field:"trafficBytes"` // 流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 总请求数
|
||||||
|
IsProcessed bool `field:"isProcessed"` // 是否已处理
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserPlanStatOperator struct {
|
||||||
|
Id any // ID
|
||||||
|
UserPlanId any // 用户套餐ID
|
||||||
|
Date any // 日期:YYYYMMDD或YYYYMM
|
||||||
|
DateType any // 日期类型:day|month
|
||||||
|
TrafficBytes any // 流量
|
||||||
|
CountRequests any // 总请求数
|
||||||
|
IsProcessed any // 是否已处理
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserPlanStatOperator() *UserPlanStatOperator {
|
||||||
|
return &UserPlanStatOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/user_plan_stat_model_ext.go
Normal file
1
internal/db/models/user_plan_stat_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
@@ -61,10 +61,7 @@ func (this *DomainRecordsCache) WriteDomainRecords(providerId int64, domain stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var clonedRecords = []*dnstypes.Record{}
|
var clonedRecords = append([]*dnstypes.Record{}, records...)
|
||||||
for _, record := range records {
|
|
||||||
clonedRecords = append(clonedRecords, record)
|
|
||||||
}
|
|
||||||
this.domainRecordsMap[domain] = &recordList{
|
this.domainRecordsMap[domain] = &recordList{
|
||||||
version: version,
|
version: version,
|
||||||
updatedAt: time.Now().Unix(),
|
updatedAt: time.Now().Unix(),
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package dnsclients
|
package dnsclients
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
"github.com/iwind/TeaGo/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BaseProvider struct{}
|
type BaseProvider struct{}
|
||||||
@@ -18,11 +17,11 @@ func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.R
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var fullname = ""
|
var fullname string
|
||||||
if len(record.Name) == 0 {
|
if len(record.Name) == 0 {
|
||||||
fullname = domain
|
fullname = domain
|
||||||
} else {
|
} else {
|
||||||
fullname = record.Name + "." + domain
|
fullname = record.Name + "." + domain
|
||||||
}
|
}
|
||||||
return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error())
|
return fmt.Errorf("record operation failed: '%s %s %s %d': %w", fullname, record.Type, record.Value, record.TTL, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/cloudflare"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/cloudflare"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
@@ -337,7 +338,7 @@ func (this *CloudFlareProvider) doAPI(method string, apiPath string, args map[st
|
|||||||
|
|
||||||
err = json.Unmarshal(data, respPtr)
|
err = json.Unmarshal(data, respPtr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decode json failed: " + err.Error() + ", response text: " + string(data))
|
return fmt.Errorf("decode json failed: %w, response text: %s", err, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ func (this *CustomHTTPProvider) Auth(params maps.Map) error {
|
|||||||
|
|
||||||
// GetDomains 获取所有域名列表
|
// GetDomains 获取所有域名列表
|
||||||
func (this *CustomHTTPProvider) GetDomains() (domains []string, err error) {
|
func (this *CustomHTTPProvider) GetDomains() (domains []string, err error) {
|
||||||
resp, err := this.post(maps.Map{})
|
resp, err := this.post(maps.Map{
|
||||||
|
"action": "GetDomains",
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -201,7 +203,7 @@ func (this *CustomHTTPProvider) post(params maps.Map) (respData []byte, err erro
|
|||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, errors.New("status should be 200, but got '" + strconv.Itoa(resp.StatusCode) + "'")
|
return nil, errors.New("status should be 200, but got '" + strconv.Itoa(resp.StatusCode) + "'")
|
||||||
}
|
}
|
||||||
return io.ReadAll(resp.Body)
|
return io.ReadAll(resp.Body)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnspod"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnspod"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||||
@@ -380,7 +381,7 @@ func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr
|
|||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, apiHost+path, strings.NewReader(query.Encode()))
|
req, err := http.NewRequest(http.MethodPost, apiHost+path, strings.NewReader(query.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create request failed: " + err.Error())
|
return fmt.Errorf("create request failed: %w", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
req.Header.Set("User-Agent", "GoEdge-Client/1.0.0 (iwind.liu@gmail.com)")
|
req.Header.Set("User-Agent", "GoEdge-Client/1.0.0 (iwind.liu@gmail.com)")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/edgeapi"
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/edgeapi"
|
||||||
@@ -435,6 +436,11 @@ func (this *EdgeDNSAPIProvider) doAPI(path string, params map[string]any, respPt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
if resp.Body != nil {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return errors.New("invalid response status code '" + types.String(resp.StatusCode) + "'")
|
return errors.New("invalid response status code '" + types.String(resp.StatusCode) + "'")
|
||||||
@@ -447,7 +453,7 @@ func (this *EdgeDNSAPIProvider) doAPI(path string, params map[string]any, respPt
|
|||||||
|
|
||||||
err = json.Unmarshal(data, respPtr)
|
err = json.Unmarshal(data, respPtr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decode response failed: " + err.Error() + ", JSON: " + string(data))
|
return fmt.Errorf("decode response failed: %w, JSON: %s", err, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !respPtr.IsValid() {
|
if !respPtr.IsValid() {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ func TestAES128CFBMethod_Encrypt(t *testing.T) {
|
|||||||
dst = dst[:len(src)]
|
dst = dst[:len(src)]
|
||||||
t.Log("dst:", string(dst))
|
t.Log("dst:", string(dst))
|
||||||
|
|
||||||
src = make([]byte, len(src))
|
|
||||||
src, err = method.Decrypt(dst)
|
src, err = method.Decrypt(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -64,7 +63,6 @@ func TestAES128CFBMethod_Encrypt2(t *testing.T) {
|
|||||||
|
|
||||||
for _, dst := range sources {
|
for _, dst := range sources {
|
||||||
dst2 := append([]byte{}, dst...)
|
dst2 := append([]byte{}, dst...)
|
||||||
src2 := make([]byte, len(dst2))
|
|
||||||
src2, err := method.Decrypt(dst2)
|
src2, err := method.Decrypt(dst2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ func (this *DetailedError) Code() string {
|
|||||||
return this.code
|
return this.code
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDetailedError(code string, error string) *DetailedError {
|
func NewDetailedError(code string, errString string) *DetailedError {
|
||||||
return &DetailedError{
|
return &DetailedError{
|
||||||
msg: error,
|
msg: errString,
|
||||||
code: code,
|
code: code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func On(event string, callback func()) {
|
|||||||
locker.Lock()
|
locker.Lock()
|
||||||
defer locker.Unlock()
|
defer locker.Unlock()
|
||||||
|
|
||||||
callbacks, _ := eventsMap[event]
|
var callbacks = eventsMap[event]
|
||||||
callbacks = append(callbacks, callback)
|
callbacks = append(callbacks, callback)
|
||||||
eventsMap[event] = callbacks
|
eventsMap[event] = callbacks
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ func On(event string, callback func()) {
|
|||||||
// Notify 通知事件
|
// Notify 通知事件
|
||||||
func Notify(event string) {
|
func Notify(event string) {
|
||||||
locker.Lock()
|
locker.Lock()
|
||||||
callbacks, _ := eventsMap[event]
|
var callbacks = eventsMap[event]
|
||||||
locker.Unlock()
|
locker.Unlock()
|
||||||
|
|
||||||
for _, callback := range callbacks {
|
for _, callback := range callbacks {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package installers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
@@ -67,7 +68,7 @@ func (this *BaseInstaller) Login(credentials *Credentials) error {
|
|||||||
signer, err = ssh.ParsePrivateKey([]byte(credentials.PrivateKey))
|
signer, err = ssh.ParsePrivateKey([]byte(credentials.PrivateKey))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("parse private key: " + err.Error())
|
return fmt.Errorf("parse private key: %w", err)
|
||||||
}
|
}
|
||||||
authMethod := ssh.PublicKeys(signer)
|
authMethod := ssh.PublicKeys(signer)
|
||||||
methods = append(methods, authMethod)
|
methods = append(methods, authMethod)
|
||||||
@@ -149,8 +150,8 @@ func (this *BaseInstaller) LookupLatestInstaller(filePrefix string) (string, err
|
|||||||
func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.NodeRole) (env *Env, err error) {
|
func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.NodeRole) (env *Env, err error) {
|
||||||
var uname = this.uname()
|
var uname = this.uname()
|
||||||
|
|
||||||
var osName = ""
|
var osName string
|
||||||
var archName = ""
|
var archName string
|
||||||
if strings.Contains(uname, "Darwin") {
|
if strings.Contains(uname, "Darwin") {
|
||||||
osName = "darwin"
|
osName = "darwin"
|
||||||
} else if strings.Contains(uname, "Linux") {
|
} else if strings.Contains(uname, "Linux") {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package installers
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"os"
|
"os"
|
||||||
@@ -24,7 +25,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
}
|
}
|
||||||
err := nodeParams.Validate()
|
err := nodeParams.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("params validation: " + err.Error())
|
return fmt.Errorf("params validation: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查目标目录是否存在
|
// 检查目标目录是否存在
|
||||||
@@ -33,7 +34,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
err = this.client.MkdirAll(dir)
|
err = this.client.MkdirAll(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
installStatus.ErrorCode = "CREATE_ROOT_DIRECTORY_FAILED"
|
installStatus.ErrorCode = "CREATE_ROOT_DIRECTORY_FAILED"
|
||||||
return errors.New("create directory '" + dir + "' failed: " + err.Error())
|
return fmt.Errorf("create directory '%s' failed: %w", dir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if firstCopyErr != nil {
|
if firstCopyErr != nil {
|
||||||
return errors.New("upload node file failed: " + firstCopyErr.Error())
|
return fmt.Errorf("upload node file failed: %w", firstCopyErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试运行环境
|
// 测试运行环境
|
||||||
@@ -82,7 +83,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
if !nodeParams.IsUpgrading {
|
if !nodeParams.IsUpgrading {
|
||||||
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=test")
|
_, stderr, err := this.client.Exec(env.HelperPath + " -cmd=test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("test failed: " + err.Error())
|
return fmt.Errorf("test failed: %w", err)
|
||||||
}
|
}
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
return errors.New("test failed: " + stderr)
|
return errors.New("test failed: " + stderr)
|
||||||
@@ -99,7 +100,7 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
// 删除可执行文件防止冲突
|
// 删除可执行文件防止冲突
|
||||||
err = this.client.Remove(exePath)
|
err = this.client.Remove(exePath)
|
||||||
if err != nil && err != os.ErrNotExist {
|
if err != nil && err != os.ErrNotExist {
|
||||||
return errors.New("remove old file failed: " + err.Error())
|
return fmt.Errorf("remove old file failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,15 +116,14 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
|||||||
|
|
||||||
// 修改配置文件
|
// 修改配置文件
|
||||||
{
|
{
|
||||||
configFile := dir + "/edge-node/configs/api.yaml"
|
var configFile = dir + "/edge-node/configs/api_node.yaml"
|
||||||
|
|
||||||
// sudo之后我们需要修改配置目录才能写入文件
|
// sudo之后我们需要修改配置目录才能写入文件
|
||||||
if this.client.sudo {
|
if this.client.sudo {
|
||||||
_, _, _ = this.client.Exec("chown " + this.client.User() + " " + filepath.Dir(configFile))
|
_, _, _ = this.client.Exec("chown " + this.client.User() + " " + filepath.Dir(configFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = []byte(`rpc:
|
var data = []byte(`rpc.endpoints: [ ${endpoints} ]
|
||||||
endpoints: [ ${endpoints} ]
|
|
||||||
nodeId: "${nodeId}"
|
nodeId: "${nodeId}"
|
||||||
secret: "${nodeSecret}"`)
|
secret: "${nodeSecret}"`)
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ secret: "${nodeSecret}"`)
|
|||||||
|
|
||||||
_, err = this.client.WriteFile(configFile, data)
|
_, err = this.client.WriteFile(configFile, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("write '" + configFile + "': " + err.Error())
|
return fmt.Errorf("write '%s': %w", configFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ secret: "${nodeSecret}"`)
|
|||||||
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node test")
|
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
installStatus.ErrorCode = "TEST_FAILED"
|
installStatus.ErrorCode = "TEST_FAILED"
|
||||||
return errors.New("test edge node failed: " + err.Error() + ", stderr: " + stderr)
|
return fmt.Errorf("test edge node failed: %w, stderr: %s", err, stderr)
|
||||||
}
|
}
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
if regexp.MustCompile(`(?i)rpc`).MatchString(stderr) {
|
if regexp.MustCompile(`(?i)rpc`).MatchString(stderr) {
|
||||||
@@ -154,7 +154,7 @@ secret: "${nodeSecret}"`)
|
|||||||
// 启动
|
// 启动
|
||||||
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node start")
|
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node start")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("start edge node failed: " + err.Error())
|
return fmt.Errorf("start edge node failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
|||||||
for _, apiNode := range apiNodes {
|
for _, apiNode := range apiNodes {
|
||||||
addrConfigs, err := apiNode.DecodeAccessAddrs()
|
addrConfigs, err := apiNode.DecodeAccessAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decode api node access addresses failed: " + err.Error())
|
return fmt.Errorf("decode api node access addresses failed: %w", err)
|
||||||
}
|
}
|
||||||
for _, addrConfig := range addrConfigs {
|
for _, addrConfig := range addrConfigs {
|
||||||
apiEndpoints = append(apiEndpoints, addrConfig.FullAddresses()...)
|
apiEndpoints = append(apiEndpoints, addrConfig.FullAddresses()...)
|
||||||
@@ -320,7 +320,7 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
|||||||
// 执行start
|
// 执行start
|
||||||
_, stderr, err := installer.client.Exec("sudo " + exe + " start")
|
_, stderr, err := installer.client.Exec("sudo " + exe + " start")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("start failed: " + err.Error())
|
return fmt.Errorf("start failed: %w", err)
|
||||||
}
|
}
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
return errors.New("start failed: " + stderr)
|
return errors.New("start failed: " + stderr)
|
||||||
@@ -427,7 +427,7 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
|||||||
// 执行stop
|
// 执行stop
|
||||||
_, stderr, err := installer.client.Exec(exe + " stop")
|
_, stderr, err := installer.client.Exec(exe + " stop")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("stop failed: " + err.Error())
|
return fmt.Errorf("stop failed: %w", err)
|
||||||
}
|
}
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
return errors.New("stop failed: " + stderr)
|
return errors.New("stop failed: " + stderr)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
@@ -285,7 +286,7 @@ func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) err
|
|||||||
this.registerServices(rpcServer)
|
this.registerServices(rpcServer)
|
||||||
err := rpcServer.Serve(listener)
|
err := rpcServer.Serve(listener)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("[API_NODE]start rpc failed: " + err.Error())
|
return fmt.Errorf("[API_NODE]start rpc failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -354,23 +355,23 @@ func (this *APINode) autoUpgrade() error {
|
|||||||
var config = &dbs.Config{}
|
var config = &dbs.Config{}
|
||||||
configData, err := os.ReadFile(Tea.ConfigFile("db.yaml"))
|
configData, err := os.ReadFile(Tea.ConfigFile("db.yaml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("read database config file failed: " + err.Error())
|
return fmt.Errorf("read database config file failed: %w", err)
|
||||||
}
|
}
|
||||||
err = yaml.Unmarshal(configData, config)
|
err = yaml.Unmarshal(configData, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decode database config failed: " + err.Error())
|
return fmt.Errorf("decode database config failed: %w", err)
|
||||||
}
|
}
|
||||||
var dbConfig = config.DBs[Tea.Env]
|
var dbConfig = config.DBs[Tea.Env]
|
||||||
db, err := dbs.NewInstanceFromConfig(dbConfig)
|
db, err := dbs.NewInstanceFromConfig(dbConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("load database failed: " + err.Error())
|
return fmt.Errorf("load database failed: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = db.Close()
|
_ = db.Close()
|
||||||
}()
|
}()
|
||||||
one, err := db.FindOne("SELECT version FROM edgeVersions LIMIT 1")
|
one, err := db.FindOne("SELECT version FROM edgeVersions LIMIT 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query version failed: " + err.Error())
|
return fmt.Errorf("query version failed: %w", err)
|
||||||
}
|
}
|
||||||
if one != nil {
|
if one != nil {
|
||||||
// 如果是同样的版本,则直接认为是最新版本
|
// 如果是同样的版本,则直接认为是最新版本
|
||||||
@@ -384,7 +385,7 @@ func (this *APINode) autoUpgrade() error {
|
|||||||
logs.Println("[API_NODE]upgrade database starting ...")
|
logs.Println("[API_NODE]upgrade database starting ...")
|
||||||
err = setup.NewSQLExecutor(dbConfig).Run(false)
|
err = setup.NewSQLExecutor(dbConfig).Run(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("execute sql failed: " + err.Error())
|
return fmt.Errorf("execute sql failed: %w", err)
|
||||||
}
|
}
|
||||||
// 不使用remotelog
|
// 不使用remotelog
|
||||||
logs.Println("[API_NODE]upgrade database done")
|
logs.Println("[API_NODE]upgrade database done")
|
||||||
|
|||||||
@@ -137,8 +137,8 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 当前TeaWeb所在的fs
|
// 当前TeaWeb所在的fs
|
||||||
rootFS := ""
|
var rootFS = ""
|
||||||
rootTotal := uint64(0)
|
var rootTotal = uint64(0)
|
||||||
if lists.ContainsString([]string{"darwin", "linux", "freebsd"}, runtime.GOOS) {
|
if lists.ContainsString([]string{"darwin", "linux", "freebsd"}, runtime.GOOS) {
|
||||||
for _, p := range partitions {
|
for _, p := range partitions {
|
||||||
if p.Mountpoint == "/" {
|
if p.Mountpoint == "/" {
|
||||||
@@ -152,9 +152,9 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total := rootTotal
|
var total = rootTotal
|
||||||
totalUsage := uint64(0)
|
var totalUsage = uint64(0)
|
||||||
maxUsage := float64(0)
|
var maxUsage = float64(0)
|
||||||
for _, partition := range partitions {
|
for _, partition := range partitions {
|
||||||
if runtime.GOOS != "windows" && !strings.Contains(partition.Device, "/") && !strings.Contains(partition.Device, "\\") {
|
if runtime.GOOS != "windows" && !strings.Contains(partition.Device, "/") && !strings.Contains(partition.Device, "\\") {
|
||||||
continue
|
continue
|
||||||
@@ -180,6 +180,8 @@ func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
status.DiskTotal = total
|
status.DiskTotal = total
|
||||||
status.DiskUsage = float64(totalUsage) / float64(total)
|
if total > 0 {
|
||||||
|
status.DiskUsage = float64(totalUsage) / float64(total)
|
||||||
|
}
|
||||||
status.DiskMaxUsage = maxUsage / 100
|
status.DiskMaxUsage = maxUsage / 100
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
|||||||
result.CountServers = countServers
|
result.CountServers = countServers
|
||||||
|
|
||||||
this.BeginTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
|
this.BeginTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
|
||||||
countAuditingServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", 0, 0, configutils.BoolStateYes, nil)
|
countAuditingServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", 0, 0, configutils.BoolStateYes, nil, 0)
|
||||||
this.EndTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
|
this.EndTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTPCachePolicyService struct {
|
type HTTPCachePolicyService struct {
|
||||||
@@ -46,7 +48,26 @@ func (this *HTTPCachePolicyService) CreateHTTPCachePolicy(ctx context.Context, r
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
policyId, err := models.SharedHTTPCachePolicyDAO.CreateCachePolicy(tx, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache)
|
if req.CapacityJSON != nil {
|
||||||
|
req.CapacityJSON, err = utils.JSONDecodeConfig(req.CapacityJSON, &shared.SizeCapacity{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.MaxSizeJSON != nil {
|
||||||
|
req.MaxSizeJSON, err = utils.JSONDecodeConfig(req.MaxSizeJSON, &shared.SizeCapacity{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.FetchTimeoutJSON != nil {
|
||||||
|
req.FetchTimeoutJSON, err = utils.JSONDecodeConfig(req.FetchTimeoutJSON, &shared.TimeDuration{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
policyId, err := models.SharedHTTPCachePolicyDAO.CreateCachePolicy(tx, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache, req.FetchTimeoutJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -63,7 +84,26 @@ func (this *HTTPCachePolicyService) UpdateHTTPCachePolicy(ctx context.Context, r
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
err = models.SharedHTTPCachePolicyDAO.UpdateCachePolicy(tx, req.HttpCachePolicyId, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache)
|
if req.CapacityJSON != nil {
|
||||||
|
req.CapacityJSON, err = utils.JSONDecodeConfig(req.CapacityJSON, &shared.SizeCapacity{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.MaxSizeJSON != nil {
|
||||||
|
req.MaxSizeJSON, err = utils.JSONDecodeConfig(req.MaxSizeJSON, &shared.SizeCapacity{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.FetchTimeoutJSON != nil {
|
||||||
|
req.FetchTimeoutJSON, err = utils.JSONDecodeConfig(req.FetchTimeoutJSON, &shared.TimeDuration{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = models.SharedHTTPCachePolicyDAO.UpdateCachePolicy(tx, req.HttpCachePolicyId, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache, req.FetchTimeoutJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -147,7 +187,7 @@ func (this *HTTPCachePolicyService) FindEnabledHTTPCachePolicyConfig(ctx context
|
|||||||
|
|
||||||
// FindEnabledHTTPCachePolicy 查找单个缓存策略信息
|
// FindEnabledHTTPCachePolicy 查找单个缓存策略信息
|
||||||
func (this *HTTPCachePolicyService) FindEnabledHTTPCachePolicy(ctx context.Context, req *pb.FindEnabledHTTPCachePolicyRequest) (*pb.FindEnabledHTTPCachePolicyResponse, error) {
|
func (this *HTTPCachePolicyService) FindEnabledHTTPCachePolicy(ctx context.Context, req *pb.FindEnabledHTTPCachePolicyRequest) (*pb.FindEnabledHTTPCachePolicyResponse, error) {
|
||||||
_, err := this.ValidateAdmin(ctx)
|
_, _, err := this.ValidateAdminAndUser(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -162,9 +202,10 @@ func (this *HTTPCachePolicyService) FindEnabledHTTPCachePolicy(ctx context.Conte
|
|||||||
return &pb.FindEnabledHTTPCachePolicyResponse{HttpCachePolicy: nil}, nil
|
return &pb.FindEnabledHTTPCachePolicyResponse{HttpCachePolicy: nil}, nil
|
||||||
}
|
}
|
||||||
return &pb.FindEnabledHTTPCachePolicyResponse{HttpCachePolicy: &pb.HTTPCachePolicy{
|
return &pb.FindEnabledHTTPCachePolicyResponse{HttpCachePolicy: &pb.HTTPCachePolicy{
|
||||||
Id: int64(policy.Id),
|
Id: int64(policy.Id),
|
||||||
Name: policy.Name,
|
Name: policy.Name,
|
||||||
IsOn: policy.IsOn,
|
IsOn: policy.IsOn,
|
||||||
|
MaxBytesJSON: policy.MaxSize,
|
||||||
}}, nil
|
}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,16 +97,12 @@ func (this *HTTPCacheTaskKeyService) ValidateHTTPCacheTaskKeys(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
var serverClusterId = int64(server.ClusterId)
|
var serverClusterId = int64(server.ClusterId)
|
||||||
if serverClusterId == 0 {
|
if serverClusterId == 0 && clusterId <= 0 {
|
||||||
if clusterId > 0 {
|
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
||||||
serverClusterId = clusterId
|
Key: key,
|
||||||
} else {
|
ReasonCode: "requireClusterId",
|
||||||
pbFailResults = append(pbFailResults, &pb.ValidateHTTPCacheTaskKeysResponse_FailKey{
|
})
|
||||||
Key: key,
|
continue
|
||||||
ReasonCode: "requireClusterId",
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
|
|||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
// 已经有的数据
|
// 已经有的数据
|
||||||
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, nil)
|
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -300,7 +300,12 @@ func (this *HTTPFirewallPolicyService) UpdateHTTPFirewallPolicy(ctx context.Cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.CaptchaOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig)
|
// MaxRequestBodySize
|
||||||
|
if req.MaxRequestBodySize < 0 {
|
||||||
|
req.MaxRequestBodySize = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
err = models.SharedHTTPFirewallPolicyDAO.UpdateFirewallPolicy(tx, req.HttpFirewallPolicyId, req.IsOn, req.Name, req.Description, inboundConfigJSON, outboundConfigJSON, req.BlockOptionsJSON, req.CaptchaOptionsJSON, req.Mode, req.UseLocalFirewall, synFloodConfig, logConfig, req.MaxRequestBodySize, req.DenyCountryHTML, req.DenyProvinceHTML)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -443,7 +448,7 @@ func (this *HTTPFirewallPolicyService) FindEnabledHTTPFirewallPolicyConfig(ctx c
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
config, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, nil)
|
config, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -507,7 +512,7 @@ func (this *HTTPFirewallPolicyService) ImportHTTPFirewallPolicy(ctx context.Cont
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
oldConfig, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, nil)
|
oldConfig, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -670,7 +675,7 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
|
|||||||
ipLong := utils.IP2Long(req.Ip)
|
ipLong := utils.IP2Long(req.Ip)
|
||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, nil)
|
firewallPolicy, err := models.SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, req.HttpFirewallPolicyId, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func (this *HTTPFirewallRuleGroupService) FindEnabledHTTPFirewallRuleGroupConfig
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, req.FirewallRuleGroupId)
|
groupConfig, err := models.SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, req.FirewallRuleGroupId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ func (this *HTTPFirewallRuleGroupService) AddHTTPFirewallRuleGroupSet(ctx contex
|
|||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
// 已经有的规则
|
// 已经有的规则
|
||||||
config, err := models.SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, req.FirewallRuleGroupId)
|
config, err := models.SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, req.FirewallRuleGroupId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
|
|||||||
if len(shutdownConfig.URL) > maxURLLength {
|
if len(shutdownConfig.URL) > maxURLLength {
|
||||||
return nil, errors.New("'url' too long")
|
return nil, errors.New("'url' too long")
|
||||||
}
|
}
|
||||||
if !regexputils.HTTPProtocol.MatchString(shutdownConfig.URL) {
|
if shutdownConfig.IsOn /** validate when it's on **/ && !regexputils.HTTPProtocol.MatchString(shutdownConfig.URL) {
|
||||||
return nil, errors.New("invalid 'url' format")
|
return nil, errors.New("invalid 'url' format")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +425,9 @@ func (this *HTTPWebService) UpdateHTTPWebPages(ctx context.Context, req *pb.Upda
|
|||||||
if len(req.PagesJSON) > 0 {
|
if len(req.PagesJSON) > 0 {
|
||||||
var pages = []*serverconfigs.HTTPPageConfig{}
|
var pages = []*serverconfigs.HTTPPageConfig{}
|
||||||
err = json.Unmarshal(req.PagesJSON, &pages)
|
err = json.Unmarshal(req.PagesJSON, &pages)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for _, page := range pages {
|
for _, page := range pages {
|
||||||
err = page.Init()
|
err = page.Init()
|
||||||
|
|||||||
@@ -1102,7 +1102,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
|
|||||||
|
|
||||||
// toa
|
// toa
|
||||||
if models.IsNotNull(cluster.Toa) {
|
if models.IsNotNull(cluster.Toa) {
|
||||||
var toaConfig = &nodeconfigs.TOAConfig{}
|
var toaConfig = nodeconfigs.NewTOAConfig()
|
||||||
err = json.Unmarshal(cluster.Toa, toaConfig)
|
err = json.Unmarshal(cluster.Toa, toaConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -47,3 +47,8 @@ func (this *NodeService) CopyNodeActionsToNodeGroup(ctx context.Context, req *pb
|
|||||||
func (this *NodeService) CopyNodeActionsToNodeCluster(ctx context.Context, req *pb.CopyNodeActionsToNodeClusterRequest) (*pb.RPCSuccess, error) {
|
func (this *NodeService) CopyNodeActionsToNodeCluster(ctx context.Context, req *pb.CopyNodeActionsToNodeClusterRequest) (*pb.RPCSuccess, error) {
|
||||||
return nil, this.NotImplementedYet()
|
return nil, this.NotImplementedYet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNodeTOAConfig 查找节点的TOA配置
|
||||||
|
func (this *NodeService) FindNodeTOAConfig(ctx context.Context, req *pb.FindNodeTOAConfigRequest) (*pb.FindNodeTOAConfigResponse, error) {
|
||||||
|
return nil, this.NotImplementedYet()
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type CommandRequestWaiting struct {
|
|||||||
|
|
||||||
func (this *CommandRequestWaiting) Close() {
|
func (this *CommandRequestWaiting) Close() {
|
||||||
defer func() {
|
defer func() {
|
||||||
recover()
|
_ = recover()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
close(this.Chan)
|
close(this.Chan)
|
||||||
@@ -207,7 +207,7 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
|
|||||||
func(req *pb.NodeStreamMessage) {
|
func(req *pb.NodeStreamMessage) {
|
||||||
// 因为 responseChan.Chan 有被关闭的风险,所以我们使用recover防止panic
|
// 因为 responseChan.Chan 有被关闭的风险,所以我们使用recover防止panic
|
||||||
defer func() {
|
defer func() {
|
||||||
recover()
|
_ = recover()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
nodeLocker.Lock()
|
nodeLocker.Lock()
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func (this *ReverseProxyService) UpdateReverseProxy(ctx context.Context, req *pb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects)
|
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects, req.Retry50X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/domainutils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
@@ -147,7 +148,7 @@ func (this *ServerService) CreateServer(ctx context.Context, req *pb.CreateServe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 套餐
|
// 套餐
|
||||||
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
|
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -346,6 +347,9 @@ func (this *ServerService) CreateBasicHTTPServer(ctx context.Context, req *pb.Cr
|
|||||||
Options: nil,
|
Options: nil,
|
||||||
}
|
}
|
||||||
reverseProxyScheduleJSON, err := json.Marshal(reverseProxyScheduleConfig)
|
reverseProxyScheduleJSON, err := json.Marshal(reverseProxyScheduleConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var primaryOrigins = []*serverconfigs.OriginRef{}
|
var primaryOrigins = []*serverconfigs.OriginRef{}
|
||||||
for _, originAddr := range req.OriginAddrs {
|
for _, originAddr := range req.OriginAddrs {
|
||||||
@@ -615,6 +619,9 @@ func (this *ServerService) CreateBasicTCPServer(ctx context.Context, req *pb.Cre
|
|||||||
Options: nil,
|
Options: nil,
|
||||||
}
|
}
|
||||||
reverseProxyScheduleJSON, err := json.Marshal(reverseProxyScheduleConfig)
|
reverseProxyScheduleJSON, err := json.Marshal(reverseProxyScheduleConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var primaryOrigins = []*serverconfigs.OriginRef{}
|
var primaryOrigins = []*serverconfigs.OriginRef{}
|
||||||
for _, originAddr := range req.OriginAddrs {
|
for _, originAddr := range req.OriginAddrs {
|
||||||
@@ -1070,6 +1077,12 @@ func (this *ServerService) UpdateServerNames(ctx context.Context, req *pb.Update
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 套餐额度限制
|
||||||
|
err = models.SharedServerDAO.CheckServerPlanQuota(tx, req.ServerId, len(serverconfigs.PlainServerNames(serverNameConfigs)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// 检查用户
|
// 检查用户
|
||||||
if userId > 0 {
|
if userId > 0 {
|
||||||
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||||
@@ -1272,7 +1285,7 @@ func (this *ServerService) CountAllEnabledServersMatch(ctx context.Context, req
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
count, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, types.Int8(req.AuditingFlag), utils.SplitStrings(req.ProtocolFamily, ","))
|
count, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, types.Int8(req.AuditingFlag), utils.SplitStrings(req.ProtocolFamily, ","), req.UserPlanId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -2013,6 +2026,52 @@ func (this *ServerService) FindAllEnabledServerNamesWithUserId(ctx context.Conte
|
|||||||
return &pb.FindAllEnabledServerNamesWithUserIdResponse{ServerNames: serverNames}, nil
|
return &pb.FindAllEnabledServerNamesWithUserIdResponse{ServerNames: serverNames}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountAllServerNamesWithUserId 计算一个用户下的所有域名数量
|
||||||
|
func (this *ServerService) CountAllServerNamesWithUserId(ctx context.Context, req *pb.CountAllServerNamesWithUserIdRequest) (*pb.RPCCountResponse, error) {
|
||||||
|
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId > 0 {
|
||||||
|
req.UserId = userId
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
count, err := models.SharedServerDAO.CountAllServerNamesWithUserId(tx, req.UserId, req.UserPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.SuccessCount(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountServerNames 计算某个网站下的域名数量
|
||||||
|
func (this *ServerService) CountServerNames(ctx context.Context, req *pb.CountServerNamesRequest) (*pb.RPCCountResponse, error) {
|
||||||
|
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.ServerId <= 0 {
|
||||||
|
return nil, errors.New("invalid 'serverId'")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
if userId > 0 {
|
||||||
|
err = models.SharedServerDAO.CheckUserServer(tx, userId, req.ServerId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := models.SharedServerDAO.CountServerNames(tx, req.ServerId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return this.SuccessCount(count)
|
||||||
|
}
|
||||||
|
|
||||||
// FindAllUserServers 查找一个用户下的所有服务
|
// FindAllUserServers 查找一个用户下的所有服务
|
||||||
func (this *ServerService) FindAllUserServers(ctx context.Context, req *pb.FindAllUserServersRequest) (*pb.FindAllUserServersResponse, error) {
|
func (this *ServerService) FindAllUserServers(ctx context.Context, req *pb.FindAllUserServersRequest) (*pb.FindAllUserServersResponse, error) {
|
||||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||||
@@ -2045,6 +2104,26 @@ func (this *ServerService) FindAllUserServers(ctx context.Context, req *pb.FindA
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountAllUserServers 计算一个用户下的所有网站数量
|
||||||
|
func (this *ServerService) CountAllUserServers(ctx context.Context, req *pb.CountAllUserServersRequest) (*pb.RPCCountResponse, error) {
|
||||||
|
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId > 0 {
|
||||||
|
req.UserId = userId
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, nil, req.UserPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.SuccessCount(countServers)
|
||||||
|
}
|
||||||
|
|
||||||
// ComposeAllUserServersConfig 查找某个用户下的服务配置
|
// ComposeAllUserServersConfig 查找某个用户下的服务配置
|
||||||
func (this *ServerService) ComposeAllUserServersConfig(ctx context.Context, req *pb.ComposeAllUserServersConfigRequest) (*pb.ComposeAllUserServersConfigResponse, error) {
|
func (this *ServerService) ComposeAllUserServersConfig(ctx context.Context, req *pb.ComposeAllUserServersConfigRequest) (*pb.ComposeAllUserServersConfigResponse, error) {
|
||||||
_, err := this.ValidateNode(ctx)
|
_, err := this.ValidateNode(ctx)
|
||||||
@@ -2638,7 +2717,7 @@ func (this *ServerService) UpdateServerUserPlan(ctx context.Context, req *pb.Upd
|
|||||||
}
|
}
|
||||||
|
|
||||||
if req.UserPlanId > 0 {
|
if req.UserPlanId > 0 {
|
||||||
userId, err := models.SharedServerDAO.FindServerUserId(tx, req.ServerId)
|
userId, err = models.SharedServerDAO.FindServerUserId(tx, req.ServerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -2656,14 +2735,47 @@ func (this *ServerService) UpdateServerUserPlan(ctx context.Context, req *pb.Upd
|
|||||||
if int64(userPlan.UserId) != userId {
|
if int64(userPlan.UserId) != userId {
|
||||||
return nil, errors.New("can not find user plan with id '" + types.String(req.UserPlanId) + "'")
|
return nil, errors.New("can not find user plan with id '" + types.String(req.UserPlanId) + "'")
|
||||||
}
|
}
|
||||||
|
if userPlan.IsExpired() {
|
||||||
|
return nil, fmt.Errorf("the user plan %q has been expired", types.String(req.UserPlanId))
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否已经被别的服务所使用
|
// 检查限制
|
||||||
serverId, err := models.SharedServerDAO.FindEnabledServerIdWithUserPlanId(tx, req.UserPlanId)
|
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if serverId > 0 && serverId != req.ServerId {
|
if plan == nil {
|
||||||
return nil, errors.New("the user plan is used by other server")
|
return nil, errors.New("can not find plan with id '" + types.String(userPlan.PlanId) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if plan.TotalServers > 0 {
|
||||||
|
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", userId, 0, configutils.BoolStateAll, nil, req.UserPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if countServers+1 > int64(plan.TotalServers) {
|
||||||
|
return nil, errors.New("total servers over quota")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countServerNames, err := models.SharedServerDAO.CountServerNames(tx, req.ServerId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if plan.TotalServerNamesPerServer > 0 {
|
||||||
|
if countServerNames > int64(plan.TotalServerNamesPerServer) {
|
||||||
|
return nil, errors.New("total server names per server over quota")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalServerNames, err := models.SharedServerDAO.CountAllServerNamesWithUserId(tx, userId, req.UserPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if plan.TotalServerNames > 0 {
|
||||||
|
if totalServerNames+countServerNames > int64(plan.TotalServerNames) {
|
||||||
|
return nil, errors.New("total server names over quota")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2708,7 +2820,7 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
|
|||||||
return &pb.FindServerUserPlanResponse{UserPlan: nil}, nil
|
return &pb.FindServerUserPlanResponse{UserPlan: nil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
|
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -2726,11 +2838,14 @@ func (this *ServerService) FindServerUserPlan(ctx context.Context, req *pb.FindS
|
|||||||
DayTo: userPlan.DayTo,
|
DayTo: userPlan.DayTo,
|
||||||
User: nil,
|
User: nil,
|
||||||
Plan: &pb.Plan{
|
Plan: &pb.Plan{
|
||||||
Id: int64(plan.Id),
|
Id: int64(plan.Id),
|
||||||
Name: plan.Name,
|
Name: plan.Name,
|
||||||
PriceType: plan.PriceType,
|
PriceType: plan.PriceType,
|
||||||
TrafficPriceJSON: plan.TrafficPrice,
|
TrafficPriceJSON: plan.TrafficPrice,
|
||||||
TrafficLimitJSON: plan.TrafficLimit,
|
TrafficLimitJSON: plan.TrafficLimit,
|
||||||
|
TotalServers: types.Int32(plan.TotalServers),
|
||||||
|
TotalServerNames: types.Int32(plan.TotalServerNames),
|
||||||
|
TotalServerNamesPerServer: types.Int32(plan.TotalServerNamesPerServer),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
@@ -2911,8 +3026,14 @@ func (this *ServerService) CopyServerConfig(ctx context.Context, req *pb.CopySer
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if req.TargetUserId <= 0 {
|
||||||
|
req.TargetUserId = userId
|
||||||
|
}
|
||||||
|
|
||||||
// 此时如果用户为0,则同步到未分配用户的服务
|
// 此时如果用户为0,则同步到未分配用户的网站
|
||||||
|
} else {
|
||||||
|
// 只能同步到自己的网站
|
||||||
|
req.TargetUserId = userId
|
||||||
}
|
}
|
||||||
err = models.SharedServerDAO.CopyServerConfigToUser(tx, req.ServerId, req.TargetUserId, req.ConfigCode)
|
err = models.SharedServerDAO.CopyServerConfigToUser(tx, req.ServerId, req.TargetUserId, req.ConfigCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -63,17 +63,31 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, stat := range m {
|
for _, stat := range m {
|
||||||
// 更新服务的带宽峰值
|
// 更新网站的带宽峰值
|
||||||
if stat.ServerId > 0 {
|
if stat.ServerId > 0 {
|
||||||
err = models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
|
// 更新带宽统计
|
||||||
|
err = models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.UserPlanId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
|
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新网站的bandwidth字段,方便快速排序
|
||||||
err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes, stat.CountRequests, stat.CountAttackRequests)
|
err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes, stat.CountRequests, stat.CountAttackRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error())
|
remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 套餐统计
|
||||||
|
if stat.UserPlanId > 0 {
|
||||||
|
// 总体统计
|
||||||
|
err = models.SharedUserPlanStatDAO.IncreaseUserPlanStat(tx, stat.UserPlanId, stat.TotalBytes, stat.CountRequests)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("ServerBandwidthStatService", "IncreaseUserPlanStat: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分时统计
|
||||||
|
err = models.SharedUserPlanBandwidthStatDAO.UpdateUserPlanBandwidth(tx, stat.UserId, stat.UserPlanId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新用户的带宽峰值
|
// 更新用户的带宽峰值
|
||||||
@@ -147,6 +161,7 @@ func (this *ServerBandwidthStatService) UploadServerBandwidthStats(ctx context.C
|
|||||||
CountRequests: stat.CountRequests,
|
CountRequests: stat.CountRequests,
|
||||||
CountCachedRequests: stat.CountCachedRequests,
|
CountCachedRequests: stat.CountCachedRequests,
|
||||||
CountAttackRequests: stat.CountAttackRequests,
|
CountAttackRequests: stat.CountAttackRequests,
|
||||||
|
UserPlanId: stat.UserPlanId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverBandwidthStatsLocker.Unlock()
|
serverBandwidthStatsLocker.Unlock()
|
||||||
@@ -177,7 +192,7 @@ func (this *ServerBandwidthStatService) FindServerBandwidthStats(ctx context.Con
|
|||||||
req.Algo = bandwidthAlgo
|
req.Algo = bandwidthAlgo
|
||||||
}
|
}
|
||||||
|
|
||||||
var stats = []*models.ServerBandwidthStat{}
|
var stats []*models.ServerBandwidthStat
|
||||||
if len(req.Day) > 0 {
|
if len(req.Day) > 0 {
|
||||||
stats, err = models.SharedServerBandwidthStatDAO.FindAllServerStatsWithDay(tx, req.ServerId, req.Day, req.Algo == systemconfigs.BandwidthAlgoAvg)
|
stats, err = models.SharedServerBandwidthStatDAO.FindAllServerStatsWithDay(tx, req.ServerId, req.Day, req.Algo == systemconfigs.BandwidthAlgoAvg)
|
||||||
} else if len(req.Month) > 0 {
|
} else if len(req.Month) > 0 {
|
||||||
@@ -398,7 +413,7 @@ func (this *ServerBandwidthStatService) FindDailyServerBandwidthStatsBetweenDays
|
|||||||
return nil, errors.New("invalid dayTo '" + req.DayTo + "'")
|
return nil, errors.New("invalid dayTo '" + req.DayTo + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
var pbStats = []*pb.FindDailyServerBandwidthStatsBetweenDaysResponse_Stat{}
|
var pbStats []*pb.FindDailyServerBandwidthStatsBetweenDaysResponse_Stat
|
||||||
var pbNthStat *pb.FindDailyServerBandwidthStatsBetweenDaysResponse_Stat
|
var pbNthStat *pb.FindDailyServerBandwidthStatsBetweenDaysResponse_Stat
|
||||||
if req.ServerId > 0 { // 服务统计
|
if req.ServerId > 0 { // 服务统计
|
||||||
pbStats, err = models.SharedServerBandwidthStatDAO.FindBandwidthStatsBetweenDays(tx, req.ServerId, req.DayFrom, req.DayTo, req.Algo == systemconfigs.BandwidthAlgoAvg)
|
pbStats, err = models.SharedServerBandwidthStatDAO.FindBandwidthStatsBetweenDays(tx, req.ServerId, req.DayFrom, req.DayTo, req.Algo == systemconfigs.BandwidthAlgoAvg)
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 网站数量
|
// 网站数量
|
||||||
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, []string{})
|
countServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", req.UserId, 0, configutils.BoolStateAll, []string{}, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package rpcutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserType = string
|
type UserType = string
|
||||||
@@ -27,5 +28,5 @@ func Wrap(description string, err error) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return errors.New(description)
|
return errors.New(description)
|
||||||
}
|
}
|
||||||
return errors.New(description + ": " + err.Error())
|
return fmt.Errorf("%s: %w", description, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package setup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
@@ -150,7 +151,7 @@ func (this *Setup) Run() error {
|
|||||||
}
|
}
|
||||||
addrsJSON, err := json.Marshal([]*serverconfigs.NetworkAddressConfig{addr})
|
addrsJSON, err := json.Marshal([]*serverconfigs.NetworkAddressConfig{addr})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("json encode api node addr failed: " + err.Error())
|
return fmt.Errorf("json encode api node addr failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpJSON []byte = nil
|
var httpJSON []byte = nil
|
||||||
@@ -166,7 +167,7 @@ func (this *Setup) Run() error {
|
|||||||
}
|
}
|
||||||
httpJSON, err = json.Marshal(httpConfig)
|
httpJSON, err = json.Marshal(httpConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("json encode api node http config failed: " + err.Error())
|
return fmt.Errorf("json encode api node http config failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if this.config.APINodeProtocol == "https" {
|
if this.config.APINodeProtocol == "https" {
|
||||||
@@ -181,14 +182,14 @@ func (this *Setup) Run() error {
|
|||||||
}
|
}
|
||||||
httpsJSON, err = json.Marshal(httpsConfig)
|
httpsJSON, err = json.Marshal(httpsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("json encode api node https config failed: " + err.Error())
|
return fmt.Errorf("json encode api node https config failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建API节点
|
// 创建API节点
|
||||||
nodeId, err := dao.CreateAPINode(nil, "默认API节点", "这是默认创建的第一个API节点", httpJSON, httpsJSON, false, nil, nil, addrsJSON, true)
|
nodeId, err := dao.CreateAPINode(nil, "默认API节点", "这是默认创建的第一个API节点", httpJSON, httpsJSON, false, nil, nil, addrsJSON, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create api node in database failed: " + err.Error())
|
return fmt.Errorf("create api node in database failed: %w", err)
|
||||||
}
|
}
|
||||||
apiNodeId = nodeId
|
apiNodeId = nodeId
|
||||||
}
|
}
|
||||||
@@ -208,7 +209,7 @@ func (this *Setup) Run() error {
|
|||||||
}
|
}
|
||||||
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
|
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("save config failed: " + err.Error())
|
return fmt.Errorf("save config failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
12816
internal/setup/sql.json
12816
internal/setup/sql.json
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,8 @@ package setup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
@@ -68,7 +68,7 @@ func (this *SQLExecutor) Run(showLog bool) error {
|
|||||||
var sqlResult = &SQLDumpResult{}
|
var sqlResult = &SQLDumpResult{}
|
||||||
err = json.Unmarshal(sqlData, sqlResult)
|
err = json.Unmarshal(sqlData, sqlResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decode sql data failed: " + err.Error())
|
return fmt.Errorf("decode sql data failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sqlDump.Apply(db, sqlResult, showLog)
|
_, err = sqlDump.Apply(db, sqlResult, showLog)
|
||||||
@@ -227,7 +227,7 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
|||||||
/// 检查是否有集群数字
|
/// 检查是否有集群数字
|
||||||
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeNodeClusters")
|
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeNodeClusters")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query clusters failed: " + err.Error())
|
return fmt.Errorf("query clusters failed: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = stmt.Close()
|
_ = stmt.Close()
|
||||||
@@ -235,7 +235,7 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
|||||||
|
|
||||||
col, err := stmt.FindCol(0)
|
col, err := stmt.FindCol(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query clusters failed: " + err.Error())
|
return fmt.Errorf("query clusters failed: %w", err)
|
||||||
}
|
}
|
||||||
count := types.Int(col)
|
count := types.Int(col)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
@@ -311,7 +311,7 @@ func (this *SQLExecutor) checkCluster(db *dbs.DB) error {
|
|||||||
func (this *SQLExecutor) checkIPList(db *dbs.DB) error {
|
func (this *SQLExecutor) checkIPList(db *dbs.DB) error {
|
||||||
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeIPLists")
|
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeIPLists")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query ip lists failed: " + err.Error())
|
return fmt.Errorf("query ip lists failed: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = stmt.Close()
|
_ = stmt.Close()
|
||||||
@@ -319,7 +319,7 @@ func (this *SQLExecutor) checkIPList(db *dbs.DB) error {
|
|||||||
|
|
||||||
col, err := stmt.FindCol(0)
|
col, err := stmt.FindCol(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query ip lists failed: " + err.Error())
|
return fmt.Errorf("query ip lists failed: %w", err)
|
||||||
}
|
}
|
||||||
count := types.Int(col)
|
count := types.Int(col)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
@@ -508,7 +508,7 @@ func (this *SQLExecutor) checkClientAgents(db *dbs.DB) error {
|
|||||||
func (this *SQLExecutor) updateVersion(db *dbs.DB, version string) error {
|
func (this *SQLExecutor) updateVersion(db *dbs.DB, version string) error {
|
||||||
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeVersions")
|
stmt, err := db.Prepare("SELECT COUNT(*) FROM edgeVersions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query version failed: " + err.Error())
|
return fmt.Errorf("query version failed: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = stmt.Close()
|
_ = stmt.Close()
|
||||||
@@ -516,20 +516,20 @@ func (this *SQLExecutor) updateVersion(db *dbs.DB, version string) error {
|
|||||||
|
|
||||||
col, err := stmt.FindCol(0)
|
col, err := stmt.FindCol(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("query version failed: " + err.Error())
|
return fmt.Errorf("query version failed: %w", err)
|
||||||
}
|
}
|
||||||
count := types.Int(col)
|
count := types.Int(col)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
_, err = db.Exec("UPDATE edgeVersions SET version=?", version)
|
_, err = db.Exec("UPDATE edgeVersions SET version=?", version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("update version failed: " + err.Error())
|
return fmt.Errorf("update version failed: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Exec("INSERT edgeVersions (version) VALUES (?)", version)
|
_, err = db.Exec("INSERT edgeVersions (version) VALUES (?)", version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create version failed: " + err.Error())
|
return fmt.Errorf("create version failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ var upgradeFuncs = []*upgradeVersion{
|
|||||||
{
|
{
|
||||||
"1.2.1", upgradeV1_2_1,
|
"1.2.1", upgradeV1_2_1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"1.2.9", upgradeV1_2_9,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeSQLData 升级SQL数据
|
// UpgradeSQLData 升级SQL数据
|
||||||
@@ -424,9 +427,7 @@ func upgradeV0_3_2(db *dbs.DB) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if sizeCapacity != nil {
|
compressionConfig.MinLength = sizeCapacity
|
||||||
compressionConfig.MinLength = sizeCapacity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxLengthBytes = []byte(gzipOne.GetString("maxLength"))
|
var maxLengthBytes = []byte(gzipOne.GetString("maxLength"))
|
||||||
@@ -436,9 +437,7 @@ func upgradeV0_3_2(db *dbs.DB) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if sizeCapacity != nil {
|
compressionConfig.MaxLength = sizeCapacity
|
||||||
compressionConfig.MaxLength = sizeCapacity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var condsBytes = []byte(gzipOne.GetString("conds"))
|
var condsBytes = []byte(gzipOne.GetString("conds"))
|
||||||
@@ -448,9 +447,7 @@ func upgradeV0_3_2(db *dbs.DB) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if conds != nil {
|
compressionConfig.Conds = conds
|
||||||
compressionConfig.Conds = conds
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configJSON, err := json.Marshal(compressionConfig)
|
configJSON, err := json.Marshal(compressionConfig)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package setup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
@@ -79,7 +79,7 @@ func upgradeV0_4_9(db *dbs.DB) error {
|
|||||||
config.DenySpiders = true
|
config.DenySpiders = true
|
||||||
configJSON, err := json.Marshal(config)
|
configJSON, err := json.Marshal(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("encode SecurityConfig failed: " + err.Error())
|
return fmt.Errorf("encode SecurityConfig failed: %w", err)
|
||||||
} else {
|
} else {
|
||||||
_, err := db.Exec("UPDATE edgeSysSettings SET value=? WHERE code=?", configJSON, systemconfigs.SettingCodeAdminSecurityConfig)
|
_, err := db.Exec("UPDATE edgeSysSettings SET value=? WHERE code=?", configJSON, systemconfigs.SettingCodeAdminSecurityConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -213,3 +213,16 @@ func upgradeV0_5_8(db *dbs.DB) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v1.2.9
|
||||||
|
func upgradeV1_2_9(db *dbs.DB) error {
|
||||||
|
// 升级WAF规则
|
||||||
|
{
|
||||||
|
_, err := db.Exec("UPDATE edgeHTTPFirewallRules SET value=? WHERE value=? AND param='${userAgent}'", "python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php\\b|rust", "python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php|rust")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -270,5 +270,3 @@ func TestUpgradeSQLData_v1_2_1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("ok")
|
t.Log("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health
|
|||||||
// 在线状态发生变化
|
// 在线状态发生变化
|
||||||
if healthCheckConfig.AutoDown {
|
if healthCheckConfig.AutoDown {
|
||||||
// 发送消息
|
// 发送消息
|
||||||
var message = ""
|
var message string
|
||||||
var messageType string
|
var messageType string
|
||||||
var messageLevel string
|
var messageLevel string
|
||||||
if result.IsOk {
|
if result.IsOk {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||||
@@ -63,7 +64,7 @@ func (this *SSLCertUpdateOCSPTask) Loop() error {
|
|||||||
var maxTries = 5
|
var maxTries = 5
|
||||||
certs, err := models.SharedSSLCertDAO.ListCertsToUpdateOCSP(tx, maxTries, size)
|
certs, err := models.SharedSSLCertDAO.ListCertsToUpdateOCSP(tx, maxTries, size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("list certs failed: " + err.Error())
|
return fmt.Errorf("list certs failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(certs) == 0 {
|
if len(certs) == 0 {
|
||||||
@@ -74,7 +75,7 @@ func (this *SSLCertUpdateOCSPTask) Loop() error {
|
|||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
err := models.SharedSSLCertDAO.PrepareCertOCSPUpdating(tx, int64(cert.Id))
|
err := models.SharedSSLCertDAO.PrepareCertOCSPUpdating(tx, int64(cert.Id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("prepare cert ocsp updating failed: " + err.Error())
|
return fmt.Errorf("prepare cert ocsp updating failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ func (this *SSLCertUpdateOCSPTask) Loop() error {
|
|||||||
}
|
}
|
||||||
err = models.SharedSSLCertDAO.UpdateCertOCSP(tx, int64(cert.Id), ocspData, expiresAt, hasErr, errString)
|
err = models.SharedSSLCertDAO.UpdateCertOCSP(tx, int64(cert.Id), ocspData, expiresAt, hasErr, errString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("update ocsp failed: " + err.Error())
|
return fmt.Errorf("update ocsp failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func TestList_ManyItems(t *testing.T) {
|
|||||||
})
|
})
|
||||||
list.GC(time.Now().Unix() + 1)
|
list.GC(time.Now().Unix() + 1)
|
||||||
t.Log("gc", count, "items")
|
t.Log("gc", count, "items")
|
||||||
t.Log(time.Now().Sub(now))
|
t.Log(time.Since(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestList_Map_Performance(t *testing.T) {
|
func TestList_Map_Performance(t *testing.T) {
|
||||||
@@ -140,7 +140,7 @@ func TestList_Map_Performance(t *testing.T) {
|
|||||||
for i := 0; i < 100_000; i++ {
|
for i := 0; i < 100_000; i++ {
|
||||||
delete(m, int64(i))
|
delete(m, int64(i))
|
||||||
}
|
}
|
||||||
t.Log(time.Now().Sub(now))
|
t.Log(time.Since(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ func TestList_Map_Performance(t *testing.T) {
|
|||||||
for i := 0; i < 100_000; i++ {
|
for i := 0; i < 100_000; i++ {
|
||||||
delete(m, uint64(i))
|
delete(m, uint64(i))
|
||||||
}
|
}
|
||||||
t.Log(time.Now().Sub(now))
|
t.Log(time.Since(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -166,7 +166,7 @@ func TestList_Map_Performance(t *testing.T) {
|
|||||||
for i := 0; i < 100_000; i++ {
|
for i := 0; i < 100_000; i++ {
|
||||||
delete(m, uint32(i))
|
delete(m, uint32(i))
|
||||||
}
|
}
|
||||||
t.Log(time.Now().Sub(now))
|
t.Log(time.Since(now))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,3 +43,32 @@ func JSONClone[T any](ptr T) (newPtr T, err error) {
|
|||||||
|
|
||||||
return newValue.(T), nil
|
return newValue.(T), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONDecodeConfig 解码并重新编码
|
||||||
|
// 是为了去除原有JSON中不需要的数据
|
||||||
|
func JSONDecodeConfig(data []byte, ptr any) (encodeJSON []byte, err error) {
|
||||||
|
err = json.Unmarshal(data, ptr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeJSON, err = json.Marshal(ptr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate config
|
||||||
|
if ptr != nil {
|
||||||
|
config, ok := ptr.(interface {
|
||||||
|
Init() error
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
initErr := config.Init()
|
||||||
|
if initErr != nil {
|
||||||
|
err = errors.New("validate config failed: " + initErr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -49,3 +50,38 @@ func TestJSONClone_Slice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
logs.PrintAsJSON(newU, t)
|
logs.PrintAsJSON(newU, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jsonUserType struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *jsonUserType) Init() error {
|
||||||
|
if len(this.Name) < 10 {
|
||||||
|
return errors.New("'name' too short")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONDecodeConfig(t *testing.T) {
|
||||||
|
var data = []byte(`{ "name":"Lily", "age":20, "description": "Nice" }`)
|
||||||
|
|
||||||
|
var u = &jsonUserType{}
|
||||||
|
newJSON, err := utils.JSONDecodeConfig(data, u)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("%+v, %s", u, string(newJSON))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONDecodeConfig_Validate(t *testing.T) {
|
||||||
|
var data = []byte(`{ "name":"Lily", "age":20, "description": "Nice" }`)
|
||||||
|
|
||||||
|
var u = &jsonUserType{}
|
||||||
|
|
||||||
|
newJSON, err := utils.JSONDecodeConfig(data, u)
|
||||||
|
if err != nil {
|
||||||
|
t.Log("ignore error:", err) // error expected
|
||||||
|
}
|
||||||
|
t.Logf("%+v, %s", u, string(newJSON))
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user