mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-03 15:00:26 +08:00
阶段性提交
This commit is contained in:
@@ -5,4 +5,5 @@ if [ -d ${TARGET} ]
|
||||
then
|
||||
rm -rf ../../EdgeAdmin/internal/serverconfigs
|
||||
fi
|
||||
cp -R ../internal/configs/serverconfigs ../../EdgeAdmin/internal/configs/
|
||||
cp -R ../internal/configs/serverconfigs ../../EdgeAdmin/internal/configs/
|
||||
cp -R ../internal/configs/serverconfigs ../../EdgeAPI/internal/configs
|
||||
12
go.mod
12
go.mod
@@ -1,21 +1,21 @@
|
||||
module github.com/TeaOSLab/EdgeNode
|
||||
|
||||
go 1.14
|
||||
go 1.15
|
||||
|
||||
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/go-redis/redis v6.15.8+incompatible // indirect
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/iwind/TeaGo v0.0.0-20200822074248-b1cf7248c98a
|
||||
github.com/iwind/TeaGo v0.0.0-20200910072805-729cffe36729
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
|
||||
google.golang.org/grpc v1.30.0
|
||||
google.golang.org/protobuf v1.25.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
google.golang.org/grpc v1.32.0
|
||||
)
|
||||
|
||||
13
go.sum
13
go.sum
@@ -12,6 +12,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -54,8 +55,11 @@ github.com/iwind/TeaGo v0.0.0-20200727075925-7e7e67b44f2d h1:V7HA0wUOdmZbXJTVpiU
|
||||
github.com/iwind/TeaGo v0.0.0-20200727075925-7e7e67b44f2d/go.mod h1:zjM7k+b+Jthhf0T0fKwuF0iy4TWb5SsU1gmKR2l+OmE=
|
||||
github.com/iwind/TeaGo v0.0.0-20200822074248-b1cf7248c98a h1:VaWcMNOzHHT1y8MeTA2fWhG6GEfAdy6CwF2tW+KiY5Y=
|
||||
github.com/iwind/TeaGo v0.0.0-20200822074248-b1cf7248c98a/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20200910072805-729cffe36729 h1:/v0WhSFVeNay/dA5zU9iCBXlgVDfxnztuanlauXE0gM=
|
||||
github.com/iwind/TeaGo v0.0.0-20200910072805-729cffe36729/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
@@ -79,6 +83,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
|
||||
@@ -93,6 +99,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
@@ -150,6 +157,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03 h1:4HYDjxeNXAOTv3o1N2tjo8UUSlhQgAD52FVkwxnWgM8=
|
||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
@@ -159,12 +167,15 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
@@ -182,5 +193,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"io/ioutil"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"testing"
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var DefaultSkippedResponseCacheControlValues = []string{"private", "no-cache", "no-store"}
|
||||
|
||||
// 缓存策略配置
|
||||
type CachePolicy struct {
|
||||
Id int `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启 TODO
|
||||
Name string `yaml:"name" json:"name"` // 名称
|
||||
|
||||
Key string `yaml:"key" json:"key"` // 每个缓存的Key规则,里面可以有变量
|
||||
Capacity shared.SizeCapacity `yaml:"capacity" json:"capacity"` // 最大内容容量
|
||||
Life shared.TimeDuration `yaml:"life" json:"life"` // 时间
|
||||
Status []int `yaml:"status" json:"status"` // 缓存的状态码列表
|
||||
MaxSize shared.SizeCapacity `yaml:"maxSize" json:"maxSize"` // 能够请求的最大尺寸
|
||||
|
||||
SkipResponseCacheControlValues []string `yaml:"skipCacheControlValues" json:"skipCacheControlValues"` // 可以跳过的响应的Cache-Control值
|
||||
SkipResponseSetCookie bool `yaml:"skipSetCookie" json:"skipSetCookie"` // 是否跳过响应的Set-Cookie Header
|
||||
EnableRequestCachePragma bool `yaml:"enableRequestCachePragma" json:"enableRequestCachePragma"` // 是否支持客户端的Pragma: no-cache
|
||||
|
||||
Cond []*shared.RequestCond `yaml:"cond" json:"cond"`
|
||||
|
||||
life time.Duration
|
||||
maxSize int64
|
||||
capacity int64
|
||||
|
||||
uppercaseSkipCacheControlValues []string
|
||||
|
||||
Type string `yaml:"type" json:"type"` // 类型
|
||||
Options map[string]interface{} `yaml:"options" json:"options"` // 选项
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewCachePolicy() *CachePolicy {
|
||||
return &CachePolicy{
|
||||
SkipResponseCacheControlValues: DefaultSkippedResponseCacheControlValues,
|
||||
SkipResponseSetCookie: true,
|
||||
}
|
||||
}
|
||||
|
||||
// 从文件中读取缓存策略
|
||||
func NewCachePolicyFromFile(file string) *CachePolicy {
|
||||
if len(file) == 0 {
|
||||
return nil
|
||||
}
|
||||
reader, err := files.NewReader(Tea.ConfigFile(file))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return nil
|
||||
}
|
||||
defer func() {
|
||||
_ = reader.Close()
|
||||
}()
|
||||
|
||||
p := NewCachePolicy()
|
||||
err = reader.ReadYAML(p)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *CachePolicy) Validate() error {
|
||||
var err error
|
||||
this.maxSize = this.MaxSize.Bytes()
|
||||
this.life = this.Life.Duration()
|
||||
this.capacity = this.Capacity.Bytes()
|
||||
|
||||
this.uppercaseSkipCacheControlValues = []string{}
|
||||
for _, value := range this.SkipResponseCacheControlValues {
|
||||
this.uppercaseSkipCacheControlValues = append(this.uppercaseSkipCacheControlValues, strings.ToUpper(value))
|
||||
}
|
||||
|
||||
// cond
|
||||
if len(this.Cond) > 0 {
|
||||
for _, cond := range this.Cond {
|
||||
err := cond.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 最大数据尺寸
|
||||
func (this *CachePolicy) MaxDataSize() int64 {
|
||||
return this.maxSize
|
||||
}
|
||||
|
||||
// 容量
|
||||
func (this *CachePolicy) CapacitySize() int64 {
|
||||
return this.capacity
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
func (this *CachePolicy) LifeDuration() time.Duration {
|
||||
return this.life
|
||||
}
|
||||
|
||||
// 保存
|
||||
func (this *CachePolicy) Save() error {
|
||||
shared.Locker.Lock()
|
||||
defer shared.Locker.Unlock()
|
||||
|
||||
filename := "cache.policy." + strconv.Itoa(this.Id) + ".conf"
|
||||
writer, err := files.NewWriter(Tea.ConfigFile(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = writer.Close()
|
||||
}()
|
||||
_, err = writer.WriteYAML(this)
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除
|
||||
func (this *CachePolicy) Delete() error {
|
||||
filename := "cache.policy." + strconv.Itoa(this.Id) + ".conf"
|
||||
return files.NewFile(Tea.ConfigFile(filename)).Delete()
|
||||
}
|
||||
|
||||
// 是否包含某个Cache-Control值
|
||||
func (this *CachePolicy) ContainsCacheControl(value string) bool {
|
||||
return lists.ContainsString(this.uppercaseSkipCacheControlValues, strings.ToUpper(value))
|
||||
}
|
||||
|
||||
// 检查是否匹配关键词
|
||||
func (this *CachePolicy) MatchKeyword(keyword string) (matched bool, name string, tags []string) {
|
||||
if configutils.MatchKeyword(this.Name, keyword) || configutils.MatchKeyword(this.Type, keyword) {
|
||||
matched = true
|
||||
name = this.Name
|
||||
if len(this.Type) > 0 {
|
||||
tags = []string{"类型:" + this.Type}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type ComponentConfig struct {
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 拷贝同类型struct指针对象中的字段
|
||||
func CopyStructObject(destPtr, sourcePtr interface{}) {
|
||||
value := reflect.ValueOf(destPtr)
|
||||
value2 := reflect.ValueOf(sourcePtr)
|
||||
|
||||
countFields := value2.Elem().NumField()
|
||||
for i := 0; i < countFields; i++ {
|
||||
v := value2.Elem().Field(i)
|
||||
if !v.IsValid() || !v.CanSet() {
|
||||
continue
|
||||
}
|
||||
value.Elem().Field(i).Set(v)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCopyStructObject(t *testing.T) {
|
||||
type Book struct {
|
||||
Name string
|
||||
Price int
|
||||
Year int
|
||||
Author string
|
||||
press string
|
||||
}
|
||||
|
||||
book1 := &Book{
|
||||
Name: "Hello Golang",
|
||||
Price: 100,
|
||||
Year: 2020,
|
||||
Author: "Liu",
|
||||
press: "Beijing",
|
||||
}
|
||||
book2 := new(Book)
|
||||
CopyStructObject(book2, book1)
|
||||
logs.PrintAsJSON(book2, t)
|
||||
logs.PrintAsJSON(book1, t)
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 从一组规则中匹配域名
|
||||
// 支持的格式:example.com, www.example.com, .example.com, *.example.com, ~(\d+).example.com
|
||||
// 更多参考:http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
|
||||
func MatchDomains(patterns []string, domain string) (isMatched bool) {
|
||||
if len(patterns) == 0 {
|
||||
return
|
||||
}
|
||||
for _, pattern := range patterns {
|
||||
if matchDomain(pattern, domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 匹配单个域名规则
|
||||
func matchDomain(pattern string, domain string) (isMatched bool) {
|
||||
if len(pattern) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 正则表达式
|
||||
if pattern[0] == '~' {
|
||||
reg, err := stringutil.RegexpCompile(strings.TrimSpace(pattern[1:]))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return false
|
||||
}
|
||||
return reg.MatchString(domain)
|
||||
}
|
||||
|
||||
if pattern[0] == '.' {
|
||||
return strings.HasSuffix(domain, pattern)
|
||||
}
|
||||
|
||||
// 其他匹配
|
||||
patternPieces := strings.Split(pattern, ".")
|
||||
domainPieces := strings.Split(domain, ".")
|
||||
if len(patternPieces) != len(domainPieces) {
|
||||
return
|
||||
}
|
||||
isMatched = true
|
||||
for index, patternPiece := range patternPieces {
|
||||
if patternPiece == "" || patternPiece == "*" || patternPiece == domainPieces[index] {
|
||||
continue
|
||||
}
|
||||
isMatched = false
|
||||
break
|
||||
}
|
||||
return isMatched
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchDomain(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
{
|
||||
ok := MatchDomains([]string{}, "example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"example.com"}, "example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"www.example.com"}, "example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "a.www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "a.www.example123.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"*.example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"*.*.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"www.*.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"gallery.*.com"}, "www.example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~\\w+.example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~\\w+.example.com"}, "a.www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "www.example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "123.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import "github.com/iwind/TeaGo/logs"
|
||||
|
||||
// 记录错误
|
||||
func LogError(arg ...interface{}) {
|
||||
if len(arg) == 0 {
|
||||
return
|
||||
}
|
||||
logs.Println(arg...)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var whitespaceReg = regexp.MustCompile(`\s+`)
|
||||
|
||||
// 关键词匹配
|
||||
func MatchKeyword(source, keyword string) bool {
|
||||
if len(keyword) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
pieces := whitespaceReg.Split(keyword, -1)
|
||||
source = strings.ToLower(source)
|
||||
for _, piece := range pieces {
|
||||
if strings.Index(source, strings.ToLower(piece)) > -1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchKeyword(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
a.IsTrue(MatchKeyword("a b c", "a"))
|
||||
a.IsFalse(MatchKeyword("a b c", ""))
|
||||
a.IsTrue(MatchKeyword("abc", "BC"))
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/go-yaml/yaml"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func UnmarshalYamlFile(file string, ptr interface{}) error {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return yaml.Unmarshal(data, ptr)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type FilterConfig struct {
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
)
|
||||
|
||||
var globalConfig *GlobalConfig = nil
|
||||
var globalConfigFile = "global.yaml"
|
||||
|
||||
// 全局设置
|
||||
type GlobalConfig struct {
|
||||
HTTPAll struct {
|
||||
MatchDomainStrictly bool `yaml:"matchDomainStrictly" json:"matchDomainStrictly"`
|
||||
} `yaml:"httpAll" json:"httpAll"`
|
||||
HTTP struct{} `yaml:"http" json:"http"`
|
||||
HTTPS struct{} `yaml:"https" json:"https"`
|
||||
TCPAll struct{} `yaml:"tcpAll" json:"tcpAll"`
|
||||
TCP struct{} `yaml:"tcp" json:"tcp"`
|
||||
TLS struct{} `yaml:"tls" json:"tls"`
|
||||
Unix struct{} `yaml:"unix" json:"unix"`
|
||||
UDP struct{} `yaml:"udp" json:"udp"`
|
||||
}
|
||||
|
||||
func SharedGlobalConfig() *GlobalConfig {
|
||||
shared.Locker.Lock()
|
||||
defer shared.Locker.Unlock()
|
||||
|
||||
if globalConfig != nil {
|
||||
return globalConfig
|
||||
}
|
||||
|
||||
err := configutils.UnmarshalYamlFile(globalConfigFile, globalConfig)
|
||||
if err != nil {
|
||||
configutils.LogError("[SharedGlobalConfig]" + err.Error())
|
||||
globalConfig = &GlobalConfig{}
|
||||
}
|
||||
return globalConfig
|
||||
}
|
||||
|
||||
func (this *GlobalConfig) Init() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type IPVersion = string
|
||||
|
||||
const (
|
||||
IPv4 IPVersion = "4"
|
||||
IPv6 IPVersion = "6"
|
||||
)
|
||||
@@ -1,4 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type LocationConfig struct {
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var regexpSinglePort = regexp.MustCompile(`^\d+$`)
|
||||
|
||||
// 网络地址配置
|
||||
type NetworkAddressConfig struct {
|
||||
Protocol string `yaml:"protocol" json:"protocol"` // 协议,http、tcp、tcp4、tcp6、unix、udp等
|
||||
Host string `yaml:"host" json:"host"` // 主机地址或主机名
|
||||
PortRange string `yaml:"portRange" json:"portRange"` // 端口范围,支持 8080、8080-8090、8080:8090
|
||||
|
||||
minPort int
|
||||
maxPort int
|
||||
}
|
||||
|
||||
func (this *NetworkAddressConfig) Init() error {
|
||||
// 8080
|
||||
if regexpSinglePort.MatchString(this.PortRange) {
|
||||
this.minPort = types.Int(this.PortRange)
|
||||
this.maxPort = this.minPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8080:8090
|
||||
if strings.Contains(this.PortRange, ":") {
|
||||
pieces := strings.SplitN(this.PortRange, ":", 2)
|
||||
minPort := types.Int(pieces[0])
|
||||
maxPort := types.Int(pieces[1])
|
||||
if minPort > maxPort {
|
||||
minPort, maxPort = maxPort, minPort
|
||||
}
|
||||
this.minPort = minPort
|
||||
this.maxPort = maxPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8080-8090
|
||||
if strings.Contains(this.PortRange, "-") {
|
||||
pieces := strings.SplitN(this.PortRange, "-", 2)
|
||||
minPort := types.Int(pieces[0])
|
||||
maxPort := types.Int(pieces[1])
|
||||
if minPort > maxPort {
|
||||
minPort, maxPort = maxPort, minPort
|
||||
}
|
||||
this.minPort = minPort
|
||||
this.maxPort = maxPort
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *NetworkAddressConfig) FullAddresses() []string {
|
||||
if this.Protocol == ProtocolUnix {
|
||||
return []string{this.Protocol + ":" + this.Host}
|
||||
}
|
||||
|
||||
result := []string{}
|
||||
for i := this.minPort; i <= this.maxPort; i++ {
|
||||
host := this.Host
|
||||
result = append(result, this.Protocol+"://"+host+":"+strconv.Itoa(i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNetworkAddressConfig_FullAddresses(t *testing.T) {
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080:8090",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080-8090",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080-8070",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 源站服务配置
|
||||
type OriginServerConfig struct {
|
||||
HeaderList *shared.HeaderList `yaml:"headers" json:"headers"`
|
||||
|
||||
Id int64 `yaml:"id" json:"id"` // ID
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用 TODO
|
||||
Version int `yaml:"version" json:"version"` // 版本
|
||||
Name string `yaml:"name" json:"name"` // 名称 TODO
|
||||
Addr *NetworkAddressConfig `yaml:"addr" json:"addr"` // 地址
|
||||
Description string `yaml:"description" json:"description"` // 描述 TODO
|
||||
Code string `yaml:"code" json:"code"` // 代号 TODO
|
||||
Scheme string `yaml:"scheme" json:"scheme"` // 协议 TODO
|
||||
|
||||
Weight uint `yaml:"weight" json:"weight"` // 权重 TODO
|
||||
IsBackup bool `yaml:"backup" json:"isBackup"` // 是否为备份 TODO
|
||||
FailTimeout string `yaml:"failTimeout" json:"failTimeout"` // 连接失败超时 TODO
|
||||
ReadTimeout string `yaml:"readTimeout" json:"readTimeout"` // 读取超时时间 TODO
|
||||
IdleTimeout string `yaml:"idleTimeout" json:"idleTimeout"` // 空闲连接超时时间 TODO
|
||||
MaxFails int32 `yaml:"maxFails" json:"maxFails"` // 最多失败次数 TODO
|
||||
CurrentFails int32 `yaml:"currentFails" json:"currentFails"` // 当前已失败次数 TODO
|
||||
MaxConns int32 `yaml:"maxConns" json:"maxConns"` // 最大并发连接数 TODO
|
||||
CurrentConns int32 `yaml:"currentConns" json:"currentConns"` // 当前连接数 TODO
|
||||
IdleConns int32 `yaml:"idleConns" json:"idleConns"` // 最大空闲连接数 TODO
|
||||
|
||||
IsDown bool `yaml:"down" json:"isDown"` // 是否下线 TODO
|
||||
DownTime time.Time `yaml:"downTime,omitempty" json:"downTime,omitempty"` // 下线时间 TODO
|
||||
|
||||
RequestURI string `yaml:"requestURI" json:"requestURI"` // 转发后的请求URI TODO
|
||||
ResponseHeaders []*shared.HeaderConfig `yaml:"responseHeaders" json:"responseHeaders"` // 响应Header TODO
|
||||
Host string `yaml:"host" json:"host"` // 自定义主机名 TODO
|
||||
|
||||
// 健康检查URL,目前支持:
|
||||
// - http|https 返回2xx-3xx认为成功
|
||||
HealthCheck struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启 TODO
|
||||
URL string `yaml:"url" json:"url"` // TODO
|
||||
Interval int `yaml:"interval" json:"interval"` // TODO
|
||||
StatusCodes []int `yaml:"statusCodes" json:"statusCodes"` // TODO
|
||||
Timeout shared.TimeDuration `yaml:"timeout" json:"timeout"` // 超时时间 TODO
|
||||
} `yaml:"healthCheck" json:"healthCheck"`
|
||||
|
||||
Cert *sslconfigs.SSLCertConfig `yaml:"cert" json:"cert"` // 请求源服务器用的证书
|
||||
|
||||
// ftp
|
||||
FTP *OriginServerFTPConfig `yaml:"ftp" json:"ftp"`
|
||||
|
||||
failTimeoutDuration time.Duration
|
||||
readTimeoutDuration time.Duration
|
||||
idleTimeoutDuration time.Duration
|
||||
|
||||
hasRequestURI bool
|
||||
requestPath string
|
||||
requestArgs string
|
||||
|
||||
hasRequestHeaders bool
|
||||
hasResponseHeaders bool
|
||||
|
||||
hasHost bool
|
||||
|
||||
uniqueKey string
|
||||
|
||||
hasAddrVariables bool // 地址中是否含有变量
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *OriginServerConfig) Init() error {
|
||||
// 证书
|
||||
if this.Cert != nil {
|
||||
err := this.Cert.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// unique key
|
||||
this.uniqueKey = strconv.FormatInt(this.Id, 10) + "@" + fmt.Sprintf("%d", this.Version)
|
||||
|
||||
// failTimeout
|
||||
if len(this.FailTimeout) > 0 {
|
||||
this.failTimeoutDuration, _ = time.ParseDuration(this.FailTimeout)
|
||||
}
|
||||
|
||||
// readTimeout
|
||||
if len(this.ReadTimeout) > 0 {
|
||||
this.readTimeoutDuration, _ = time.ParseDuration(this.ReadTimeout)
|
||||
}
|
||||
|
||||
// idleTimeout
|
||||
if len(this.IdleTimeout) > 0 {
|
||||
this.idleTimeoutDuration, _ = time.ParseDuration(this.IdleTimeout)
|
||||
}
|
||||
|
||||
// Headers
|
||||
if this.HeaderList != nil {
|
||||
err := this.HeaderList.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// request uri
|
||||
if len(this.RequestURI) == 0 || this.RequestURI == "${requestURI}" {
|
||||
this.hasRequestURI = false
|
||||
} else {
|
||||
this.hasRequestURI = true
|
||||
|
||||
if strings.Contains(this.RequestURI, "?") {
|
||||
pieces := strings.SplitN(this.RequestURI, "?", -1)
|
||||
this.requestPath = pieces[0]
|
||||
this.requestArgs = pieces[1]
|
||||
} else {
|
||||
this.requestPath = this.RequestURI
|
||||
}
|
||||
}
|
||||
|
||||
// TODO init health check
|
||||
|
||||
// headers
|
||||
if this.HeaderList != nil {
|
||||
this.hasRequestHeaders = len(this.HeaderList.RequestHeaders) > 0
|
||||
}
|
||||
this.hasResponseHeaders = len(this.ResponseHeaders) > 0
|
||||
|
||||
// host
|
||||
this.hasHost = len(this.Host) > 0
|
||||
|
||||
// variables
|
||||
// TODO 在host和port中支持变量
|
||||
this.hasAddrVariables = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 候选对象代号
|
||||
func (this *OriginServerConfig) CandidateCodes() []string {
|
||||
codes := []string{strconv.FormatInt(this.Id, 10)}
|
||||
if len(this.Code) > 0 {
|
||||
codes = append(codes, this.Code)
|
||||
}
|
||||
return codes
|
||||
}
|
||||
|
||||
// 候选对象权重
|
||||
func (this *OriginServerConfig) CandidateWeight() uint {
|
||||
return this.Weight
|
||||
}
|
||||
|
||||
// 连接源站
|
||||
func (this *OriginServerConfig) Connect() (net.Conn, error) {
|
||||
switch this.Scheme {
|
||||
case "", ProtocolTCP:
|
||||
// TODO 支持TCP4/TCP6
|
||||
// TODO 支持指定特定网卡
|
||||
// TODO Addr支持端口范围,如果有多个端口时,随机一个端口使用
|
||||
return net.DialTimeout("tcp", this.Addr.Host+":"+this.Addr.PortRange, this.failTimeoutDuration)
|
||||
case ProtocolTLS:
|
||||
// TODO 支持TCP4/TCP6
|
||||
// TODO 支持指定特定网卡
|
||||
// TODO Addr支持端口范围,如果有多个端口时,随机一个端口使用
|
||||
// TODO 支持使用证书
|
||||
return tls.Dial("tcp", this.Addr.Host+":"+this.Addr.PortRange, &tls.Config{})
|
||||
}
|
||||
|
||||
// TODO 支持从Unix、Pipe、HTTP、HTTPS中读取数据
|
||||
|
||||
return nil, errors.New("invalid scheme '" + this.Scheme + "'")
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
// FTP源站配置
|
||||
type OriginServerFTPConfig struct {
|
||||
Username string `yaml:"username" json:"username"` // 用户名
|
||||
Password string `yaml:"password" json:"password"` // 密码
|
||||
Dir string `yaml:"dir" json:"dir"` // 目录
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
// TODO 需要实现
|
||||
type OriginServerGroupConfig struct {
|
||||
Origins []*OriginServerConfig `yaml:"origins" json:"origins"` // 源站列表
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type Protocol = string
|
||||
|
||||
const (
|
||||
ProtocolHTTP Protocol = "http"
|
||||
ProtocolHTTPS Protocol = "https"
|
||||
ProtocolTCP Protocol = "tcp"
|
||||
ProtocolTLS Protocol = "tls"
|
||||
ProtocolUnix Protocol = "unix"
|
||||
ProtocolUDP Protocol = "udp"
|
||||
|
||||
// 子协议
|
||||
ProtocolHTTP4 Protocol = "http4"
|
||||
ProtocolHTTP6 Protocol = "http6"
|
||||
|
||||
ProtocolHTTPS4 Protocol = "https4"
|
||||
ProtocolHTTPS6 Protocol = "https6"
|
||||
|
||||
ProtocolTCP4 Protocol = "tcp4"
|
||||
ProtocolTCP6 Protocol = "tcp6"
|
||||
|
||||
ProtocolTLS4 Protocol = "tls4"
|
||||
ProtocolTLS6 Protocol = "tls6"
|
||||
)
|
||||
|
||||
func AllProtocols() []Protocol {
|
||||
return []Protocol{ProtocolHTTP, ProtocolHTTPS, ProtocolTCP, ProtocolTLS, ProtocolUnix, ProtocolUDP, ProtocolHTTP4, ProtocolHTTP6, ProtocolHTTPS4, ProtocolHTTPS6, ProtocolTCP4, ProtocolTCP6, ProtocolTLS4, ProtocolTLS6}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
// 协议基础数据结构
|
||||
type BaseProtocol struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
Listen []*NetworkAddressConfig `yaml:"listen" json:"listen"` // 绑定的网络地址
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *BaseProtocol) InitBase() error {
|
||||
for _, addr := range this.Listen {
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取完整的地址列表
|
||||
func (this *BaseProtocol) FullAddresses() []string {
|
||||
result := []string{}
|
||||
for _, addr := range this.Listen {
|
||||
result = append(result, addr.FullAddresses()...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 添加地址
|
||||
func (this *BaseProtocol) AddListen(addr ...*NetworkAddressConfig) {
|
||||
this.Listen = append(this.Listen, addr...)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type HTTPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *HTTPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
|
||||
// TLS Version
|
||||
type TLSVersion = string
|
||||
|
||||
// Cipher Suites
|
||||
type TLSCipherSuite = string
|
||||
|
||||
type HTTPSProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
|
||||
SSL *sslconfigs.SSLConfig `yaml:"ssl"`
|
||||
}
|
||||
|
||||
func (this *HTTPSProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type TCPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *TCPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
|
||||
type TLSProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
|
||||
SSL *sslconfigs.SSLConfig `yaml:"ssl" json:"ssl"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *TLSProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type UDPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *UDPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type UnixProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *UnixProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/scheduling"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 反向代理设置
|
||||
type ReverseProxyConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用 TODO
|
||||
Origins []*OriginServerConfig `yaml:"origins" json:"origins"` // 源站列表
|
||||
Scheduling *SchedulingConfig `yaml:"scheduling" json:"scheduling"` // 调度算法选项
|
||||
|
||||
hasOrigins bool
|
||||
schedulingIsBackup bool
|
||||
schedulingObject scheduling.SchedulingInterface
|
||||
schedulingLocker sync.Mutex
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *ReverseProxyConfig) Init() error {
|
||||
this.hasOrigins = len(this.Origins) > 0
|
||||
|
||||
for _, origin := range this.Origins {
|
||||
err := origin.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// scheduling
|
||||
this.SetupScheduling(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 取得下一个可用的后端服务
|
||||
func (this *ReverseProxyConfig) NextOrigin(call *shared.RequestCall) *OriginServerConfig {
|
||||
this.schedulingLocker.Lock()
|
||||
defer this.schedulingLocker.Unlock()
|
||||
|
||||
if this.schedulingObject == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if this.Scheduling != nil && call != nil && call.Options != nil {
|
||||
for k, v := range this.Scheduling.Options {
|
||||
call.Options[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
candidate := this.schedulingObject.Next(call)
|
||||
if candidate == nil {
|
||||
// 启用备用服务器
|
||||
if !this.schedulingIsBackup {
|
||||
this.SetupScheduling(true)
|
||||
|
||||
candidate = this.schedulingObject.Next(call)
|
||||
if candidate == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if candidate == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return candidate.(*OriginServerConfig)
|
||||
}
|
||||
|
||||
// 设置调度算法
|
||||
func (this *ReverseProxyConfig) SetupScheduling(isBackup bool) {
|
||||
if !isBackup {
|
||||
this.schedulingLocker.Lock()
|
||||
defer this.schedulingLocker.Unlock()
|
||||
}
|
||||
this.schedulingIsBackup = isBackup
|
||||
|
||||
if this.Scheduling == nil {
|
||||
this.schedulingObject = &scheduling.RandomScheduling{}
|
||||
} else {
|
||||
typeCode := this.Scheduling.Code
|
||||
s := scheduling.FindSchedulingType(typeCode)
|
||||
if s == nil {
|
||||
this.Scheduling = nil
|
||||
this.schedulingObject = &scheduling.RandomScheduling{}
|
||||
} else {
|
||||
this.schedulingObject = s["instance"].(scheduling.SchedulingInterface)
|
||||
}
|
||||
}
|
||||
|
||||
for _, origin := range this.Origins {
|
||||
if origin.IsOn && !origin.IsDown {
|
||||
if isBackup && origin.IsBackup {
|
||||
this.schedulingObject.Add(origin)
|
||||
} else if !isBackup && !origin.IsBackup {
|
||||
this.schedulingObject.Add(origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.schedulingObject.Start()
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
// 候选对象接口
|
||||
type CandidateInterface interface {
|
||||
// 权重
|
||||
CandidateWeight() uint
|
||||
|
||||
// 代号
|
||||
CandidateCodes() []string
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 调度算法接口
|
||||
type SchedulingInterface interface {
|
||||
// 是否有候选对象
|
||||
HasCandidates() bool
|
||||
|
||||
// 添加候选对象
|
||||
Add(candidate ...CandidateInterface)
|
||||
|
||||
// 启动
|
||||
Start()
|
||||
|
||||
// 查找下一个候选对象
|
||||
Next(call *shared.RequestCall) CandidateInterface
|
||||
|
||||
// 获取简要信息
|
||||
Summary() maps.Map
|
||||
}
|
||||
|
||||
// 调度算法基础类
|
||||
type Scheduling struct {
|
||||
Candidates []CandidateInterface
|
||||
}
|
||||
|
||||
// 判断是否有候选对象
|
||||
func (this *Scheduling) HasCandidates() bool {
|
||||
return len(this.Candidates) > 0
|
||||
}
|
||||
|
||||
// 添加候选对象
|
||||
func (this *Scheduling) Add(candidate ...CandidateInterface) {
|
||||
this.Candidates = append(this.Candidates, candidate...)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// Hash调度算法
|
||||
type HashScheduling struct {
|
||||
Scheduling
|
||||
|
||||
count uint32
|
||||
}
|
||||
|
||||
// 启动
|
||||
func (this *HashScheduling) Start() {
|
||||
this.count = uint32(len(this.Candidates))
|
||||
}
|
||||
|
||||
// 获取下一个候选对象
|
||||
func (this *HashScheduling) Next(call *shared.RequestCall) CandidateInterface {
|
||||
if this.count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
key := call.Options.GetString("key")
|
||||
|
||||
if call.Formatter != nil {
|
||||
key = call.Formatter(key)
|
||||
}
|
||||
|
||||
sum := crc32.ChecksumIEEE([]byte(key))
|
||||
return this.Candidates[sum%this.count]
|
||||
}
|
||||
|
||||
// 获取简要信息
|
||||
func (this *HashScheduling) Summary() maps.Map {
|
||||
return maps.Map{
|
||||
"code": "hash",
|
||||
"name": "Hash算法",
|
||||
"description": "根据自定义的键值的Hash值分配后端服务器",
|
||||
"networks": []string{"http"},
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestHashScheduling_Next(t *testing.T) {
|
||||
s := &HashScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 30,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
hits := map[string]uint{}
|
||||
for _, c := range s.Candidates {
|
||||
hits[c.(*TestCandidate).Name] = 0
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
for i := 0; i < 1000000; i ++ {
|
||||
call := shared.NewRequestCall()
|
||||
call.Options["key"] = "192.168.1." + fmt.Sprintf("%d", rand.Int())
|
||||
|
||||
c := s.Next(call)
|
||||
hits[c.(*TestCandidate).Name] ++
|
||||
}
|
||||
t.Log(hits)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 随机调度算法
|
||||
type RandomScheduling struct {
|
||||
Scheduling
|
||||
|
||||
array []CandidateInterface
|
||||
count uint // 实际总的服务器数
|
||||
}
|
||||
|
||||
// 启动
|
||||
func (this *RandomScheduling) Start() {
|
||||
sumWeight := uint(0)
|
||||
for _, c := range this.Candidates {
|
||||
weight := c.CandidateWeight()
|
||||
if weight == 0 {
|
||||
weight = 1
|
||||
} else if weight > 10000 {
|
||||
weight = 10000
|
||||
}
|
||||
sumWeight += weight
|
||||
}
|
||||
|
||||
if sumWeight == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, c := range this.Candidates {
|
||||
weight := c.CandidateWeight()
|
||||
if weight == 0 {
|
||||
weight = 1
|
||||
} else if weight > 10000 {
|
||||
weight = 10000
|
||||
}
|
||||
count := uint(0)
|
||||
if sumWeight <= 1000 {
|
||||
count = weight
|
||||
} else {
|
||||
count = uint(math.Round(float64(weight*10000) / float64(sumWeight))) // 1% 产生 100个数据,最多支持10000个服务器
|
||||
}
|
||||
for i := uint(0); i < count; i++ {
|
||||
this.array = append(this.array, c)
|
||||
}
|
||||
this.count += count
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// 获取下一个候选对象
|
||||
func (this *RandomScheduling) Next(call *shared.RequestCall) CandidateInterface {
|
||||
if this.count == 0 {
|
||||
return nil
|
||||
}
|
||||
if this.count == 1 {
|
||||
return this.array[0]
|
||||
}
|
||||
index := rand.Int() % int(this.count)
|
||||
return this.array[index]
|
||||
}
|
||||
|
||||
// 获取简要信息
|
||||
func (this *RandomScheduling) Summary() maps.Map {
|
||||
return maps.Map{
|
||||
"code": "random",
|
||||
"name": "Random随机算法",
|
||||
"description": "根据权重设置随机分配后端服务器",
|
||||
"networks": []string{"http", "tcp"},
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestCandidate struct {
|
||||
Name string
|
||||
Weight uint
|
||||
}
|
||||
|
||||
func (this *TestCandidate) CandidateWeight() uint {
|
||||
return this.Weight
|
||||
}
|
||||
|
||||
func (this *TestCandidate) CandidateCodes() []string {
|
||||
return []string{this.Name}
|
||||
}
|
||||
|
||||
func TestRandomScheduling_Next(t *testing.T) {
|
||||
s := &RandomScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 30,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
/**for _, c := range s.array {
|
||||
t.Log(c.(*TestCandidate).Name, ":", c.CandidateWeight())
|
||||
}**/
|
||||
|
||||
hits := map[string]uint{}
|
||||
for _, c := range s.array {
|
||||
hits[c.(*TestCandidate).Name] = 0
|
||||
}
|
||||
|
||||
t.Log("count:", s.count, "array length:", len(s.array))
|
||||
|
||||
var locker sync.Mutex
|
||||
var wg = sync.WaitGroup{}
|
||||
wg.Add(100 * 10000)
|
||||
for i := 0; i < 100*10000; i ++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
c := s.Next(nil)
|
||||
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
hits[c.(*TestCandidate).Name] ++
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
t.Log(hits)
|
||||
}
|
||||
|
||||
func TestRandomScheduling_NextZero(t *testing.T) {
|
||||
s := &RandomScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 0,
|
||||
})
|
||||
s.Start()
|
||||
t.Log(s.Next(nil))
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 轮询调度算法
|
||||
type RoundRobinScheduling struct {
|
||||
Scheduling
|
||||
|
||||
rawWeights []uint
|
||||
currentWeights []uint
|
||||
count uint
|
||||
index uint
|
||||
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
// 启动
|
||||
func (this *RoundRobinScheduling) Start() {
|
||||
lists.Sort(this.Candidates, func(i int, j int) bool {
|
||||
c1 := this.Candidates[i]
|
||||
c2 := this.Candidates[j]
|
||||
return c1.CandidateWeight() > c2.CandidateWeight()
|
||||
})
|
||||
|
||||
for _, c := range this.Candidates {
|
||||
weight := c.CandidateWeight()
|
||||
if weight == 0 {
|
||||
weight = 1
|
||||
} else if weight > 10000 {
|
||||
weight = 10000
|
||||
}
|
||||
this.rawWeights = append(this.rawWeights, weight)
|
||||
}
|
||||
|
||||
this.currentWeights = append([]uint{}, this.rawWeights...)
|
||||
this.count = uint(len(this.Candidates))
|
||||
}
|
||||
|
||||
// 获取下一个候选对象
|
||||
func (this *RoundRobinScheduling) Next(call *shared.RequestCall) CandidateInterface {
|
||||
if this.count == 0 {
|
||||
return nil
|
||||
}
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
if this.index > this.count-1 {
|
||||
this.index = 0
|
||||
}
|
||||
weight := this.currentWeights[this.index]
|
||||
|
||||
// 已经一轮了,则重置状态
|
||||
if weight == 0 {
|
||||
if this.currentWeights[0] == 0 {
|
||||
this.currentWeights = append([]uint{}, this.rawWeights...)
|
||||
}
|
||||
this.index = 0
|
||||
weight = this.currentWeights[this.index]
|
||||
}
|
||||
|
||||
c := this.Candidates[this.index]
|
||||
this.currentWeights[this.index] --
|
||||
this.index++
|
||||
return c
|
||||
}
|
||||
|
||||
// 获取简要信息
|
||||
func (this *RoundRobinScheduling) Summary() maps.Map {
|
||||
return maps.Map{
|
||||
"code": "roundRobin",
|
||||
"name": "RoundRobin轮询算法",
|
||||
"description": "根据权重,依次分配后端服务器",
|
||||
"networks": []string{"http", "tcp"},
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRoundRobinScheduling_Next(t *testing.T) {
|
||||
s := &RoundRobinScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 5,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 20,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 30,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
for _, c := range s.Candidates {
|
||||
t.Log(c.(*TestCandidate).Name, c.CandidateWeight())
|
||||
}
|
||||
|
||||
t.Log(s.currentWeights)
|
||||
|
||||
for i := 0; i < 100; i ++ {
|
||||
t.Log("===", "round", i, "===")
|
||||
t.Log(s.Next(nil))
|
||||
t.Log(s.currentWeights)
|
||||
t.Log(s.rawWeights)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundRobinScheduling_Two(t *testing.T) {
|
||||
s := &RoundRobinScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 10,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
for _, c := range s.Candidates {
|
||||
t.Log(c.(*TestCandidate).Name, c.CandidateWeight())
|
||||
}
|
||||
|
||||
t.Log(s.currentWeights)
|
||||
|
||||
for i := 0; i < 100; i ++ {
|
||||
t.Log("===", "round", i, "===")
|
||||
t.Log(s.Next(nil))
|
||||
t.Log(s.currentWeights)
|
||||
t.Log(s.rawWeights)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundRobinScheduling_NextPerformance(t *testing.T) {
|
||||
s := &RoundRobinScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 1,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 2,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 3,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 6,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
for _, c := range s.Candidates {
|
||||
t.Log(c.(*TestCandidate).Name, c.CandidateWeight())
|
||||
}
|
||||
|
||||
t.Log(s.currentWeights)
|
||||
|
||||
hits := map[string]uint{}
|
||||
for _, c := range s.Candidates {
|
||||
hits[c.(*TestCandidate).Name] = 0
|
||||
}
|
||||
for i := 0; i < 100*10000; i ++ {
|
||||
c := s.Next(nil)
|
||||
hits[c.(*TestCandidate).Name] ++
|
||||
}
|
||||
|
||||
t.Log(hits)
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Sticky调度算法
|
||||
type StickyScheduling struct {
|
||||
Scheduling
|
||||
|
||||
count uint32
|
||||
mapping map[string]CandidateInterface // code => candidate
|
||||
}
|
||||
|
||||
// 启动
|
||||
func (this *StickyScheduling) Start() {
|
||||
this.mapping = map[string]CandidateInterface{}
|
||||
for _, c := range this.Candidates {
|
||||
for _, code := range c.CandidateCodes() {
|
||||
this.mapping[code] = c
|
||||
}
|
||||
}
|
||||
|
||||
this.count = uint32(len(this.Candidates))
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// 获取下一个候选对象
|
||||
func (this *StickyScheduling) Next(call *shared.RequestCall) CandidateInterface {
|
||||
if this.count == 0 {
|
||||
return nil
|
||||
}
|
||||
typeCode := call.Options.GetString("type")
|
||||
param := call.Options.GetString("param")
|
||||
|
||||
if call.Request == nil {
|
||||
return this.Candidates[uint32(rand.Int())%this.count]
|
||||
}
|
||||
|
||||
code := ""
|
||||
if typeCode == "cookie" {
|
||||
cookie, err := call.Request.Cookie(param)
|
||||
if err == nil {
|
||||
code = cookie.Value
|
||||
}
|
||||
} else if typeCode == "header" {
|
||||
code = call.Request.Header.Get(param)
|
||||
} else if typeCode == "argument" {
|
||||
code = call.Request.URL.Query().Get(param)
|
||||
}
|
||||
|
||||
matched := false
|
||||
var c CandidateInterface = nil
|
||||
|
||||
defer func() {
|
||||
if !matched && c != nil {
|
||||
codes := c.CandidateCodes()
|
||||
if len(codes) == 0 {
|
||||
return
|
||||
}
|
||||
if typeCode == "cookie" {
|
||||
call.AddResponseCall(func(resp http.ResponseWriter) {
|
||||
http.SetCookie(resp, &http.Cookie{
|
||||
Name: param,
|
||||
Value: codes[0],
|
||||
Path: "/",
|
||||
Expires: time.Now().AddDate(0, 1, 0),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
call.AddResponseCall(func(resp http.ResponseWriter) {
|
||||
resp.Header().Set(param, codes[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if len(code) == 0 {
|
||||
c = this.Candidates[uint32(rand.Int())%this.count]
|
||||
return c
|
||||
}
|
||||
|
||||
found := false
|
||||
c, found = this.mapping[code]
|
||||
if !found {
|
||||
c = this.Candidates[uint32(rand.Int())%this.count]
|
||||
return c
|
||||
}
|
||||
|
||||
matched = true
|
||||
return c
|
||||
}
|
||||
|
||||
// 获取简要信息
|
||||
func (this *StickyScheduling) Summary() maps.Map {
|
||||
return maps.Map{
|
||||
"code": "sticky",
|
||||
"name": "Sticky算法",
|
||||
"description": "利用Cookie、URL参数或者HTTP Header来指定后端服务器",
|
||||
"networks": []string{"http"},
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStickyScheduling_NextArgument(t *testing.T) {
|
||||
s := &StickyScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 1,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 2,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 3,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 6,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
t.Log(s.mapping)
|
||||
|
||||
req, err := http.NewRequest("GET", "http://www.example.com/?backend=c", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
options := maps.Map{
|
||||
"type": "argument",
|
||||
"param": "backend",
|
||||
}
|
||||
call := shared.NewRequestCall()
|
||||
call.Request = req
|
||||
call.Options = options
|
||||
t.Log(s.Next(call))
|
||||
t.Log(options)
|
||||
}
|
||||
|
||||
func TestStickyScheduling_NextCookie(t *testing.T) {
|
||||
s := &StickyScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 1,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 2,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 3,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 6,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
t.Log(s.mapping)
|
||||
|
||||
req, err := http.NewRequest("GET", "http://www.example.com/?backend=c", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: "backend",
|
||||
Value: "c",
|
||||
})
|
||||
|
||||
options := maps.Map{
|
||||
"type": "cookie",
|
||||
"param": "backend",
|
||||
}
|
||||
call := shared.NewRequestCall()
|
||||
call.Request = req
|
||||
call.Options = options
|
||||
t.Log(s.Next(call))
|
||||
t.Log(options)
|
||||
}
|
||||
|
||||
func TestStickyScheduling_NextHeader(t *testing.T) {
|
||||
s := &StickyScheduling{}
|
||||
s.Add(&TestCandidate{
|
||||
Name: "a",
|
||||
Weight: 1,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "b",
|
||||
Weight: 2,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "c",
|
||||
Weight: 3,
|
||||
})
|
||||
s.Add(&TestCandidate{
|
||||
Name: "d",
|
||||
Weight: 6,
|
||||
})
|
||||
s.Start()
|
||||
|
||||
t.Log(s.mapping)
|
||||
|
||||
req, err := http.NewRequest("GET", "http://www.example.com/?backend=c", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set("backend", "c")
|
||||
|
||||
options := maps.Map{
|
||||
"type": "header",
|
||||
"param": "backend",
|
||||
}
|
||||
call := shared.NewRequestCall()
|
||||
call.Request = req
|
||||
call.Options = options
|
||||
t.Log(s.Next(call))
|
||||
t.Log(options)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package scheduling
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
// 所有请求类型
|
||||
func AllSchedulingTypes() []maps.Map {
|
||||
types := []maps.Map{}
|
||||
for _, s := range []SchedulingInterface{
|
||||
new(RandomScheduling),
|
||||
new(RoundRobinScheduling),
|
||||
new(HashScheduling),
|
||||
new(StickyScheduling),
|
||||
} {
|
||||
summary := s.Summary()
|
||||
summary["instance"] = s
|
||||
types = append(types, summary)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func FindSchedulingType(code string) maps.Map {
|
||||
for _, summary := range AllSchedulingTypes() {
|
||||
if summary["code"] == code {
|
||||
return summary
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
// 调度算法配置
|
||||
type SchedulingConfig struct {
|
||||
Code string `yaml:"code" json:"code"` // 类型
|
||||
Options maps.Map `yaml:"options" json:"options"` // 选项
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewSchedulingConfig() *SchedulingConfig {
|
||||
return &SchedulingConfig{}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
Id string `yaml:"id" json:"id"` // ID
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
Components []*ComponentConfig `yaml:"components" json:"components"` // 组件
|
||||
Filters []*FilterConfig `yaml:"filters" json:"filters"` // 过滤器
|
||||
Name string `yaml:"name" json:"name"` // 名称
|
||||
Description string `yaml:"description" json:"description"` // 描述
|
||||
ServerNames []*ServerNameConfig `yaml:"serverNames" json:"serverNames"` // 域名
|
||||
|
||||
// 前端协议
|
||||
HTTP *HTTPProtocolConfig `yaml:"http" json:"http"` // HTTP配置
|
||||
HTTPS *HTTPSProtocolConfig `yaml:"https" json:"https"` // HTTPS配置
|
||||
TCP *TCPProtocolConfig `yaml:"tcp" json:"tcp"` // TCP配置
|
||||
TLS *TLSProtocolConfig `yaml:"tls" json:"tls"` // TLS配置
|
||||
Unix *UnixProtocolConfig `yaml:"unix" json:"unix"` // Unix配置
|
||||
UDP *UDPProtocolConfig `yaml:"udp" json:"udp"` // UDP配置
|
||||
|
||||
// Web配置
|
||||
Web *WebConfig `yaml:"web" json:"web"`
|
||||
|
||||
// 反向代理配置
|
||||
ReverseProxy *ReverseProxyConfig `yaml:"reverseProxy" json:"reverseProxy"`
|
||||
}
|
||||
|
||||
func NewServerConfig() *ServerConfig {
|
||||
return &ServerConfig{}
|
||||
}
|
||||
|
||||
func (this *ServerConfig) Init() error {
|
||||
if this.HTTP != nil {
|
||||
err := this.HTTP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.HTTPS != nil {
|
||||
err := this.HTTPS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.TCP != nil {
|
||||
err := this.TCP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.TLS != nil {
|
||||
err := this.TLS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.Unix != nil {
|
||||
err := this.Unix.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.UDP != nil {
|
||||
err := this.UDP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.ReverseProxy != nil {
|
||||
err := this.ReverseProxy.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) FullAddresses() []string {
|
||||
result := []Protocol{}
|
||||
if this.HTTP != nil && this.HTTP.IsOn {
|
||||
result = append(result, this.HTTP.FullAddresses()...)
|
||||
}
|
||||
if this.HTTPS != nil && this.HTTPS.IsOn {
|
||||
result = append(result, this.HTTPS.FullAddresses()...)
|
||||
}
|
||||
if this.TCP != nil && this.TCP.IsOn {
|
||||
result = append(result, this.TCP.FullAddresses()...)
|
||||
}
|
||||
if this.TLS != nil && this.TLS.IsOn {
|
||||
result = append(result, this.TLS.FullAddresses()...)
|
||||
}
|
||||
if this.Unix != nil && this.Unix.IsOn {
|
||||
result = append(result, this.Unix.FullAddresses()...)
|
||||
}
|
||||
if this.UDP != nil && this.UDP.IsOn {
|
||||
result = append(result, this.UDP.FullAddresses()...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *ServerConfig) Listen() []*NetworkAddressConfig {
|
||||
result := []*NetworkAddressConfig{}
|
||||
if this.HTTP != nil {
|
||||
result = append(result, this.HTTP.Listen...)
|
||||
}
|
||||
if this.HTTPS != nil {
|
||||
result = append(result, this.HTTPS.Listen...)
|
||||
}
|
||||
if this.TCP != nil {
|
||||
result = append(result, this.TCP.Listen...)
|
||||
}
|
||||
if this.TLS != nil {
|
||||
result = append(result, this.TLS.Listen...)
|
||||
}
|
||||
if this.Unix != nil {
|
||||
result = append(result, this.Unix.Listen...)
|
||||
}
|
||||
if this.UDP != nil {
|
||||
result = append(result, this.UDP.Listen...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *ServerConfig) AsJSON() ([]byte, error) {
|
||||
return json.Marshal(this)
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsHTTP() bool {
|
||||
return this.HTTP != nil || this.HTTPS != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsTCP() bool {
|
||||
return this.TCP != nil || this.TLS != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsUnix() bool {
|
||||
return this.Unix != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsUDP() bool {
|
||||
return this.UDP != nil
|
||||
}
|
||||
|
||||
// 判断是否和域名匹配
|
||||
func (this *ServerConfig) MatchName(name string) bool {
|
||||
for _, serverName := range this.ServerNames {
|
||||
if serverName.Match(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断是否严格匹配
|
||||
func (this *ServerConfig) MatchNameStrictly(name string) bool {
|
||||
for _, serverName := range this.ServerNames {
|
||||
if serverName.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SSL信息
|
||||
func (this *ServerConfig) SSLConfig() *sslconfigs.SSLConfig {
|
||||
if this.HTTPS != nil {
|
||||
return this.HTTPS.SSL
|
||||
}
|
||||
if this.TLS != nil {
|
||||
return this.TLS.SSL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestServerConfig_Protocols(t *testing.T) {
|
||||
{
|
||||
server := NewServerConfig()
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
server := NewServerConfig()
|
||||
server.HTTP = &HTTPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolHTTP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.HTTPS = &HTTPSProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolUnix,
|
||||
Host: "/hello.sock",
|
||||
PortRange: "1235",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.TCP = &TCPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolHTTPS,
|
||||
PortRange: "1236",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.TLS = &TLSProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolTCP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.Unix = &UnixProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolTLS,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.UDP = &UDPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolUDP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
err := server.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "strings"
|
||||
|
||||
type ServerGroup struct {
|
||||
fullAddr string
|
||||
Servers []*ServerConfig
|
||||
}
|
||||
|
||||
func NewServerGroup(fullAddr string) *ServerGroup {
|
||||
return &ServerGroup{fullAddr: fullAddr}
|
||||
}
|
||||
|
||||
// 添加服务
|
||||
func (this *ServerGroup) Add(server *ServerConfig) {
|
||||
this.Servers = append(this.Servers, server)
|
||||
}
|
||||
|
||||
// 获取完整的地址
|
||||
func (this *ServerGroup) FullAddr() string {
|
||||
return this.fullAddr
|
||||
}
|
||||
|
||||
// 获取当前分组的协议
|
||||
func (this *ServerGroup) Protocol() Protocol {
|
||||
for _, p := range AllProtocols() {
|
||||
if strings.HasPrefix(this.fullAddr, p+":") {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return ProtocolHTTP
|
||||
}
|
||||
|
||||
// 获取当前分组的地址
|
||||
func (this *ServerGroup) Addr() string {
|
||||
protocol := this.Protocol()
|
||||
if protocol == ProtocolUnix {
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+":")
|
||||
}
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+"://")
|
||||
}
|
||||
|
||||
// 判断当前分组是否为HTTP
|
||||
func (this *ServerGroup) IsHTTP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolHTTP || p == ProtocolHTTP4 || p == ProtocolHTTP6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为HTTPS
|
||||
func (this *ServerGroup) IsHTTPS() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolHTTPS || p == ProtocolHTTPS4 || p == ProtocolHTTPS6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为TCP
|
||||
func (this *ServerGroup) IsTCP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolTCP || p == ProtocolTCP4 || p == ProtocolTCP6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为TLS
|
||||
func (this *ServerGroup) IsTLS() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolTLS || p == ProtocolTLS4 || p == ProtocolTLS6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为Unix
|
||||
func (this *ServerGroup) IsUnix() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolUnix
|
||||
}
|
||||
|
||||
// 判断当前分组是否为UDP
|
||||
func (this *ServerGroup) IsUDP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolUDP
|
||||
}
|
||||
|
||||
// 获取第一个Server
|
||||
func (this *ServerGroup) FirstServer() *ServerConfig {
|
||||
if len(this.Servers) > 0 {
|
||||
return this.Servers[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServerGroup_Protocol(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
|
||||
{
|
||||
group := NewServerGroup("tcp://127.0.0.1:1234")
|
||||
a.IsTrue(group.Protocol() == ProtocolTCP)
|
||||
a.IsTrue(group.Addr() == "127.0.0.1:1234")
|
||||
}
|
||||
|
||||
{
|
||||
group := NewServerGroup("http4://127.0.0.1:1234")
|
||||
a.IsTrue(group.Protocol() == ProtocolHTTP4)
|
||||
a.IsTrue(group.Addr() == "127.0.0.1:1234")
|
||||
}
|
||||
|
||||
{
|
||||
group := NewServerGroup("127.0.0.1:1234")
|
||||
a.IsTrue(group.Protocol() == ProtocolHTTP)
|
||||
a.IsTrue(group.Addr() == "127.0.0.1:1234")
|
||||
}
|
||||
|
||||
{
|
||||
group := NewServerGroup("unix:/tmp/my.sock")
|
||||
a.IsTrue(group.Protocol() == ProtocolUnix)
|
||||
a.IsTrue(group.Addr() == "/tmp/my.sock")
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
|
||||
type ServerNameType = string
|
||||
|
||||
const (
|
||||
ServerNameTypeFull = "full" // 完整的域名,包含通配符等
|
||||
ServerNameTypePrefix = "prefix" // 前缀
|
||||
ServerNameTypeSuffix = "suffix" // 后缀
|
||||
ServerNameTypeMatch = "match" // 正则匹配
|
||||
)
|
||||
|
||||
// 主机名(域名)配置
|
||||
type ServerNameConfig struct {
|
||||
Name string `yaml:"name" json:"name"` // 名称
|
||||
Type string `yaml:"type" json:"type"` // 类型
|
||||
}
|
||||
|
||||
// 判断主机名是否匹配
|
||||
func (this *ServerNameConfig) Match(name string) bool {
|
||||
return configutils.MatchDomains([]string{this.Name}, name)
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var regexpNamedVariable = regexp.MustCompile("\\${[\\w.-]+}")
|
||||
|
||||
// 头部信息定义
|
||||
type HeaderConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
Id string `yaml:"id" json:"id"` // ID
|
||||
Name string `yaml:"name" json:"name"` // Name
|
||||
Value string `yaml:"value" json:"value"` // Value
|
||||
Always bool `yaml:"always" json:"always"` // 是否忽略状态码
|
||||
Status []int `yaml:"status" json:"status"` // 支持的状态码
|
||||
|
||||
statusMap map[int]bool
|
||||
hasVariables bool
|
||||
}
|
||||
|
||||
// 获取新Header对象
|
||||
func NewHeaderConfig() *HeaderConfig {
|
||||
return &HeaderConfig{
|
||||
IsOn: true,
|
||||
Id: stringutil.Rand(16),
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *HeaderConfig) Validate() error {
|
||||
this.statusMap = map[int]bool{}
|
||||
this.hasVariables = regexpNamedVariable.MatchString(this.Value)
|
||||
|
||||
if this.Status == nil {
|
||||
this.Status = []int{}
|
||||
}
|
||||
|
||||
for _, status := range this.Status {
|
||||
this.statusMap[status] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否匹配状态码
|
||||
func (this *HeaderConfig) Match(statusCode int) bool {
|
||||
if !this.IsOn {
|
||||
return false
|
||||
}
|
||||
|
||||
if this.Always {
|
||||
return true
|
||||
}
|
||||
|
||||
if this.statusMap != nil {
|
||||
_, found := this.statusMap[statusCode]
|
||||
return found
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 是否有变量
|
||||
func (this *HeaderConfig) HasVariables() bool {
|
||||
return this.hasVariables
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HeaderList相关操作接口
|
||||
type HeaderListInterface interface {
|
||||
// 校验
|
||||
ValidateHeaders() error
|
||||
|
||||
// 取得所有的IgnoreHeader
|
||||
AllIgnoreResponseHeaders() []string
|
||||
|
||||
// 添加IgnoreHeader
|
||||
AddIgnoreResponseHeader(name string)
|
||||
|
||||
// 判断是否包含IgnoreHeader
|
||||
ContainsIgnoreResponseHeader(name string) bool
|
||||
|
||||
// 移除IgnoreHeader
|
||||
RemoveIgnoreResponseHeader(name string)
|
||||
|
||||
// 修改IgnoreHeader
|
||||
UpdateIgnoreResponseHeader(oldName string, newName string)
|
||||
|
||||
// 取得所有的Header
|
||||
AllResponseHeaders() []*HeaderConfig
|
||||
|
||||
// 添加Header
|
||||
AddResponseHeader(header *HeaderConfig)
|
||||
|
||||
// 判断是否包含Header
|
||||
ContainsResponseHeader(name string) bool
|
||||
|
||||
// 查找Header
|
||||
FindResponseHeader(headerId string) *HeaderConfig
|
||||
|
||||
// 移除Header
|
||||
RemoveResponseHeader(headerId string)
|
||||
|
||||
// 取得所有的请求Header
|
||||
AllRequestHeaders() []*HeaderConfig
|
||||
|
||||
// 添加请求Header
|
||||
AddRequestHeader(header *HeaderConfig)
|
||||
|
||||
// 查找请求Header
|
||||
FindRequestHeader(headerId string) *HeaderConfig
|
||||
|
||||
// 移除请求Header
|
||||
RemoveRequestHeader(headerId string)
|
||||
}
|
||||
|
||||
// HeaderList定义
|
||||
type HeaderList struct {
|
||||
// 添加的响应Headers
|
||||
Headers []*HeaderConfig `yaml:"headers" json:"headers"`
|
||||
|
||||
// 忽略的响应Headers
|
||||
IgnoreHeaders []string `yaml:"ignoreHeaders" json:"ignoreHeaders"`
|
||||
|
||||
// 自定义请求Headers
|
||||
RequestHeaders []*HeaderConfig `yaml:"requestHeaders" json:"requestHeaders"`
|
||||
|
||||
hasResponseHeaders bool
|
||||
hasRequestHeaders bool
|
||||
|
||||
hasIgnoreHeaders bool
|
||||
uppercaseIgnoreHeaders []string
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *HeaderList) Init() error {
|
||||
this.hasResponseHeaders = len(this.Headers) > 0
|
||||
this.hasRequestHeaders = len(this.RequestHeaders) > 0
|
||||
|
||||
for _, h := range this.Headers {
|
||||
err := h.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, h := range this.RequestHeaders {
|
||||
err := h.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
this.hasIgnoreHeaders = len(this.IgnoreHeaders) > 0
|
||||
this.uppercaseIgnoreHeaders = []string{}
|
||||
for _, headerKey := range this.IgnoreHeaders {
|
||||
this.uppercaseIgnoreHeaders = append(this.uppercaseIgnoreHeaders, strings.ToUpper(headerKey))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否有Headers
|
||||
func (this *HeaderList) HasResponseHeaders() bool {
|
||||
return this.hasResponseHeaders
|
||||
}
|
||||
|
||||
// 取得所有的IgnoreHeader
|
||||
func (this *HeaderList) AllIgnoreResponseHeaders() []string {
|
||||
if this.IgnoreHeaders == nil {
|
||||
return []string{}
|
||||
}
|
||||
return this.IgnoreHeaders
|
||||
}
|
||||
|
||||
// 添加IgnoreHeader
|
||||
func (this *HeaderList) AddIgnoreResponseHeader(name string) {
|
||||
if !lists.ContainsString(this.IgnoreHeaders, name) {
|
||||
this.IgnoreHeaders = append(this.IgnoreHeaders, name)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否包含IgnoreHeader
|
||||
func (this *HeaderList) ContainsIgnoreResponseHeader(name string) bool {
|
||||
if len(this.IgnoreHeaders) == 0 {
|
||||
return false
|
||||
}
|
||||
return lists.ContainsString(this.IgnoreHeaders, name)
|
||||
}
|
||||
|
||||
// 修改IgnoreHeader
|
||||
func (this *HeaderList) UpdateIgnoreResponseHeader(oldName string, newName string) {
|
||||
result := []string{}
|
||||
for _, h := range this.IgnoreHeaders {
|
||||
if h == oldName {
|
||||
result = append(result, newName)
|
||||
} else {
|
||||
result = append(result, h)
|
||||
}
|
||||
}
|
||||
this.IgnoreHeaders = result
|
||||
}
|
||||
|
||||
// 移除IgnoreHeader
|
||||
func (this *HeaderList) RemoveIgnoreResponseHeader(name string) {
|
||||
result := []string{}
|
||||
for _, n := range this.IgnoreHeaders {
|
||||
if n == name {
|
||||
continue
|
||||
}
|
||||
result = append(result, n)
|
||||
}
|
||||
this.IgnoreHeaders = result
|
||||
}
|
||||
|
||||
// 取得所有的Header
|
||||
func (this *HeaderList) AllResponseHeaders() []*HeaderConfig {
|
||||
if this.Headers == nil {
|
||||
return []*HeaderConfig{}
|
||||
}
|
||||
return this.Headers
|
||||
}
|
||||
|
||||
// 添加Header
|
||||
func (this *HeaderList) AddResponseHeader(header *HeaderConfig) {
|
||||
this.Headers = append(this.Headers, header)
|
||||
}
|
||||
|
||||
// 判断是否包含Header
|
||||
func (this *HeaderList) ContainsResponseHeader(name string) bool {
|
||||
for _, h := range this.Headers {
|
||||
if h.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 查找Header
|
||||
func (this *HeaderList) FindResponseHeader(headerId string) *HeaderConfig {
|
||||
for _, h := range this.Headers {
|
||||
if h.Id == headerId {
|
||||
return h
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 移除Header
|
||||
func (this *HeaderList) RemoveResponseHeader(headerId string) {
|
||||
result := []*HeaderConfig{}
|
||||
for _, h := range this.Headers {
|
||||
if h.Id == headerId {
|
||||
continue
|
||||
}
|
||||
result = append(result, h)
|
||||
}
|
||||
this.Headers = result
|
||||
}
|
||||
|
||||
// 添加请求Header
|
||||
func (this *HeaderList) AddRequestHeader(header *HeaderConfig) {
|
||||
this.RequestHeaders = append(this.RequestHeaders, header)
|
||||
}
|
||||
|
||||
// 判断是否有请求Header
|
||||
func (this *HeaderList) HasRequestHeaders() bool {
|
||||
return this.hasRequestHeaders
|
||||
}
|
||||
|
||||
// 取得所有的请求Header
|
||||
func (this *HeaderList) AllRequestHeaders() []*HeaderConfig {
|
||||
return this.RequestHeaders
|
||||
}
|
||||
|
||||
// 查找请求Header
|
||||
func (this *HeaderList) FindRequestHeader(headerId string) *HeaderConfig {
|
||||
for _, h := range this.RequestHeaders {
|
||||
if h.Id == headerId {
|
||||
return h
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 移除请求Header
|
||||
func (this *HeaderList) RemoveRequestHeader(headerId string) {
|
||||
result := []*HeaderConfig{}
|
||||
for _, h := range this.RequestHeaders {
|
||||
if h.Id == headerId {
|
||||
continue
|
||||
}
|
||||
result = append(result, h)
|
||||
}
|
||||
this.RequestHeaders = result
|
||||
}
|
||||
|
||||
// 判断是否有Ignore Headers
|
||||
func (this *HeaderList) HasIgnoreHeaders() bool {
|
||||
return this.hasIgnoreHeaders
|
||||
}
|
||||
|
||||
// 查找大写的Ignore Headers
|
||||
func (this *HeaderList) UppercaseIgnoreHeaders() []string {
|
||||
return this.uppercaseIgnoreHeaders
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHeaderList_FormatHeaders(t *testing.T) {
|
||||
list := &HeaderList{}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
list.AddRequestHeader(&HeaderConfig{
|
||||
IsOn: true,
|
||||
Name: "A" + fmt.Sprintf("%d", i),
|
||||
Value: "ABCDEFGHIJ${name}KLM${hello}NEFGHIJILKKKk",
|
||||
})
|
||||
}
|
||||
|
||||
err := list.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHeaderConfig_Match(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
h := NewHeaderConfig()
|
||||
err := h.Validate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.IsFalse(h.Match(200))
|
||||
a.IsFalse(h.Match(400))
|
||||
|
||||
h.Status = []int{200, 201, 400}
|
||||
err = h.Validate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.IsTrue(h.Match(400))
|
||||
a.IsFalse(h.Match(500))
|
||||
|
||||
h.Always = true
|
||||
a.IsTrue(h.Match(500))
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var Locker = new(FileLocker)
|
||||
|
||||
// global file modify locker
|
||||
type FileLocker struct {
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
// lock
|
||||
func (this *FileLocker) Lock() {
|
||||
this.locker.Lock()
|
||||
}
|
||||
|
||||
func (this *FileLocker) Unlock() {
|
||||
this.locker.Unlock()
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package shared
|
||||
|
||||
import "regexp"
|
||||
|
||||
// 常用的正则表达式
|
||||
var (
|
||||
RegexpDigitNumber = regexp.MustCompile(`^\d+$`) // 正整数
|
||||
RegexpFloatNumber = regexp.MustCompile(`^\d+(\.\d+)?$`) // 正浮点数,不支持e
|
||||
RegexpAllDigitNumber = regexp.MustCompile(`^[+-]?\d+$`) // 整数,支持正负数
|
||||
RegexpAllFloatNumber = regexp.MustCompile(`^[+-]?\d+(\.\d+)?$`) // 浮点数,支持正负数,不支持e
|
||||
RegexpExternalURL = regexp.MustCompile("(?i)^(http|https|ftp)://") // URL
|
||||
RegexpNamedVariable = regexp.MustCompile("\\${[\\w.-]+}") // 命名变量
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegexp(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
|
||||
a.IsTrue(RegexpFloatNumber.MatchString("123"))
|
||||
a.IsTrue(RegexpFloatNumber.MatchString("123.456"))
|
||||
a.IsFalse(RegexpFloatNumber.MatchString(".456"))
|
||||
a.IsFalse(RegexpFloatNumber.MatchString("abc"))
|
||||
a.IsFalse(RegexpFloatNumber.MatchString("123."))
|
||||
a.IsFalse(RegexpFloatNumber.MatchString("123.456e7"))
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 请求调用
|
||||
type RequestCall struct {
|
||||
Formatter func(source string) string
|
||||
Request *http.Request
|
||||
ResponseCallbacks []func(resp http.ResponseWriter)
|
||||
Options maps.Map
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewRequestCall() *RequestCall {
|
||||
return &RequestCall{
|
||||
Options: maps.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// 重置
|
||||
func (this *RequestCall) Reset() {
|
||||
this.Formatter = nil
|
||||
this.Request = nil
|
||||
this.ResponseCallbacks = nil
|
||||
this.Options = maps.Map{}
|
||||
}
|
||||
|
||||
// 添加响应回调
|
||||
func (this *RequestCall) AddResponseCall(callback func(resp http.ResponseWriter)) {
|
||||
this.ResponseCallbacks = append(this.ResponseCallbacks, callback)
|
||||
}
|
||||
|
||||
// 执行响应回调
|
||||
func (this *RequestCall) CallResponseCallbacks(resp http.ResponseWriter) {
|
||||
for _, callback := range this.ResponseCallbacks {
|
||||
callback(resp)
|
||||
}
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 重写条件定义
|
||||
type RequestCond struct {
|
||||
Id string `yaml:"id" json:"id"` // ID
|
||||
|
||||
// 要测试的字符串
|
||||
// 其中可以使用跟请求相关的参数,比如:
|
||||
// ${arg.name}, ${requestPath}
|
||||
Param string `yaml:"param" json:"param"`
|
||||
|
||||
// 运算符
|
||||
Operator RequestCondOperator `yaml:"operator" json:"operator"`
|
||||
|
||||
// 对比
|
||||
Value string `yaml:"value" json:"value"`
|
||||
|
||||
isInt bool
|
||||
isFloat bool
|
||||
isIP bool
|
||||
|
||||
regValue *regexp.Regexp
|
||||
floatValue float64
|
||||
ipValue net.IP
|
||||
arrayValue []string
|
||||
}
|
||||
|
||||
// 取得新对象
|
||||
func NewRequestCond() *RequestCond {
|
||||
return &RequestCond{
|
||||
Id: stringutil.Rand(16),
|
||||
}
|
||||
}
|
||||
|
||||
// 校验配置
|
||||
func (this *RequestCond) Validate() error {
|
||||
this.isInt = RegexpDigitNumber.MatchString(this.Value)
|
||||
this.isFloat = RegexpFloatNumber.MatchString(this.Value)
|
||||
|
||||
if lists.ContainsString([]string{
|
||||
RequestCondOperatorRegexp,
|
||||
RequestCondOperatorNotRegexp,
|
||||
}, this.Operator) {
|
||||
reg, err := regexp.Compile(this.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.regValue = reg
|
||||
} else if lists.ContainsString([]string{
|
||||
RequestCondOperatorEqFloat,
|
||||
RequestCondOperatorGtFloat,
|
||||
RequestCondOperatorGteFloat,
|
||||
RequestCondOperatorLtFloat,
|
||||
RequestCondOperatorLteFloat,
|
||||
}, this.Operator) {
|
||||
this.floatValue = types.Float64(this.Value)
|
||||
} else if lists.ContainsString([]string{
|
||||
RequestCondOperatorEqIP,
|
||||
RequestCondOperatorGtIP,
|
||||
RequestCondOperatorGteIP,
|
||||
RequestCondOperatorLtIP,
|
||||
RequestCondOperatorLteIP,
|
||||
}, this.Operator) {
|
||||
this.ipValue = net.ParseIP(this.Value)
|
||||
this.isIP = this.ipValue != nil
|
||||
|
||||
if !this.isIP {
|
||||
return errors.New("value should be a valid ip")
|
||||
}
|
||||
} else if lists.ContainsString([]string{
|
||||
RequestCondOperatorIPRange,
|
||||
}, this.Operator) {
|
||||
if strings.Contains(this.Value, ",") {
|
||||
ipList := strings.SplitN(this.Value, ",", 2)
|
||||
ipString1 := strings.TrimSpace(ipList[0])
|
||||
ipString2 := strings.TrimSpace(ipList[1])
|
||||
|
||||
if len(ipString1) > 0 {
|
||||
ip1 := net.ParseIP(ipString1)
|
||||
if ip1 == nil {
|
||||
return errors.New("start ip is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipString2) > 0 {
|
||||
ip2 := net.ParseIP(ipString2)
|
||||
if ip2 == nil {
|
||||
return errors.New("end ip is invalid")
|
||||
}
|
||||
}
|
||||
} else if strings.Contains(this.Value, "/") {
|
||||
_, _, err := net.ParseCIDR(this.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return errors.New("invalid ip range")
|
||||
}
|
||||
} else if lists.ContainsString([]string{
|
||||
RequestCondOperatorIn,
|
||||
RequestCondOperatorNotIn,
|
||||
RequestCondOperatorFileExt,
|
||||
}, this.Operator) {
|
||||
stringsValue := []string{}
|
||||
err := json.Unmarshal([]byte(this.Value), &stringsValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.arrayValue = stringsValue
|
||||
} else if lists.ContainsString([]string{
|
||||
RequestCondOperatorFileMimeType,
|
||||
}, this.Operator) {
|
||||
stringsValue := []string{}
|
||||
err := json.Unmarshal([]byte(this.Value), &stringsValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range stringsValue {
|
||||
if strings.Contains(v, "*") {
|
||||
v = regexp.QuoteMeta(v)
|
||||
v = strings.Replace(v, `\*`, ".*", -1)
|
||||
stringsValue[k] = v
|
||||
}
|
||||
}
|
||||
this.arrayValue = stringsValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 将此条件应用于请求,检查是否匹配
|
||||
func (this *RequestCond) Match(formatter func(source string) string) bool {
|
||||
paramValue := formatter(this.Param)
|
||||
switch this.Operator {
|
||||
case RequestCondOperatorRegexp:
|
||||
if this.regValue == nil {
|
||||
return false
|
||||
}
|
||||
return this.regValue.MatchString(paramValue)
|
||||
case RequestCondOperatorNotRegexp:
|
||||
if this.regValue == nil {
|
||||
return false
|
||||
}
|
||||
return !this.regValue.MatchString(paramValue)
|
||||
case RequestCondOperatorEqInt:
|
||||
return this.isInt && paramValue == this.Value
|
||||
case RequestCondOperatorEqFloat:
|
||||
return this.isFloat && types.Float64(paramValue) == this.floatValue
|
||||
case RequestCondOperatorGtFloat:
|
||||
return this.isFloat && types.Float64(paramValue) > this.floatValue
|
||||
case RequestCondOperatorGteFloat:
|
||||
return this.isFloat && types.Float64(paramValue) >= this.floatValue
|
||||
case RequestCondOperatorLtFloat:
|
||||
return this.isFloat && types.Float64(paramValue) < this.floatValue
|
||||
case RequestCondOperatorLteFloat:
|
||||
return this.isFloat && types.Float64(paramValue) <= this.floatValue
|
||||
case RequestCondOperatorMod:
|
||||
pieces := strings.SplitN(this.Value, ",", 2)
|
||||
if len(pieces) == 1 {
|
||||
rem := types.Int64(pieces[0])
|
||||
return types.Int64(paramValue)%10 == rem
|
||||
}
|
||||
div := types.Int64(pieces[0])
|
||||
if div == 0 {
|
||||
return false
|
||||
}
|
||||
rem := types.Int64(pieces[1])
|
||||
return types.Int64(paramValue)%div == rem
|
||||
case RequestCondOperatorMod10:
|
||||
return types.Int64(paramValue)%10 == types.Int64(this.Value)
|
||||
case RequestCondOperatorMod100:
|
||||
return types.Int64(paramValue)%100 == types.Int64(this.Value)
|
||||
case RequestCondOperatorEqString:
|
||||
return paramValue == this.Value
|
||||
case RequestCondOperatorNeqString:
|
||||
return paramValue != this.Value
|
||||
case RequestCondOperatorHasPrefix:
|
||||
return strings.HasPrefix(paramValue, this.Value)
|
||||
case RequestCondOperatorHasSuffix:
|
||||
return strings.HasSuffix(paramValue, this.Value)
|
||||
case RequestCondOperatorContainsString:
|
||||
return strings.Contains(paramValue, this.Value)
|
||||
case RequestCondOperatorNotContainsString:
|
||||
return !strings.Contains(paramValue, this.Value)
|
||||
case RequestCondOperatorEqIP:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return this.isIP && bytes.Compare(this.ipValue, ip) == 0
|
||||
case RequestCondOperatorGtIP:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return this.isIP && bytes.Compare(ip, this.ipValue) > 0
|
||||
case RequestCondOperatorGteIP:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return this.isIP && bytes.Compare(ip, this.ipValue) >= 0
|
||||
case RequestCondOperatorLtIP:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return this.isIP && bytes.Compare(ip, this.ipValue) < 0
|
||||
case RequestCondOperatorLteIP:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return this.isIP && bytes.Compare(ip, this.ipValue) <= 0
|
||||
case RequestCondOperatorIPRange:
|
||||
ip := net.ParseIP(paramValue)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查IP范围格式
|
||||
if strings.Contains(this.Value, ",") {
|
||||
ipList := strings.SplitN(this.Value, ",", 2)
|
||||
ipString1 := strings.TrimSpace(ipList[0])
|
||||
ipString2 := strings.TrimSpace(ipList[1])
|
||||
|
||||
if len(ipString1) > 0 {
|
||||
ip1 := net.ParseIP(ipString1)
|
||||
if ip1 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if bytes.Compare(ip, ip1) < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipString2) > 0 {
|
||||
ip2 := net.ParseIP(ipString2)
|
||||
if ip2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if bytes.Compare(ip, ip2) > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} else if strings.Contains(this.Value, "/") {
|
||||
_, ipNet, err := net.ParseCIDR(this.Value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ipNet.Contains(ip)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case RequestCondOperatorIn:
|
||||
return lists.ContainsString(this.arrayValue, paramValue)
|
||||
case RequestCondOperatorNotIn:
|
||||
return !lists.ContainsString(this.arrayValue, paramValue)
|
||||
case RequestCondOperatorFileExt:
|
||||
ext := filepath.Ext(paramValue)
|
||||
if len(ext) > 0 {
|
||||
ext = ext[1:] // remove dot
|
||||
}
|
||||
return lists.ContainsString(this.arrayValue, strings.ToLower(ext))
|
||||
case RequestCondOperatorFileMimeType:
|
||||
index := strings.Index(paramValue, ";")
|
||||
if index >= 0 {
|
||||
paramValue = strings.TrimSpace(paramValue[:index])
|
||||
}
|
||||
if len(this.arrayValue) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, v := range this.arrayValue {
|
||||
if strings.Contains(v, "*") {
|
||||
reg, err := stringutil.RegexpCompile("^" + v + "$")
|
||||
if err == nil && reg.MatchString(paramValue) {
|
||||
return true
|
||||
}
|
||||
} else if paramValue == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case RequestCondOperatorVersionRange:
|
||||
if strings.Contains(this.Value, ",") {
|
||||
versions := strings.SplitN(this.Value, ",", 2)
|
||||
version1 := strings.TrimSpace(versions[0])
|
||||
version2 := strings.TrimSpace(versions[1])
|
||||
if len(version1) > 0 && stringutil.VersionCompare(paramValue, version1) < 0 {
|
||||
return false
|
||||
}
|
||||
if len(version2) > 0 && stringutil.VersionCompare(paramValue, version2) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return stringutil.VersionCompare(paramValue, this.Value) >= 0
|
||||
}
|
||||
case RequestCondOperatorIPMod:
|
||||
pieces := strings.SplitN(this.Value, ",", 2)
|
||||
if len(pieces) == 1 {
|
||||
rem := types.Int64(pieces[0])
|
||||
return this.ipToInt64(net.ParseIP(paramValue))%10 == rem
|
||||
}
|
||||
div := types.Int64(pieces[0])
|
||||
if div == 0 {
|
||||
return false
|
||||
}
|
||||
rem := types.Int64(pieces[1])
|
||||
return this.ipToInt64(net.ParseIP(paramValue))%div == rem
|
||||
case RequestCondOperatorIPMod10:
|
||||
return this.ipToInt64(net.ParseIP(paramValue))%10 == types.Int64(this.Value)
|
||||
case RequestCondOperatorIPMod100:
|
||||
return this.ipToInt64(net.ParseIP(paramValue))%100 == types.Int64(this.Value)
|
||||
case RequestCondOperatorFileExist:
|
||||
index := strings.Index(paramValue, "?")
|
||||
if index > -1 {
|
||||
paramValue = paramValue[:index]
|
||||
}
|
||||
if len(paramValue) == 0 {
|
||||
return false
|
||||
}
|
||||
if !filepath.IsAbs(paramValue) {
|
||||
paramValue = Tea.Root + Tea.DS + paramValue
|
||||
}
|
||||
stat, err := os.Stat(paramValue)
|
||||
return err == nil && !stat.IsDir()
|
||||
case RequestCondOperatorFileNotExist:
|
||||
index := strings.Index(paramValue, "?")
|
||||
if index > -1 {
|
||||
paramValue = paramValue[:index]
|
||||
}
|
||||
if len(paramValue) == 0 {
|
||||
return true
|
||||
}
|
||||
if !filepath.IsAbs(paramValue) {
|
||||
paramValue = Tea.Root + Tea.DS + paramValue
|
||||
}
|
||||
stat, err := os.Stat(paramValue)
|
||||
return err != nil || stat.IsDir()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *RequestCond) ipToInt64(ip net.IP) int64 {
|
||||
if len(ip) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(ip) == 16 {
|
||||
return int64(binary.BigEndian.Uint32(ip[12:16]))
|
||||
}
|
||||
return int64(binary.BigEndian.Uint32(ip))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,226 +0,0 @@
|
||||
package shared
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
// 运算符定义
|
||||
type RequestCondOperator = string
|
||||
|
||||
const (
|
||||
// 正则
|
||||
RequestCondOperatorRegexp RequestCondOperator = "regexp"
|
||||
RequestCondOperatorNotRegexp RequestCondOperator = "not regexp"
|
||||
|
||||
// 数字相关
|
||||
RequestCondOperatorEqInt RequestCondOperator = "eq int" // 整数等于
|
||||
RequestCondOperatorEqFloat RequestCondOperator = "eq float" // 浮点数等于
|
||||
RequestCondOperatorGtFloat RequestCondOperator = "gt"
|
||||
RequestCondOperatorGteFloat RequestCondOperator = "gte"
|
||||
RequestCondOperatorLtFloat RequestCondOperator = "lt"
|
||||
RequestCondOperatorLteFloat RequestCondOperator = "lte"
|
||||
|
||||
// 取模
|
||||
RequestCondOperatorMod10 RequestCondOperator = "mod 10"
|
||||
RequestCondOperatorMod100 RequestCondOperator = "mod 100"
|
||||
RequestCondOperatorMod RequestCondOperator = "mod"
|
||||
|
||||
// 字符串相关
|
||||
RequestCondOperatorEqString RequestCondOperator = "eq"
|
||||
RequestCondOperatorNeqString RequestCondOperator = "not"
|
||||
RequestCondOperatorHasPrefix RequestCondOperator = "prefix"
|
||||
RequestCondOperatorHasSuffix RequestCondOperator = "suffix"
|
||||
RequestCondOperatorContainsString RequestCondOperator = "contains"
|
||||
RequestCondOperatorNotContainsString RequestCondOperator = "not contains"
|
||||
RequestCondOperatorIn RequestCondOperator = "in"
|
||||
RequestCondOperatorNotIn RequestCondOperator = "not in"
|
||||
RequestCondOperatorFileExt RequestCondOperator = "file ext"
|
||||
RequestCondOperatorFileMimeType RequestCondOperator = "mime type"
|
||||
RequestCondOperatorVersionRange RequestCondOperator = "version range"
|
||||
|
||||
// IP相关
|
||||
RequestCondOperatorEqIP RequestCondOperator = "eq ip"
|
||||
RequestCondOperatorGtIP RequestCondOperator = "gt ip"
|
||||
RequestCondOperatorGteIP RequestCondOperator = "gte ip"
|
||||
RequestCondOperatorLtIP RequestCondOperator = "lt ip"
|
||||
RequestCondOperatorLteIP RequestCondOperator = "lte ip"
|
||||
RequestCondOperatorIPRange RequestCondOperator = "ip range"
|
||||
RequestCondOperatorIPMod10 RequestCondOperator = "ip mod 10"
|
||||
RequestCondOperatorIPMod100 RequestCondOperator = "ip mod 100"
|
||||
RequestCondOperatorIPMod RequestCondOperator = "ip mod"
|
||||
|
||||
// 文件相关
|
||||
RequestCondOperatorFileExist RequestCondOperator = "file exist"
|
||||
RequestCondOperatorFileNotExist RequestCondOperator = "file not exist"
|
||||
)
|
||||
|
||||
// 所有的运算符
|
||||
func AllRequestOperators() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"name": "正则表达式匹配",
|
||||
"op": RequestCondOperatorRegexp,
|
||||
"description": "判断是否正则表达式匹配",
|
||||
},
|
||||
{
|
||||
"name": "正则表达式不匹配",
|
||||
"op": RequestCondOperatorNotRegexp,
|
||||
"description": "判断是否正则表达式不匹配",
|
||||
},
|
||||
{
|
||||
"name": "字符串等于",
|
||||
"op": RequestCondOperatorEqString,
|
||||
"description": "使用字符串对比参数值是否相等于某个值",
|
||||
},
|
||||
{
|
||||
"name": "字符串前缀",
|
||||
"op": RequestCondOperatorHasPrefix,
|
||||
"description": "参数值包含某个前缀",
|
||||
},
|
||||
{
|
||||
"name": "字符串后缀",
|
||||
"op": RequestCondOperatorHasSuffix,
|
||||
"description": "参数值包含某个后缀",
|
||||
},
|
||||
{
|
||||
"name": "字符串包含",
|
||||
"op": RequestCondOperatorContainsString,
|
||||
"description": "参数值包含另外一个字符串",
|
||||
},
|
||||
{
|
||||
"name": "字符串不包含",
|
||||
"op": RequestCondOperatorNotContainsString,
|
||||
"description": "参数值不包含另外一个字符串",
|
||||
},
|
||||
{
|
||||
"name": "字符串不等于",
|
||||
"op": RequestCondOperatorNeqString,
|
||||
"description": "使用字符串对比参数值是否不相等于某个值",
|
||||
},
|
||||
{
|
||||
"name": "在列表中",
|
||||
"op": RequestCondOperatorIn,
|
||||
"description": "判断参数值在某个列表中",
|
||||
},
|
||||
{
|
||||
"name": "不在列表中",
|
||||
"op": RequestCondOperatorNotIn,
|
||||
"description": "判断参数值不在某个列表中",
|
||||
},
|
||||
{
|
||||
"name": "扩展名",
|
||||
"op": RequestCondOperatorFileExt,
|
||||
"description": "判断小写的扩展名(不带点)在某个列表中",
|
||||
},
|
||||
{
|
||||
"name": "MimeType",
|
||||
"op": RequestCondOperatorFileMimeType,
|
||||
"description": "判断MimeType在某个列表中,支持类似于image/*的语法",
|
||||
},
|
||||
{
|
||||
"name": "版本号范围",
|
||||
"op": RequestCondOperatorVersionRange,
|
||||
"description": "判断版本号在某个范围内,格式为version1,version2",
|
||||
},
|
||||
{
|
||||
"name": "整数等于",
|
||||
"op": RequestCondOperatorEqInt,
|
||||
"description": "将参数转换为整数数字后进行对比",
|
||||
},
|
||||
{
|
||||
"name": "浮点数等于",
|
||||
"op": RequestCondOperatorEqFloat,
|
||||
"description": "将参数转换为可以有小数的浮点数字进行对比",
|
||||
},
|
||||
{
|
||||
"name": "数字大于",
|
||||
"op": RequestCondOperatorGtFloat,
|
||||
"description": "将参数转换为数字进行对比",
|
||||
},
|
||||
{
|
||||
"name": "数字大于等于",
|
||||
"op": RequestCondOperatorGteFloat,
|
||||
"description": "将参数转换为数字进行对比",
|
||||
},
|
||||
{
|
||||
"name": "数字小于",
|
||||
"op": RequestCondOperatorLtFloat,
|
||||
"description": "将参数转换为数字进行对比",
|
||||
},
|
||||
{
|
||||
"name": "数字小于等于",
|
||||
"op": RequestCondOperatorLteFloat,
|
||||
"description": "将参数转换为数字进行对比",
|
||||
},
|
||||
{
|
||||
"name": "整数取模10",
|
||||
"op": RequestCondOperatorMod10,
|
||||
"description": "对整数参数值取模,除数为10,对比值为余数",
|
||||
},
|
||||
{
|
||||
"name": "整数取模100",
|
||||
"op": RequestCondOperatorMod100,
|
||||
"description": "对整数参数值取模,除数为100,对比值为余数",
|
||||
},
|
||||
{
|
||||
"name": "整数取模",
|
||||
"op": RequestCondOperatorMod,
|
||||
"description": "对整数参数值取模,对比值格式为:除数,余数,比如10,1",
|
||||
},
|
||||
{
|
||||
"name": "IP等于",
|
||||
"op": RequestCondOperatorEqIP,
|
||||
"description": "将参数转换为IP进行对比",
|
||||
},
|
||||
{
|
||||
"name": "IP大于",
|
||||
"op": RequestCondOperatorGtIP,
|
||||
"description": "将参数转换为IP进行对比",
|
||||
},
|
||||
{
|
||||
"name": "IP大于等于",
|
||||
"op": RequestCondOperatorGteIP,
|
||||
"description": "将参数转换为IP进行对比",
|
||||
},
|
||||
{
|
||||
"name": "IP小于",
|
||||
"op": RequestCondOperatorLtIP,
|
||||
"description": "将参数转换为IP进行对比",
|
||||
},
|
||||
{
|
||||
"name": "IP小于等于",
|
||||
"op": RequestCondOperatorLteIP,
|
||||
"description": "将参数转换为IP进行对比",
|
||||
},
|
||||
{
|
||||
"name": "IP范围",
|
||||
"op": RequestCondOperatorIPRange,
|
||||
"description": "IP在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits",
|
||||
},
|
||||
{
|
||||
"name": "IP取模10",
|
||||
"op": RequestCondOperatorIPMod10,
|
||||
"description": "对IP参数值取模,除数为10,对比值为余数",
|
||||
},
|
||||
{
|
||||
"name": "IP取模100",
|
||||
"op": RequestCondOperatorIPMod100,
|
||||
"description": "对IP参数值取模,除数为100,对比值为余数",
|
||||
},
|
||||
{
|
||||
"name": "IP取模",
|
||||
"op": RequestCondOperatorIPMod,
|
||||
"description": "对IP参数值取模,对比值格式为:除数,余数,比如10,1",
|
||||
},
|
||||
|
||||
{
|
||||
"name": "文件存在",
|
||||
"op": RequestCondOperatorFileExist,
|
||||
"description": "判断参数值解析后的文件是否存在",
|
||||
},
|
||||
|
||||
{
|
||||
"name": "文件不存在",
|
||||
"op": RequestCondOperatorFileNotExist,
|
||||
"description": "判断参数值解析后的文件是否不存在",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package shared
|
||||
|
||||
type SizeCapacityUnit = string
|
||||
|
||||
const (
|
||||
SizeCapacityUnitByte SizeCapacityUnit = "byte"
|
||||
SizeCapacityUnitKB SizeCapacityUnit = "kb"
|
||||
SizeCapacityUnitMB SizeCapacityUnit = "mb"
|
||||
SizeCapacityUnitGB SizeCapacityUnit = "gb"
|
||||
)
|
||||
|
||||
type SizeCapacity struct {
|
||||
Count int64 `json:"count" yaml:"count"`
|
||||
Unit SizeCapacityUnit `json:"unit" yaml:"unit"`
|
||||
}
|
||||
|
||||
func (this *SizeCapacity) Bytes() int64 {
|
||||
switch this.Unit {
|
||||
case SizeCapacityUnitByte:
|
||||
return this.Count
|
||||
case SizeCapacityUnitKB:
|
||||
return this.Count * 1024
|
||||
case SizeCapacityUnitMB:
|
||||
return this.Count * 1024 * 1024
|
||||
case SizeCapacityUnitGB:
|
||||
return this.Count * 1024 * 1024 * 1024
|
||||
default:
|
||||
return this.Count
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package shared
|
||||
|
||||
import "time"
|
||||
|
||||
type TimeDurationUnit = string
|
||||
|
||||
const (
|
||||
TimeDurationUnitMS TimeDurationUnit = "ms"
|
||||
TimeDurationUnitSecond TimeDurationUnit = "second"
|
||||
TimeDurationUnitMinute TimeDurationUnit = "minute"
|
||||
TimeDurationUnitHour TimeDurationUnit = "hour"
|
||||
TimeDurationUnitDay TimeDurationUnit = "day"
|
||||
)
|
||||
|
||||
// 时间间隔
|
||||
type TimeDuration struct {
|
||||
Count int64 `yaml:"count" json:"count"` // 数量
|
||||
Unit TimeDurationUnit `yaml:"unit" json:"unit"` // 单位
|
||||
}
|
||||
|
||||
func (this *TimeDuration) Duration() time.Duration {
|
||||
switch this.Unit {
|
||||
case TimeDurationUnitMS:
|
||||
return time.Duration(this.Count) * time.Millisecond
|
||||
case TimeDurationUnitSecond:
|
||||
return time.Duration(this.Count) * time.Second
|
||||
case TimeDurationUnitMinute:
|
||||
return time.Duration(this.Count) * time.Minute
|
||||
case TimeDurationUnitHour:
|
||||
return time.Duration(this.Count) * time.Hour
|
||||
case TimeDurationUnitDay:
|
||||
return time.Duration(this.Count) * 24 * time.Hour
|
||||
default:
|
||||
return time.Duration(this.Count) * time.Second
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TLS Version
|
||||
type TLSVersion = string
|
||||
|
||||
// Cipher Suites
|
||||
type TLSCipherSuite = string
|
||||
|
||||
// SSL配置
|
||||
type SSLConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
|
||||
Certs []*SSLCertConfig `yaml:"certs" json:"certs"`
|
||||
ClientAuthType SSLClientAuthType `yaml:"clientAuthType" json:"clientAuthType"` // 客户端认证类型
|
||||
ClientCACertIds []string `yaml:"clientCACertIds" json:"clientCACertIds"` // 客户端认证CA
|
||||
|
||||
Listen []string `yaml:"listen" json:"listen"` // 网络地址
|
||||
MinVersion TLSVersion `yaml:"minVersion" json:"minVersion"` // 支持的最小版本
|
||||
CipherSuites []TLSCipherSuite `yaml:"cipherSuites" json:"cipherSuites"` // 加密算法套件
|
||||
|
||||
HSTS *HSTSConfig `yaml:"hsts2" json:"hsts"` // HSTS配置,yaml之所以使用hsts2,是因为要和以前的版本分开
|
||||
HTTP2Disabled bool `yaml:"http2Disabled" json:"http2Disabled"` // 是否禁用HTTP2
|
||||
|
||||
nameMapping map[string]*tls.Certificate // dnsName => cert
|
||||
|
||||
minVersion uint16
|
||||
cipherSuites []uint16
|
||||
|
||||
clientCAPool *x509.CertPool
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewSSLConfig() *SSLConfig {
|
||||
return &SSLConfig{}
|
||||
}
|
||||
|
||||
// 校验配置
|
||||
func (this *SSLConfig) Init() error {
|
||||
if !this.IsOn {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(this.Certs) == 0 {
|
||||
return errors.New("no certificates in https config")
|
||||
}
|
||||
|
||||
for _, cert := range this.Certs {
|
||||
err := cert.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.Listen == nil {
|
||||
this.Listen = []string{}
|
||||
} else {
|
||||
for index, addr := range this.Listen {
|
||||
_, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
this.Listen[index] = strings.TrimSuffix(addr, ":") + ":443"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// min version
|
||||
this.convertMinVersion()
|
||||
|
||||
// cipher suite categories
|
||||
this.initCipherSuites()
|
||||
|
||||
// hsts
|
||||
if this.HSTS != nil {
|
||||
err := this.HSTS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// CA证书
|
||||
if len(this.ClientCACertIds) > 0 && this.ClientAuthType != SSLClientAuthTypeNoClientCert {
|
||||
this.clientCAPool = x509.NewCertPool()
|
||||
list := SharedSSLCertList()
|
||||
for _, certId := range this.ClientCACertIds {
|
||||
cert := list.FindCert(certId)
|
||||
if cert == nil {
|
||||
continue
|
||||
}
|
||||
if !cert.IsOn {
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadFile(cert.FullCertPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.clientCAPool.AppendCertsFromPEM(data)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 取得最小版本
|
||||
func (this *SSLConfig) TLSMinVersion() uint16 {
|
||||
return this.minVersion
|
||||
}
|
||||
|
||||
// 套件
|
||||
func (this *SSLConfig) TLSCipherSuites() []uint16 {
|
||||
return this.cipherSuites
|
||||
}
|
||||
|
||||
// 校验是否匹配某个域名
|
||||
func (this *SSLConfig) MatchDomain(domain string) (cert *tls.Certificate, ok bool) {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.MatchDomain(domain) {
|
||||
return cert.CertObject(), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// 取得第一个证书
|
||||
func (this *SSLConfig) FirstCert() *tls.Certificate {
|
||||
for _, cert := range this.Certs {
|
||||
return cert.CertObject()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否包含某个证书或密钥路径
|
||||
func (this *SSLConfig) ContainsFile(file string) bool {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.CertFile == file || cert.KeyFile == file {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除证书文件
|
||||
func (this *SSLConfig) DeleteFiles() error {
|
||||
var resultErr error = nil
|
||||
|
||||
for _, cert := range this.Certs {
|
||||
err := cert.DeleteFiles()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// 查找单个证书配置
|
||||
func (this *SSLConfig) FindCert(certId string) *SSLCertConfig {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加证书
|
||||
func (this *SSLConfig) AddCert(cert *SSLCertConfig) {
|
||||
this.Certs = append(this.Certs, cert)
|
||||
}
|
||||
|
||||
// CA证书Pool,用于TLS对客户端进行认证
|
||||
func (this *SSLConfig) CAPool() *x509.CertPool {
|
||||
return this.clientCAPool
|
||||
}
|
||||
|
||||
// 分解所有监听地址
|
||||
func (this *SSLConfig) ParseListenAddresses() []string {
|
||||
result := []string{}
|
||||
var reg = regexp.MustCompile(`\[\s*(\d+)\s*[,:-]\s*(\d+)\s*]$`)
|
||||
for _, addr := range this.Listen {
|
||||
match := reg.FindStringSubmatch(addr)
|
||||
if len(match) == 0 {
|
||||
result = append(result, addr)
|
||||
} else {
|
||||
min := types.Int(match[1])
|
||||
max := types.Int(match[2])
|
||||
if min > max {
|
||||
min, max = max, min
|
||||
}
|
||||
for i := min; i <= max; i++ {
|
||||
newAddr := reg.ReplaceAllString(addr, ":"+strconv.Itoa(i))
|
||||
result = append(result, newAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 认证类型
|
||||
type SSLClientAuthType = int
|
||||
|
||||
const (
|
||||
SSLClientAuthTypeNoClientCert SSLClientAuthType = 0
|
||||
SSLClientAuthTypeRequestClientCert SSLClientAuthType = 1
|
||||
SSLClientAuthTypeRequireAnyClientCert SSLClientAuthType = 2
|
||||
SSLClientAuthTypeVerifyClientCertIfGiven SSLClientAuthType = 3
|
||||
SSLClientAuthTypeRequireAndVerifyClientCert SSLClientAuthType = 4
|
||||
)
|
||||
|
||||
// 所有的客户端认证类型
|
||||
func AllSSLClientAuthTypes() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"name": "不需要客户端证书",
|
||||
"type": SSLClientAuthTypeNoClientCert,
|
||||
"requireCA": false,
|
||||
},
|
||||
{
|
||||
"name": "请求客户端证书",
|
||||
"type": SSLClientAuthTypeRequestClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "需要客户端证书,但不校验",
|
||||
"type": SSLClientAuthTypeRequireAnyClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "有客户端证书的时候才校验",
|
||||
"type": SSLClientAuthTypeVerifyClientCertIfGiven,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "校验客户端提供的证书",
|
||||
"type": SSLClientAuthTypeRequireAndVerifyClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 查找单个认证方式的名称
|
||||
func FindSSLClientAuthTypeName(authType SSLClientAuthType) string {
|
||||
for _, m := range AllSSLClientAuthTypes() {
|
||||
if m.GetInt("type") == authType {
|
||||
return m.GetString("name")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 认证类型和tls包内类型的映射
|
||||
func GoSSLClientAuthType(authType SSLClientAuthType) tls.ClientAuthType {
|
||||
switch authType {
|
||||
case SSLClientAuthTypeNoClientCert:
|
||||
return tls.NoClientCert
|
||||
case SSLClientAuthTypeRequestClientCert:
|
||||
return tls.RequestClientCert
|
||||
case SSLClientAuthTypeRequireAnyClientCert:
|
||||
return tls.RequireAnyClientCert
|
||||
case SSLClientAuthTypeVerifyClientCertIfGiven:
|
||||
return tls.VerifyClientCertIfGiven
|
||||
case SSLClientAuthTypeRequireAndVerifyClientCert:
|
||||
return tls.RequireAndVerifyClientCert
|
||||
}
|
||||
return tls.NoClientCert
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSL证书
|
||||
type SSLCertConfig struct {
|
||||
Id string `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Description string `yaml:"description" json:"description"` // 说明
|
||||
CertFile string `yaml:"certFile" json:"certFile"`
|
||||
KeyFile string `yaml:"keyFile" json:"keyFile"`
|
||||
IsLocal bool `yaml:"isLocal" json:"isLocal"` // 是否为本地文件
|
||||
TaskId string `yaml:"taskId" json:"taskId"` // 生成证书任务ID
|
||||
IsShared bool `yaml:"isShared" json:"isShared"` // 是否为公用组件
|
||||
ServerName string `yaml:"serverName" json:"serverName"` // 证书使用的主机名,在请求TLS服务器时需要
|
||||
IsCA bool `yaml:"isCA" json:"isCA"` // 是否为CA证书
|
||||
|
||||
dnsNames []string
|
||||
cert *tls.Certificate
|
||||
timeBefore time.Time
|
||||
timeAfter time.Time
|
||||
issuer pkix.Name
|
||||
}
|
||||
|
||||
// 获取新的SSL证书
|
||||
func NewSSLCertConfig(certFile string, keyFile string) *SSLCertConfig {
|
||||
return &SSLCertConfig{
|
||||
IsOn: true,
|
||||
Id: stringutil.Rand(16),
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *SSLCertConfig) Init() error {
|
||||
if this.IsShared {
|
||||
shared := this.FindShared()
|
||||
if shared == nil {
|
||||
return errors.New("the shared cert has been deleted")
|
||||
}
|
||||
|
||||
// 拷贝之前需要保留的
|
||||
serverName := this.ServerName
|
||||
|
||||
// copy
|
||||
configutils.CopyStructObject(this, shared)
|
||||
this.ServerName = serverName
|
||||
}
|
||||
|
||||
this.dnsNames = []string{}
|
||||
|
||||
if len(this.CertFile) == 0 {
|
||||
return errors.New("cert file should not be empty")
|
||||
}
|
||||
|
||||
// 分析证书
|
||||
if this.IsCA { // CA证书
|
||||
data, err := ioutil.ReadFile(this.FullCertPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
index := -1
|
||||
this.cert = &tls.Certificate{
|
||||
Certificate: [][]byte{},
|
||||
}
|
||||
for {
|
||||
index++
|
||||
|
||||
block, rest := pem.Decode(data)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
break
|
||||
}
|
||||
this.cert.Certificate = append(this.cert.Certificate, block.Bytes)
|
||||
data = rest
|
||||
c, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
return errors.New("no available certificates in file")
|
||||
}
|
||||
|
||||
dnsNames := c.DNSNames
|
||||
if len(dnsNames) > 0 {
|
||||
for _, dnsName := range dnsNames {
|
||||
if !lists.ContainsString(this.dnsNames, dnsName) {
|
||||
this.dnsNames = append(this.dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
this.timeBefore = c.NotBefore
|
||||
this.timeAfter = c.NotAfter
|
||||
this.issuer = c.Issuer
|
||||
}
|
||||
}
|
||||
} else { // 证书+私钥
|
||||
if len(this.KeyFile) == 0 {
|
||||
return errors.New("key file should not be empty")
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(this.FullCertPath(), this.FullKeyPath())
|
||||
if err != nil {
|
||||
return errors.New("load certificate '" + this.CertFile + "', '" + this.KeyFile + "' failed:" + err.Error())
|
||||
}
|
||||
|
||||
for index, data := range cert.Certificate {
|
||||
c, err := x509.ParseCertificate(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
dnsNames := c.DNSNames
|
||||
if len(dnsNames) > 0 {
|
||||
for _, dnsName := range dnsNames {
|
||||
if !lists.ContainsString(this.dnsNames, dnsName) {
|
||||
this.dnsNames = append(this.dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
this.timeBefore = c.NotBefore
|
||||
this.timeAfter = c.NotAfter
|
||||
this.issuer = c.Issuer
|
||||
}
|
||||
}
|
||||
|
||||
this.cert = &cert
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查找共享的证书
|
||||
func (this *SSLCertConfig) FindShared() *SSLCertConfig {
|
||||
if !this.IsShared {
|
||||
return nil
|
||||
}
|
||||
return SharedSSLCertList().FindCert(this.Id)
|
||||
}
|
||||
|
||||
// 证书文件路径
|
||||
func (this *SSLCertConfig) FullCertPath() string {
|
||||
if len(this.CertFile) == 0 {
|
||||
return ""
|
||||
}
|
||||
if !strings.ContainsAny(this.CertFile, "/\\") {
|
||||
return Tea.ConfigFile(this.CertFile)
|
||||
}
|
||||
return this.CertFile
|
||||
}
|
||||
|
||||
// 密钥文件路径
|
||||
func (this *SSLCertConfig) FullKeyPath() string {
|
||||
if len(this.KeyFile) == 0 {
|
||||
return ""
|
||||
}
|
||||
if !strings.ContainsAny(this.KeyFile, "/\\") {
|
||||
return Tea.ConfigFile(this.KeyFile)
|
||||
}
|
||||
return this.KeyFile
|
||||
}
|
||||
|
||||
// 校验是否匹配某个域名
|
||||
func (this *SSLCertConfig) MatchDomain(domain string) bool {
|
||||
if len(this.dnsNames) == 0 {
|
||||
return false
|
||||
}
|
||||
return configutils.MatchDomains(this.dnsNames, domain)
|
||||
}
|
||||
|
||||
// 证书中的域名
|
||||
func (this *SSLCertConfig) DNSNames() []string {
|
||||
return this.dnsNames
|
||||
}
|
||||
|
||||
// 获取证书对象
|
||||
func (this *SSLCertConfig) CertObject() *tls.Certificate {
|
||||
return this.cert
|
||||
}
|
||||
|
||||
// 开始时间
|
||||
func (this *SSLCertConfig) TimeBefore() time.Time {
|
||||
return this.timeBefore
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
func (this *SSLCertConfig) TimeAfter() time.Time {
|
||||
return this.timeAfter
|
||||
}
|
||||
|
||||
// 发行信息
|
||||
func (this *SSLCertConfig) Issuer() pkix.Name {
|
||||
return this.issuer
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
func (this *SSLCertConfig) DeleteFiles() error {
|
||||
if this.IsLocal {
|
||||
return nil
|
||||
}
|
||||
|
||||
var resultErr error = nil
|
||||
if len(this.CertFile) > 0 && !strings.ContainsAny(this.CertFile, "/\\") {
|
||||
err := files.NewFile(this.FullCertPath()).Delete()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
|
||||
if len(this.KeyFile) > 0 && !strings.ContainsAny(this.KeyFile, "/\\") {
|
||||
err := files.NewFile(this.FullKeyPath()).Delete()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// 读取证书文件
|
||||
func (this *SSLCertConfig) ReadCert() ([]byte, error) {
|
||||
if len(this.CertFile) == 0 {
|
||||
return nil, errors.New("cert file should not be empty")
|
||||
}
|
||||
|
||||
if this.IsLocal {
|
||||
return ioutil.ReadFile(this.CertFile)
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(Tea.ConfigFile(this.CertFile))
|
||||
}
|
||||
|
||||
// 读取密钥文件
|
||||
func (this *SSLCertConfig) ReadKey() ([]byte, error) {
|
||||
if len(this.KeyFile) == 0 {
|
||||
return nil, errors.New("key file should not be empty")
|
||||
}
|
||||
|
||||
if this.IsLocal {
|
||||
return ioutil.ReadFile(this.KeyFile)
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(Tea.ConfigFile(this.KeyFile))
|
||||
}
|
||||
|
||||
// 匹配关键词
|
||||
func (this *SSLCertConfig) MatchKeyword(keyword string) (matched bool, name string, tags []string) {
|
||||
if configutils.MatchKeyword(this.Description, keyword) {
|
||||
matched = true
|
||||
name = this.Description
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
sslCertListFilename = "ssl.certs.conf"
|
||||
)
|
||||
|
||||
// 获取证书列表实例
|
||||
// 一定会返回不为nil的值
|
||||
func SharedSSLCertList() *SSLCertList {
|
||||
data, err := ioutil.ReadFile(Tea.ConfigFile(sslCertListFilename))
|
||||
if err != nil {
|
||||
return NewSSLCertList()
|
||||
}
|
||||
|
||||
list := &SSLCertList{}
|
||||
err = yaml.Unmarshal(data, list)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return NewSSLCertList()
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// 公共的SSL证书列表
|
||||
type SSLCertList struct {
|
||||
Certs []*SSLCertConfig `yaml:"certs" json:"certs"` // 证书
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewSSLCertList() *SSLCertList {
|
||||
return &SSLCertList{
|
||||
Certs: []*SSLCertConfig{},
|
||||
}
|
||||
}
|
||||
|
||||
// 添加证书
|
||||
func (this *SSLCertList) AddCert(cert *SSLCertConfig) {
|
||||
this.Certs = append(this.Certs, cert)
|
||||
}
|
||||
|
||||
// 删除证书
|
||||
func (this *SSLCertList) RemoveCert(certId string) {
|
||||
result := []*SSLCertConfig{}
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
continue
|
||||
}
|
||||
result = append(result, cert)
|
||||
}
|
||||
this.Certs = result
|
||||
}
|
||||
|
||||
// 查找证书
|
||||
func (this *SSLCertList) FindCert(certId string) *SSLCertConfig {
|
||||
if len(certId) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 保存
|
||||
func (this *SSLCertList) Save() error {
|
||||
shared.Locker.Lock()
|
||||
defer shared.Locker.Unlock()
|
||||
|
||||
data, err := yaml.Marshal(this)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(Tea.ConfigFile(sslCertListFilename), data, 0777)
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
// +build !go1.12
|
||||
|
||||
package sslconfigs
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
var AllTlsVersions = []TLSVersion{"SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2"}
|
||||
|
||||
var AllTLSCipherSuites = []TLSCipherSuite{
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
}
|
||||
|
||||
var TLSModernCipherSuites = []string{
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
}
|
||||
|
||||
var TLSIntermediateCipherSuites = []string{
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
}
|
||||
|
||||
func (this *SSLConfig) convertMinVersion() {
|
||||
switch this.MinVersion {
|
||||
case "SSL 3.0":
|
||||
this.minVersion = tls.VersionSSL30
|
||||
case "TLS 1.0":
|
||||
this.minVersion = tls.VersionTLS10
|
||||
case "TLS 1.1":
|
||||
this.minVersion = tls.VersionTLS11
|
||||
case "TLS 1.2":
|
||||
this.minVersion = tls.VersionTLS12
|
||||
default:
|
||||
this.minVersion = tls.VersionTLS10
|
||||
}
|
||||
}
|
||||
|
||||
func (this *SSLConfig) initCipherSuites() {
|
||||
// cipher suites
|
||||
suites := []uint16{}
|
||||
for _, suite := range this.CipherSuites {
|
||||
switch suite {
|
||||
case "TLS_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
|
||||
}
|
||||
}
|
||||
this.cipherSuites = suites
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// +build go1.12
|
||||
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"os"
|
||||
)
|
||||
|
||||
var AllTlsVersions = []TLSVersion{"SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2", "TLS 1.3"}
|
||||
|
||||
var AllTLSCipherSuites = []TLSCipherSuite{
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
}
|
||||
|
||||
var TLSModernCipherSuites = []string{
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
}
|
||||
|
||||
var TLSIntermediateCipherSuites = []string{
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
}
|
||||
|
||||
func (this *SSLConfig) convertMinVersion() {
|
||||
switch this.MinVersion {
|
||||
case "SSL 3.0":
|
||||
this.minVersion = tls.VersionSSL30
|
||||
case "TLS 1.0":
|
||||
this.minVersion = tls.VersionTLS10
|
||||
case "TLS 1.1":
|
||||
this.minVersion = tls.VersionTLS11
|
||||
case "TLS 1.2":
|
||||
this.minVersion = tls.VersionTLS12
|
||||
case "TLS 1.3":
|
||||
this.minVersion = tls.VersionTLS13
|
||||
|
||||
os.Setenv("GODEBUG", "tls13=1") // TODO should be removed in go 1.14, in go 1.12 tls IS NOT FULL IMPLEMENTED YET
|
||||
default:
|
||||
this.minVersion = tls.VersionTLS10
|
||||
}
|
||||
}
|
||||
|
||||
func (this *SSLConfig) initCipherSuites() {
|
||||
// cipher suites
|
||||
suites := []uint16{}
|
||||
for _, suite := range this.CipherSuites {
|
||||
switch suite {
|
||||
case "TLS_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_AES_128_GCM_SHA256)
|
||||
case "TLS_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_AES_256_GCM_SHA384)
|
||||
case "TLS_CHACHA20_POLY1305_SHA256":
|
||||
suites = append(suites, tls.TLS_CHACHA20_POLY1305_SHA256)
|
||||
}
|
||||
}
|
||||
this.cipherSuites = suites
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HSTS设置
|
||||
// 参考: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
||||
type HSTSConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
MaxAge int `yaml:"maxAge" json:"maxAge"` // 单位秒
|
||||
IncludeSubDomains bool `yaml:"includeSubDomains" json:"includeSubDomains"`
|
||||
Preload bool `yaml:"preload" json:"preload"`
|
||||
Domains []string `yaml:"domains" json:"domains"`
|
||||
|
||||
hasDomains bool
|
||||
headerValue string
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *HSTSConfig) Init() error {
|
||||
this.hasDomains = len(this.Domains) > 0
|
||||
this.headerValue = this.asHeaderValue()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否匹配域名
|
||||
func (this *HSTSConfig) Match(domain string) bool {
|
||||
if !this.hasDomains {
|
||||
return true
|
||||
}
|
||||
return configutils.MatchDomains(this.Domains, domain)
|
||||
}
|
||||
|
||||
// Header Key
|
||||
func (this *HSTSConfig) HeaderKey() string {
|
||||
return "Strict-Transport-Security"
|
||||
}
|
||||
|
||||
// 取得当前的Header值
|
||||
func (this *HSTSConfig) HeaderValue() string {
|
||||
return this.headerValue
|
||||
}
|
||||
|
||||
// 转换为Header值
|
||||
func (this *HSTSConfig) asHeaderValue() string {
|
||||
b := strings.Builder{}
|
||||
b.WriteString("max-age=")
|
||||
if this.MaxAge > 0 {
|
||||
b.WriteString(strconv.Itoa(this.MaxAge))
|
||||
} else {
|
||||
b.WriteString("31536000") // 1 year
|
||||
}
|
||||
if this.IncludeSubDomains {
|
||||
b.WriteString("; includeSubDomains")
|
||||
}
|
||||
if this.Preload {
|
||||
b.WriteString("; preload")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHSTSConfig(t *testing.T) {
|
||||
h := &HSTSConfig{}
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.IncludeSubDomains = true
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.Preload = true
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.IncludeSubDomains = false
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.MaxAge = 86400
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
a := assert.NewAssertion(t)
|
||||
a.IsTrue(h.Match("abc.com"))
|
||||
|
||||
h.Domains = []string{"abc.com"}
|
||||
h.Init()
|
||||
a.IsTrue(h.Match("abc.com"))
|
||||
|
||||
h.Domains = []string{"1.abc.com"}
|
||||
h.Init()
|
||||
a.IsFalse(h.Match("abc.com"))
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package serverconfigs
|
||||
|
||||
type WebConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
|
||||
Locations []*LocationConfig `yaml:"locations" json:"locations"` // 路径规则 TODO
|
||||
|
||||
// 本地静态资源配置
|
||||
Root string `yaml:"root" json:"root"` // 资源根目录 TODO
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package nodes
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
@@ -3,8 +3,8 @@ package nodes
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
http2 "golang.org/x/net/http2"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"golang.org/x/net/http2"
|
||||
"net"
|
||||
|
||||
@@ -2,7 +2,7 @@ package nodes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"net"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"net"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package nodes
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
|
||||
// 域名和服务映射
|
||||
type NamedServer struct {
|
||||
|
||||
@@ -3,9 +3,9 @@ package nodes
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"time"
|
||||
|
||||
@@ -2,9 +2,9 @@ package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Node struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
|
||||
InstallDir string `protobuf:"bytes,4,opt,name=installDir,proto3" json:"installDir,omitempty"`
|
||||
IsInstalled bool `protobuf:"varint,5,opt,name=isInstalled,proto3" json:"isInstalled,omitempty"`
|
||||
Code string `protobuf:"bytes,6,opt,name=code,proto3" json:"code,omitempty"`
|
||||
UniqueId string `protobuf:"bytes,7,opt,name=uniqueId,proto3" json:"uniqueId,omitempty"`
|
||||
Secret string `protobuf:"bytes,8,opt,name=secret,proto3" json:"secret,omitempty"`
|
||||
Cluster *NodeCluster `protobuf:"bytes,32,opt,name=cluster,proto3" json:"cluster,omitempty"`
|
||||
Login *NodeLogin `protobuf:"bytes,33,opt,name=login,proto3" json:"login,omitempty"`
|
||||
InstallStatus *NodeInstallStatus `protobuf:"bytes,34,opt,name=installStatus,proto3" json:"installStatus,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Node) Reset() {
|
||||
*x = Node{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Node) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Node) ProtoMessage() {}
|
||||
|
||||
func (x *Node) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Node.ProtoReflect.Descriptor instead.
|
||||
func (*Node) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Node) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Node) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetStatus() string {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetInstallDir() string {
|
||||
if x != nil {
|
||||
return x.InstallDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetIsInstalled() bool {
|
||||
if x != nil {
|
||||
return x.IsInstalled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Node) GetCode() string {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetUniqueId() string {
|
||||
if x != nil {
|
||||
return x.UniqueId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetSecret() string {
|
||||
if x != nil {
|
||||
return x.Secret
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetCluster() *NodeCluster {
|
||||
if x != nil {
|
||||
return x.Cluster
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Node) GetLogin() *NodeLogin {
|
||||
if x != nil {
|
||||
return x.Login
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Node) GetInstallStatus() *NodeInstallStatus {
|
||||
if x != nil {
|
||||
return x.InstallStatus
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_model_node_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x18, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f,
|
||||
0x64, 0x65, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x1a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f,
|
||||
0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x02, 0x0a, 0x04, 0x4e, 0x6f,
|
||||
0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02,
|
||||
0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x63, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x29, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4e,
|
||||
0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x21, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x3b, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_proto_rawDescOnce sync.Once
|
||||
file_model_node_proto_rawDescData = file_model_node_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_proto_rawDescGZIP() []byte {
|
||||
file_model_node_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_proto_goTypes = []interface{}{
|
||||
(*Node)(nil), // 0: pb.Node
|
||||
(*NodeCluster)(nil), // 1: pb.NodeCluster
|
||||
(*NodeLogin)(nil), // 2: pb.NodeLogin
|
||||
(*NodeInstallStatus)(nil), // 3: pb.NodeInstallStatus
|
||||
}
|
||||
var file_model_node_proto_depIdxs = []int32{
|
||||
1, // 0: pb.Node.cluster:type_name -> pb.NodeCluster
|
||||
2, // 1: pb.Node.login:type_name -> pb.NodeLogin
|
||||
3, // 2: pb.Node.installStatus:type_name -> pb.NodeInstallStatus
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_proto_init() }
|
||||
func file_model_node_proto_init() {
|
||||
if File_model_node_proto != nil {
|
||||
return
|
||||
}
|
||||
file_model_node_cluster_proto_init()
|
||||
file_model_node_login_proto_init()
|
||||
file_model_node_install_status_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Node); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_proto_depIdxs,
|
||||
MessageInfos: file_model_node_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_proto = out.File
|
||||
file_model_node_proto_rawDesc = nil
|
||||
file_model_node_proto_goTypes = nil
|
||||
file_model_node_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_cluster.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeCluster struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
CreatedAt int64 `protobuf:"varint,3,opt,name=createdAt,proto3" json:"createdAt,omitempty"`
|
||||
GrantId int64 `protobuf:"varint,4,opt,name=grantId,proto3" json:"grantId,omitempty"`
|
||||
InstallDir string `protobuf:"bytes,5,opt,name=installDir,proto3" json:"installDir,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeCluster) Reset() {
|
||||
*x = NodeCluster{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_cluster_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeCluster) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeCluster) ProtoMessage() {}
|
||||
|
||||
func (x *NodeCluster) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_cluster_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeCluster.ProtoReflect.Descriptor instead.
|
||||
func (*NodeCluster) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_cluster_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetCreatedAt() int64 {
|
||||
if x != nil {
|
||||
return x.CreatedAt
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetGrantId() int64 {
|
||||
if x != nil {
|
||||
return x.GrantId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetInstallDir() string {
|
||||
if x != nil {
|
||||
return x.InstallDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_model_node_cluster_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_cluster_proto_rawDesc = []byte{
|
||||
0x0a, 0x18, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6c, 0x75,
|
||||
0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x89,
|
||||
0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_cluster_proto_rawDescOnce sync.Once
|
||||
file_model_node_cluster_proto_rawDescData = file_model_node_cluster_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_cluster_proto_rawDescGZIP() []byte {
|
||||
file_model_node_cluster_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_cluster_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_cluster_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_cluster_proto_goTypes = []interface{}{
|
||||
(*NodeCluster)(nil), // 0: pb.NodeCluster
|
||||
}
|
||||
var file_model_node_cluster_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_cluster_proto_init() }
|
||||
func file_model_node_cluster_proto_init() {
|
||||
if File_model_node_cluster_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_cluster_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeCluster); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_cluster_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_cluster_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_cluster_proto_depIdxs,
|
||||
MessageInfos: file_model_node_cluster_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_cluster_proto = out.File
|
||||
file_model_node_cluster_proto_rawDesc = nil
|
||||
file_model_node_cluster_proto_goTypes = nil
|
||||
file_model_node_cluster_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_grant.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeGrant struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
|
||||
Username string `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Su bool `protobuf:"varint,6,opt,name=su,proto3" json:"su,omitempty"`
|
||||
PrivateKey string `protobuf:"bytes,7,opt,name=privateKey,proto3" json:"privateKey,omitempty"`
|
||||
Description string `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"`
|
||||
NodeId int64 `protobuf:"varint,9,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeGrant) Reset() {
|
||||
*x = NodeGrant{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_grant_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeGrant) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeGrant) ProtoMessage() {}
|
||||
|
||||
func (x *NodeGrant) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_grant_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeGrant.ProtoReflect.Descriptor instead.
|
||||
func (*NodeGrant) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_grant_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetMethod() string {
|
||||
if x != nil {
|
||||
return x.Method
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetUsername() string {
|
||||
if x != nil {
|
||||
return x.Username
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetPassword() string {
|
||||
if x != nil {
|
||||
return x.Password
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetSu() bool {
|
||||
if x != nil {
|
||||
return x.Su
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetPrivateKey() string {
|
||||
if x != nil {
|
||||
return x.PrivateKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetNodeId() int64 {
|
||||
if x != nil {
|
||||
return x.NodeId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_model_node_grant_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_grant_proto_rawDesc = []byte{
|
||||
0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x67, 0x72, 0x61,
|
||||
0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xe9, 0x01, 0x0a,
|
||||
0x09, 0x4e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x73, 0x75, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x73, 0x75, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_grant_proto_rawDescOnce sync.Once
|
||||
file_model_node_grant_proto_rawDescData = file_model_node_grant_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_grant_proto_rawDescGZIP() []byte {
|
||||
file_model_node_grant_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_grant_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_grant_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_grant_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_grant_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_grant_proto_goTypes = []interface{}{
|
||||
(*NodeGrant)(nil), // 0: pb.NodeGrant
|
||||
}
|
||||
var file_model_node_grant_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_grant_proto_init() }
|
||||
func file_model_node_grant_proto_init() {
|
||||
if File_model_node_grant_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_grant_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeGrant); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_grant_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_grant_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_grant_proto_depIdxs,
|
||||
MessageInfos: file_model_node_grant_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_grant_proto = out.File
|
||||
file_model_node_grant_proto_rawDesc = nil
|
||||
file_model_node_grant_proto_goTypes = nil
|
||||
file_model_node_grant_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_install_status.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeInstallStatus struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IsRunning bool `protobuf:"varint,1,opt,name=isRunning,proto3" json:"isRunning,omitempty"`
|
||||
IsFinished bool `protobuf:"varint,2,opt,name=isFinished,proto3" json:"isFinished,omitempty"`
|
||||
IsOk bool `protobuf:"varint,3,opt,name=isOk,proto3" json:"isOk,omitempty"`
|
||||
Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
|
||||
UpdatedAt int64 `protobuf:"varint,5,opt,name=updatedAt,proto3" json:"updatedAt,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) Reset() {
|
||||
*x = NodeInstallStatus{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_install_status_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeInstallStatus) ProtoMessage() {}
|
||||
|
||||
func (x *NodeInstallStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_install_status_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeInstallStatus.ProtoReflect.Descriptor instead.
|
||||
func (*NodeInstallStatus) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_install_status_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsRunning() bool {
|
||||
if x != nil {
|
||||
return x.IsRunning
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsFinished() bool {
|
||||
if x != nil {
|
||||
return x.IsFinished
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsOk() bool {
|
||||
if x != nil {
|
||||
return x.IsOk
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetUpdatedAt() int64 {
|
||||
if x != nil {
|
||||
return x.UpdatedAt
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_model_node_install_status_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_install_status_proto_rawDesc = []byte{
|
||||
0x0a, 0x1f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x73,
|
||||
0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x99, 0x01, 0x0a, 0x11, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69,
|
||||
0x73, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
|
||||
0x69, 0x73, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x46,
|
||||
0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
|
||||
0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f,
|
||||
0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41,
|
||||
0x74, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_install_status_proto_rawDescOnce sync.Once
|
||||
file_model_node_install_status_proto_rawDescData = file_model_node_install_status_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_install_status_proto_rawDescGZIP() []byte {
|
||||
file_model_node_install_status_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_install_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_install_status_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_install_status_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_install_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_install_status_proto_goTypes = []interface{}{
|
||||
(*NodeInstallStatus)(nil), // 0: pb.NodeInstallStatus
|
||||
}
|
||||
var file_model_node_install_status_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_install_status_proto_init() }
|
||||
func file_model_node_install_status_proto_init() {
|
||||
if File_model_node_install_status_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_install_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeInstallStatus); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_install_status_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_install_status_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_install_status_proto_depIdxs,
|
||||
MessageInfos: file_model_node_install_status_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_install_status_proto = out.File
|
||||
file_model_node_install_status_proto_rawDesc = nil
|
||||
file_model_node_install_status_proto_goTypes = nil
|
||||
file_model_node_install_status_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_login.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeLogin struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Params []byte `protobuf:"bytes,4,opt,name=params,proto3" json:"params,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeLogin) Reset() {
|
||||
*x = NodeLogin{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_login_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeLogin) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeLogin) ProtoMessage() {}
|
||||
|
||||
func (x *NodeLogin) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_login_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeLogin.ProtoReflect.Descriptor instead.
|
||||
func (*NodeLogin) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_login_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetParams() []byte {
|
||||
if x != nil {
|
||||
return x.Params
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_model_node_login_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_login_proto_rawDesc = []byte{
|
||||
0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x5b, 0x0a, 0x09,
|
||||
0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70,
|
||||
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_login_proto_rawDescOnce sync.Once
|
||||
file_model_node_login_proto_rawDescData = file_model_node_login_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_login_proto_rawDescGZIP() []byte {
|
||||
file_model_node_login_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_login_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_login_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_login_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_login_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_login_proto_goTypes = []interface{}{
|
||||
(*NodeLogin)(nil), // 0: pb.NodeLogin
|
||||
}
|
||||
var file_model_node_login_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_login_proto_init() }
|
||||
func file_model_node_login_proto_init() {
|
||||
if File_model_node_login_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_login_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeLogin); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_login_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_login_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_login_proto_depIdxs,
|
||||
MessageInfos: file_model_node_login_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_login_proto = out.File
|
||||
file_model_node_login_proto_rawDesc = nil
|
||||
file_model_node_login_proto_goTypes = nil
|
||||
file_model_node_login_proto_depIdxs = nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "./pb";
|
||||
|
||||
package pb;
|
||||
import "model_node.proto";
|
||||
import "model_node_login.proto";
|
||||
|
||||
service NodeService {
|
||||
// 创建节点
|
||||
rpc createNode (CreateNodeRequest) returns (CreateNodeResponse);
|
||||
|
||||
// 节点数量
|
||||
rpc countAllEnabledNodes (CountAllEnabledNodesRequest) returns (CountAllEnabledNodesResponse);
|
||||
|
||||
// 计算匹配的节点数量
|
||||
rpc countAllEnabledNodesMatch (CountAllEnabledNodesMatchRequest) returns (CountAllEnabledNodesMatchResponse);
|
||||
|
||||
// 列出单页节点
|
||||
rpc listEnabledNodesMatch (ListEnabledNodesMatchRequest) returns (ListEnabledNodesMatchResponse);
|
||||
|
||||
// 禁用节点
|
||||
rpc disableNode (DisableNodeRequest) returns (DisableNodeResponse);
|
||||
|
||||
// 修改节点
|
||||
rpc updateNode (UpdateNodeRequest) returns (UpdateNodeResponse);
|
||||
|
||||
// 查看单个节点
|
||||
rpc findEnabledNode (FindEnabledNodeRequest) returns (FindEnabledNodeResponse);
|
||||
|
||||
// 组合单个节点配置
|
||||
rpc composeNodeConfig (ComposeNodeConfigRequest) returns (ComposeNodeConfigResponse);
|
||||
|
||||
// 节点stream
|
||||
rpc nodeStream (stream NodeStreamRequest) returns (stream NodeStreamResponse);
|
||||
|
||||
// 更新节点状态
|
||||
rpc updateNodeStatus (UpdateNodeStatusRequest) returns (UpdateNodeStatusResponse);
|
||||
|
||||
// 同步集群中的节点版本
|
||||
rpc syncNodesVersionWithCluster (SyncNodesVersionWithClusterRequest) returns (SyncNodesVersionWithClusterResponse);
|
||||
|
||||
// 修改节点安装状态
|
||||
rpc updateNodeIsInstalled (UpdateNodeIsInstalledRequest) returns (UpdateNodeIsInstalledResponse);
|
||||
|
||||
// 安装节点
|
||||
rpc installNode (InstallNodeRequest) returns (InstallNodeResponse);
|
||||
}
|
||||
|
||||
// 创建节点
|
||||
message CreateNodeRequest {
|
||||
string name = 1;
|
||||
int64 clusterId = 2;
|
||||
NodeLogin Login = 3;
|
||||
}
|
||||
|
||||
message CreateNodeResponse {
|
||||
int64 nodeId = 1;
|
||||
}
|
||||
|
||||
// 节点数量
|
||||
message CountAllEnabledNodesRequest {
|
||||
|
||||
}
|
||||
|
||||
message CountAllEnabledNodesResponse {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
// 列出单页节点
|
||||
message ListEnabledNodesMatchRequest {
|
||||
int64 offset = 1;
|
||||
int64 size = 2;
|
||||
int64 clusterId = 3;
|
||||
int32 installState = 4;
|
||||
}
|
||||
|
||||
message ListEnabledNodesMatchResponse {
|
||||
repeated Node nodes = 1;
|
||||
}
|
||||
|
||||
// 禁用节点
|
||||
message DisableNodeRequest {
|
||||
int64 nodeId = 1;
|
||||
}
|
||||
|
||||
message DisableNodeResponse {
|
||||
|
||||
}
|
||||
|
||||
// 修改节点
|
||||
message UpdateNodeRequest {
|
||||
int64 nodeId = 1;
|
||||
string name = 2;
|
||||
int64 clusterId = 3;
|
||||
NodeLogin Login = 4;
|
||||
}
|
||||
|
||||
message UpdateNodeResponse {
|
||||
|
||||
}
|
||||
|
||||
// 查找节点
|
||||
message FindEnabledNodeRequest {
|
||||
int64 nodeId = 1;
|
||||
}
|
||||
|
||||
message FindEnabledNodeResponse {
|
||||
Node node = 1;
|
||||
}
|
||||
|
||||
// 组合单个节点配置
|
||||
message ComposeNodeConfigRequest {
|
||||
|
||||
}
|
||||
|
||||
message ComposeNodeConfigResponse {
|
||||
bytes configJSON = 1;
|
||||
}
|
||||
|
||||
// 节点stream
|
||||
message NodeStreamRequest {
|
||||
|
||||
}
|
||||
|
||||
message NodeStreamResponse {
|
||||
|
||||
}
|
||||
|
||||
// 更新节点状态
|
||||
message UpdateNodeStatusRequest {
|
||||
int64 nodeId = 1;
|
||||
bytes statusJSON = 2;
|
||||
}
|
||||
|
||||
message UpdateNodeStatusResponse {
|
||||
|
||||
}
|
||||
|
||||
// 同步集群中的节点版本
|
||||
message SyncNodesVersionWithClusterRequest {
|
||||
int64 clusterId = 1;
|
||||
}
|
||||
|
||||
message SyncNodesVersionWithClusterResponse {
|
||||
}
|
||||
|
||||
// 计算匹配的节点数量
|
||||
message CountAllEnabledNodesMatchRequest {
|
||||
int64 clusterId = 1;
|
||||
int32 installState = 2;
|
||||
}
|
||||
|
||||
message CountAllEnabledNodesMatchResponse {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
// 修改节点安装状态
|
||||
message UpdateNodeIsInstalledRequest {
|
||||
int64 nodeId = 1;
|
||||
bool isInstalled = 2;
|
||||
}
|
||||
|
||||
message UpdateNodeIsInstalledResponse {
|
||||
|
||||
}
|
||||
|
||||
// 安装节点
|
||||
message InstallNodeRequest {
|
||||
int64 nodeId = 1;
|
||||
}
|
||||
|
||||
message InstallNodeResponse {
|
||||
|
||||
}
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/encrypt"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
Reference in New Issue
Block a user