Compare commits

...

31 Commits

Author SHA1 Message Date
刘祥超
d0b908bcaa 自动添加firewalld使用异步 2022-09-04 06:36:22 +08:00
刘祥超
3de25d4fe1 优化代码 2022-09-03 22:23:16 +08:00
刘祥超
07194855bf 优化代码 2022-09-03 22:03:22 +08:00
刘祥超
d0f1eb13ee 优化节点活跃检测机制 2022-09-03 12:43:06 +08:00
刘祥超
a0930bfd74 远程安装节点出错时打印stderr 2022-08-30 11:40:01 +08:00
刘祥超
08cff8affc 可以通过用户API修改鉴权 2022-08-30 11:23:35 +08:00
刘祥超
02132e9262 用户系统也可以申请ACME证书 2022-08-28 20:02:13 +08:00
刘祥超
61b6a49885 增加修改全体用户功能API 2022-08-28 17:01:09 +08:00
刘祥超
896e54ebe8 提供按小时、按天查询带宽峰值的API 2022-08-28 15:56:16 +08:00
刘祥超
1b36bad60a 指标统计使用事务 2022-08-27 18:50:42 +08:00
刘祥超
fc14800d70 服务列表带宽使用新的算法 2022-08-27 18:39:00 +08:00
刘祥超
fa61f277e4 服务访问日志改成通过事务写入,以提升写入速度 2022-08-27 14:57:47 +08:00
刘祥超
9117309472 可以修改服务的CNAME 2022-08-26 19:51:21 +08:00
刘祥超
6bb2977d59 Ln节点可以指定访问IP 2022-08-25 20:37:10 +08:00
刘祥超
df9dce76cb 集群DNS设置中增加”包含Ln节点“选项 2022-08-25 19:18:30 +08:00
刘祥超
4cb9c85a1c 节点运行日志可以按照节点ID设置为已读 2022-08-25 18:26:52 +08:00
刘祥超
f4f5389ffb 请求限制API支持用户调用 2022-08-25 15:35:55 +08:00
刘祥超
5d336eb77d 优化代码 2022-08-23 21:42:05 +08:00
刘祥超
c552eb3b0e IP库增加制品管理/统计中相关区域名称可以显示别名 2022-08-23 19:40:17 +08:00
刘祥超
455952e9e4 提交SQL 2022-08-22 15:12:20 +08:00
刘祥超
7132401c7f NS节点基本的DDoS防护 2022-08-22 15:11:22 +08:00
刘祥超
a4dddfb139 优化代码 2022-08-22 11:02:16 +08:00
刘祥超
7ef32bad97 IP库改为手动初始化 2022-08-21 23:09:59 +08:00
刘祥超
732513a644 用户节点版本修改为0.4.1 2022-08-21 20:50:00 +08:00
刘祥超
756cf4a9ae 初步完成新版IP库 2022-08-21 20:38:34 +08:00
刘祥超
a15a630265 更新SQL 2022-08-20 19:57:25 +08:00
刘祥超
3fab1b8294 DNS节点版本号改为0.2.6 2022-08-20 15:27:02 +08:00
刘祥超
215635f429 版本修改为0.5.2 2022-08-17 18:58:20 +08:00
刘祥超
dbb1ae180b 版本修改为0.5.1 2022-08-15 19:38:40 +08:00
刘祥超
e8d4d01d85 改进一处日志 2022-08-15 15:17:09 +08:00
刘祥超
6593989a84 修复日志内容可能过长而无法存入数据库的问题 2022-08-15 15:05:47 +08:00
92 changed files with 1890 additions and 4803 deletions

View File

@@ -95,9 +95,6 @@ function build() {
cp -R "$ROOT"/deploy "$DIST/"
rm -f "$DIST"/deploy/.gitignore
cp -R "$ROOT"/installers "$DIST"/
cp -R "$ROOT"/resources "$DIST"/
rm -f "$DIST"/resources/ipdata/ip2region/global_region.csv
rm -f "$DIST"/resources/ipdata/ip2region/ip.merge.txt
# building edge installer
echo "building node installer ..."

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,6 @@ import (
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock"
"io/ioutil"
"log"
"os"
)
@@ -130,7 +129,7 @@ func main() {
flagSet.BoolVar(&formatJSON, "json", false, "")
_ = flagSet.Parse(os.Args[2:])
data, err := ioutil.ReadFile(Tea.LogFile("issues.log"))
data, err := os.ReadFile(Tea.LogFile("issues.log"))
if err != nil {
if formatJSON {
fmt.Print("[]")

View File

@@ -1,193 +0,0 @@
package main
import (
"bytes"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"io/ioutil"
"os"
"regexp"
"strings"
)
func main() {
// 导入数据
if lists.ContainsString(os.Args, "import") {
dbs.NotifyReady()
data, err := ioutil.ReadFile(Tea.Root + "/resources/ipdata/ip2region/global_region.csv")
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if len(data) == 0 {
logs.Println("[ERROR]file content should not be empty")
return
}
lines := bytes.Split(data, []byte{'\n'})
for _, line := range lines {
line = bytes.TrimSpace(line)
if len(line) == 0 {
continue
}
s := string(line)
reg := regexp.MustCompile(`(?U)(\d+),(\d+),(.+),(\d+),`)
if !reg.MatchString(s) {
continue
}
result := reg.FindStringSubmatch(s)
dataId := result[1]
parentDataId := result[2]
name := result[3]
level := result[4]
switch level {
case "1": // 国家|地区
countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithDataId(nil, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if countryId == 0 {
logs.Println("creating country or region ", name)
_, err = regions.SharedRegionCountryDAO.CreateCountry(nil, name, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
}
case "2": // 省份|地区
provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithDataId(nil, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if provinceId == 0 {
logs.Println("creating province", name)
countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithDataId(nil, parentDataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if countryId == 0 {
logs.Println("[ERROR]can not find country from data id '" + parentDataId + "'")
return
}
_, err = regions.SharedRegionProvinceDAO.CreateProvince(nil, countryId, name, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
}
case "3": // 城市
cityId, err := regions.SharedRegionCityDAO.FindCityWithDataId(nil, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if cityId == 0 {
logs.Println("creating city", name)
provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithDataId(nil, parentDataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
_, err = regions.SharedRegionCityDAO.CreateCity(nil, provinceId, name, dataId)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
}
}
}
logs.Println("done")
}
// 检查数据
if lists.ContainsString(os.Args, "check") {
dbs.NotifyReady()
data, err := ioutil.ReadFile(Tea.Root + "/resources/ipdata/ip2region/ip.merge.txt")
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if len(data) == 0 {
logs.Println("[ERROR]file should not be empty")
return
}
lines := bytes.Split(data, []byte("\n"))
for index, line := range lines {
s := string(bytes.TrimSpace(line))
if len(s) == 0 {
continue
}
pieces := strings.Split(s, "|")
countryName := pieces[2]
provinceName := pieces[4]
providerName := pieces[6]
// 记录provider
if len(providerName) > 0 && providerName != "0" {
providerId, err := regions.SharedRegionProviderDAO.FindProviderIdWithNameCacheable(nil, providerName)
if err != nil {
logs.Println("[ERROR]find provider id failed: " + err.Error())
return
}
if providerId == 0 {
logs.Println("creating new provider '"+providerName+"' ... ", index, "line")
_, err = regions.SharedRegionProviderDAO.CreateProvider(nil, providerName)
if err != nil {
logs.Println("create new provider failed: " + providerName)
return
}
logs.Println("created new provider '" + providerName + "'")
return
}
}
if lists.ContainsString([]string{"0", "欧洲", "北美地区", "法国南部领地", "非洲地区", "亚太地区"}, countryName) {
continue
}
// 检查国家
countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithNameCacheable(nil, countryName)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if countryId == 0 {
logs.Println("[ERROR]can not find country '"+countryName+"', index: ", index, "data: "+s)
return
}
// 检查省份
if countryName == "中国" {
if lists.ContainsString([]string{"0"}, provinceName) {
continue
}
provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithNameCacheable(nil, countryId, provinceName)
if err != nil {
logs.Println("[ERROR]" + err.Error())
return
}
if provinceId == 0 {
logs.Println("[ERROR]can not find province '"+provinceName+"', index: ", index, "data: "+s)
return
}
}
}
logs.Println("done")
}
}

View File

@@ -7,7 +7,6 @@ import (
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"go/format"
"io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -67,7 +66,7 @@ func init() {
return
}
err = ioutil.WriteFile(sqlFile, dst, 0666)
err = os.WriteFile(sqlFile, dst, 0666)
if err != nil {
fmt.Println("[ERROR]write file failed: " + err.Error())
return

View File

@@ -24,11 +24,11 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value := dns01.GetRecord(domain, keyAuth)
// 设置记录
index := strings.Index(fqdn, "."+this.dnsDomain)
var index = strings.Index(fqdn, "."+this.dnsDomain)
if index < 0 {
return errors.New("invalid fqdn value")
}
recordName := fqdn[:index]
var recordName = fqdn[:index]
record, err := this.raw.QueryRecord(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
if err != nil {
return errors.New("query DNS record failed: " + err.Error())

View File

@@ -75,7 +75,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
return
}
config := lego.NewConfig(this.task.User)
var config = lego.NewConfig(this.task.User)
config.Certificate.KeyType = certcrypto.RSA2048
config.CADirURL = this.task.Provider.APIURL
config.UserAgent = teaconst.ProductName + "/" + teaconst.Version
@@ -86,7 +86,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
}
// 注册用户
resource := this.task.User.GetRegistration()
var resource = this.task.User.GetRegistration()
if resource != nil {
resource, err = client.Registration.QueryRegistration()
if err != nil {
@@ -124,7 +124,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
}
// 申请证书
request := certificate.ObtainRequest{
var request = certificate.ObtainRequest{
Domains: this.task.Domains,
Bundle: true,
}
@@ -146,7 +146,7 @@ func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
return
}
config := lego.NewConfig(this.task.User)
var config = lego.NewConfig(this.task.User)
config.Certificate.KeyType = certcrypto.RSA2048
config.CADirURL = this.task.Provider.APIURL
config.UserAgent = teaconst.ProductName + "/" + teaconst.Version
@@ -157,7 +157,7 @@ func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
}
// 注册用户
resource := this.task.User.GetRegistration()
var resource = this.task.User.GetRegistration()
if resource != nil {
resource, err = client.Registration.QueryRegistration()
if err != nil {
@@ -195,7 +195,7 @@ func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
}
// 申请证书
request := certificate.ObtainRequest{
var request = certificate.ObtainRequest{
Domains: this.task.Domains,
Bundle: true,
}

View File

@@ -1,7 +1,7 @@
package teaconst
const (
Version = "0.5.0"
Version = "0.5.2"
ProductName = "Edge API"
ProcessName = "edge-api"
@@ -18,11 +18,11 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.5.0"
UserNodeVersion = "0.4.0"
NodeVersion = "0.5.2"
UserNodeVersion = "0.4.1"
AuthorityNodeVersion = "0.0.2"
MonitorNodeVersion = "0.0.4"
DNSNodeVersion = "0.2.5"
DNSNodeVersion = "0.2.6"
ReportNodeVersion = "0.1.1"
// SQLVersion SQL版本号

View File

@@ -1,6 +1,7 @@
package acme
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
@@ -72,8 +73,9 @@ func (this *ACMEProviderAccountDAO) FindACMEProviderAccountName(tx *dbs.Tx, id i
}
// CreateAccount 创建账号
func (this *ACMEProviderAccountDAO) CreateAccount(tx *dbs.Tx, name string, providerCode string, eabKid string, eabKey string) (int64, error) {
func (this *ACMEProviderAccountDAO) CreateAccount(tx *dbs.Tx, userId int64, name string, providerCode string, eabKid string, eabKey string) (int64, error) {
var op = NewACMEProviderAccountOperator()
op.UserId = userId
op.Name = name
op.ProviderCode = providerCode
op.EabKid = eabKid
@@ -98,15 +100,18 @@ func (this *ACMEProviderAccountDAO) UpdateAccount(tx *dbs.Tx, accountId int64, n
}
// CountAllEnabledAccounts 计算账号数量
func (this *ACMEProviderAccountDAO) CountAllEnabledAccounts(tx *dbs.Tx) (int64, error) {
func (this *ACMEProviderAccountDAO) CountAllEnabledAccounts(tx *dbs.Tx, userId int64) (int64, error) {
return this.Query(tx).
State(ACMEProviderAccountStateEnabled).
Attr("userId", userId).
Count()
}
// ListEnabledAccounts 查找单页账号
func (this *ACMEProviderAccountDAO) ListEnabledAccounts(tx *dbs.Tx, offset int64, size int64) (result []*ACMEProviderAccount, err error) {
func (this *ACMEProviderAccountDAO) ListEnabledAccounts(tx *dbs.Tx, userId int64, offset int64, size int64) (result []*ACMEProviderAccount, err error) {
_, err = this.Query(tx).
State(ACMEProviderAccountStateEnabled).
Attr("userId", userId).
Offset(offset).
Limit(size).
DescPk().
@@ -116,12 +121,34 @@ func (this *ACMEProviderAccountDAO) ListEnabledAccounts(tx *dbs.Tx, offset int64
}
// FindAllEnabledAccountsWithProviderCode 根据服务商代号查找账号
func (this *ACMEProviderAccountDAO) FindAllEnabledAccountsWithProviderCode(tx *dbs.Tx, providerCode string) (result []*ACMEProviderAccount, err error) {
func (this *ACMEProviderAccountDAO) FindAllEnabledAccountsWithProviderCode(tx *dbs.Tx, userId int64, providerCode string) (result []*ACMEProviderAccount, err error) {
_, err = this.Query(tx).
State(ACMEProviderAccountStateEnabled).
Attr("providerCode", providerCode).
Attr("userId", userId).
DescPk().
Slice(&result).
FindAll()
return
}
// CheckUserAccount 检查是否为用户的服务商账号
func (this *ACMEProviderAccountDAO) CheckUserAccount(tx *dbs.Tx, userId int64, accountId int64) error {
if userId <= 0 || accountId <= 0 {
return models.ErrNotFound
}
b, err := this.Query(tx).
Pk(accountId).
State(ACMEProviderAccountStateEnabled).
Attr("userId", userId).
Exist()
if err != nil {
return err
}
if !b {
return models.ErrNotFound
}
return nil
}

View File

@@ -3,24 +3,26 @@ package acme
// ACMEProviderAccount ACME提供商
type ACMEProviderAccount struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称
ProviderCode string `field:"providerCode"` // 代号
Error string `field:"error"` // 最后一条错误信息
EabKid string `field:"eabKid"` // KID
EabKey string `field:"eabKey"` // Key
Error string `field:"error"` // 最后一条错误信息
State uint8 `field:"state"` // 状态
}
type ACMEProviderAccountOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启
Name interface{} // 名称
ProviderCode interface{} // 代号
Error interface{} // 最后一条错误信息
EabKid interface{} // KID
EabKey interface{} // Key
State interface{} // 状态
Id any // ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 名称
ProviderCode any // 代号
EabKid any // KID
EabKey any // Key
Error any // 最后一条错误信息
State any // 状态
}
func NewACMEProviderAccountOperator() *ACMEProviderAccountOperator {

View File

@@ -107,7 +107,11 @@ func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) err
// CountAllEnabledACMETasks 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string) (int64, error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
var query = this.Query(tx)
if adminId > 0 {
query.Attr("adminId", adminId)
}
query.Attr("userId", userId) // 这个条件必须加上
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -138,7 +142,11 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, use
// ListEnabledACMETasks 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, offset int64, size int64) (result []*ACMETask, err error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
var query = this.Query(tx)
if adminId > 0 {
query.Attr("adminId", adminId)
}
query.Attr("userId", userId) // 这个条件必须加上
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -228,7 +236,13 @@ func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId
// CheckACMETask 检查权限
func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, adminId int64, userId int64, acmeTaskId int64) (bool, error) {
return dbutils.NewQuery(tx, this, adminId, userId).
var query = this.Query(tx)
if adminId > 0 {
query.Attr("adminId", adminId)
}
query.Attr("userId", userId) // 这个条件必须加上
return query.
State(ACMETaskStateEnabled).
Pk(acmeTaskId).
Exist()
@@ -319,7 +333,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
return
}
remoteUser := acmeutils.NewUser(user.Email, privateKey, func(resource *registration.Resource) error {
var remoteUser = acmeutils.NewUser(user.Email, privateKey, func(resource *registration.Resource) error {
resourceJSON, err := json.Marshal(resource)
if err != nil {
return err
@@ -382,7 +396,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
acmeTask.Provider = acmeProvider
acmeTask.Account = acmeAccount
acmeRequest := acmeutils.NewRequest(acmeTask)
var acmeRequest = acmeutils.NewRequest(acmeTask)
acmeRequest.OnAuth(func(domain, token, keyAuth string) {
err := SharedACMEAuthenticationDAO.CreateAuth(tx, taskId, domain, token, keyAuth)
if err != nil {
@@ -398,7 +412,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
if err != nil {
remotelogs.Error("ACME", "encode auth data failed: '"+task.AuthURL+"'")
} else {
client := utils.SharedHttpClient(5 * time.Second)
var client = utils.SharedHttpClient(10 * time.Second)
req, err := http.NewRequest(http.MethodPost, task.AuthURL, bytes.NewReader(authJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
@@ -423,7 +437,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
}
// 分析证书
sslConfig := &sslconfigs.SSLCertConfig{
var sslConfig = &sslconfigs.SSLCertConfig{
CertData: certData,
KeyData: keyData,
}

View File

@@ -16,8 +16,11 @@ import (
// CheckClusterDNS 检查集群的DNS问题
// 藏这么深是避免package循环引用的问题
func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster) (issues []*pb.DNSIssue, err error) {
clusterId := int64(cluster.Id)
domainId := int64(cluster.DnsDomainId)
var clusterId = int64(cluster.Id)
var domainId = int64(cluster.DnsDomainId)
// 集群DNS设置
var clusterDNSConfig, _ = cluster.DecodeDNSConfig()
// 检查域名
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, domainId, nil)
@@ -101,7 +104,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster) (issues []*pb.DNSI
// TODO 检查域名是否已解析
// 检查节点
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true)
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, clusterDNSConfig != nil && clusterDNSConfig.IncludingLnNodes)
if err != nil {
return nil, err
}

View File

@@ -39,9 +39,10 @@ var SharedHTTPAccessLogDAO *HTTPAccessLogDAO
var (
oldAccessLogQueue = make(chan *pb.HTTPAccessLog)
accessLogQueue = make(chan *pb.HTTPAccessLog, 10_000)
accessLogQueueMaxLength = 100_000
accessLogQueuePercent = 100 // 0-100
accessLogCountPerSecond = 10_000 // 0 表示不限制
accessLogQueueMaxLength = 100_000 //队列最大长度
accessLogQueuePercent = 100 // 0-100
accessLogCountPerSecond = 10_000 // 每秒钟写入条数,0 表示不限制
accessLogPerTx = 100 // 单事务写入条数
accessLogConfigJSON = []byte{}
accessLogQueueChanged = make(chan zero.Zero, 1)
@@ -85,10 +86,17 @@ func init() {
goman.New(func() {
var ticker = time.NewTicker(1 * time.Second)
for range ticker.C {
var tx *dbs.Tx
err := SharedHTTPAccessLogDAO.DumpAccessLogsFromQueue(tx, accessLogCountPerSecond)
if err != nil {
remotelogs.Error("HTTP_ACCESS_LOG_QUEUE", "dump access logs failed: "+err.Error())
var countTxs = accessLogCountPerSecond / accessLogPerTx
if countTxs <= 0 {
countTxs = 1
}
for i := 0; i < countTxs; i++ {
hasMore, err := SharedHTTPAccessLogDAO.DumpAccessLogsFromQueue(accessLogPerTx)
if err != nil {
remotelogs.Error("HTTP_ACCESS_LOG_QUEUE", "dump access logs failed: "+err.Error())
} else if !hasMore {
break
}
}
}
})
@@ -132,7 +140,11 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogs(tx *dbs.Tx, accessLogs []*pb.
}
// DumpAccessLogsFromQueue 从队列导入访问日志
func (this *HTTPAccessLogDAO) DumpAccessLogsFromQueue(tx *dbs.Tx, size int) error {
func (this *HTTPAccessLogDAO) DumpAccessLogsFromQueue(size int) (hasMore bool, err error) {
if size <= 0 {
size = 100
}
var dao = randomHTTPAccessLogDAO()
if dao == nil {
dao = &HTTPAccessLogDAOWrapper{
@@ -141,14 +153,25 @@ func (this *HTTPAccessLogDAO) DumpAccessLogsFromQueue(tx *dbs.Tx, size int) erro
}
}
if size <= 0 {
size = 1_000_000
if len(oldAccessLogQueue) == 0 && len(accessLogQueue) == 0 {
return false, nil
}
// 开始事务
tx, err := dao.DAO.Instance.Begin()
if err != nil {
return false, err
}
defer func() {
_ = tx.Commit()
}()
// 复制变量,防止中途改变
var oldQueue = oldAccessLogQueue
var newQueue = accessLogQueue
hasMore = true
Loop:
for i := 0; i < size; i++ {
// old
@@ -156,7 +179,7 @@ Loop:
case accessLog := <-oldQueue:
err := this.CreateHTTPAccessLog(tx, dao.DAO, accessLog)
if err != nil {
return err
return false, err
}
continue Loop
default:
@@ -168,15 +191,16 @@ Loop:
case accessLog := <-newQueue:
err := this.CreateHTTPAccessLog(tx, dao.DAO, accessLog)
if err != nil {
return err
return false, err
}
continue Loop
default:
hasMore = false
break Loop
}
}
return nil
return hasMore, nil
}
// CreateHTTPAccessLog 写入单条访问日志
@@ -767,6 +791,9 @@ func (this *HTTPAccessLogDAO) SetupQueue() {
accessLogQueuePercent = config.Percent
accessLogCountPerSecond = config.CountPerSecond
if accessLogCountPerSecond <= 0 {
accessLogCountPerSecond = 10_000
}
if config.MaxLength <= 0 {
config.MaxLength = 100_000
}

View File

@@ -21,13 +21,13 @@ func TestCreateHTTPAccessLog(t *testing.T) {
t.Fatal(err)
}
accessLog := &pb.HTTPAccessLog{
var accessLog = &pb.HTTPAccessLog{
ServerId: 1,
NodeId: 4,
Status: 200,
Timestamp: time.Now().Unix(),
}
dao := randomHTTPAccessLogDAO()
var dao = randomHTTPAccessLogDAO()
t.Log("dao:", dao)
// 先初始化
@@ -37,12 +37,59 @@ func TestCreateHTTPAccessLog(t *testing.T) {
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
for i := 0; i < 1000; i++ {
err = SharedHTTPAccessLogDAO.CreateHTTPAccessLog(tx, dao.DAO, accessLog)
if err != nil {
t.Fatal(err)
}
}
t.Log("ok")
}
func TestCreateHTTPAccessLog_Tx(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
err := NewDBNodeInitializer().loop()
if err != nil {
t.Fatal(err)
}
var accessLog = &pb.HTTPAccessLog{
ServerId: 1,
NodeId: 4,
Status: 200,
Timestamp: time.Now().Unix(),
}
var dao = randomHTTPAccessLogDAO()
t.Log("dao:", dao)
// 先初始化
_ = SharedHTTPAccessLogDAO.CreateHTTPAccessLog(tx, dao.DAO, accessLog)
var before = time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
tx, err = dao.DAO.Instance.Begin()
if err != nil {
t.Fatal(err)
}
for i := 0; i < 1000; i++ {
err = SharedHTTPAccessLogDAO.CreateHTTPAccessLog(tx, dao.DAO, accessLog)
if err != nil {
t.Fatal(err)
}
}
err = tx.Commit()
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -68,8 +68,9 @@ func (this *HTTPAuthPolicyDAO) FindEnabledHTTPAuthPolicy(tx *dbs.Tx, id int64) (
}
// CreateHTTPAuthPolicy 创建策略
func (this *HTTPAuthPolicyDAO) CreateHTTPAuthPolicy(tx *dbs.Tx, name string, methodType string, paramsJSON []byte) (int64, error) {
func (this *HTTPAuthPolicyDAO) CreateHTTPAuthPolicy(tx *dbs.Tx, userId int64, name string, methodType string, paramsJSON []byte) (int64, error) {
var op = NewHTTPAuthPolicyOperator()
op.UserId = userId
op.Name = name
op.Type = methodType
op.Params = paramsJSON
@@ -137,6 +138,20 @@ func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, c
return config, nil
}
// CheckUserPolicy 检查用户权限
func (this *HTTPAuthPolicyDAO) CheckUserPolicy(tx *dbs.Tx, userId int64, policyId int64) error {
if userId <= 0 || policyId <= 0 {
return ErrNotFound
}
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithHTTPAuthPolicyId(tx, policyId)
if err != nil {
return err
}
return SharedHTTPWebDAO.CheckUserWeb(tx, userId, webId)
}
// NotifyUpdate 通知更改
func (this *HTTPAuthPolicyDAO) NotifyUpdate(tx *dbs.Tx, policyId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithHTTPAuthPolicyId(tx, policyId)

View File

@@ -1042,6 +1042,10 @@ func (this *HTTPWebDAO) FindWebServerGroupId(tx *dbs.Tx, webId int64) (groupId i
// CheckUserWeb 检查用户权限
func (this *HTTPWebDAO) CheckUserWeb(tx *dbs.Tx, userId int64, webId int64) error {
if userId <= 0 || webId <= 0 {
return ErrNotFound
}
serverId, err := this.FindWebServerId(tx, webId)
if err != nil {
return err

View File

@@ -0,0 +1,140 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
stringutil "github.com/iwind/TeaGo/utils/string"
)
const (
IPLibraryArtifactStateEnabled = 1 // 已启用
IPLibraryArtifactStateDisabled = 0 // 已禁用
)
type IPLibraryArtifactDAO dbs.DAO
func NewIPLibraryArtifactDAO() *IPLibraryArtifactDAO {
return dbs.NewDAO(&IPLibraryArtifactDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeIPLibraryArtifacts",
Model: new(IPLibraryArtifact),
PkName: "id",
},
}).(*IPLibraryArtifactDAO)
}
var SharedIPLibraryArtifactDAO *IPLibraryArtifactDAO
func init() {
dbs.OnReady(func() {
SharedIPLibraryArtifactDAO = NewIPLibraryArtifactDAO()
})
}
// EnableIPLibraryArtifact 启用条目
func (this *IPLibraryArtifactDAO) EnableIPLibraryArtifact(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", IPLibraryArtifactStateEnabled).
Update()
return err
}
// DisableIPLibraryArtifact 禁用条目
func (this *IPLibraryArtifactDAO) DisableIPLibraryArtifact(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", IPLibraryArtifactStateDisabled).
Update()
return err
}
// FindEnabledIPLibraryArtifact 查找启用中的条目
func (this *IPLibraryArtifactDAO) FindEnabledIPLibraryArtifact(tx *dbs.Tx, id int64) (*IPLibraryArtifact, error) {
result, err := this.Query(tx).
Pk(id).
State(IPLibraryArtifactStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*IPLibraryArtifact), err
}
// CreateArtifact 创建制品
func (this *IPLibraryArtifactDAO) CreateArtifact(tx *dbs.Tx, name string, fileId int64, libraryFileId int64, meta *iplibrary.Meta) (int64, error) {
var op = NewIPLibraryArtifactOperator()
op.Name = name
op.FileId = fileId
op.LibraryFileId = libraryFileId
metaJSON, err := json.Marshal(meta)
if err != nil {
return 0, err
}
op.Meta = metaJSON
op.State = IPLibraryArtifactStateEnabled
var code = stringutil.Md5(utils.Sha1RandomString())[:8]
meta.Code = code
op.Code = code // 要比较短,方便识别
return this.SaveInt64(tx, op)
}
// FindAllArtifacts 查找制品列表
func (this *IPLibraryArtifactDAO) FindAllArtifacts(tx *dbs.Tx) (result []*IPLibraryArtifact, err error) {
_, err = this.Query(tx).
State(IPLibraryArtifactStateEnabled).
DescPk().
Slice(&result).
FindAll()
return
}
// FindPublicArtifact 查找当前使用的制品
func (this *IPLibraryArtifactDAO) FindPublicArtifact(tx *dbs.Tx) (*IPLibraryArtifact, error) {
one, err := this.Query(tx).
State(IPLibraryArtifactStateEnabled).
Attr("isPublic", true).
Result("id", "fileId", "code").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*IPLibraryArtifact), nil
}
// UpdateArtifactPublic 使用某个制品
func (this *IPLibraryArtifactDAO) UpdateArtifactPublic(tx *dbs.Tx, artifactId int64, isPublic bool) error {
// 取消使用
if !isPublic {
return this.Query(tx).
Pk(artifactId).
Set("isPublic", false).
UpdateQuickly()
}
// 使用
// 先取消别的
err := this.Query(tx).
Neq("id", artifactId).
State(IPLibraryArtifactStateEnabled).
Attr("isPublic", true).
Set("isPublic", false).
UpdateQuickly()
if err != nil {
return err
}
return this.Query(tx).
Pk(artifactId).
Set("isPublic", true).
UpdateQuickly()
}

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
// IPLibraryArtifact IP库制品
type IPLibraryArtifact struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
FileId uint64 `field:"fileId"` // 文件ID
LibraryFileId uint32 `field:"libraryFileId"` // IP库文件ID
CreatedAt uint64 `field:"createdAt"` // 创建时间
Meta dbs.JSON `field:"meta"` // 元数据
IsPublic bool `field:"isPublic"` // 是否为公用
Code string `field:"code"` // 代号
State uint8 `field:"state"` // 状态
}
type IPLibraryArtifactOperator struct {
Id any // ID
Name any // 名称
FileId any // 文件ID
LibraryFileId any // IP库文件ID
CreatedAt any // 创建时间
Meta any // 元数据
IsPublic any // 是否为公用
Code any // 代号
State any // 状态
}
func NewIPLibraryArtifactOperator() *IPLibraryArtifactOperator {
return &IPLibraryArtifactOperator{}
}

View File

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

View File

@@ -72,8 +72,9 @@ func (this *IPLibraryFileDAO) FindEnabledIPLibraryFile(tx *dbs.Tx, id int64) (*I
}
// CreateLibraryFile 创建文件
func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, template string, emptyValues []string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) {
func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, template string, emptyValues []string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) {
var op = NewIPLibraryFileOperator()
op.Name = name
op.Template = template
if emptyValues == nil {
@@ -137,6 +138,18 @@ func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, template string, emp
return this.SaveInt64(tx, op)
}
// FindAllFinishedLibraryFiles 查找所有已完成的文件
func (this *IPLibraryFileDAO) FindAllFinishedLibraryFiles(tx *dbs.Tx) (result []*IPLibraryFile, err error) {
_, err = this.Query(tx).
State(IPLibraryFileStateEnabled).
Result("id", "fileId", "createdAt", "generatedFileId", "generatedAt", "name"). // 这里不需要其他信息
Attr("isFinished", true).
DescPk().
Slice(&result).
FindAll()
return
}
// FindAllUnfinishedLibraryFiles 查找所有未完成的文件
func (this *IPLibraryFileDAO) FindAllUnfinishedLibraryFiles(tx *dbs.Tx) (result []*IPLibraryFile, err error) {
_, err = this.Query(tx).
@@ -324,7 +337,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countries = []*iplibrary.Country{}
for _, country := range dbCountries {
countries = append(countries, &iplibrary.Country{
Id: int64(country.Id),
Id: country.Id,
Name: country.DisplayName(),
Codes: country.AllCodes(),
})
@@ -339,7 +352,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var provinces = []*iplibrary.Province{}
for _, province := range dbProvinces {
provinces = append(provinces, &iplibrary.Province{
Id: int64(province.Id),
Id: province.Id,
Name: province.DisplayName(),
Codes: province.AllCodes(),
})
@@ -354,7 +367,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var cities = []*iplibrary.City{}
for _, city := range dbCities {
cities = append(cities, &iplibrary.City{
Id: int64(city.Id),
Id: city.Id,
Name: city.DisplayName(),
Codes: city.AllCodes(),
})
@@ -369,7 +382,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var towns = []*iplibrary.Town{}
for _, town := range dbTowns {
towns = append(towns, &iplibrary.Town{
Id: int64(town.Id),
Id: town.Id,
Name: town.DisplayName(),
Codes: town.AllCodes(),
})
@@ -384,7 +397,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var providers = []*iplibrary.Provider{}
for _, provider := range dbProviders {
providers = append(providers, &iplibrary.Provider{
Id: int64(provider.Id),
Id: provider.Id,
Name: provider.DisplayName(),
Codes: provider.AllCodes(),
})
@@ -392,7 +405,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var libraryCode = utils.Sha1RandomString() // 每次都生成新的code
var filePath = dir + "/" + this.composeFilename(libraryFileId, libraryCode)
writer, err := iplibrary.NewFileWriter(filePath, &iplibrary.Meta{
var meta = &iplibrary.Meta{
Author: "", // 将来用户可以自行填写
CreatedAt: time.Now().Unix(),
Countries: countries,
@@ -400,13 +413,15 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
Cities: cities,
Towns: towns,
Providers: providers,
})
}
writer, err := iplibrary.NewFileWriter(filePath, meta)
if err != nil {
return err
}
defer func() {
_ = writer.Close()
_ = os.Remove(filePath)
}()
err = writer.WriteMeta()
@@ -563,6 +578,12 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
return err
}
// 添加制品
_, err = SharedIPLibraryArtifactDAO.CreateArtifact(tx, libraryFile.Name, generatedFileId, libraryFileId, meta)
if err != nil {
return err
}
return nil
}

View File

@@ -12,7 +12,7 @@ func TestIPLibraryFileDAO_GenerateIPLibrary(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
err := models.SharedIPLibraryFileDAO.GenerateIPLibrary(tx, 3)
err := models.SharedIPLibraryFileDAO.GenerateIPLibrary(tx, 4)
if err != nil {
t.Fatal(err)
}

View File

@@ -5,6 +5,7 @@ import "github.com/iwind/TeaGo/dbs"
// IPLibraryFile IP库上传的文件
type IPLibraryFile struct {
Id uint64 `field:"id"` // ID
Name string `field:"name"` // IP库名称
FileId uint64 `field:"fileId"` // 原始文件ID
Template string `field:"template"` // 模板
EmptyValues dbs.JSON `field:"emptyValues"` // 空值列表
@@ -23,6 +24,7 @@ type IPLibraryFile struct {
type IPLibraryFileOperator struct {
Id any // ID
Name any // IP库名称
FileId any // 原始文件ID
Template any // 模板
EmptyValues any // 空值列表

View File

@@ -3,6 +3,7 @@ package models
import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -38,7 +39,7 @@ func init() {
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error {
var op = NewLogOperator()
op.Level = level
op.Description = description
op.Description = utils.LimitString(description, 1000)
op.Action = action
op.Ip = ip
op.Type = adminType

View File

@@ -147,11 +147,12 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
op.DnsDomainId = dnsDomainId
op.DnsName = dnsName
var dnsConfig = &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: true,
ServersAutoSync: true,
CNameRecords: []string{},
CNameAsDomain: true,
TTL: 0,
NodesAutoSync: true,
ServersAutoSync: true,
CNameRecords: []string{},
CNameAsDomain: true,
TTL: 0,
IncludingLnNodes: true,
}
dnsJSON, err := json.Marshal(dnsConfig)
if err != nil {
@@ -468,7 +469,7 @@ func (this *NodeClusterDAO) ExistClusterDNSName(tx *dbs.Tx, dnsName string, excl
}
// UpdateClusterDNS 修改集群DNS相关信息
func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsName string, dnsDomainId int64, nodesAutoSync bool, serversAutoSync bool, cnameRecords []string, ttl int32, cnameAsDomain bool) error {
func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsName string, dnsDomainId int64, nodesAutoSync bool, serversAutoSync bool, cnameRecords []string, ttl int32, cnameAsDomain bool, includingLnNodes bool) error {
if clusterId <= 0 {
return errors.New("invalid clusterId")
}
@@ -504,11 +505,12 @@ func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsNam
}
var dnsConfig = &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: nodesAutoSync,
ServersAutoSync: serversAutoSync,
CNameRecords: cnameRecords,
TTL: ttl,
CNameAsDomain: cnameAsDomain,
NodesAutoSync: nodesAutoSync,
ServersAutoSync: serversAutoSync,
CNameRecords: cnameRecords,
TTL: ttl,
CNameAsDomain: cnameAsDomain,
IncludingLnNodes: includingLnNodes,
}
dnsJSON, err := json.Marshal(dnsConfig)
if err != nil {
@@ -1066,7 +1068,7 @@ func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int6
return one.(*NodeCluster).DecodeDDoSProtection(), nil
}
// UpdateClusterDDoSProtection 设置集群的DDOS设置
// UpdateClusterDDoSProtection 设置集群的DDoS设置
func (this *NodeClusterDAO) UpdateClusterDDoSProtection(tx *dbs.Tx, clusterId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if clusterId <= 0 {
return ErrNotFound

View File

@@ -11,13 +11,15 @@ func (this *NodeCluster) DecodeDNSConfig() (*dnsconfigs.ClusterDNSConfig, error)
if len(this.Dns) == 0 {
// 一定要返回一个默认的值防止产生nil
return &dnsconfigs.ClusterDNSConfig{
NodesAutoSync: false,
ServersAutoSync: false,
CNameAsDomain: true,
NodesAutoSync: false,
ServersAutoSync: false,
CNameAsDomain: true,
IncludingLnNodes: true,
}, nil
}
var dnsConfig = &dnsconfigs.ClusterDNSConfig{
CNameAsDomain: true,
CNameAsDomain: true,
IncludingLnNodes: true,
}
err := json.Unmarshal(this.Dns, &dnsConfig)
if err != nil {

View File

@@ -199,7 +199,7 @@ func (this *NodeDAO) CreateNode(tx *dbs.Tx, adminId int64, name string, clusterI
}
// UpdateNode 修改节点
func (this *NodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, name string, clusterId int64, secondaryClusterIds []int64, groupId int64, regionId int64, isOn bool, level int) error {
func (this *NodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, name string, clusterId int64, secondaryClusterIds []int64, groupId int64, regionId int64, isOn bool, level int, lnAddrs []string) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
}
@@ -248,6 +248,15 @@ func (this *NodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, name string, clusterId
if teaconst.IsPlus {
op.Level = level
if lnAddrs == nil {
lnAddrs = []string{}
}
lnAddrsJSON, err := json.Marshal(lnAddrs)
if err != nil {
return err
}
op.LnAddrs = lnAddrsJSON
}
err = this.Save(tx, op)
@@ -605,7 +614,7 @@ func (this *NodeDAO) FindEnabledNodesWithGroupIdAndLevel(tx *dbs.Tx, groupId int
}
_, err = this.Query(tx).
State(NodeStateEnabled).
Result("id", "clusterId", "secondaryClusterIds", "uniqueId", "secret").
Result("id", "clusterId", "secondaryClusterIds", "uniqueId", "secret", "lnAddrs").
Attr("isOn", true).
Attr("groupId", groupId).
Attr("level", level).
@@ -1403,7 +1412,7 @@ func (this *NodeDAO) CountAllEnabledNodesWithRegionId(tx *dbs.Tx, regionId int64
}
// FindAllEnabledNodesDNSWithClusterId 获取一个集群的节点DNS信息
func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool) (result []*Node, err error) {
func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, includingLnNodes bool) (result []*Node, err error) {
if clusterId <= 0 {
return nil, nil
}
@@ -1415,6 +1424,9 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
} else {
query.Attr("clusterId", clusterId)
}
if !includingLnNodes {
query.Lte("level", 1)
}
_, err = query.
State(NodeStateEnabled).
Attr("isOn", true).
@@ -1878,14 +1890,18 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
if len(parentNodes) > 0 {
for _, node := range parentNodes {
addrs, err := SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
var addrStrings = []string{}
for _, addr := range addrs {
if addr.IsOn {
addrStrings = append(addrStrings, addr.DNSIP())
// 是否有Ln地址
var addrStrings = node.DecodeLnAddrs()
if len(addrStrings) == 0 {
// 如果没有就取节点的可访问地址
addrs, err := SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
for _, addr := range addrs {
if addr.IsOn {
addrStrings = append(addrStrings, addr.DNSIP())
}
}
}
@@ -1924,7 +1940,7 @@ func (this *NodeDAO) FindNodeDDoSProtection(tx *dbs.Tx, nodeId int64) (*ddosconf
return one.(*Node).DecodeDDoSProtection(), nil
}
// UpdateNodeDDoSProtection 设置集群的DDOS设置
// UpdateNodeDDoSProtection 设置集群的DDoS设置
func (this *NodeDAO) UpdateNodeDDoSProtection(tx *dbs.Tx, nodeId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if nodeId <= 0 {
return ErrNotFound

View File

@@ -4,6 +4,7 @@ import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -43,6 +44,8 @@ func init() {
// CreateLog 创建日志
func (this *NodeLogDAO) CreateLog(tx *dbs.Tx, nodeRole nodeconfigs.NodeRole, nodeId int64, serverId int64, originId int64, level string, tag string, description string, createdAt int64, logType string, paramsJSON []byte) error {
description = utils.LimitString(description, 1000)
// 修复以前同样的日志
if nodeId > 0 && level == "success" && len(logType) > 0 && len(paramsJSON) > 0 {
err := this.Query(tx).
@@ -339,8 +342,8 @@ func (this *NodeLogDAO) CountAllUnreadNodeLogs(tx *dbs.Tx) (int64, error) {
Count()
}
// UpdateNodeLogsRead 设置日志为已读
func (this *NodeLogDAO) UpdateNodeLogsRead(tx *dbs.Tx, nodeLogIds []int64) error {
// UpdateNodeLogIdsRead 设置一组日志为已读
func (this *NodeLogDAO) UpdateNodeLogIdsRead(tx *dbs.Tx, nodeLogIds []int64) error {
for _, logId := range nodeLogIds {
err := this.Query(tx).
Pk(logId).
@@ -353,6 +356,16 @@ func (this *NodeLogDAO) UpdateNodeLogsRead(tx *dbs.Tx, nodeLogIds []int64) error
return nil
}
// UpdateNodeLogsRead 设置节点日志为已读
func (this *NodeLogDAO) UpdateNodeLogsRead(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64) error {
return this.Query(tx).
Attr("role", role).
Attr("nodeId", nodeId).
Attr("isRead", false).
Set("isRead", true).
UpdateQuickly()
}
// UpdateAllNodeLogsRead 设置所有日志为已读
func (this *NodeLogDAO) UpdateAllNodeLogsRead(tx *dbs.Tx) error {
return this.Query(tx).

View File

@@ -8,6 +8,7 @@ type Node struct {
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
Level uint8 `field:"level"` // 级别
LnAddrs dbs.JSON `field:"lnAddrs"` // Ln级别访问地址
IsOn bool `field:"isOn"` // 是否启用
IsUp bool `field:"isUp"` // 是否在线
CountUp uint32 `field:"countUp"` // 连续在线次数
@@ -42,41 +43,42 @@ type Node struct {
}
type NodeOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
Level interface{} // 级别
IsOn interface{} // 是否启用
IsUp interface{} // 是否在线
CountUp interface{} // 连续在线次数
CountDown interface{} // 连续线次数
IsActive interface{} // 是否活跃
InactiveNotifiedAt interface{} // 离线通知时间
UniqueId interface{} // 节点ID
Secret interface{} // 密钥
Name interface{} // 节点名
Code interface{} // 代号
ClusterId interface{} // 主集群ID
SecondaryClusterIds interface{} // 集群ID
RegionId interface{} // 区域ID
GroupId interface{} // 分组ID
CreatedAt interface{} // 创建时间
Status interface{} // 最新的状态
Version interface{} // 当前版本号
LatestVersion interface{} // 最后版本号
InstallDir interface{} // 安装目录
IsInstalled interface{} // 是否已安装
InstallStatus interface{} // 安装状态
State interface{} // 状态
ConnectedAPINodes interface{} // 当前连接的API节点
MaxCPU interface{} // 可以使用的最多CPU
MaxThreads interface{} // 最大线程数
DdosProtection interface{} // DDOS配置
DnsRoutes interface{} // DNS线路设
MaxCacheDiskCapacity interface{} // 硬盘缓存容量
MaxCacheMemoryCapacity interface{} // 内存缓存容量
CacheDiskDir interface{} // 缓存目录
DnsResolver interface{} // DNS解析器
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
Level any // 级别
LnAddrs any // Ln级别访问地址
IsOn any // 是否启用
IsUp any // 是否在线
CountUp any // 连续线次数
CountDown any // 连续下线次数
IsActive any // 是否活跃
InactiveNotifiedAt any // 离线通知时间
UniqueId any // 节点ID
Secret any // 密钥
Name any // 节点名
Code any // 代号
ClusterId any // 集群ID
SecondaryClusterIds any // 从集群ID
RegionId any // 区域ID
GroupId any // 分组ID
CreatedAt any // 创建时间
Status any // 最新的状态
Version any // 当前版本号
LatestVersion any // 最后版本号
InstallDir any // 安装目录
IsInstalled any // 是否已安装
InstallStatus any // 安装状态
State any // 状态
ConnectedAPINodes any // 当前连接的API节点
MaxCPU any // 可以使用的最多CPU
MaxThreads any // 最大线程数
DdosProtection any // DDOS配
DnsRoutes any // DNS线路设置
MaxCacheDiskCapacity any // 硬盘缓存容量
MaxCacheMemoryCapacity any // 内存缓存容量
CacheDiskDir any // 缓存目录
DnsResolver any // DNS解析器
}
func NewNodeOperator() *NodeOperator {

View File

@@ -168,3 +168,16 @@ func (this *Node) DecodeDNSResolver() *nodeconfigs.DNSResolverConfig {
}
return resolverConfig
}
func (this *Node) DecodeLnAddrs() []string {
if IsNull(this.LnAddrs) {
return nil
}
var result = []string{}
err := json.Unmarshal(this.LnAddrs, &result)
if err != nil {
// ignore error
}
return result
}

View File

@@ -23,11 +23,12 @@ const (
// NS相关
NSNodeTaskTypeConfigChanged NodeTaskType = "nsConfigChanged"
NSNodeTaskTypeDomainChanged NodeTaskType = "nsDomainChanged"
NSNodeTaskTypeRecordChanged NodeTaskType = "nsRecordChanged"
NSNodeTaskTypeRouteChanged NodeTaskType = "nsRouteChanged"
NSNodeTaskTypeKeyChanged NodeTaskType = "nsKeyChanged"
NSNodeTaskTypeConfigChanged NodeTaskType = "nsConfigChanged"
NSNodeTaskTypeDomainChanged NodeTaskType = "nsDomainChanged"
NSNodeTaskTypeRecordChanged NodeTaskType = "nsRecordChanged"
NSNodeTaskTypeRouteChanged NodeTaskType = "nsRouteChanged"
NSNodeTaskTypeKeyChanged NodeTaskType = "nsKeyChanged"
NSNodeTaskTypeDDosProtectionChanged NodeTaskType = "nsDDoSProtectionChanged" // 节点DDoS配置变更
)
type NodeTaskDAO dbs.DAO

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -325,6 +326,45 @@ func (this *NSClusterDAO) CountAllClustersWithSSLPolicyIds(tx *dbs.Tx, sslPolicy
Count()
}
// FindClusterDDoSProtection 获取集群的DDoS设置
func (this *NSClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx).
Result("ddosProtection").
Pk(clusterId).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*NSCluster).DecodeDDoSProtection(), nil
}
// UpdateClusterDDoSProtection 设置集群的DDoS设置
func (this *NSClusterDAO) UpdateClusterDDoSProtection(tx *dbs.Tx, clusterId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if clusterId <= 0 {
return ErrNotFound
}
var op = NewNSClusterOperator()
op.Id = clusterId
if ddosProtection == nil {
op.DdosProtection = "{}"
} else {
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return err
}
op.DdosProtection = ddosProtectionJSON
}
err := this.Save(tx, op)
if err != nil {
return err
}
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, NSNodeTaskTypeDDosProtectionChanged)
}
// NotifyUpdate 通知更改
func (this *NSClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, NSNodeTaskTypeConfigChanged)

View File

@@ -4,31 +4,33 @@ import "github.com/iwind/TeaGo/dbs"
// NSCluster 域名服务器集群
type NSCluster struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 集群名
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
AccessLog dbs.JSON `field:"accessLog"` // 访问日志配置
GrantId uint32 `field:"grantId"` // 授权ID
Recursion dbs.JSON `field:"recursion"` // 递归DNS设置
Tcp dbs.JSON `field:"tcp"` // TCP设置
Tls dbs.JSON `field:"tls"` // TLS设置
Udp dbs.JSON `field:"udp"` // UDP设置
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 集群名
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
AccessLog dbs.JSON `field:"accessLog"` // 访问日志配置
GrantId uint32 `field:"grantId"` // 授权ID
Recursion dbs.JSON `field:"recursion"` // 递归DNS设置
Tcp dbs.JSON `field:"tcp"` // TCP设置
Tls dbs.JSON `field:"tls"` // TLS设置
Udp dbs.JSON `field:"udp"` // UDP设置
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
}
type NSClusterOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
Name interface{} // 集群名
InstallDir interface{} // 安装目录
State interface{} // 状态
AccessLog interface{} // 访问日志配置
GrantId interface{} // 授权ID
Recursion interface{} // 递归DNS设置
Tcp interface{} // TCP设置
Tls interface{} // TLS设置
Udp interface{} // UDP设置
Id any // ID
IsOn any // 是否启用
Name any // 集群名
InstallDir any // 安装目录
State any // 状态
AccessLog any // 访问日志配置
GrantId any // 授权ID
Recursion any // 递归DNS设置
Tcp any // TCP设置
Tls any // TLS设置
Udp any // UDP设置
DdosProtection any // DDoS防护设置
}
func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -1 +1,29 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
)
// DecodeDDoSProtection 解析DDOS Protection设置
func (this *NSCluster) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
if IsNull(this.DdosProtection) {
return nil
}
var result = &ddosconfigs.ProtectionConfig{}
err := json.Unmarshal(this.DdosProtection, &result)
if err != nil {
// ignore err
}
return result
}
// HasDDoSProtection 检查是否有DDOS设置
func (this *NSCluster) HasDDoSProtection() bool {
var config = this.DecodeDDoSProtection()
if config != nil {
return config.IsOn()
}
return false
}

View File

@@ -9,12 +9,14 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"time"
)
const (
@@ -347,7 +349,7 @@ func (this *NSNodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstall
}
// UpdateNodeStatus 更改节点状态
func (this NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
func (this *NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *nodeconfigs.NodeStatus) error {
if nodeStatus == nil {
return nil
}
@@ -484,6 +486,19 @@ func (this *NSNodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64) (*dnsconfigs.
config.UDP = udpConfig
}
// DDoS
config.DDoSProtection = cluster.DecodeDDoSProtection()
// DDoS Protection
var ddosProtection = node.DecodeDDoSProtection()
if ddosProtection != nil {
if config.DDoSProtection == nil {
config.DDoSProtection = ddosProtection
} else {
config.DDoSProtection.Merge(ddosProtection)
}
}
return config, nil
}
@@ -516,6 +531,7 @@ func (this *NSNodeDAO) UpdateNodeActive(tx *dbs.Tx, nodeId int64, isActive bool)
Pk(nodeId).
Set("isActive", isActive).
Set("statusIsNotified", false).
Set("inactiveNotifiedAt", 0).
Update()
return err
}
@@ -562,9 +578,18 @@ func (this *NSNodeDAO) UpdateNodeStatusIsNotified(tx *dbs.Tx, nodeId int64) erro
return this.Query(tx).
Pk(nodeId).
Set("statusIsNotified", true).
Set("inactiveNotifiedAt", time.Now().Unix()).
UpdateQuickly()
}
// FindNodeInactiveNotifiedAt 读取上次的节点离线通知时间
func (this *NSNodeDAO) FindNodeInactiveNotifiedAt(tx *dbs.Tx, nodeId int64) (int64, error) {
return this.Query(tx).
Pk(nodeId).
Result("inactiveNotifiedAt").
FindInt64Col(0)
}
// FindAllNodeIdsMatch 匹配节点并返回节点ID
func (this *NSNodeDAO) FindAllNodeIdsMatch(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, isOn configutils.BoolState) (result []int64, err error) {
query := this.Query(tx)
@@ -629,6 +654,53 @@ func (this *NSNodeDAO) FindEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int
return result, nil
}
// FindNodeDDoSProtection 获取节点的DDOS设置
func (this *NSNodeDAO) FindNodeDDoSProtection(tx *dbs.Tx, nodeId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx).
Result("ddosProtection").
Pk(nodeId).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*NSNode).DecodeDDoSProtection(), nil
}
// UpdateNodeDDoSProtection 设置集群的DDOS设置
func (this *NSNodeDAO) UpdateNodeDDoSProtection(tx *dbs.Tx, nodeId int64, ddosProtection *ddosconfigs.ProtectionConfig) error {
if nodeId <= 0 {
return ErrNotFound
}
var op = NewNSNodeOperator()
op.Id = nodeId
if ddosProtection == nil {
op.DdosProtection = "{}"
} else {
ddosProtectionJSON, err := json.Marshal(ddosProtection)
if err != nil {
return err
}
op.DdosProtection = ddosProtectionJSON
}
err := this.Save(tx, op)
if err != nil {
return err
}
clusterId, err := this.FindNodeClusterId(tx, nodeId)
if err != nil {
return err
}
if clusterId > 0 {
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleDNS, clusterId, nodeId, 0, NSNodeTaskTypeDDosProtectionChanged, 0)
}
return nil
}
// NotifyUpdate 通知更新
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
// TODO 先什么都不做

View File

@@ -4,41 +4,45 @@ import "github.com/iwind/TeaGo/dbs"
// NSNode 域名服务器节点
type NSNode struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
ClusterId uint32 `field:"clusterId"` // 集群ID
Name string `field:"name"` // 节点名称
IsOn bool `field:"isOn"` // 是否启用
Status dbs.JSON `field:"status"` // 运行状态
UniqueId string `field:"uniqueId"` // 节点ID
Secret string `field:"secret"` // 密钥
IsUp bool `field:"isUp"` // 是否运行
IsInstalled bool `field:"isInstalled"` // 是否已安装
InstallStatus dbs.JSON `field:"installStatus"` // 安装状态
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
IsActive bool `field:"isActive"` // 是否活跃
StatusIsNotified uint8 `field:"statusIsNotified"` // 活跃状态已经通知
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
ClusterId uint32 `field:"clusterId"` // 集群ID
Name string `field:"name"` // 节点名称
IsOn bool `field:"isOn"` // 是否启用
Status dbs.JSON `field:"status"` // 运行状态
UniqueId string `field:"uniqueId"` // 节点ID
Secret string `field:"secret"` // 密钥
IsUp bool `field:"isUp"` // 是否运行
IsInstalled bool `field:"isInstalled"` // 是否已安装
InstallStatus dbs.JSON `field:"installStatus"` // 安装状态
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
IsActive bool `field:"isActive"` // 是否活跃
StatusIsNotified uint8 `field:"statusIsNotified"` // 活跃状态已经通知
InactiveNotifiedAt uint64 `field:"inactiveNotifiedAt"` // 离线通知时间
ConnectedAPINodes dbs.JSON `field:"connectedAPINodes"` // 当前连接的API节点
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
}
type NSNodeOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
ClusterId interface{} // 集群ID
Name interface{} // 节点名称
IsOn interface{} // 是否启用
Status interface{} // 运行状态
UniqueId interface{} // 节点ID
Secret interface{} // 密钥
IsUp interface{} // 是否运行
IsInstalled interface{} // 是否已安装
InstallStatus interface{} // 安装状态
InstallDir interface{} // 安装目录
State interface{} // 状态
IsActive interface{} // 是否活跃
StatusIsNotified interface{} // 活跃状态已经通知
ConnectedAPINodes interface{} // 当前连接的API节点
Id any // ID
AdminId any // 管理员ID
ClusterId any // 集群ID
Name any // 节点名称
IsOn any // 是否启用
Status any // 运行状态
UniqueId any // 节点ID
Secret any // 密钥
IsUp any // 是否运行
IsInstalled any // 是否已安装
InstallStatus any // 安装状态
InstallDir any // 安装目录
State any // 状态
IsActive any // 是否活跃
StatusIsNotified any // 活跃状态已经通知
InactiveNotifiedAt any // 离线通知时间
ConnectedAPINodes any // 当前连接的API节点
DdosProtection any // DDoS防护设置
}
func NewNSNodeOperator() *NSNodeOperator {

View File

@@ -3,6 +3,7 @@ package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"time"
)
@@ -39,3 +40,40 @@ func (this *NSNode) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
}
return status, nil
}
// DecodeDDoSProtection 解析DDoS Protection设置
func (this *NSNode) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
if IsNull(this.DdosProtection) {
return nil
}
var result = &ddosconfigs.ProtectionConfig{}
err := json.Unmarshal(this.DdosProtection, &result)
if err != nil {
// ignore err
}
return result
}
// HasDDoSProtection 检查是否有DDOS设置
func (this *NSNode) HasDDoSProtection() bool {
var config = this.DecodeDDoSProtection()
if config != nil {
return !config.IsPriorEmpty()
}
return false
}
// DecodeConnectedAPINodes 解析连接的API节点列表
func (this *NSNode) DecodeConnectedAPINodes() []int64 {
if IsNull(this.ConnectedAPINodes) {
return nil
}
var result = []int64{}
err := json.Unmarshal(this.ConnectedAPINodes, &result)
if err != nil {
// ignore err
}
return result
}

View File

@@ -162,3 +162,19 @@ func (this *RegionTownDAO) FindSimilarTowns(towns []*RegionTown, townName string
return
}
// CreateTown 创建区县
func (this *RegionTownDAO) CreateTown(tx *dbs.Tx, cityId int64, townName string) (int64, error) {
var op = NewRegionTownOperator()
op.CityId = cityId
op.Name = townName
codes, err := json.Marshal([]string{townName})
if err != nil {
return 0, err
}
op.Codes = codes
op.State = RegionTownStateEnabled
return this.SaveInt64(tx, op)
}

View File

@@ -4,6 +4,8 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -12,6 +14,7 @@ import (
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"math"
"strings"
"sync"
"time"
)
@@ -89,6 +92,59 @@ func (this *ServerBandwidthStatDAO) FindMinutelyPeekBandwidthBytes(tx *dbs.Tx, s
FindInt64Col(0)
}
// FindHourlyBandwidthStats 按小时获取带宽峰值
func (this *ServerBandwidthStatDAO) FindHourlyBandwidthStats(tx *dbs.Tx, serverId int64, hours int32) (result []*pb.FindHourlyServerBandwidthStatsResponse_Stat, err error) {
if hours <= 0 {
hours = 24
}
var timestamp = time.Now().Unix() - int64(hours)*3600
ones, _, err := this.Query(tx).
Table(this.partialTable(serverId)).
Result("MAX(bytes) AS bytes", "CONCAT(day, '.', SUBSTRING(timeAt, 1, 2)) AS fullTime").
Attr("serverId", serverId).
Gte("CONCAT(day, '.', SUBSTRING(timeAt, 1, 2))", timeutil.FormatTime("Ymd.H", timestamp)).
Group("fullTime").
FindOnes()
if err != nil {
return nil, err
}
var m = map[string]*pb.FindHourlyServerBandwidthStatsResponse_Stat{}
for _, one := range ones {
var fullTime = one.GetString("fullTime")
var timePieces = strings.Split(fullTime, ".")
var day = timePieces[0]
var hour = timePieces[1]
m[day+hour] = &pb.FindHourlyServerBandwidthStatsResponse_Stat{
Bytes: one.GetInt64("bytes"),
Day: day,
Hour: types.Int32(hour),
}
}
fullHours, err := utils.RangeHours(timeutil.FormatTime("YmdH", timestamp), timeutil.Format("YmdH"))
if err != nil {
return nil, err
}
for _, fullHour := range fullHours {
stat, ok := m[fullHour]
if ok {
result = append(result, stat)
} else {
result = append(result, &pb.FindHourlyServerBandwidthStatsResponse_Stat{
Bytes: 0,
Day: fullHour[:8],
Hour: types.Int32(fullHour[8:]),
})
}
}
return result, nil
}
// FindDailyPeekBandwidthBytes 获取某天的带宽峰值
// day YYYYMMDD
func (this *ServerBandwidthStatDAO) FindDailyPeekBandwidthBytes(tx *dbs.Tx, serverId int64, day string) (int64, error) {
@@ -99,6 +155,54 @@ func (this *ServerBandwidthStatDAO) FindDailyPeekBandwidthBytes(tx *dbs.Tx, serv
FindInt64Col(0)
}
// FindDailyBandwidthStats 按天获取带宽峰值
func (this *ServerBandwidthStatDAO) FindDailyBandwidthStats(tx *dbs.Tx, serverId int64, days int32) (result []*pb.FindDailyServerBandwidthStatsResponse_Stat, err error) {
if days <= 0 {
days = 14
}
var timestamp = time.Now().Unix() - int64(days)*86400
ones, _, err := this.Query(tx).
Table(this.partialTable(serverId)).
Result("MAX(bytes) AS bytes", "day").
Attr("serverId", serverId).
Gte("day", timeutil.FormatTime("Ymd", timestamp)).
Group("day").
FindOnes()
if err != nil {
return nil, err
}
var m = map[string]*pb.FindDailyServerBandwidthStatsResponse_Stat{}
for _, one := range ones {
var day = one.GetString("day")
m[day] = &pb.FindDailyServerBandwidthStatsResponse_Stat{
Bytes: one.GetInt64("bytes"),
Day: day,
}
}
allDays, err := utils.RangeDays(timeutil.FormatTime("Ymd", timestamp), timeutil.Format("Ymd"))
if err != nil {
return nil, err
}
for _, day := range allDays {
stat, ok := m[day]
if ok {
result = append(result, stat)
} else {
result = append(result, &pb.FindDailyServerBandwidthStatsResponse_Stat{
Bytes: 0,
Day: day,
})
}
}
return result, nil
}
// FindMonthlyPeekBandwidthBytes 获取某月的带宽峰值
// month YYYYMM
func (this *ServerBandwidthStatDAO) FindMonthlyPeekBandwidthBytes(tx *dbs.Tx, serverId int64, month string) (int64, error) {

View File

@@ -6,6 +6,7 @@ import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time"
"testing"
@@ -77,3 +78,24 @@ func TestServerBandwidthStatDAO_Clean(t *testing.T) {
}
t.Log("ok", time.Since(before).Seconds()*1000, "ms")
}
func TestServerBandwidthStatDAO_FindHourlyBandwidthStats(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
stats, err := dao.FindHourlyBandwidthStats(tx, 23, 24)
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(stats, t)
}
func TestServerBandwidthStatDAO_FindDailyBandwidthStats(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
stats, err := dao.FindDailyBandwidthStats(tx, 23, 14)
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(stats, t)
}

View File

@@ -759,7 +759,8 @@ func (this *ServerDAO) CountAllEnabledServers(tx *dbs.Tx) (int64, error) {
// CountAllEnabledServersMatch 计算所有可用服务数量
// 参数:
// groupId 分组ID如果为-1则搜索没有分组的服务
//
// groupId 分组ID如果为-1则搜索没有分组的服务
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string) (int64, error) {
query := this.Query(tx).
State(ServerStateEnabled)
@@ -810,7 +811,8 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
// ListEnabledServersMatch 列出单页的服务
// 参数:
// groupId 分组ID如果为-1则搜索没有分组的服务
//
// groupId 分组ID如果为-1则搜索没有分组的服务
func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size int64, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag int32, protocolFamilies []string, order string) (result []*Server, err error) {
query := this.Query(tx).
State(ServerStateEnabled).
@@ -860,49 +862,32 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
}
// 排序
var day = timeutil.Format("Ymd")
var minute = timeutil.FormatTime("His", time.Now().Unix()/300*300-300)
var selfTable = this.Table
var statTable = SharedServerDailyStatDAO.Table
var hasOnlyIds = false
var timestamp = time.Now().Unix() / 300 * 300
var currentTime = timeutil.FormatTime("YmdHi", timestamp)
var prevTime = timeutil.FormatTime("YmdHi", timestamp-300)
switch order {
case "trafficOutAsc":
query.Result("id")
query.Join(SharedServerDailyStatDAO, dbs.QueryJoinLeft, selfTable+".id="+statTable+".serverId AND "+statTable+".day=:day AND "+statTable+".timeFrom=:minute")
query.Param("day", day)
query.Param("minute", minute)
query.Group(selfTable + ".id")
query.Asc("SUM(" + statTable + ".bytes)").
DescPk()
hasOnlyIds = true
query.Asc("IF(IF(bandwidthTime=:currentTime, bandwidthBytes, 0) > 0, IF(bandwidthTime=:currentTime, bandwidthBytes, 0), IF(bandwidthTime=:prevTime, bandwidthBytes, 0))")
query.Param("currentTime", currentTime)
query.Param("prevTime", prevTime)
query.DescPk()
case "trafficOutDesc":
query.Result("id")
query.Join(SharedServerDailyStatDAO, dbs.QueryJoinLeft, selfTable+".id="+statTable+".serverId AND "+statTable+".day=:day AND "+statTable+".timeFrom=:minute")
query.Param("day", day)
query.Param("minute", minute)
query.Group(selfTable + ".id")
query.Desc("SUM(" + statTable + ".bytes)").
DescPk()
hasOnlyIds = true
query.Desc("IF(IF(bandwidthTime=:currentTime, bandwidthBytes, 0) > 0, IF(bandwidthTime=:currentTime, bandwidthBytes, 0), IF(bandwidthTime=:prevTime, bandwidthBytes, 0))")
query.Param("currentTime", currentTime)
query.Param("prevTime", prevTime)
query.DescPk()
default:
query.DescPk()
}
_, err = query.FindAll()
if hasOnlyIds {
var newResult = []*Server{}
for _, one := range result {
server, err := this.Find(tx, one.Id)
if err != nil {
return nil, err
}
if server == nil {
continue
}
newResult = append(newResult, server.(*Server))
// 修正带宽统计数据
for _, server := range result {
if len(server.BandwidthTime) > 0 && server.BandwidthBytes > 0 && server.BandwidthTime < prevTime {
server.BandwidthBytes = 0
}
result = newResult
}
return
@@ -1629,6 +1614,33 @@ func (this *ServerDAO) GenerateServerDNSName(tx *dbs.Tx, serverId int64) (string
return dnsName, nil
}
// UpdateServerDNSName 设置CNAME
func (this *ServerDAO) UpdateServerDNSName(tx *dbs.Tx, serverId int64, dnsName string) error {
if serverId <= 0 || len(dnsName) == 0 {
return nil
}
dnsName = strings.ToLower(dnsName)
err := this.Query(tx).
Pk(serverId).
Set("dnsName", dnsName).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyDNSUpdate(tx, serverId)
}
// FindServerIdWithDNSName 根据CNAME查询服务ID
func (this *ServerDAO) FindServerIdWithDNSName(tx *dbs.Tx, clusterId int64, dnsName string) (int64, error) {
return this.Query(tx).
ResultPk().
State(ServerStateEnabled).
Attr("clusterId", clusterId).
Attr("dnsName", dnsName).
FindInt64Col(0)
}
// FindServerClusterId 查询当前服务的集群ID
func (this *ServerDAO) FindServerClusterId(tx *dbs.Tx, serverId int64) (int64, error) {
return this.Query(tx).
@@ -2549,6 +2561,22 @@ func (this *ServerDAO) FindUserServerClusterIds(tx *dbs.Tx, userId int64) ([]int
return clusterIds, nil
}
// UpdateServerBandwidth 更新服务带宽
// fullTime YYYYMMDDHHII
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64) error {
if serverId <= 0 {
return nil
}
if bandwidthBytes < 0 {
bandwidthBytes = 0
}
return this.Query(tx).
Pk(serverId).
Set("bandwidthTime", fullTime).
Set("bandwidthBytes", bandwidthBytes).
UpdateQuickly()
}
// NotifyUpdate 同步服务所在的集群
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
// 创建任务

View File

@@ -48,53 +48,57 @@ type Server struct {
UserPlanId uint32 `field:"userPlanId"` // 所属套餐ID
LastUserPlanId uint32 `field:"lastUserPlanId"` // 上一次使用的套餐
Uam dbs.JSON `field:"uam"` // UAM设置
BandwidthTime string `field:"bandwidthTime"` // 带宽更新时间YYYYMMDDHHII
BandwidthBytes uint64 `field:"bandwidthBytes"` // 最近带宽峰值
}
type ServerOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
Type interface{} // 服务类型
Name interface{} // 名称
Description interface{} // 描述
PlainServerNames interface{} // 扁平化域名列表
ServerNames interface{} // 域名列表
AuditingAt interface{} // 审核提交时间
AuditingServerNames interface{} // 审核中的域名
IsAuditing interface{} // 是否正在审核
AuditingResult interface{} // 审核结果
Http interface{} // HTTP配置
Https interface{} // HTTPS配置
Tcp interface{} // TCP配置
Tls interface{} // TLS配置
Unix interface{} // Unix配置
Udp interface{} // UDP配置
WebId interface{} // WEB配置
ReverseProxy interface{} // 反向代理配置
GroupIds interface{} // 分组ID列表
Config interface{} // 服务配置,自动生成
ConfigMd5 interface{} // Md5
ClusterId interface{} // 集群ID
IncludeNodes interface{} // 部署条件
ExcludeNodes interface{} // 节点排除条件
Version interface{} // 版本号
CreatedAt interface{} // 创建时间
State interface{} // 状态
DnsName interface{} // DNS名称
TcpPorts interface{} // 所包含TCP端口
UdpPorts interface{} // 所包含UDP端口
SupportCNAME interface{} // 允许CNAME不在域名名单
TrafficLimit interface{} // 流量限制
TrafficDay interface{} // YYYYMMDD
TrafficMonth interface{} // YYYYMM
TotalDailyTraffic interface{} // 日流量
TotalMonthlyTraffic interface{} // 月流量
TrafficLimitStatus interface{} // 流量限制状态
TotalTraffic interface{} // 总流量
UserPlanId interface{} // 所属套餐ID
LastUserPlanId interface{} // 上一次使用的套餐
Uam interface{} // UAM设置
Id any // ID
IsOn any // 是否启用
UserId any // 用户ID
AdminId any // 管理员ID
Type any // 服务类型
Name any // 名称
Description any // 描述
PlainServerNames any // 扁平化域名列表
ServerNames any // 域名列表
AuditingAt any // 审核提交时间
AuditingServerNames any // 审核中的域名
IsAuditing any // 是否正在审核
AuditingResult any // 审核结果
Http any // HTTP配置
Https any // HTTPS配置
Tcp any // TCP配置
Tls any // TLS配置
Unix any // Unix配置
Udp any // UDP配置
WebId any // WEB配置
ReverseProxy any // 反向代理配置
GroupIds any // 分组ID列表
Config any // 服务配置,自动生成
ConfigMd5 any // Md5
ClusterId any // 集群ID
IncludeNodes any // 部署条件
ExcludeNodes any // 节点排除条件
Version any // 版本号
CreatedAt any // 创建时间
State any // 状态
DnsName any // DNS名称
TcpPorts any // 所包含TCP端口
UdpPorts any // 所包含UDP端口
SupportCNAME any // 允许CNAME不在域名名单
TrafficLimit any // 流量限制
TrafficDay any // YYYYMMDD
TrafficMonth any // YYYYMM
TotalDailyTraffic any // 日流量
TotalMonthlyTraffic any // 月流量
TrafficLimitStatus any // 流量限制状态
TotalTraffic any // 总流量
UserPlanId any // 所属套餐ID
LastUserPlanId any // 上一次使用的套餐
Uam any // UAM设置
BandwidthTime any // 带宽更新时间YYYYMMDDHHII
BandwidthBytes any // 最近带宽峰值
}
func NewServerOperator() *ServerOperator {

View File

@@ -358,7 +358,7 @@ func (this *SSLCertDAO) FindAllExpiringCerts(tx *dbs.Tx, days int) (result []*SS
days = 0
}
deltaSeconds := int64(days * 86400)
var deltaSeconds = int64(days * 86400)
_, err = this.Query(tx).
State(SSLCertStateEnabled).
Where("FROM_UNIXTIME(timeEndAt, '%Y-%m-%d')=:day AND FROM_UNIXTIME(notifiedAt, '%Y-%m-%d')!=:today").

View File

@@ -10,6 +10,7 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time"
@@ -352,7 +353,7 @@ func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error)
FindInt64Col(0)
}
// UpdateUserFeatures 更新用户Features
// UpdateUserFeatures 更新单个用户Features
func (this *UserDAO) UpdateUserFeatures(tx *dbs.Tx, userId int64, featuresJSON []byte) error {
if userId <= 0 {
return errors.New("invalid userId")
@@ -370,6 +371,74 @@ func (this *UserDAO) UpdateUserFeatures(tx *dbs.Tx, userId int64, featuresJSON [
return nil
}
// UpdateUsersFeatures 更新所有用户的Features
func (this *UserDAO) UpdateUsersFeatures(tx *dbs.Tx, featureCodes []string, overwrite bool) error {
if featureCodes == nil {
featureCodes = []string{}
}
if overwrite {
featureCodesJSON, err := json.Marshal(featureCodes)
if err != nil {
return err
}
err = this.Query(tx).
State(UserStateEnabled).
Set("features", featureCodesJSON).
UpdateQuickly()
return err
}
var lastId int64
const size = 1000
for {
ones, _, err := this.Query(tx).
Result("id", "features").
State(UserStateEnabled).
Gt("id", lastId).
Limit(size).
AscPk().
FindOnes()
if err != nil {
return err
}
for _, one := range ones {
var userId = one.GetInt64("id")
var userFeaturesJSON = one.GetBytes("features")
var userFeatures = []string{}
if len(userFeaturesJSON) > 0 {
err = json.Unmarshal(userFeaturesJSON, &userFeatures)
if err != nil {
return err
}
}
for _, featureCode := range featureCodes {
if !lists.ContainsString(userFeatures, featureCode) {
userFeatures = append(userFeatures, featureCode)
}
}
userFeaturesJSON, err = json.Marshal(userFeatures)
if err != nil {
return err
}
err = this.Query(tx).
Pk(userId).
Set("features", userFeaturesJSON).
UpdateQuickly()
if err != nil {
return err
}
}
if len(ones) < size {
break
}
lastId += size
}
return nil
}
// FindUserFeatures 查找用户Features
func (this *UserDAO) FindUserFeatures(tx *dbs.Tx, userId int64) ([]*userconfigs.UserFeature, error) {
featuresJSON, err := this.Query(tx).

View File

@@ -1,5 +1,21 @@
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestUserDAO_UpdateUserFeatures(t *testing.T) {
var dao = NewUserDAO()
var tx *dbs.Tx
err := dao.UpdateUsersFeatures(tx, []string{
userconfigs.UserFeatureCodeFinance,
userconfigs.UserFeatureCodeServerACME,
}, false)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -123,7 +123,7 @@ secret: "${nodeSecret}"`)
_, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node test")
if err != nil {
installStatus.ErrorCode = "TEST_FAILED"
return errors.New("test edge node failed: " + err.Error())
return errors.New("test edge node failed: " + err.Error() + ", stderr: " + stderr)
}
if len(stderr) > 0 {
if regexp.MustCompile(`(?i)rpc`).MatchString(stderr) {

View File

@@ -123,7 +123,7 @@ secret: "${nodeSecret}"`)
_, stderr, err = this.client.Exec(dir + "/edge-dns/bin/edge-dns test")
if err != nil {
installStatus.ErrorCode = "TEST_FAILED"
return errors.New("test edge node failed: " + err.Error())
return errors.New("test edge node failed: " + err.Error() + ", stderr: " + stderr)
}
if len(stderr) > 0 {
if regexp.MustCompile(`(?i)rpc`).MatchString(stderr) {

View File

@@ -1,5 +0,0 @@
package iplibrary
func init() {
}

View File

@@ -1,130 +0,0 @@
// 源码改自https://github.com/lionsoul2014/ip2region/blob/master/binding/golang/ip2region/ip2Region.go
package iplibrary
import (
"errors"
"os"
"strconv"
"strings"
)
const (
IndexBlockLength = 12
)
var err error
type IP2Region struct {
headerSip []int64
headerPtr []int64
headerLen int64
// super block index info
firstIndexPtr int64
lastIndexPtr int64
totalBlocks int64
dbData []byte
}
type IpInfo struct {
CityId int64
Country string
Region string
Province string
City string
ISP string
}
func (ip IpInfo) String() string {
return strconv.FormatInt(ip.CityId, 10) + "|" + ip.Country + "|" + ip.Region + "|" + ip.Province + "|" + ip.City + "|" + ip.ISP
}
func getIpInfo(cityId int64, line []byte) *IpInfo {
lineSlice := strings.Split(string(line), "|")
ipInfo := &IpInfo{}
length := len(lineSlice)
ipInfo.CityId = cityId
if length < 5 {
for i := 0; i <= 5-length; i++ {
lineSlice = append(lineSlice, "")
}
}
ipInfo.Country = lineSlice[0]
ipInfo.Region = lineSlice[1]
ipInfo.Province = lineSlice[2]
ipInfo.City = lineSlice[3]
ipInfo.ISP = lineSlice[4]
return ipInfo
}
func NewIP2Region(path string) (*IP2Region, error) {
var region = &IP2Region{}
region.dbData, err = os.ReadFile(path)
if err != nil {
return nil, err
}
region.firstIndexPtr = region.ipLongAtOffset(0)
region.lastIndexPtr = region.ipLongAtOffset(4)
region.totalBlocks = (region.lastIndexPtr-region.firstIndexPtr)/IndexBlockLength + 1
return region, nil
}
func (this *IP2Region) MemorySearch(ipStr string) (ipInfo *IpInfo, err error) {
ip, err := ip2long(ipStr)
if err != nil {
return nil, err
}
h := this.totalBlocks
var dataPtr, l int64
for l <= h {
m := (l + h) >> 1
p := this.firstIndexPtr + m*IndexBlockLength
sip := this.ipLongAtOffset(p)
if ip < sip {
h = m - 1
} else {
eip := this.ipLongAtOffset(p + 4)
if ip > eip {
l = m + 1
} else {
dataPtr = this.ipLongAtOffset(p + 8)
break
}
}
}
if dataPtr == 0 {
return nil, nil
}
dataLen := (dataPtr >> 24) & 0xFF
dataPtr = dataPtr & 0x00FFFFFF
return getIpInfo(this.ipLongAtOffset(dataPtr), this.dbData[(dataPtr)+4:dataPtr+dataLen]), nil
}
func (this *IP2Region) ipLongAtOffset(offset int64) int64 {
return int64(this.dbData[offset]) |
int64(this.dbData[offset+1])<<8 |
int64(this.dbData[offset+2])<<16 |
int64(this.dbData[offset+3])<<24
}
func ip2long(IpStr string) (int64, error) {
bits := strings.Split(IpStr, ".")
if len(bits) != 4 {
return 0, errors.New("ip format error")
}
var sum int64
for i, n := range bits {
bit, _ := strconv.ParseInt(n, 10, 64)
sum += bit << uint(24-8*i)
}
return sum, nil
}

View File

@@ -1,12 +0,0 @@
package iplibrary
type LibraryInterface interface {
// 加载数据库文件
Load(dbPath string) error
// 查询IP
Lookup(ip string) (*Result, error)
// 关闭数据库文件
Close()
}

View File

@@ -1,81 +0,0 @@
package iplibrary
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"net"
"strings"
)
type IP2RegionLibrary struct {
db *IP2Region
}
func (this *IP2RegionLibrary) Load(dbPath string) error {
db, err := NewIP2Region(dbPath)
if err != nil {
return err
}
this.db = db
return nil
}
func (this *IP2RegionLibrary) Lookup(ip string) (*Result, error) {
if this.db == nil {
return nil, errors.New("library has not been loaded")
}
// 只支持IPv4
if strings.Contains(ip, ":") {
return nil, nil
}
if net.ParseIP(ip) == nil {
return nil, nil
}
defer func() {
// 防止panic发生
err := recover()
if err != nil {
remotelogs.Error("IP2RegionLibrary", "panic: "+fmt.Sprintf("%#v", err))
}
}()
info, err := this.db.MemorySearch(ip)
if err != nil {
return nil, err
}
if info.Country == "0" {
info.Country = ""
}
if info.Region == "0" {
info.Region = ""
}
if info.Province == "0" {
info.Province = ""
}
if info.City == "0" {
info.City = ""
}
if info.ISP == "0" {
info.ISP = ""
}
return &Result{
CityId: info.CityId,
Country: info.Country,
Region: info.Region,
Province: info.Province,
City: info.City,
ISP: info.ISP,
}, nil
}
func (this *IP2RegionLibrary) Close() {
if this.db != nil {
return
}
}

View File

@@ -1,78 +0,0 @@
package iplibrary
import (
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
"runtime"
"strconv"
"testing"
"time"
)
func TestIP2RegionLibrary_Lookup(t *testing.T) {
library := &IP2RegionLibrary{}
err := library.Load(Tea.Root + "/resources/ipdata/ip2region/ip2region.db")
if err != nil {
t.Fatal(err)
}
result, err := library.Lookup("114.240.223.47")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(result, t)
}
func TestIP2RegionLibrary_Lookup_Valid_IP(t *testing.T) {
library := &IP2RegionLibrary{}
err := library.Load(Tea.Root + "/resources/ipdata/ip2region/ip2region.db")
if err != nil {
t.Fatal(err)
}
{
result, err := library.Lookup("114.240.223")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(result, t)
}
{
result, err := library.Lookup("abc")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(result, t)
}
}
func TestIP2RegionLibrary_Memory(t *testing.T) {
library := &IP2RegionLibrary{}
err := library.Load(Tea.Root + "/resources/ipdata/ip2region/ip2region.db")
if err != nil {
t.Fatal(err)
}
before := time.Now()
for i := 0; i < 1_000_000; i++ {
_, _ = library.Lookup(strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)))
}
t.Log("cost:", time.Since(before).Seconds()*1000, "ms")
}
func BenchmarkIP2RegionLibrary_Lookup(b *testing.B) {
runtime.GOMAXPROCS(1)
library := &IP2RegionLibrary{}
err := library.Load(Tea.Root + "/resources/ipdata/ip2region/ip2region.db")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
_, _ = library.Lookup(strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)) + "." + strconv.Itoa(rands.Int(0, 254)))
}
}

View File

@@ -1,90 +0,0 @@
package iplibrary
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/files"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
"regexp"
"strings"
)
var SharedManager = NewManager()
var SharedLibrary LibraryInterface
func init() {
dbs.OnReady(func() {
// 初始化
library, err := SharedManager.Load()
if err != nil {
logs.Println("[IP_LIBRARY]" + err.Error())
return
}
SharedLibrary = library
})
}
type Manager struct {
code string
}
func NewManager() *Manager {
return &Manager{}
}
func (this *Manager) Load() (LibraryInterface, error) {
// 当前正在使用的IP库代号
config, err := models.SharedSysSettingDAO.ReadGlobalConfig(nil)
if err != nil {
return nil, err
}
code := config.IPLibrary.Code
if len(code) == 0 {
code = serverconfigs.DefaultIPLibraryType
}
dir := Tea.Root + "/resources/ipdata/" + code
var lastVersion int64 = -1
lastFilename := ""
for _, file := range files.NewFile(dir).List() {
filename := file.Name()
reg := regexp.MustCompile(`^` + regexp.QuoteMeta(code) + `.(\d+)\.`)
if reg.MatchString(filename) { // 先查找有版本号的
result := reg.FindStringSubmatch(filename)
version := types.Int64(result[1])
if version > lastVersion {
lastVersion = version
lastFilename = filename
}
} else if strings.HasPrefix(filename, code+".") { // 后查找默认的
if lastVersion == -1 {
lastFilename = filename
lastVersion = 0
}
}
}
if len(lastFilename) == 0 {
return nil, errors.New("ip library file not found")
}
var libraryPtr LibraryInterface
switch code {
case serverconfigs.IPLibraryTypeIP2Region:
libraryPtr = &IP2RegionLibrary{}
default:
return nil, errors.New("invalid ip library code '" + code + "'")
}
err = libraryPtr.Load(dir + "/" + lastFilename)
if err != nil {
return nil, err
}
return libraryPtr, nil
}

View File

@@ -1,26 +0,0 @@
package iplibrary
import (
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestManager_Load(t *testing.T) {
dbs.NotifyReady()
manager := NewManager()
lib, err := manager.Load()
if err != nil {
t.Fatal(err)
}
t.Log(lib.Lookup("1.2.3.4"))
t.Log(lib.Lookup("2.3.4.5"))
t.Log(lib.Lookup("200.200.200.200"))
t.Log(lib.Lookup("202.106.0.20"))
}
func TestNewManager(t *testing.T) {
dbs.NotifyReady()
t.Log(SharedLibrary)
}

View File

@@ -1,29 +0,0 @@
package iplibrary
import (
"github.com/iwind/TeaGo/lists"
"strings"
)
type Result struct {
CityId int64
Country string
Region string
Province string
City string
ISP string
}
func (this *Result) Summary() string {
pieces := []string{}
if len(this.Country) > 0 {
pieces = append(pieces, this.Country)
}
if len(this.Province) > 0 && !lists.ContainsString(pieces, this.Province) {
pieces = append(pieces, this.Province)
}
if len(this.City) > 0 && !lists.ContainsString(pieces, this.City) && !lists.ContainsString(pieces, strings.TrimSuffix(this.City, "市")) {
pieces = append(pieces, this.City)
}
return strings.Join(pieces, " ")
}

View File

@@ -1,125 +0,0 @@
package iplibrary
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"os"
"time"
)
func init() {
dbs.OnReady(func() {
updater := NewUpdater()
updater.Start()
})
}
// Updater IP库更新程序
type Updater struct {
}
// NewUpdater 获取新对象
func NewUpdater() *Updater {
return &Updater{}
}
// Start 开始更新
func (this *Updater) Start() {
// 这里不需要太频繁检查更新因为通常不需要更新IP库
ticker := time.NewTicker(1 * time.Hour)
goman.New(func() {
for range ticker.C {
err := this.loop()
if err != nil {
logs.Println("[IP_LIBRARY]" + err.Error())
}
}
})
}
// 单次任务
func (this *Updater) loop() error {
config, err := models.SharedSysSettingDAO.ReadGlobalConfig(nil)
if err != nil {
return err
}
code := config.IPLibrary.Code
if len(code) == 0 {
code = serverconfigs.DefaultIPLibraryType
}
lib, err := models.SharedIPLibraryDAO.FindLatestIPLibraryWithType(nil, code)
if err != nil {
return err
}
if lib == nil {
return nil
}
typeInfo := serverconfigs.FindIPLibraryWithType(code)
if typeInfo == nil {
return errors.New("invalid ip library code '" + code + "'")
}
path := Tea.Root + "/resources/ipdata/" + code + "/" + code + "." + fmt.Sprintf("%d", lib.CreatedAt) + typeInfo.GetString("ext")
// 是否已经存在
_, err = os.Stat(path)
if err == nil {
return nil
}
// 开始下载
chunkIds, err := models.SharedFileChunkDAO.FindAllFileChunkIds(nil, int64(lib.FileId))
if err != nil {
return err
}
isOk := false
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return err
}
defer func() {
// 如果保存不成功就直接删除
if !isOk {
_ = fp.Close()
_ = os.Remove(path)
}
}()
for _, chunkId := range chunkIds {
chunk, err := models.SharedFileChunkDAO.FindFileChunk(nil, chunkId)
if err != nil {
return err
}
if chunk == nil {
continue
}
_, err = fp.Write(chunk.Data)
if err != nil {
return err
}
}
err = fp.Close()
if err != nil {
return err
}
// 重新加载
library, err := SharedManager.Load()
if err != nil {
return err
}
SharedLibrary = library
isOk = true
return nil
}

View File

@@ -1,18 +0,0 @@
package iplibrary
import (
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestUpdater_loop(t *testing.T) {
dbs.NotifyReady()
updater := NewUpdater()
err := updater.loop()
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/rpc"
"github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -86,6 +87,13 @@ func (this *APINode) Start() {
return
}
// 启动IP库
remotelogs.Println("API_NODE", "initializing ip library ...")
err = iplibrary.InitDefault()
if err != nil {
remotelogs.Error("API_NODE", "initialize ip library failed: "+err.Error())
}
// 检查数据库连接
err = this.checkDB()
if err != nil {
@@ -569,7 +577,7 @@ func (this *APINode) listenPorts(apiNode *models.APINode) (isListening bool) {
// add to local firewall
if len(ports) > 0 {
utils.AddPortsToFirewall(ports)
go utils.AddPortsToFirewall(ports)
}
return
@@ -684,12 +692,12 @@ func (this *APINode) listenSock() error {
err := this.sock.Listen()
if err != nil {
logs.Println("API_NODE", err.Error())
remotelogs.Println("API_NODE", err.Error())
}
})
events.On(events.EventQuit, func() {
logs.Println("API_NODE", "quit unix sock")
remotelogs.Println("API_NODE", "quit unix sock")
_ = this.sock.Close()
})

View File

@@ -247,6 +247,11 @@ func (this *APINode) registerServices(server *grpc.Server) {
pb.RegisterIPLibraryFileServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.IPLibraryArtifactService{}).(*services.IPLibraryArtifactService)
pb.RegisterIPLibraryArtifactServiceServer(server, instance)
this.rest(instance)
}
{
var instance = this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
pb.RegisterFileChunkServiceServer(server, instance)

View File

@@ -0,0 +1,105 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodes
import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
"io"
"os"
"time"
)
func init() {
dbs.OnReady(func() {
goman.New(func() {
iplibrary.NewUpdater(NewIPLibraryUpdater(), 10*time.Minute).Start()
})
})
}
type IPLibraryUpdater struct {
}
func NewIPLibraryUpdater() *IPLibraryUpdater {
return &IPLibraryUpdater{}
}
// DataDir 文件目录
func (this *IPLibraryUpdater) DataDir() string {
// data/
var dir = Tea.Root + "/data"
stat, err := os.Stat(dir)
if err == nil && stat.IsDir() {
return dir
}
err = os.Mkdir(dir, 0666)
if err == nil {
return dir
}
remotelogs.Error("IP_LIBRARY_UPDATER", "create directory '"+dir+"' failed: "+err.Error())
// 如果不能创建 data/ 目录,那么使用临时目录
return os.TempDir()
}
// FindLatestFile 检查最新的IP库文件
func (this *IPLibraryUpdater) FindLatestFile() (code string, fileId int64, err error) {
artifact, err := models.SharedIPLibraryArtifactDAO.FindPublicArtifact(nil)
if err != nil {
return "", 0, err
}
if artifact == nil {
return "", 0, nil
}
return artifact.Code, int64(artifact.FileId), nil
}
// DownloadFile 下载文件
func (this *IPLibraryUpdater) DownloadFile(fileId int64, writer io.Writer) error {
if fileId <= 0 {
return errors.New("invalid fileId: " + types.String(fileId))
}
var tx *dbs.Tx
chunkIds, err := models.SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
if err != nil {
return err
}
for _, chunkId := range chunkIds {
chunk, err := models.SharedFileChunkDAO.FindFileChunk(tx, chunkId)
if err != nil {
return err
}
if chunk == nil {
return errors.New("can not find file chunk with chunk id '" + types.String(chunkId) + "'")
}
_, err = writer.Write(chunk.Data)
if err != nil {
return err
}
}
return nil
}
// LogInfo 普通日志
func (this *IPLibraryUpdater) LogInfo(message string) {
remotelogs.Println("IP_LIBRARY_UPDATER", message)
}
// LogError 错误日志
func (this *IPLibraryUpdater) LogError(err error) {
if err == nil {
return
}
remotelogs.Error("IP_LIBRARY_UPDATER", err.Error())
}

View File

@@ -15,7 +15,7 @@ type ACMEProviderService struct {
// FindAllACMEProviders 查找所有的服务商
func (this *ACMEProviderService) FindAllACMEProviders(ctx context.Context, req *pb.FindAllACMEProvidersRequest) (*pb.FindAllACMEProvidersResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, _, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
@@ -37,7 +37,7 @@ func (this *ACMEProviderService) FindAllACMEProviders(ctx context.Context, req *
// FindACMEProviderWithCode 根据代号查找服务商
func (this *ACMEProviderService) FindACMEProviderWithCode(ctx context.Context, req *pb.FindACMEProviderWithCodeRequest) (*pb.FindACMEProviderWithCodeResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, _, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}

View File

@@ -16,13 +16,13 @@ type ACMEProviderAccountService struct {
// CreateACMEProviderAccount 创建服务商账号
func (this *ACMEProviderAccountService) CreateACMEProviderAccount(ctx context.Context, req *pb.CreateACMEProviderAccountRequest) (*pb.CreateACMEProviderAccountResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
accountId, err := acme.SharedACMEProviderAccountDAO.CreateAccount(tx, req.Name, req.ProviderCode, req.EabKid, req.EabKey)
accountId, err := acme.SharedACMEProviderAccountDAO.CreateAccount(tx, userId, req.Name, req.ProviderCode, req.EabKid, req.EabKey)
if err != nil {
return nil, err
}
@@ -33,13 +33,13 @@ func (this *ACMEProviderAccountService) CreateACMEProviderAccount(ctx context.Co
// FindAllACMEProviderAccountsWithProviderCode 使用代号查找服务商账号
func (this *ACMEProviderAccountService) FindAllACMEProviderAccountsWithProviderCode(ctx context.Context, req *pb.FindAllACMEProviderAccountsWithProviderCodeRequest) (*pb.FindAllACMEProviderAccountsWithProviderCodeResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
accounts, err := acme.SharedACMEProviderAccountDAO.FindAllEnabledAccountsWithProviderCode(tx, req.AcmeProviderCode)
accounts, err := acme.SharedACMEProviderAccountDAO.FindAllEnabledAccountsWithProviderCode(tx, userId, req.AcmeProviderCode)
if err != nil {
return nil, err
}
@@ -76,12 +76,21 @@ func (this *ACMEProviderAccountService) FindAllACMEProviderAccountsWithProviderC
// UpdateACMEProviderAccount 修改服务商账号
func (this *ACMEProviderAccountService) UpdateACMEProviderAccount(ctx context.Context, req *pb.UpdateACMEProviderAccountRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查权限
if userId > 0 {
err = acme.SharedACMEProviderAccountDAO.CheckUserAccount(tx, userId, req.AcmeProviderAccountId)
if err != nil {
return nil, err
}
}
err = acme.SharedACMEProviderAccountDAO.UpdateAccount(tx, req.AcmeProviderAccountId, req.Name, req.EabKid, req.EabKey)
if err != nil {
return nil, err
@@ -91,12 +100,21 @@ func (this *ACMEProviderAccountService) UpdateACMEProviderAccount(ctx context.Co
// DeleteACMEProviderAccount 删除服务商账号
func (this *ACMEProviderAccountService) DeleteACMEProviderAccount(ctx context.Context, req *pb.DeleteACMEProviderAccountRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查权限
if userId > 0 {
err = acme.SharedACMEProviderAccountDAO.CheckUserAccount(tx, userId, req.AcmeProviderAccountId)
if err != nil {
return nil, err
}
}
err = acme.SharedACMEProviderAccountDAO.DisableACMEProviderAccount(tx, req.AcmeProviderAccountId)
if err != nil {
return nil, err
@@ -106,12 +124,21 @@ func (this *ACMEProviderAccountService) DeleteACMEProviderAccount(ctx context.Co
// FindEnabledACMEProviderAccount 查找单个服务商账号
func (this *ACMEProviderAccountService) FindEnabledACMEProviderAccount(ctx context.Context, req *pb.FindEnabledACMEProviderAccountRequest) (*pb.FindEnabledACMEProviderAccountResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查权限
if userId > 0 {
err = acme.SharedACMEProviderAccountDAO.CheckUserAccount(tx, userId, req.AcmeProviderAccountId)
if err != nil {
return nil, err
}
}
account, err := acme.SharedACMEProviderAccountDAO.FindEnabledACMEProviderAccount(tx, req.AcmeProviderAccountId)
if err != nil {
return nil, err
@@ -147,13 +174,13 @@ func (this *ACMEProviderAccountService) FindEnabledACMEProviderAccount(ctx conte
// CountAllEnabledACMEProviderAccounts 计算所有服务商账号数量
func (this *ACMEProviderAccountService) CountAllEnabledACMEProviderAccounts(ctx context.Context, req *pb.CountAllEnabledACMEProviderAccountsRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := acme.SharedACMEProviderAccountDAO.CountAllEnabledAccounts(tx)
count, err := acme.SharedACMEProviderAccountDAO.CountAllEnabledAccounts(tx, userId)
if err != nil {
return nil, err
}
@@ -162,13 +189,13 @@ func (this *ACMEProviderAccountService) CountAllEnabledACMEProviderAccounts(ctx
// ListEnabledACMEProviderAccounts 列出单页服务商账号
func (this *ACMEProviderAccountService) ListEnabledACMEProviderAccounts(ctx context.Context, req *pb.ListEnabledACMEProviderAccountsRequest) (*pb.ListEnabledACMEProviderAccountsResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
accounts, err := acme.SharedACMEProviderAccountDAO.ListEnabledAccounts(tx, req.Offset, req.Size)
accounts, err := acme.SharedACMEProviderAccountDAO.ListEnabledAccounts(tx, userId, req.Offset, req.Size)
if err != nil {
return nil, err
}

View File

@@ -90,7 +90,7 @@ func (this *ACMETaskService) ListEnabledACMETasks(ctx context.Context, req *pb.L
return nil, err
}
result := []*pb.ACMETask{}
var result = []*pb.ACMETask{}
for _, task := range tasks {
// ACME用户
acmeUser, err := acmemodels.SharedACMEUserDAO.FindEnabledACMEUser(tx, int64(task.AcmeUserId))

View File

@@ -417,9 +417,10 @@ func (this *DNSDomainService) convertRecordToPB(record *dnstypes.Record) *pb.DNS
// 检查集群节点变化
func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, records []*dnstypes.Record, domainName string, defaultRoute string) (result []maps.Map, doneNodeRecords []*dnstypes.Record, doneServerRecords []*dnstypes.Record, countAllNodes int64, countAllServers int64, nodesChanged bool, serversChanged bool, err error) {
clusterId := int64(cluster.Id)
clusterDnsName := cluster.DnsName
clusterDomain := clusterDnsName + "." + domainName
var clusterId = int64(cluster.Id)
var clusterDnsName = cluster.DnsName
var clusterDomain = clusterDnsName + "." + domainName
var dnsConfig, _ = cluster.DecodeDNSConfig()
var tx = this.NullTx()
@@ -437,7 +438,7 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
}
// 节点域名
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true)
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, dnsConfig != nil && dnsConfig.IncludingLnNodes)
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}

View File

@@ -40,7 +40,7 @@ func (this *FileChunkService) CreateFileChunk(ctx context.Context, req *pb.Creat
// FindAllFileChunkIds 获取的一个文件的所有片段IDs
func (this *FileChunkService) FindAllFileChunkIds(ctx context.Context, req *pb.FindAllFileChunkIdsRequest) (*pb.FindAllFileChunkIdsResponse, error) {
// 校验请求
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
if err != nil {
return nil, err
}
@@ -60,7 +60,7 @@ func (this *FileChunkService) FindAllFileChunkIds(ctx context.Context, req *pb.F
// DownloadFileChunk 下载文件片段
func (this *FileChunkService) DownloadFileChunk(ctx context.Context, req *pb.DownloadFileChunkRequest) (*pb.DownloadFileChunkResponse, error) {
// 校验请求
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
if err != nil {
return nil, err
}

View File

@@ -15,13 +15,13 @@ type HTTPAuthPolicyService struct {
// CreateHTTPAuthPolicy 创建策略
func (this *HTTPAuthPolicyService) CreateHTTPAuthPolicy(ctx context.Context, req *pb.CreateHTTPAuthPolicyRequest) (*pb.CreateHTTPAuthPolicyResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
policyId, err := models.SharedHTTPAuthPolicyDAO.CreateHTTPAuthPolicy(tx, req.Name, req.Type, req.ParamsJSON)
policyId, err := models.SharedHTTPAuthPolicyDAO.CreateHTTPAuthPolicy(tx, userId, req.Name, req.Type, req.ParamsJSON)
if err != nil {
return nil, err
}
@@ -30,12 +30,21 @@ func (this *HTTPAuthPolicyService) CreateHTTPAuthPolicy(ctx context.Context, req
// UpdateHTTPAuthPolicy 修改策略
func (this *HTTPAuthPolicyService) UpdateHTTPAuthPolicy(ctx context.Context, req *pb.UpdateHTTPAuthPolicyRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查用户权限
if userId > 0 {
err = models.SharedHTTPAuthPolicyDAO.CheckUserPolicy(tx, userId, req.HttpAuthPolicyId)
if err != nil {
return nil, err
}
}
err = models.SharedHTTPAuthPolicyDAO.UpdateHTTPAuthPolicy(tx, req.HttpAuthPolicyId, req.Name, req.ParamsJSON, req.IsOn)
if err != nil {
return nil, err
@@ -45,12 +54,21 @@ func (this *HTTPAuthPolicyService) UpdateHTTPAuthPolicy(ctx context.Context, req
// FindEnabledHTTPAuthPolicy 查找策略信息
func (this *HTTPAuthPolicyService) FindEnabledHTTPAuthPolicy(ctx context.Context, req *pb.FindEnabledHTTPAuthPolicyRequest) (*pb.FindEnabledHTTPAuthPolicyResponse, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查用户权限
if userId > 0 {
err = models.SharedHTTPAuthPolicyDAO.CheckUserPolicy(tx, userId, req.HttpAuthPolicyId)
if err != nil {
return nil, err
}
}
policy, err := models.SharedHTTPAuthPolicyDAO.FindEnabledHTTPAuthPolicy(tx, req.HttpAuthPolicyId)
if err != nil {
return nil, err

View File

@@ -4,10 +4,9 @@ import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/iplibrary"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/lists"
@@ -794,20 +793,14 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
}
// 检查封禁的地区和省份
info, err := iplibrary.SharedLibrary.Lookup(req.Ip)
if err != nil {
return nil, err
}
if info != nil {
var info = iplibrary.LookupIP(req.Ip)
if info != nil && info.IsOk() {
if firewallPolicy.Inbound != nil &&
firewallPolicy.Inbound.IsOn &&
firewallPolicy.Inbound.Region != nil &&
firewallPolicy.Inbound.Region.IsOn {
// 检查封禁的地区
countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithNameCacheable(tx, info.Country)
if err != nil {
return nil, err
}
var countryId = info.CountryId()
if countryId > 0 && lists.ContainsInt64(firewallPolicy.Inbound.Region.DenyCountryIds, countryId) {
return &pb.CheckHTTPFirewallPolicyIPStatusResponse{
IsOk: true,
@@ -818,7 +811,7 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
IpItem: nil,
RegionCountry: &pb.RegionCountry{
Id: countryId,
Name: info.Country,
Name: info.CountryName(),
},
RegionProvince: nil,
}, nil
@@ -826,10 +819,7 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
// 检查封禁的省份
if countryId > 0 {
provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithNameCacheable(tx, countryId, info.Province)
if err != nil {
return nil, err
}
var provinceId = info.ProvinceId()
if provinceId > 0 && lists.ContainsInt64(firewallPolicy.Inbound.Region.DenyProvinceIds, provinceId) {
return &pb.CheckHTTPFirewallPolicyIPStatusResponse{
IsOk: true,
@@ -840,11 +830,11 @@ func (this *HTTPFirewallPolicyService) CheckHTTPFirewallPolicyIPStatus(ctx conte
IpItem: nil,
RegionCountry: &pb.RegionCountry{
Id: countryId,
Name: info.Country,
Name: info.CountryName(),
},
RegionProvince: &pb.RegionProvince{
Id: provinceId,
Name: info.Province,
Name: info.ProvinceName(),
},
}, nil
}

View File

@@ -663,13 +663,20 @@ func (this *HTTPWebService) UpdateHTTPWebCommon(ctx context.Context, req *pb.Upd
// UpdateHTTPWebRequestLimit 修改请求限制
func (this *HTTPWebService) UpdateHTTPWebRequestLimit(ctx context.Context, req *pb.UpdateHTTPWebRequestLimitRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
_, userId, err := this.ValidateAdminAndUser(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = models.SharedHTTPWebDAO.CheckUserWeb(tx, userId, req.HttpWebId)
if err != nil {
return nil, err
}
}
var config = &serverconfigs.HTTPRequestLimitConfig{}
err = json.Unmarshal(req.RequestLimitJSON, config)
if err != nil {

View File

@@ -3,9 +3,8 @@ package services
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/TeaOSLab/EdgeAPI/internal/iplibrary"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
@@ -183,34 +182,19 @@ func (this *IPLibraryService) LookupIPRegion(ctx context.Context, req *pb.Lookup
return nil, err
}
result, err := iplibrary.SharedLibrary.Lookup(req.Ip)
if err != nil {
return nil, err
}
if result == nil {
var result = iplibrary.LookupIP(req.Ip)
if result == nil || !result.IsOk() {
return &pb.LookupIPRegionResponse{IpRegion: nil}, nil
}
var tx = this.NullTx()
countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithNameCacheable(tx, result.Country)
if err != nil {
return nil, err
}
provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithNameCacheable(tx, countryId, result.Province)
if err != nil {
return nil, err
}
return &pb.LookupIPRegionResponse{IpRegion: &pb.IPRegion{
Country: result.Country,
Region: result.Region,
Province: result.Province,
City: result.City,
Isp: result.ISP,
CountryId: countryId,
ProvinceId: provinceId,
Country: result.CountryName(),
Region: "",
Province: result.ProvinceName(),
City: result.CityName(),
Isp: result.ProviderName(),
CountryId: result.CountryId(),
ProvinceId: result.ProvinceId(),
Summary: result.Summary(),
}}, nil
}
@@ -223,20 +207,17 @@ func (this *IPLibraryService) LookupIPRegions(ctx context.Context, req *pb.Looku
return nil, err
}
result := map[string]*pb.IPRegion{}
var result = map[string]*pb.IPRegion{}
if len(req.IpList) > 0 {
for _, ip := range req.IpList {
info, err := iplibrary.SharedLibrary.Lookup(ip)
if err != nil {
return nil, err
}
if info != nil {
var info = iplibrary.LookupIP(ip)
if info != nil && info.IsOk() {
result[ip] = &pb.IPRegion{
Country: info.Country,
Region: info.Region,
Province: info.Province,
City: info.City,
Isp: info.ISP,
Country: info.CountryName(),
Region: "",
Province: info.ProvinceName(),
City: info.CityName(),
Isp: info.ProviderName(),
Summary: info.Summary(),
}
}

View File

@@ -0,0 +1,166 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// IPLibraryArtifactService IP库制品
type IPLibraryArtifactService struct {
BaseService
}
// CreateIPLibraryArtifact 创建制品
func (this *IPLibraryArtifactService) CreateIPLibraryArtifact(ctx context.Context, req *pb.CreateIPLibraryArtifactRequest) (*pb.CreateIPLibraryArtifactResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var meta = &iplibrary.Meta{}
err = json.Unmarshal(req.MetaJSON, meta)
if err != nil {
return nil, errors.New("decode meta failed: " + err.Error())
}
// TODO 更新数据库中的省市县等信息?
artifactId, err := models.SharedIPLibraryArtifactDAO.CreateArtifact(tx, req.Name, req.FileId, 0, meta)
if err != nil {
return nil, err
}
return &pb.CreateIPLibraryArtifactResponse{IpLibraryArtifactId: artifactId}, nil
}
// UpdateIPLibraryArtifactIsPublic 使用/取消使用制品
func (this *IPLibraryArtifactService) UpdateIPLibraryArtifactIsPublic(ctx context.Context, req *pb.UpdateIPLibraryArtifactIsPublicRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedIPLibraryArtifactDAO.UpdateArtifactPublic(tx, req.IpLibraryArtifactId, req.IsPublic)
if err != nil {
return nil, err
}
return this.Success()
}
// FindAllIPLibraryArtifacts 查询所有制品
func (this *IPLibraryArtifactService) FindAllIPLibraryArtifacts(ctx context.Context, req *pb.FindAllIPLibraryArtifactsRequest) (*pb.FindAllIPLibraryArtifactsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
artifacts, err := models.SharedIPLibraryArtifactDAO.FindAllArtifacts(tx)
if err != nil {
return nil, err
}
var pbArtifacts = []*pb.IPLibraryArtifact{}
for _, artifact := range artifacts {
pbArtifacts = append(pbArtifacts, &pb.IPLibraryArtifact{
Id: int64(artifact.Id),
Name: artifact.Name,
FileId: int64(artifact.FileId),
CreatedAt: int64(artifact.CreatedAt),
MetaJSON: artifact.Meta,
IsPublic: artifact.IsPublic,
Code: artifact.Code,
})
}
return &pb.FindAllIPLibraryArtifactsResponse{
IpLibraryArtifacts: pbArtifacts,
}, nil
}
// FindIPLibraryArtifact 查找当前正在使用的制品
func (this *IPLibraryArtifactService) FindIPLibraryArtifact(ctx context.Context, req *pb.FindIPLibraryArtifactRequest) (*pb.FindIPLibraryArtifactResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
artifact, err := models.SharedIPLibraryArtifactDAO.FindEnabledIPLibraryArtifact(tx, req.IpLibraryArtifactId)
if err != nil {
return nil, err
}
if artifact == nil {
return &pb.FindIPLibraryArtifactResponse{
IpLibraryArtifact: nil,
}, nil
}
return &pb.FindIPLibraryArtifactResponse{
IpLibraryArtifact: &pb.IPLibraryArtifact{
Id: int64(artifact.Id),
FileId: int64(artifact.FileId),
CreatedAt: int64(artifact.CreatedAt),
MetaJSON: artifact.Meta,
IsPublic: artifact.IsPublic,
Code: artifact.Code,
},
}, nil
}
// FindPublicIPLibraryArtifact 查找当前正在使用的制品
func (this *IPLibraryArtifactService) FindPublicIPLibraryArtifact(ctx context.Context, req *pb.FindPublicIPLibraryArtifactRequest) (*pb.FindPublicIPLibraryArtifactResponse, error) {
_, _, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS)
if err != nil {
return nil, err
}
var tx = this.NullTx()
artifact, err := models.SharedIPLibraryArtifactDAO.FindPublicArtifact(tx)
if err != nil {
return nil, err
}
if artifact == nil {
return &pb.FindPublicIPLibraryArtifactResponse{
IpLibraryArtifact: nil,
}, nil
}
return &pb.FindPublicIPLibraryArtifactResponse{
IpLibraryArtifact: &pb.IPLibraryArtifact{
Id: int64(artifact.Id),
FileId: int64(artifact.FileId),
CreatedAt: int64(artifact.CreatedAt),
MetaJSON: artifact.Meta,
IsPublic: artifact.IsPublic,
Code: artifact.Code,
},
}, nil
}
// DeleteIPLibraryArtifact 删除制品
func (this *IPLibraryArtifactService) DeleteIPLibraryArtifact(ctx context.Context, req *pb.DeleteIPLibraryArtifactRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedIPLibraryArtifactDAO.DisableIPLibraryArtifact(tx, req.IpLibraryArtifactId)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -18,6 +18,71 @@ type IPLibraryFileService struct {
BaseService
}
// FindAllFinishedIPLibraryFiles 查找所有已完成的IP库文件
func (this *IPLibraryFileService) FindAllFinishedIPLibraryFiles(ctx context.Context, req *pb.FindAllFinishedIPLibraryFilesRequest) (*pb.FindAllFinishedIPLibraryFilesResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
libraryFiles, err := models.SharedIPLibraryFileDAO.FindAllFinishedLibraryFiles(tx)
if err != nil {
return nil, err
}
var pbLibraryFiles = []*pb.IPLibraryFile{}
for _, libraryFile := range libraryFiles {
var pbCountryNames = libraryFile.DecodeCountries()
var pbProviderNames = libraryFile.DecodeProviders()
var pbProvinces = []*pb.IPLibraryFile_Province{}
for _, province := range libraryFile.DecodeProvinces() {
pbProvinces = append(pbProvinces, &pb.IPLibraryFile_Province{
CountryName: province[0],
ProvinceName: province[1],
})
}
var pbCities = []*pb.IPLibraryFile_City{}
for _, city := range libraryFile.DecodeCities() {
pbCities = append(pbCities, &pb.IPLibraryFile_City{
CountryName: city[0],
ProvinceName: city[1],
CityName: city[2],
})
}
var pbTowns = []*pb.IPLibraryFile_Town{}
for _, town := range libraryFile.DecodeTowns() {
pbTowns = append(pbTowns, &pb.IPLibraryFile_Town{
CountryName: town[0],
ProvinceName: town[1],
CityName: town[2],
TownName: town[3],
})
}
pbLibraryFiles = append(pbLibraryFiles, &pb.IPLibraryFile{
Id: int64(libraryFile.Id),
Name: libraryFile.Name,
FileId: int64(libraryFile.FileId),
IsFinished: libraryFile.IsFinished,
CreatedAt: int64(libraryFile.CreatedAt),
GeneratedFileId: int64(libraryFile.GeneratedFileId),
GeneratedAt: int64(libraryFile.GeneratedAt),
CountryNames: pbCountryNames,
Provinces: pbProvinces,
Cities: pbCities,
Towns: pbTowns,
ProviderNames: pbProviderNames,
})
}
return &pb.FindAllFinishedIPLibraryFilesResponse{
IpLibraryFiles: pbLibraryFiles,
}, nil
}
// FindAllUnfinishedIPLibraryFiles 查找所有未完成的IP库文件
func (this *IPLibraryFileService) FindAllUnfinishedIPLibraryFiles(ctx context.Context, req *pb.FindAllUnfinishedIPLibraryFilesRequest) (*pb.FindAllUnfinishedIPLibraryFilesResponse, error) {
_, err := this.ValidateAdmin(ctx)
@@ -64,6 +129,7 @@ func (this *IPLibraryFileService) FindAllUnfinishedIPLibraryFiles(ctx context.Co
pbLibraryFiles = append(pbLibraryFiles, &pb.IPLibraryFile{
Id: int64(libraryFile.Id),
Name: libraryFile.Name,
FileId: int64(libraryFile.FileId),
IsFinished: libraryFile.IsFinished,
CreatedAt: int64(libraryFile.CreatedAt),
@@ -130,15 +196,19 @@ func (this *IPLibraryFileService) FindIPLibraryFile(ctx context.Context, req *pb
return &pb.FindIPLibraryFileResponse{
IpLibraryFile: &pb.IPLibraryFile{
Id: int64(libraryFile.Id),
FileId: int64(libraryFile.FileId),
IsFinished: libraryFile.IsFinished,
CreatedAt: int64(libraryFile.CreatedAt),
CountryNames: pbCountryNames,
Provinces: pbProvinces,
Cities: pbCities,
Towns: pbTowns,
ProviderNames: pbProviderNames,
Id: int64(libraryFile.Id),
Name: libraryFile.Name,
Template: libraryFile.Template,
EmptyValues: libraryFile.DecodeEmptyValues(),
FileId: int64(libraryFile.FileId),
IsFinished: libraryFile.IsFinished,
CreatedAt: int64(libraryFile.CreatedAt),
GeneratedFileId: int64(libraryFile.GeneratedFileId),
CountryNames: pbCountryNames,
Provinces: pbProvinces,
Cities: pbCities,
Towns: pbTowns,
ProviderNames: pbProviderNames,
},
}, nil
}
@@ -182,7 +252,7 @@ func (this *IPLibraryFileService) CreateIPLibraryFile(ctx context.Context, req *
}
var tx = this.NullTx()
libraryFileId, err := models.SharedIPLibraryFileDAO.CreateLibraryFile(tx, req.Template, req.EmptyValues, req.FileId, countries, provinces, cities, towns, providers)
libraryFileId, err := models.SharedIPLibraryFileDAO.CreateLibraryFile(tx, req.Name, req.Template, req.EmptyValues, req.FileId, countries, provinces, cities, towns, providers)
if err != nil {
return nil, err
}
@@ -481,6 +551,9 @@ func (this *IPLibraryFileService) CheckTownsWithIPLibraryFileId(ctx context.Cont
}
}
cityMap[cityKey] = cityId
if cityId > 0 {
cityIds = append(cityIds, cityId)
}
}
// town
@@ -607,3 +680,34 @@ func (this *IPLibraryFileService) GenerateIPLibraryFile(ctx context.Context, req
return this.Success()
}
// UpdateIPLibraryFileFinished 设置某个IP库为已完成
func (this *IPLibraryFileService) UpdateIPLibraryFileFinished(ctx context.Context, req *pb.UpdateIPLibraryFileFinishedRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedIPLibraryFileDAO.UpdateLibraryFileIsFinished(tx, req.IpLibraryFileId)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteIPLibraryFile 删除IP库文件
func (this *IPLibraryFileService) DeleteIPLibraryFile(ctx context.Context, req *pb.DeleteIPLibraryFileRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedIPLibraryFileDAO.DisableIPLibraryFile(tx, req.IpLibraryFileId)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -27,8 +27,6 @@ func init() {
var countKeys = 0
for key := range metricStatKeysQueue {
err := func(key string) error {
var tx *dbs.Tx
metricStatsLocker.Lock()
req, ok := metricStatsMap[key]
if !ok {
@@ -45,7 +43,20 @@ func init() {
var itemId = types.Int64(pieces[3])
// 删除旧的数据
err := models.SharedMetricStatDAO.DeleteNodeItemStats(tx, nodeId, serverId, itemId, req.Time)
tx, err := models.SharedMetricStatDAO.Instance.Begin()
if err != nil {
return err
}
defer func() {
// 失败时不需要rollback
commitErr := tx.Commit()
if commitErr != nil {
remotelogs.Error("METRIC_STAT", "commit metric stats failed: "+commitErr.Error())
}
}()
err = models.SharedMetricStatDAO.DeleteNodeItemStats(tx, nodeId, serverId, itemId, req.Time)
if err != nil {
return err
}

View File

@@ -475,7 +475,7 @@ func (this *NodeService) UpdateNode(ctx context.Context, req *pb.UpdateNodeReque
var tx = this.NullTx()
err = models.SharedNodeDAO.UpdateNode(tx, req.NodeId, req.Name, req.NodeClusterId, req.SecondaryNodeClusterIds, req.NodeGroupId, req.NodeRegionId, req.IsOn, int(req.Level))
err = models.SharedNodeDAO.UpdateNode(tx, req.NodeId, req.Name, req.NodeClusterId, req.SecondaryNodeClusterIds, req.NodeGroupId, req.NodeRegionId, req.IsOn, int(req.Level), req.LnAddrs)
if err != nil {
return nil, err
}
@@ -673,6 +673,7 @@ func (this *NodeService) FindEnabledNode(ctx context.Context, req *pb.FindEnable
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
CacheDiskDir: node.CacheDiskDir,
Level: int32(node.Level),
LnAddrs: node.DecodeLnAddrs(),
DnsRoutes: pbRoutes,
}}, nil
}
@@ -1304,18 +1305,19 @@ func (this *NodeService) FindAllEnabledNodesDNSWithNodeClusterId(ctx context.Con
if clusterDNS == nil {
return nil, errors.New("not found clusterId '" + numberutils.FormatInt64(req.NodeClusterId) + "'")
}
dnsDomainId := int64(clusterDNS.DnsDomainId)
var dnsConfig, _ = clusterDNS.DecodeDNSConfig()
var dnsDomainId = int64(clusterDNS.DnsDomainId)
routes, err := dns.SharedDNSDomainDAO.FindDomainRoutes(tx, dnsDomainId)
if err != nil {
return nil, err
}
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, req.NodeClusterId, true)
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, req.NodeClusterId, true, dnsConfig != nil && dnsConfig.IncludingLnNodes)
if err != nil {
return nil, err
}
result := []*pb.NodeDNSInfo{}
var result = []*pb.NodeDNSInfo{}
for _, node := range nodes {
ipAddresses, err := models.SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
if err != nil {
@@ -1327,7 +1329,7 @@ func (this *NodeService) FindAllEnabledNodesDNSWithNodeClusterId(ctx context.Con
return nil, err
}
pbRoutes := []*pb.DNSRoute{}
var pbRoutes = []*pb.DNSRoute{}
for _, routeCode := range domainRouteCodes {
for _, r := range routes {
if r.Code == routeCode {
@@ -1868,7 +1870,7 @@ func (this *NodeService) FindNodeDDoSProtection(ctx context.Context, req *pb.Fin
return result, nil
}
// UpdateNodeDDoSProtection 修改集群的DDOS设置
// UpdateNodeDDoSProtection 修改集群的DDoS设置
func (this *NodeService) UpdateNodeDDoSProtection(ctx context.Context, req *pb.UpdateNodeDDoSProtectionRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {

View File

@@ -450,14 +450,15 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
if dnsInfo.DnsDomainId == 0 {
return &pb.FindEnabledNodeClusterDNSResponse{
Name: dnsInfo.DnsName,
Domain: nil,
Provider: nil,
NodesAutoSync: dnsConfig.NodesAutoSync,
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
Name: dnsInfo.DnsName,
Domain: nil,
Provider: nil,
NodesAutoSync: dnsConfig.NodesAutoSync,
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
IncludingLnNodes: dnsConfig.IncludingLnNodes,
}, nil
}
@@ -509,15 +510,16 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
}
return &pb.FindEnabledNodeClusterDNSResponse{
Name: dnsInfo.DnsName,
Domain: pbDomain,
Provider: pbProvider,
NodesAutoSync: dnsConfig.NodesAutoSync,
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
DefaultRoute: defaultRoute,
Name: dnsInfo.DnsName,
Domain: pbDomain,
Provider: pbProvider,
NodesAutoSync: dnsConfig.NodesAutoSync,
ServersAutoSync: dnsConfig.ServersAutoSync,
CnameRecords: dnsConfig.CNameRecords,
Ttl: dnsConfig.TTL,
CnameAsDomain: dnsConfig.CNameAsDomain,
IncludingLnNodes: dnsConfig.IncludingLnNodes,
DefaultRoute: defaultRoute,
}, nil
}
@@ -610,7 +612,7 @@ func (this *NodeClusterService) UpdateNodeClusterDNS(ctx context.Context, req *p
var tx = this.NullTx()
err = models.SharedNodeClusterDAO.UpdateClusterDNS(tx, req.NodeClusterId, req.DnsName, req.DnsDomainId, req.NodesAutoSync, req.ServersAutoSync, req.CnameRecords, req.Ttl, req.CnameAsDomain)
err = models.SharedNodeClusterDAO.UpdateClusterDNS(tx, req.NodeClusterId, req.DnsName, req.DnsDomainId, req.NodesAutoSync, req.ServersAutoSync, req.CnameRecords, req.Ttl, req.CnameAsDomain, req.IncludingLnNodes)
if err != nil {
return nil, err
}
@@ -1184,7 +1186,7 @@ func (this *NodeClusterService) UpdateNodeClusterUAMPolicy(ctx context.Context,
return this.Success()
}
// FindNodeClusterDDoSProtection 获取集群的DDOS设置
// FindNodeClusterDDoSProtection 获取集群的DDoS设置
func (this *NodeClusterService) FindNodeClusterDDoSProtection(ctx context.Context, req *pb.FindNodeClusterDDoSProtectionRequest) (*pb.FindNodeClusterDDoSProtectionResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
@@ -1211,7 +1213,7 @@ func (this *NodeClusterService) FindNodeClusterDDoSProtection(ctx context.Contex
return result, nil
}
// UpdateNodeClusterDDoSProtection 修改集群的DDOS设置
// UpdateNodeClusterDDoSProtection 修改集群的DDoS设置
func (this *NodeClusterService) UpdateNodeClusterDDoSProtection(ctx context.Context, req *pb.UpdateNodeClusterDDoSProtectionRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {

View File

@@ -148,10 +148,20 @@ func (this *NodeLogService) UpdateNodeLogsRead(ctx context.Context, req *pb.Upda
}
var tx = this.NullTx()
err = models.SharedNodeLogDAO.UpdateNodeLogsRead(tx, req.NodeLogIds)
if err != nil {
return nil, err
if len(req.NodeLogIds) > 0 {
err = models.SharedNodeLogDAO.UpdateNodeLogIdsRead(tx, req.NodeLogIds)
if err != nil {
return nil, err
}
}
if req.NodeId > 0 && len(req.Role) > 0 {
err = models.SharedNodeLogDAO.UpdateNodeLogsRead(tx, req.Role, req.NodeId)
if err != nil {
return nil, err
}
}
return this.Success()
}

View File

@@ -124,6 +124,7 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
return err
}
if inactiveNotifiedAt > 0 {
// 设置为活跃
err = models.SharedNodeDAO.UpdateNodeActive(tx, nodeId, true)
if err != nil {
return err
@@ -144,6 +145,12 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
if err != nil {
return err
}
} else {
// 设置为活跃
err = models.SharedNodeDAO.UpdateNodeActive(tx, nodeId, true)
if err != nil {
return err
}
}
}

View File

@@ -88,7 +88,7 @@ func (this *RegionProvinceService) FindAllRegionProvincesWithRegionCountryId(ctx
if err != nil {
return nil, err
}
result := []*pb.RegionProvince{}
var result = []*pb.RegionProvince{}
for _, province := range provinces {
result = append(result, &pb.RegionProvince{
Id: int64(province.Id),

View File

@@ -15,6 +15,8 @@ import (
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"strings"
)
type ServerService struct {
@@ -643,8 +645,8 @@ func (this *ServerService) UpdateServerDNS(ctx context.Context, req *pb.UpdateSe
return this.Success()
}
// RegenerateServerCNAME 重新生成CNAME
func (this *ServerService) RegenerateServerCNAME(ctx context.Context, req *pb.RegenerateServerCNAMERequest) (*pb.RPCSuccess, error) {
// RegenerateServerDNSName 重新生成CNAME
func (this *ServerService) RegenerateServerDNSName(ctx context.Context, req *pb.RegenerateServerDNSNameRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
@@ -658,6 +660,81 @@ func (this *ServerService) RegenerateServerCNAME(ctx context.Context, req *pb.Re
return this.Success()
}
// UpdateServerDNSName 修改服务的CNAME
func (this *ServerService) UpdateServerDNSName(ctx context.Context, req *pb.UpdateServerDNSNameRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
var dnsName = req.DnsName
if req.ServerId <= 0 {
return nil, errors.New("invalid 'serverId'")
}
if len(dnsName) == 0 {
return nil, errors.New("'dnsName' must not be empty")
}
// 处理格式
dnsName = strings.ToLower(dnsName)
const maxLen = 30
if len(dnsName) > maxLen {
return nil, errors.New("'dnsName' too long than " + types.String(maxLen))
}
if !regexp.MustCompile(`^[a-z0-9]{1,` + types.String(maxLen) + `}$`).MatchString(dnsName) {
return nil, errors.New("invalid 'dnsName': contains invalid character(s)")
}
// 检查是否被使用
clusterId, err := models.SharedServerDAO.FindServerClusterId(tx, req.ServerId)
if err != nil {
return nil, err
}
if clusterId <= 0 {
return nil, errors.New("the server is not belong to any cluster")
}
serverId, err := models.SharedServerDAO.FindServerIdWithDNSName(tx, clusterId, dnsName)
if err != nil {
return nil, err
}
if serverId > 0 && serverId != req.ServerId {
return nil, errors.New("the 'dnsName': " + dnsName + " has already been used")
}
err = models.SharedServerDAO.UpdateServerDNSName(tx, req.ServerId, dnsName)
if err != nil {
return nil, err
}
return this.Success()
}
// FindServerIdWithDNSName 使用CNAME查找服务
func (this *ServerService) FindServerIdWithDNSName(ctx context.Context, req *pb.FindServerIdWithDNSNameRequest) (*pb.FindServerIdWithDNSNameResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
if len(req.DnsName) == 0 {
return nil, errors.New("'dnsName' must not be empty")
}
var tx = this.NullTx()
serverId, err := models.SharedServerDAO.FindServerIdWithDNSName(tx, req.NodeClusterId, req.DnsName)
if err != nil {
return nil, err
}
return &pb.FindServerIdWithDNSNameResponse{
ServerId: serverId,
}, nil
}
// CountAllEnabledServersMatch 计算服务数量
func (this *ServerService) CountAllEnabledServersMatch(ctx context.Context, req *pb.CountAllEnabledServersMatchRequest) (*pb.RPCCountResponse, error) {
// 校验请求
@@ -705,7 +782,7 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
if err != nil {
return nil, err
}
result := []*pb.Server{}
var result = []*pb.Server{}
for _, server := range servers {
clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(server.ClusterId))
if err != nil {
@@ -713,9 +790,9 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
}
// 分组信息
pbGroups := []*pb.ServerGroup{}
var pbGroups = []*pb.ServerGroup{}
if models.IsNotNull(server.GroupIds) {
groupIds := []int64{}
var groupIds = []int64{}
err = json.Unmarshal(server.GroupIds, &groupIds)
if err != nil {
return nil, err
@@ -750,7 +827,7 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
}
// 审核结果
auditingResult := &pb.ServerNameAuditingResult{}
var auditingResult = &pb.ServerNameAuditingResult{}
if len(server.AuditingResult) > 0 {
err = json.Unmarshal(server.AuditingResult, auditingResult)
if err != nil {
@@ -770,27 +847,6 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
return nil, err
}
// 当前统计
dailyStat, err := models.SharedServerDailyStatDAO.SumCurrentDailyStat(tx, int64(server.Id))
if err != nil {
return nil, err
}
var pbDailyStat *pb.ServerDailyStat
if dailyStat != nil {
pbDailyStat = &pb.ServerDailyStat{
Bytes: int64(dailyStat.Bytes),
CachedBytes: int64(dailyStat.CachedBytes),
AttackBytes: int64(dailyStat.AttackBytes),
CountRequests: int64(dailyStat.CountRequests),
CountCachedRequests: int64(dailyStat.CountCachedRequests),
CountAttackRequests: int64(dailyStat.CountAttackRequests),
Day: dailyStat.Day,
Hour: dailyStat.Hour,
TimeFrom: dailyStat.TimeFrom,
TimeTo: dailyStat.TimeTo,
}
}
result = append(result, &pb.Server{
Id: int64(server.Id),
IsOn: server.IsOn,
@@ -818,9 +874,10 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
Id: int64(server.ClusterId),
Name: clusterName,
},
ServerGroups: pbGroups,
User: pbUser,
LatestServerDailyStat: pbDailyStat,
ServerGroups: pbGroups,
User: pbUser,
BandwidthTime: server.BandwidthTime,
BandwidthBytes: int64(server.BandwidthBytes),
})
}

View File

@@ -29,19 +29,36 @@ func init() {
goman.New(func() {
for range ticker.C {
func() {
var tx *dbs.Tx
serverBandwidthStatsLocker.Lock()
var m = serverBandwidthStatsMap
serverBandwidthStatsMap = map[string]*pb.ServerBandwidthStat{}
serverBandwidthStatsLocker.Unlock()
tx, err := models.SharedServerBandwidthStatDAO.Instance.Begin()
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "begin transaction failed: "+err.Error())
return
}
defer func() {
_ = tx.Commit()
}()
for _, stat := range m {
err := models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.Day, stat.TimeAt, stat.Bytes)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
// 更新服务的带宽峰值
if stat.ServerId > 0 {
err := models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.Day, stat.TimeAt, stat.Bytes)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
}
err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes)
if err != nil {
remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error())
}
}
// 更新服务的带宽峰值
if stat.UserId > 0 {
err = models.SharedUserBandwidthStatDAO.UpdateUserBandwidth(tx, stat.UserId, stat.Day, stat.TimeAt, stat.Bytes)
if err != nil {
@@ -144,3 +161,39 @@ func (this *ServerBandwidthStatService) FindServerBandwidthStats(ctx context.Con
ServerBandwidthStats: pbStats,
}, nil
}
// FindHourlyServerBandwidthStats 获取最近N小时峰值带宽
func (this *ServerBandwidthStatService) FindHourlyServerBandwidthStats(ctx context.Context, req *pb.FindHourlyServerBandwidthStatsRequest) (*pb.FindHourlyServerBandwidthStatsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
stats, err := models.SharedServerBandwidthStatDAO.FindHourlyBandwidthStats(tx, req.ServerId, req.Hours)
if err != nil {
return nil, err
}
return &pb.FindHourlyServerBandwidthStatsResponse{
Stats: stats,
}, nil
}
// FindDailyServerBandwidthStats 获取最近N天峰值带宽
func (this *ServerBandwidthStatService) FindDailyServerBandwidthStats(ctx context.Context, req *pb.FindDailyServerBandwidthStatsRequest) (*pb.FindDailyServerBandwidthStatsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
stats, err := models.SharedServerBandwidthStatDAO.FindDailyBandwidthStats(tx, req.ServerId, req.Days)
if err != nil {
return nil, err
}
return &pb.FindDailyServerBandwidthStatsResponse{
Stats: stats,
}, nil
}

View File

@@ -32,7 +32,7 @@ func (this *ServerRegionCityMonthlyStatService) FindTopServerRegionCityMonthlySt
if err != nil {
return nil, err
}
pbStats := []*pb.FindTopServerRegionCityMonthlyStatsResponse_Stat{}
var pbStats = []*pb.FindTopServerRegionCityMonthlyStatsResponse_Stat{}
for _, stat := range statList {
pbStat := &pb.FindTopServerRegionCityMonthlyStatsResponse_Stat{
Count: int64(stat.Count),
@@ -63,15 +63,15 @@ func (this *ServerRegionCityMonthlyStatService) FindTopServerRegionCityMonthlySt
}
pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id),
Name: country.Name,
Name: country.DisplayName(),
}
pbStat.RegionProvince = &pb.RegionProvince{
Id: int64(province.Id),
Name: province.Name,
Name: province.DisplayName(),
}
pbStat.RegionCity = &pb.RegionCity{
Id: int64(city.Id),
Name: city.Name,
Name: city.DisplayName(),
}
pbStats = append(pbStats, pbStat)
}

View File

@@ -32,7 +32,7 @@ func (this *ServerRegionCountryMonthlyStatService) FindTopServerRegionCountryMon
if err != nil {
return nil, err
}
pbStats := []*pb.FindTopServerRegionCountryMonthlyStatsResponse_Stat{}
var pbStats = []*pb.FindTopServerRegionCountryMonthlyStatsResponse_Stat{}
for _, stat := range statList {
pbStat := &pb.FindTopServerRegionCountryMonthlyStatsResponse_Stat{
Count: int64(stat.Count),
@@ -47,7 +47,7 @@ func (this *ServerRegionCountryMonthlyStatService) FindTopServerRegionCountryMon
}
pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id),
Name: country.Name,
Name: country.DisplayName(),
}
pbStats = append(pbStats, pbStat)

View File

@@ -32,7 +32,7 @@ func (this *ServerRegionProviderMonthlyStatService) FindTopServerRegionProviderM
if err != nil {
return nil, err
}
pbStats := []*pb.FindTopServerRegionProviderMonthlyStatsResponse_Stat{}
var pbStats = []*pb.FindTopServerRegionProviderMonthlyStatsResponse_Stat{}
for _, stat := range statList {
pbStat := &pb.FindTopServerRegionProviderMonthlyStatsResponse_Stat{
Count: int64(stat.Count),
@@ -46,7 +46,7 @@ func (this *ServerRegionProviderMonthlyStatService) FindTopServerRegionProviderM
}
pbStat.RegionProvider = &pb.RegionProvider{
Id: int64(provider.Id),
Name: provider.Name,
Name: provider.DisplayName(),
}
pbStats = append(pbStats, pbStat)
}

View File

@@ -32,7 +32,7 @@ func (this *ServerRegionProvinceMonthlyStatService) FindTopServerRegionProvinceM
if err != nil {
return nil, err
}
pbStats := []*pb.FindTopServerRegionProvinceMonthlyStatsResponse_Stat{}
var pbStats = []*pb.FindTopServerRegionProvinceMonthlyStatsResponse_Stat{}
for _, stat := range statList {
pbStat := &pb.FindTopServerRegionProvinceMonthlyStatsResponse_Stat{
Count: int64(stat.Count),
@@ -53,11 +53,11 @@ func (this *ServerRegionProvinceMonthlyStatService) FindTopServerRegionProvinceM
}
pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id),
Name: country.Name,
Name: country.DisplayName(),
}
pbStat.RegionProvince = &pb.RegionProvince{
Id: int64(province.Id),
Name: province.Name,
Name: province.DisplayName(),
}
pbStats = append(pbStats, pbStat)
}

View File

@@ -424,10 +424,6 @@ func (this *ServerStatBoardService) ComposeServerStatBoard(ctx context.Context,
if err != nil {
return nil, err
}
if bytes == 0 {
// 尝试从缓存中读取
bytes = ServerBandwidthGetCacheBytes(req.ServerId, day, minute)
}
if bytes > 0 {
result.MinutelyPeekBandwidthBytes = bytes

View File

@@ -557,6 +557,22 @@ func (this *UserService) UpdateUserFeatures(ctx context.Context, req *pb.UpdateU
return this.Success()
}
// UpdateAllUsersFeatures 设置所有用户能使用的功能
func (this *UserService) UpdateAllUsersFeatures(ctx context.Context, req *pb.UpdateAllUsersFeaturesRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedUserDAO.UpdateUsersFeatures(tx, req.FeatureCodes, req.Overwrite)
if err != nil {
return nil, err
}
return this.Success()
}
// FindUserFeatures 获取用户所有的功能列表
func (this *UserService) FindUserFeatures(ctx context.Context, req *pb.FindUserFeaturesRequest) (*pb.FindUserFeaturesResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx)

File diff suppressed because one or more lines are too long

View File

@@ -355,12 +355,12 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, clusterId int64) error {
}
// 当前的节点记录
newRecordKeys := []string{}
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true)
var newRecordKeys = []string{}
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, dnsConfig != nil && dnsConfig.IncludingLnNodes)
if err != nil {
return err
}
isChanged := false
var isChanged = false
for _, node := range nodes {
routes, err := node.DNSRouteCodesForDomainId(domainId)
if err != nil {
@@ -379,7 +379,7 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, clusterId int64) error {
continue
}
for _, ipAddress := range ipAddresses {
ip := ipAddress.DNSIP()
var ip = ipAddress.DNSIP()
if len(ip) == 0 || !ipAddress.CanAccess || !ipAddress.IsUp || !ipAddress.IsOn {
continue
}
@@ -387,14 +387,14 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, clusterId int64) error {
continue
}
for _, route := range routes {
key := route + "@" + ip
var key = route + "@" + ip
_, ok := oldRecordsMap[key]
if ok {
newRecordKeys = append(newRecordKeys, key)
continue
}
recordType := dnstypes.RecordTypeA
var recordType = dnstypes.RecordTypeA
if utils.IsIPv6(ip) {
recordType = dnstypes.RecordTypeAAAA
}

View File

@@ -1,92 +0,0 @@
package tasks
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
"time"
)
func init() {
dbs.OnReadyDone(func() {
goman.New(func() {
NewNSNodeMonitorTask(1 * time.Minute).Start()
})
})
}
// NSNodeMonitorTask 边缘节点监控任务
type NSNodeMonitorTask struct {
BaseTask
ticker *time.Ticker
}
func NewNSNodeMonitorTask(duration time.Duration) *NSNodeMonitorTask {
return &NSNodeMonitorTask{
ticker: time.NewTicker(duration),
}
}
func (this *NSNodeMonitorTask) Start() {
for range this.ticker.C {
err := this.Loop()
if err != nil {
this.logErr("NS_NODE_MONITOR", err.Error())
}
}
}
func (this *NSNodeMonitorTask) Loop() error {
// 检查是否为主节点
if !models.SharedAPINodeDAO.CheckAPINodeIsPrimaryWithoutErr() {
return nil
}
clusters, err := models.SharedNSClusterDAO.FindAllEnabledClusters(nil)
if err != nil {
return err
}
for _, cluster := range clusters {
err := this.monitorCluster(cluster)
if err != nil {
return err
}
}
return nil
}
func (this *NSNodeMonitorTask) monitorCluster(cluster *models.NSCluster) error {
clusterId := int64(cluster.Id)
// 检查离线节点
inactiveNodes, err := models.SharedNSNodeDAO.FindAllNotifyingInactiveNodesWithClusterId(nil, clusterId)
if err != nil {
return err
}
for _, node := range inactiveNodes {
subject := "DNS节点\"" + node.Name + "\"已处于离线状态"
msg := "DNS节点\"" + node.Name + "\"已处于离线状态"
err = models.SharedMessageDAO.CreateNodeMessage(nil, nodeconfigs.NodeRoleDNS, clusterId, int64(node.Id), models.MessageTypeNSNodeInactive, models.LevelError, subject, msg, nil, false)
if err != nil {
return err
}
// 修改在线状态
err = models.SharedNSNodeDAO.UpdateNodeStatusIsNotified(nil, int64(node.Id))
if err != nil {
return err
}
}
// TODO 检查恢复连接
// 检查CPU、内存、磁盘不足节点而且离线的节点不再重复提示
// TODO 需要实现
// TODO 检查53/tcp、53/udp是否能够访问
return nil
}

View File

@@ -102,8 +102,8 @@ func (this *SSLCertExpireCheckExecutor) Loop() error {
}
for _, cert := range certs {
// 发送消息
subject := "SSL证书\"" + cert.Name + "\"在" + strconv.Itoa(days) + "天后将到期,"
msg := "SSL证书\"" + cert.Name + "\"" + string(cert.DnsNames) + ")在" + strconv.Itoa(days) + "天后将到期,"
var subject = "SSL证书\"" + cert.Name + "\"在" + strconv.Itoa(days) + "天后将到期,"
var msg = "SSL证书\"" + cert.Name + "\"" + string(cert.DnsNames) + ")在" + strconv.Itoa(days) + "天后将到期,"
// 是否有自动更新任务
if cert.AcmeTaskId > 0 {
@@ -116,7 +116,7 @@ func (this *SSLCertExpireCheckExecutor) Loop() error {
isOk, errMsg, _ := acme.SharedACMETaskDAO.RunTask(nil, int64(cert.AcmeTaskId))
if isOk {
// 发送成功通知
subject := "系统已成功为你自动更新了证书\"" + cert.Name + "\""
subject = "系统已成功为你自动更新了证书\"" + cert.Name + "\""
msg = "系统已成功为你自动更新了证书\"" + cert.Name + "\"" + string(cert.DnsNames) + ")。"
err = models.SharedMessageDAO.CreateMessage(nil, int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskSuccess, models.MessageLevelSuccess, subject, msg, maps.Map{
"certId": cert.Id,
@@ -130,7 +130,7 @@ func (this *SSLCertExpireCheckExecutor) Loop() error {
}
} else {
// 发送失败通知
subject := "系统在尝试自动更新证书\"" + cert.Name + "\"时发生错误"
subject = "系统在尝试自动更新证书\"" + cert.Name + "\"时发生错误"
msg = "系统在尝试自动更新证书\"" + cert.Name + "\"" + string(cert.DnsNames) + ")时发生错误:" + errMsg + "。请检查系统设置并修复错误。"
err = models.SharedMessageDAO.CreateMessage(nil, int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskFailed, models.MessageLevelError, subject, msg, maps.Map{
"certId": cert.Id,

View File

@@ -62,3 +62,23 @@ func Similar(s1 string, s2 string) float32 {
return (float32(count)/float32(l1) + float32(count)/float32(l2)) / 2
}
// LimitString 限制字符串长度
func LimitString(s string, maxLength int) string {
if len(s) <= maxLength {
return s
}
if maxLength <= 0 {
return ""
}
var runes = []rune(s)
var rs = len(runes)
for i := 0; i < rs; i++ {
if len(string(runes[:i+1])) > maxLength {
return string(runes[:i])
}
}
return s
}

View File

@@ -28,3 +28,15 @@ func TestSimilar(t *testing.T) {
t.Log(utils.Similar("efgj", "hijk"))
t.Log(utils.Similar("efgj", "klmn"))
}
func TestLimitString(t *testing.T) {
var a = assert.NewAssertion(t)
a.IsTrue(utils.LimitString("", 4) == "")
a.IsTrue(utils.LimitString("abcd", 0) == "")
a.IsTrue(utils.LimitString("abcd", 5) == "abcd")
a.IsTrue(utils.LimitString("abcd", 4) == "abcd")
a.IsTrue(utils.LimitString("abcd", 3) == "abc")
a.IsTrue(utils.LimitString("abcd", 1) == "a")
a.IsTrue(utils.LimitString("中文测试", 1) == "")
a.IsTrue(utils.LimitString("中文测试", 3) == "中")
}