Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c66e28cb9d | ||
|
|
e5109b24d4 | ||
|
|
695b8482de | ||
|
|
d0b908bcaa | ||
|
|
3de25d4fe1 | ||
|
|
07194855bf | ||
|
|
d0f1eb13ee | ||
|
|
a0930bfd74 | ||
|
|
08cff8affc | ||
|
|
02132e9262 | ||
|
|
61b6a49885 | ||
|
|
896e54ebe8 | ||
|
|
1b36bad60a | ||
|
|
fc14800d70 | ||
|
|
fa61f277e4 | ||
|
|
9117309472 | ||
|
|
6bb2977d59 | ||
|
|
df9dce76cb | ||
|
|
4cb9c85a1c | ||
|
|
f4f5389ffb | ||
|
|
5d336eb77d | ||
|
|
c552eb3b0e | ||
|
|
455952e9e4 | ||
|
|
7132401c7f | ||
|
|
a4dddfb139 | ||
|
|
7ef32bad97 | ||
|
|
732513a644 | ||
|
|
756cf4a9ae | ||
|
|
a15a630265 | ||
|
|
3fab1b8294 | ||
|
|
215635f429 | ||
|
|
dbb1ae180b | ||
|
|
e8d4d01d85 | ||
|
|
6593989a84 | ||
|
|
004e640321 | ||
|
|
7ad315ae4b | ||
|
|
ba938e5361 | ||
|
|
9ddf02a0e6 | ||
|
|
ebcbd5690d | ||
|
|
bbca766fa4 | ||
|
|
99c7819d3a | ||
|
|
08bb3e66f8 | ||
|
|
9159820742 | ||
|
|
1a565b2ebb | ||
|
|
98847c53ea | ||
|
|
14bafc8f20 | ||
|
|
58a5bd0092 | ||
|
|
4f1ce52f6a | ||
|
|
14ba7f6899 | ||
|
|
e582e37c06 | ||
|
|
6a3fa9f0ca | ||
|
|
e0a9965fed | ||
|
|
481fa8cd2d | ||
|
|
95349dc457 | ||
|
|
fc839f96d2 | ||
|
|
0414cc02e8 | ||
|
|
b8babaae39 | ||
|
|
285ce1b312 | ||
|
|
c309da81ae | ||
|
|
c325fde52b | ||
|
|
0f69b45d25 | ||
|
|
e02084ba5d | ||
|
|
642b23dbb7 | ||
|
|
b1dc385c87 | ||
|
|
89a69e3165 | ||
|
|
530954dd6c | ||
|
|
33635f7a1b | ||
|
|
8ac964e805 | ||
|
|
a1519baf0f | ||
|
|
e6e32a39bb | ||
|
|
d828b7f8a4 | ||
|
|
07b377c2fb | ||
|
|
33a3795773 | ||
|
|
bddb3cae96 | ||
|
|
6a525c2b82 | ||
|
|
3a137c1c3f | ||
|
|
19867568a9 | ||
|
|
c2600b911b | ||
|
|
fe511ae7e5 | ||
|
|
876c631c85 | ||
|
|
a4cc138ef3 | ||
|
|
3f9a7a8a49 | ||
|
|
09d8ef00c2 | ||
|
|
b4f77ddc63 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*_plus.go
|
||||
*-plus.sh
|
||||
*-plus.sh
|
||||
*_plus_test.go
|
||||
@@ -88,15 +88,13 @@ function build() {
|
||||
mkdir "$DIST"/bin
|
||||
mkdir "$DIST"/configs
|
||||
mkdir "$DIST"/logs
|
||||
mkdir "$DIST"/data
|
||||
fi
|
||||
cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/
|
||||
cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/
|
||||
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
Binary file not shown.
@@ -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("[]")
|
||||
@@ -161,6 +160,20 @@ func main() {
|
||||
}
|
||||
}
|
||||
})
|
||||
app.On("instance", func() {
|
||||
var sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||
reply, err := sock.Send(&gosock.Command{Code: "instance"})
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]" + err.Error())
|
||||
} else {
|
||||
replyJSON, err := json.MarshalIndent(reply.Params, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]marshal result failed: " + err.Error())
|
||||
} else {
|
||||
fmt.Println(string(replyJSON))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.Run(func() {
|
||||
nodes.NewAPINode().Start()
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
6
go.mod
6
go.mod
@@ -12,8 +12,8 @@ require (
|
||||
github.com/go-acme/lego/v4 v4.5.2
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
||||
github.com/iwind/TeaGo v0.0.0-20220811034530-657e3f15b79e
|
||||
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
|
||||
github.com/mozillazg/go-pinyin v0.18.0
|
||||
github.com/pkg/sftp v1.12.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.2
|
||||
@@ -21,7 +21,7 @@ require (
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
|
||||
google.golang.org/grpc v1.45.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
6
go.sum
6
go.sum
@@ -239,8 +239,12 @@ github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7Q
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570 h1:zqz2FiMMkSHXWO1EsTRJDPTwX9xQ4uuyD5GAE4JGlhM=
|
||||
github.com/iwind/TeaGo v0.0.0-20220408111647-f36b9bba3570/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/TeaGo v0.0.0-20220811034530-657e3f15b79e h1:cw4b6ecXdXvLd45YSstD8r9ClcnVK4ljZMZCept2aOk=
|
||||
github.com/iwind/TeaGo v0.0.0-20220811034530-657e3f15b79e/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo=
|
||||
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@@ -787,6 +791,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseStorage struct {
|
||||
isOk bool
|
||||
version int
|
||||
firewallOnly bool
|
||||
}
|
||||
|
||||
func (this *BaseStorage) SetVersion(version int) {
|
||||
this.version = version
|
||||
}
|
||||
|
||||
func (this *BaseStorage) Version() int {
|
||||
return this.version
|
||||
}
|
||||
|
||||
func (this *BaseStorage) IsOk() bool {
|
||||
return this.isOk
|
||||
}
|
||||
|
||||
func (this *BaseStorage) SetOk(isOk bool) {
|
||||
this.isOk = isOk
|
||||
}
|
||||
|
||||
func (this *BaseStorage) SetFirewallOnly(firewallOnly bool) {
|
||||
this.firewallOnly = firewallOnly
|
||||
}
|
||||
|
||||
// Marshal 对日志进行编码
|
||||
func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) {
|
||||
return json.Marshal(accessLog)
|
||||
}
|
||||
|
||||
// FormatVariables 格式化字符串中的变量
|
||||
func (this *BaseStorage) FormatVariables(s string) string {
|
||||
var now = time.Now()
|
||||
return configutils.ParseVariables(s, func(varName string) (value string) {
|
||||
switch varName {
|
||||
case "year":
|
||||
return strconv.Itoa(now.Year())
|
||||
case "month":
|
||||
return fmt.Sprintf("%02d", now.Month())
|
||||
case "week":
|
||||
_, week := now.ISOWeek()
|
||||
return fmt.Sprintf("%02d", week)
|
||||
case "day":
|
||||
return fmt.Sprintf("%02d", now.Day())
|
||||
case "hour":
|
||||
return fmt.Sprintf("%02d", now.Hour())
|
||||
case "minute":
|
||||
return fmt.Sprintf("%02d", now.Minute())
|
||||
case "second":
|
||||
return fmt.Sprintf("%02d", now.Second())
|
||||
case "date":
|
||||
return fmt.Sprintf("%d%02d%02d", now.Year(), now.Month(), now.Day())
|
||||
}
|
||||
|
||||
return varName
|
||||
})
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CommandStorage 通过命令行存储
|
||||
type CommandStorage struct {
|
||||
BaseStorage
|
||||
|
||||
config *serverconfigs.AccessLogCommandStorageConfig
|
||||
|
||||
writeLocker sync.Mutex
|
||||
}
|
||||
|
||||
func NewCommandStorage(config *serverconfigs.AccessLogCommandStorageConfig) *CommandStorage {
|
||||
return &CommandStorage{config: config}
|
||||
}
|
||||
|
||||
func (this *CommandStorage) Config() interface{} {
|
||||
return this.config
|
||||
}
|
||||
|
||||
// Start 启动
|
||||
func (this *CommandStorage) Start() error {
|
||||
if len(this.config.Command) == 0 {
|
||||
return errors.New("'command' should not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
func (this *CommandStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
if len(accessLogs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
this.writeLocker.Lock()
|
||||
defer this.writeLocker.Unlock()
|
||||
|
||||
cmd := exec.Command(this.config.Command, this.config.Args...)
|
||||
if len(this.config.Dir) > 0 {
|
||||
cmd.Dir = this.config.Dir
|
||||
}
|
||||
|
||||
stdout := bytes.NewBuffer([]byte{})
|
||||
cmd.Stdout = stdout
|
||||
|
||||
w, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, accessLog := range accessLogs {
|
||||
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("\n"))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
}
|
||||
_ = w.Close()
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
|
||||
if stdout.Len() > 0 {
|
||||
logs.Error(errors.New(string(stdout.Bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (this *CommandStorage) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCommandStorage_Write(t *testing.T) {
|
||||
php, err := exec.LookPath("php")
|
||||
if err != nil { // not found php, so we can not test
|
||||
t.Log("php:", err)
|
||||
return
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
before := time.Now()
|
||||
|
||||
storage := NewCommandStorage(&serverconfigs.AccessLogCommandStorageConfig{
|
||||
Command: php,
|
||||
Args: []string{cwd + "/tests/command_storage.php"},
|
||||
})
|
||||
err = storage.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/hello",
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/world",
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/lu",
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/ping",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = storage.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(time.Since(before).Seconds(), "seconds")
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ESStorage ElasticSearch存储策略
|
||||
type ESStorage struct {
|
||||
BaseStorage
|
||||
|
||||
config *serverconfigs.AccessLogESStorageConfig
|
||||
}
|
||||
|
||||
func NewESStorage(config *serverconfigs.AccessLogESStorageConfig) *ESStorage {
|
||||
return &ESStorage{config: config}
|
||||
}
|
||||
|
||||
func (this *ESStorage) Config() interface{} {
|
||||
return this.config
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (this *ESStorage) Start() error {
|
||||
if len(this.config.Endpoint) == 0 {
|
||||
return errors.New("'endpoint' should not be nil")
|
||||
}
|
||||
if !regexp.MustCompile(`(?i)^(http|https)://`).MatchString(this.config.Endpoint) {
|
||||
this.config.Endpoint = "http://" + this.config.Endpoint
|
||||
}
|
||||
if len(this.config.Index) == 0 {
|
||||
return errors.New("'index' should not be nil")
|
||||
}
|
||||
if len(this.config.MappingType) == 0 {
|
||||
return errors.New("'mappingType' should not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
func (this *ESStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
if len(accessLogs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bulk := &strings.Builder{}
|
||||
indexName := this.FormatVariables(this.config.Index)
|
||||
typeName := this.FormatVariables(this.config.MappingType)
|
||||
for _, accessLog := range accessLogs {
|
||||
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(accessLog.RequestId) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
opData, err := json.Marshal(map[string]interface{}{
|
||||
"index": map[string]interface{}{
|
||||
"_index": indexName,
|
||||
"_type": typeName,
|
||||
"_id": accessLog.RequestId,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_ES_STORAGE", "write failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_ES_STORAGE", "marshal data failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
bulk.Write(opData)
|
||||
bulk.WriteString("\n")
|
||||
bulk.Write(data)
|
||||
bulk.WriteString("\n")
|
||||
}
|
||||
|
||||
if bulk.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, this.config.Endpoint+"/_bulk", strings.NewReader(bulk.String()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", strings.ReplaceAll(teaconst.ProductName, " ", "-")+"/"+teaconst.Version)
|
||||
if len(this.config.Username) > 0 || len(this.config.Password) > 0 {
|
||||
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(this.config.Username+":"+this.config.Password)))
|
||||
}
|
||||
client := utils.SharedHttpClient(10 * time.Second)
|
||||
defer func() {
|
||||
_ = req.Body.Close()
|
||||
}()
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyData, _ := ioutil.ReadAll(resp.Body)
|
||||
return errors.New("ElasticSearch response status code: " + fmt.Sprintf("%d", resp.StatusCode) + " content: " + string(bodyData))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (this *ESStorage) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestESStorage_Write(t *testing.T) {
|
||||
storage := NewESStorage(&serverconfigs.AccessLogESStorageConfig{
|
||||
Endpoint: "http://127.0.0.1:9200",
|
||||
Index: "logs",
|
||||
MappingType: "accessLogs",
|
||||
Username: "hello",
|
||||
Password: "world",
|
||||
})
|
||||
err := storage.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
{
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestMethod: "POST",
|
||||
RequestPath: "/1",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
TimeISO8601: "2018-07-23T22:23:35+08:00",
|
||||
Header: map[string]*pb.Strings{
|
||||
"Content-Type": {Values: []string{"text/html"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/2",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
TimeISO8601: "2018-07-23T22:23:35+08:00",
|
||||
Header: map[string]*pb.Strings{
|
||||
"Content-Type": {Values: []string{"text/css"}},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = storage.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// FileStorage 文件存储策略
|
||||
type FileStorage struct {
|
||||
BaseStorage
|
||||
|
||||
config *serverconfigs.AccessLogFileStorageConfig
|
||||
|
||||
writeLocker sync.Mutex
|
||||
|
||||
files map[string]*os.File // path => *File
|
||||
filesLocker sync.Mutex
|
||||
}
|
||||
|
||||
func NewFileStorage(config *serverconfigs.AccessLogFileStorageConfig) *FileStorage {
|
||||
return &FileStorage{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *FileStorage) Config() interface{} {
|
||||
return this.config
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (this *FileStorage) Start() error {
|
||||
if len(this.config.Path) == 0 {
|
||||
return errors.New("'path' should not be empty")
|
||||
}
|
||||
|
||||
this.files = map[string]*os.File{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write 写入日志
|
||||
func (this *FileStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
if len(accessLogs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fp := this.fp()
|
||||
if fp == nil {
|
||||
return errors.New("file pointer should not be nil")
|
||||
}
|
||||
this.writeLocker.Lock()
|
||||
defer this.writeLocker.Unlock()
|
||||
|
||||
for _, accessLog := range accessLogs {
|
||||
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
_, err = fp.Write(data)
|
||||
if err != nil {
|
||||
_ = this.Close()
|
||||
break
|
||||
}
|
||||
_, _ = fp.WriteString("\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (this *FileStorage) Close() error {
|
||||
this.filesLocker.Lock()
|
||||
defer this.filesLocker.Unlock()
|
||||
|
||||
var resultErr error
|
||||
for _, f := range this.files {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
return resultErr
|
||||
}
|
||||
|
||||
func (this *FileStorage) fp() *os.File {
|
||||
path := this.FormatVariables(this.config.Path)
|
||||
|
||||
this.filesLocker.Lock()
|
||||
defer this.filesLocker.Unlock()
|
||||
fp, ok := this.files[path]
|
||||
if ok {
|
||||
return fp
|
||||
}
|
||||
|
||||
// 关闭其他的文件
|
||||
for _, f := range this.files {
|
||||
_ = f.Close()
|
||||
}
|
||||
|
||||
// 是否创建文件目录
|
||||
if this.config.AutoCreate {
|
||||
dir := filepath.Dir(path)
|
||||
_, err := os.Stat(dir)
|
||||
if os.IsNotExist(err) {
|
||||
err = os.MkdirAll(dir, 0777)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打开新文件
|
||||
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return nil
|
||||
}
|
||||
this.files[path] = fp
|
||||
|
||||
return fp
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFileStorage_Write(t *testing.T) {
|
||||
storage := NewFileStorage(&serverconfigs.AccessLogFileStorageConfig{
|
||||
Path: Tea.Root + "/logs/access-${date}.log",
|
||||
})
|
||||
err := storage.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
{
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestPath: "/hello",
|
||||
},
|
||||
{
|
||||
RequestPath: "/world",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestPath: "/1",
|
||||
},
|
||||
{
|
||||
RequestPath: "/2",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestMethod: "POST",
|
||||
RequestPath: "/1",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/2",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = storage.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
|
||||
// StorageInterface 日志存储接口
|
||||
type StorageInterface interface {
|
||||
// Version 获取版本
|
||||
Version() int
|
||||
|
||||
// SetVersion 设置版本
|
||||
SetVersion(version int)
|
||||
|
||||
// SetFirewallOnly 设置是否只处理防火墙相关的访问日志
|
||||
SetFirewallOnly(firewallOnly bool)
|
||||
|
||||
IsOk() bool
|
||||
|
||||
SetOk(ok bool)
|
||||
|
||||
// Config 获取配置
|
||||
Config() interface{}
|
||||
|
||||
// Start 开启
|
||||
Start() error
|
||||
|
||||
// Write 写入日志
|
||||
Write(accessLogs []*pb.HTTPAccessLog) error
|
||||
|
||||
// Close 关闭
|
||||
Close() error
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var SharedStorageManager = NewStorageManager()
|
||||
|
||||
type StorageManager struct {
|
||||
storageMap map[int64]StorageInterface // policyId => Storage
|
||||
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
func NewStorageManager() *StorageManager {
|
||||
return &StorageManager{
|
||||
storageMap: map[int64]StorageInterface{},
|
||||
}
|
||||
}
|
||||
|
||||
func (this *StorageManager) Start() {
|
||||
var ticker = time.NewTicker(1 * time.Minute)
|
||||
if Tea.IsTesting() {
|
||||
ticker = time.NewTicker(5 * time.Second)
|
||||
}
|
||||
|
||||
// 启动时执行一次
|
||||
var err = this.Loop()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "update error: "+err.Error())
|
||||
}
|
||||
|
||||
// 循环执行
|
||||
for range ticker.C {
|
||||
err := this.Loop()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "update error: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop 更新
|
||||
func (this *StorageManager) Loop() error {
|
||||
policies, err := models.SharedHTTPAccessLogPolicyDAO.FindAllEnabledAndOnPolicies(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var policyIds = []int64{}
|
||||
for _, policy := range policies {
|
||||
if policy.IsOn {
|
||||
policyIds = append(policyIds, int64(policy.Id))
|
||||
}
|
||||
}
|
||||
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
// 关闭不用的
|
||||
for policyId, storage := range this.storageMap {
|
||||
if !lists.ContainsInt64(policyIds, policyId) {
|
||||
err := storage.Close()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "close '"+types.String(policyId)+"' failed: "+err.Error())
|
||||
}
|
||||
delete(this.storageMap, policyId)
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "remove '"+types.String(policyId)+"'")
|
||||
}
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
var policyId = int64(policy.Id)
|
||||
storage, ok := this.storageMap[policyId]
|
||||
if ok {
|
||||
// 检查配置是否有变更
|
||||
if types.Int(policy.Version) != storage.Version() {
|
||||
err = storage.Close()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "close policy '"+types.String(policyId)+"' failed: "+err.Error())
|
||||
|
||||
// 继续往下执行
|
||||
}
|
||||
|
||||
if len(policy.Options) > 0 {
|
||||
err = json.Unmarshal(policy.Options, storage.Config())
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "unmarshal policy '"+types.String(policyId)+"' config failed: "+err.Error())
|
||||
storage.SetOk(false)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
storage.SetVersion(types.Int(policy.Version))
|
||||
storage.SetFirewallOnly(policy.FirewallOnly == 1)
|
||||
err := storage.Start()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
storage.SetOk(true)
|
||||
remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "restart policy '"+types.String(policyId)+"'")
|
||||
}
|
||||
} else {
|
||||
storage, err := this.createStorage(policy.Type, policy.Options)
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "create policy '"+types.String(policyId)+"' failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
storage.SetVersion(types.Int(policy.Version))
|
||||
storage.SetFirewallOnly(policy.FirewallOnly == 1)
|
||||
this.storageMap[policyId] = storage
|
||||
err = storage.Start()
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
storage.SetOk(true)
|
||||
remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"'")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *StorageManager) createStorage(storageType string, optionsJSON []byte) (StorageInterface, error) {
|
||||
switch storageType {
|
||||
case serverconfigs.AccessLogStorageTypeFile:
|
||||
var config = &serverconfigs.AccessLogFileStorageConfig{}
|
||||
if len(optionsJSON) > 0 {
|
||||
err := json.Unmarshal(optionsJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewFileStorage(config), nil
|
||||
case serverconfigs.AccessLogStorageTypeES:
|
||||
var config = &serverconfigs.AccessLogESStorageConfig{}
|
||||
if len(optionsJSON) > 0 {
|
||||
err := json.Unmarshal(optionsJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewESStorage(config), nil
|
||||
case serverconfigs.AccessLogStorageTypeTCP:
|
||||
var config = &serverconfigs.AccessLogTCPStorageConfig{}
|
||||
if len(optionsJSON) > 0 {
|
||||
err := json.Unmarshal(optionsJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewTCPStorage(config), nil
|
||||
case serverconfigs.AccessLogStorageTypeSyslog:
|
||||
var config = &serverconfigs.AccessLogSyslogStorageConfig{}
|
||||
if len(optionsJSON) > 0 {
|
||||
err := json.Unmarshal(optionsJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewSyslogStorage(config), nil
|
||||
case serverconfigs.AccessLogStorageTypeCommand:
|
||||
var config = &serverconfigs.AccessLogCommandStorageConfig{}
|
||||
if len(optionsJSON) > 0 {
|
||||
err := json.Unmarshal(optionsJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewCommandStorage(config), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("invalid policy type '" + storageType + "'")
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStorageManager_Loop(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var storage = NewStorageManager()
|
||||
err := storage.Loop()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(storage.storageMap)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// 写入日志
|
||||
func (this *StorageManager) Write(policyId int64, accessLogs []*pb.HTTPAccessLog) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SyslogStorageProtocol = string
|
||||
|
||||
const (
|
||||
SyslogStorageProtocolTCP SyslogStorageProtocol = "tcp"
|
||||
SyslogStorageProtocolUDP SyslogStorageProtocol = "udp"
|
||||
SyslogStorageProtocolNone SyslogStorageProtocol = "none"
|
||||
SyslogStorageProtocolSocket SyslogStorageProtocol = "socket"
|
||||
)
|
||||
|
||||
type SyslogStoragePriority = int
|
||||
|
||||
// SyslogStorage syslog存储策略
|
||||
type SyslogStorage struct {
|
||||
BaseStorage
|
||||
|
||||
config *serverconfigs.AccessLogSyslogStorageConfig
|
||||
|
||||
exe string
|
||||
}
|
||||
|
||||
func NewSyslogStorage(config *serverconfigs.AccessLogSyslogStorageConfig) *SyslogStorage {
|
||||
return &SyslogStorage{config: config}
|
||||
}
|
||||
|
||||
func (this *SyslogStorage) Config() interface{} {
|
||||
return this.config
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (this *SyslogStorage) Start() error {
|
||||
if runtime.GOOS != "linux" {
|
||||
return errors.New("'syslog' storage only works on linux")
|
||||
}
|
||||
|
||||
exe, err := exec.LookPath("logger")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
this.exe = exe
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
if len(accessLogs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
args := []string{}
|
||||
if len(this.config.Tag) > 0 {
|
||||
args = append(args, "-t", this.config.Tag)
|
||||
}
|
||||
|
||||
if this.config.Priority >= 0 {
|
||||
args = append(args, "-p", strconv.Itoa(this.config.Priority))
|
||||
}
|
||||
|
||||
switch this.config.Protocol {
|
||||
case SyslogStorageProtocolTCP:
|
||||
args = append(args, "-T")
|
||||
if len(this.config.ServerAddr) > 0 {
|
||||
args = append(args, "-n", this.config.ServerAddr)
|
||||
}
|
||||
if this.config.ServerPort > 0 {
|
||||
args = append(args, "-P", strconv.Itoa(this.config.ServerPort))
|
||||
}
|
||||
case SyslogStorageProtocolUDP:
|
||||
args = append(args, "-d")
|
||||
if len(this.config.ServerAddr) > 0 {
|
||||
args = append(args, "-n", this.config.ServerAddr)
|
||||
}
|
||||
if this.config.ServerPort > 0 {
|
||||
args = append(args, "-P", strconv.Itoa(this.config.ServerPort))
|
||||
}
|
||||
case SyslogStorageProtocolSocket:
|
||||
args = append(args, "-u")
|
||||
args = append(args, this.config.Socket)
|
||||
case SyslogStorageProtocolNone:
|
||||
// do nothing
|
||||
}
|
||||
|
||||
args = append(args, "-S", "10240")
|
||||
|
||||
var cmd = exec.Command(this.exe, args...)
|
||||
var stderrBuffer = &bytes.Buffer{}
|
||||
cmd.Stderr = stderrBuffer
|
||||
|
||||
w, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, accessLog := range accessLogs {
|
||||
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "marshal accesslog failed: "+err.Error())
|
||||
continue
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("\n"))
|
||||
if err != nil {
|
||||
remotelogs.Error("ACCESS_LOG_POLICY_SYSLOG", "write accesslog failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
_ = w.Close()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
return errors.New("send syslog failed: " + err.Error() + ", stderr: " + stderrBuffer.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (this *SyslogStorage) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TCPStorage TCP存储策略
|
||||
type TCPStorage struct {
|
||||
BaseStorage
|
||||
|
||||
config *serverconfigs.AccessLogTCPStorageConfig
|
||||
|
||||
writeLocker sync.Mutex
|
||||
|
||||
connLocker sync.Mutex
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func NewTCPStorage(config *serverconfigs.AccessLogTCPStorageConfig) *TCPStorage {
|
||||
return &TCPStorage{config: config}
|
||||
}
|
||||
|
||||
func (this *TCPStorage) Config() interface{} {
|
||||
return this.config
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (this *TCPStorage) Start() error {
|
||||
if len(this.config.Network) == 0 {
|
||||
return errors.New("'network' should not be empty")
|
||||
}
|
||||
if len(this.config.Addr) == 0 {
|
||||
return errors.New("'addr' should not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
func (this *TCPStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
|
||||
if len(accessLogs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := this.connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn := this.conn
|
||||
if conn == nil {
|
||||
return errors.New("connection should not be nil")
|
||||
}
|
||||
|
||||
this.writeLocker.Lock()
|
||||
defer this.writeLocker.Unlock()
|
||||
|
||||
for _, accessLog := range accessLogs {
|
||||
if this.firewallOnly && accessLog.FirewallPolicyId == 0 {
|
||||
continue
|
||||
}
|
||||
data, err := this.Marshal(accessLog)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
_, err = conn.Write(data)
|
||||
if err != nil {
|
||||
_ = this.Close()
|
||||
break
|
||||
}
|
||||
_, err = conn.Write([]byte("\n"))
|
||||
if err != nil {
|
||||
_ = this.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (this *TCPStorage) Close() error {
|
||||
this.connLocker.Lock()
|
||||
defer this.connLocker.Unlock()
|
||||
|
||||
if this.conn != nil {
|
||||
err := this.conn.Close()
|
||||
this.conn = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *TCPStorage) connect() error {
|
||||
this.connLocker.Lock()
|
||||
defer this.connLocker.Unlock()
|
||||
|
||||
if this.conn != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
conn, err := net.Dial(this.config.Network, this.config.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.conn = conn
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package accesslogs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTCPStorage_Write(t *testing.T) {
|
||||
go func() {
|
||||
server, err := net.Listen("tcp", "127.0.0.1:9981")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
conn, err := server.Accept()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, err := conn.Read(buf)
|
||||
if n > 0 {
|
||||
t.Log(string(buf[:n]))
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
_ = server.Close()
|
||||
}()
|
||||
|
||||
storage := NewTCPStorage(&serverconfigs.AccessLogTCPStorageConfig{
|
||||
Network: "tcp",
|
||||
Addr: "127.0.0.1:9981",
|
||||
})
|
||||
err := storage.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
{
|
||||
err = storage.Write([]*pb.HTTPAccessLog{
|
||||
{
|
||||
RequestMethod: "POST",
|
||||
RequestPath: "/1",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
},
|
||||
{
|
||||
RequestMethod: "GET",
|
||||
RequestPath: "/2",
|
||||
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
err = storage.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
// test command storage
|
||||
|
||||
// open access log file
|
||||
$fp = fopen("/tmp/goedge-command-storage.log", "a+");
|
||||
|
||||
// read access logs from stdin
|
||||
$stdin = fopen("php://stdin", "r");
|
||||
while(true) {
|
||||
if (feof($stdin)) {
|
||||
break;
|
||||
}
|
||||
$line = fgets($stdin);
|
||||
|
||||
// write to access log file
|
||||
fwrite($fp, $line);
|
||||
}
|
||||
|
||||
// close file pointers
|
||||
fclose($fp);
|
||||
fclose($stdin);
|
||||
|
||||
?>
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
acmelog "github.com/go-acme/lego/v4/log"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
@@ -50,7 +50,7 @@ func (this *MyProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
|
||||
// 参考 https://go-acme.github.io/lego/usage/library/
|
||||
func TestGenerate(t *testing.T) {
|
||||
acmelog.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
|
||||
acmelog.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
|
||||
// 生成私钥
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
@@ -94,7 +94,7 @@ func TestGenerate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerate_EAB(t *testing.T) {
|
||||
acmelog.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
|
||||
acmelog.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
|
||||
// 生成私钥
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
acmelog "github.com/go-acme/lego/v4/log"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (this *Request) Run() (certData []byte, keyData []byte, err error) {
|
||||
|
||||
func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
|
||||
if !this.debug {
|
||||
acmelog.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
|
||||
acmelog.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
if this.task.User == nil {
|
||||
@@ -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,
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
|
||||
|
||||
func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
|
||||
if !this.debug {
|
||||
acmelog.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
|
||||
acmelog.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
if this.task.User == nil {
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
@@ -42,7 +41,7 @@ func SharedAPIConfig() (*APIConfig, error) {
|
||||
var data []byte
|
||||
var err error
|
||||
for _, path := range paths {
|
||||
data, err = ioutil.ReadFile(path)
|
||||
data, err = os.ReadFile(path)
|
||||
if err == nil {
|
||||
if path == localFile {
|
||||
isFromLocal = true
|
||||
@@ -63,7 +62,7 @@ func SharedAPIConfig() (*APIConfig, error) {
|
||||
|
||||
if !isFromLocal {
|
||||
// 恢复文件
|
||||
_ = ioutil.WriteFile(localFile, data, 0666)
|
||||
_ = os.WriteFile(localFile, data, 0666)
|
||||
}
|
||||
|
||||
// 恢复数据库文件
|
||||
@@ -80,9 +79,9 @@ func SharedAPIConfig() (*APIConfig, error) {
|
||||
for _, path := range paths {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
data, err := os.ReadFile(path)
|
||||
if err == nil {
|
||||
_ = ioutil.WriteFile(dbConfigFile, data, 0666)
|
||||
_ = os.WriteFile(dbConfigFile, data, 0666)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -122,14 +121,14 @@ func (this *APIConfig) WriteFile(path string) error {
|
||||
for _, backupDir := range backupDirs {
|
||||
stat, err := os.Stat(backupDir)
|
||||
if err == nil && stat.IsDir() {
|
||||
_ = ioutil.WriteFile(backupDir+"/"+filename, data, 0666)
|
||||
_ = os.WriteFile(backupDir+"/"+filename, data, 0666)
|
||||
} else if err != nil && os.IsNotExist(err) {
|
||||
err = os.Mkdir(backupDir, 0777)
|
||||
if err == nil {
|
||||
_ = ioutil.WriteFile(backupDir+"/"+filename, data, 0666)
|
||||
_ = os.WriteFile(backupDir+"/"+filename, data, 0666)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, data, 0666)
|
||||
return os.WriteFile(path, data, 0666)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.4.9"
|
||||
Version = "0.5.2.1"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,11 +18,11 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "0.4.9"
|
||||
UserNodeVersion = "0.3.5"
|
||||
NodeVersion = "0.5.2"
|
||||
UserNodeVersion = "0.4.1"
|
||||
DNSNodeVersion = "0.2.6"
|
||||
AuthorityNodeVersion = "0.0.2"
|
||||
MonitorNodeVersion = "0.0.4"
|
||||
DNSNodeVersion = "0.2.4"
|
||||
ReportNodeVersion = "0.1.1"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
|
||||
@@ -2,9 +2,18 @@
|
||||
|
||||
package teaconst
|
||||
|
||||
var (
|
||||
IsPlus = false
|
||||
MaxNodes int32 = 0
|
||||
NodeId int64 = 0
|
||||
Debug = false
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
IsPlus = false
|
||||
MaxNodes int32 = 0
|
||||
NodeId int64 = 0
|
||||
Debug = false
|
||||
InstanceCode = fmt.Sprintf("%x", sha1.Sum([]byte("INSTANCE"+types.String(time.Now().UnixNano())+"@"+types.String(rands.Int64()))))
|
||||
)
|
||||
|
||||
33
internal/db/models/accounts/order_method_dao.go
Normal file
33
internal/db/models/accounts/order_method_dao.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
OrderMethodStateEnabled = 1 // 已启用
|
||||
OrderMethodStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type OrderMethodDAO dbs.DAO
|
||||
|
||||
func NewOrderMethodDAO() *OrderMethodDAO {
|
||||
return dbs.NewDAO(&OrderMethodDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeOrderMethods",
|
||||
Model: new(OrderMethod),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*OrderMethodDAO)
|
||||
}
|
||||
|
||||
var SharedOrderMethodDAO *OrderMethodDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedOrderMethodDAO = NewOrderMethodDAO()
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package nameservers
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
36
internal/db/models/accounts/order_method_model.go
Normal file
36
internal/db/models/accounts/order_method_model.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// OrderMethod 订单支付方式
|
||||
type OrderMethod struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 名称
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
Description string `field:"description"` // 描述
|
||||
ParentCode string `field:"parentCode"` // 内置的父级代号
|
||||
Code string `field:"code"` // 代号
|
||||
Url string `field:"url"` // URL
|
||||
Secret string `field:"secret"` // 密钥
|
||||
Params dbs.JSON `field:"params"` // 参数
|
||||
Order uint32 `field:"order"` // 排序
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type OrderMethodOperator struct {
|
||||
Id interface{} // ID
|
||||
Name interface{} // 名称
|
||||
IsOn interface{} // 是否启用
|
||||
Description interface{} // 描述
|
||||
ParentCode interface{} // 内置的父级代号
|
||||
Code interface{} // 代号
|
||||
Url interface{} // URL
|
||||
Secret interface{} // 密钥
|
||||
Params interface{} // 参数
|
||||
Order interface{} // 排序
|
||||
State interface{} // 状态
|
||||
}
|
||||
|
||||
func NewOrderMethodOperator() *OrderMethodOperator {
|
||||
return &OrderMethodOperator{}
|
||||
}
|
||||
1
internal/db/models/accounts/order_method_model_ext.go
Normal file
1
internal/db/models/accounts/order_method_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
33
internal/db/models/accounts/user_order_dao.go
Normal file
33
internal/db/models/accounts/user_order_dao.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
UserOrderStateEnabled = 1 // 已启用
|
||||
UserOrderStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type UserOrderDAO dbs.DAO
|
||||
|
||||
func NewUserOrderDAO() *UserOrderDAO {
|
||||
return dbs.NewDAO(&UserOrderDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserOrders",
|
||||
Model: new(UserOrder),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserOrderDAO)
|
||||
}
|
||||
|
||||
var SharedUserOrderDAO *UserOrderDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserOrderDAO = NewUserOrderDAO()
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package nameservers
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
28
internal/db/models/accounts/user_order_log_dao.go
Normal file
28
internal/db/models/accounts/user_order_log_dao.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
type UserOrderLogDAO dbs.DAO
|
||||
|
||||
func NewUserOrderLogDAO() *UserOrderLogDAO {
|
||||
return dbs.NewDAO(&UserOrderLogDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserOrderLogs",
|
||||
Model: new(UserOrderLog),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserOrderLogDAO)
|
||||
}
|
||||
|
||||
var SharedUserOrderLogDAO *UserOrderLogDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserOrderLogDAO = NewUserOrderLogDAO()
|
||||
})
|
||||
}
|
||||
6
internal/db/models/accounts/user_order_log_dao_test.go
Normal file
6
internal/db/models/accounts/user_order_log_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
28
internal/db/models/accounts/user_order_log_model.go
Normal file
28
internal/db/models/accounts/user_order_log_model.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// UserOrderLog 订单日志
|
||||
type UserOrderLog struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
AdminId uint64 `field:"adminId"` // 管理员ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
OrderId uint64 `field:"orderId"` // 订单ID
|
||||
Status string `field:"status"` // 状态
|
||||
Snapshot dbs.JSON `field:"snapshot"` // 状态快照
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
}
|
||||
|
||||
type UserOrderLogOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
OrderId interface{} // 订单ID
|
||||
Status interface{} // 状态
|
||||
Snapshot interface{} // 状态快照
|
||||
CreatedAt interface{} // 创建时间
|
||||
}
|
||||
|
||||
func NewUserOrderLogOperator() *UserOrderLogOperator {
|
||||
return &UserOrderLogOperator{}
|
||||
}
|
||||
1
internal/db/models/accounts/user_order_log_model_ext.go
Normal file
1
internal/db/models/accounts/user_order_log_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
40
internal/db/models/accounts/user_order_model.go
Normal file
40
internal/db/models/accounts/user_order_model.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// UserOrder 用户订单
|
||||
type UserOrder struct {
|
||||
Id uint64 `field:"id"` // 用户订单
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
Code string `field:"code"` // 订单号
|
||||
Type string `field:"type"` // 订单类型
|
||||
MethodId uint32 `field:"methodId"` // 支付方式
|
||||
Status string `field:"status"` // 订单状态
|
||||
Amount float64 `field:"amount"` // 金额
|
||||
Params dbs.JSON `field:"params"` // 附加参数
|
||||
ExpiredAt uint64 `field:"expiredAt"` // 过期时间
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
CancelledAt uint64 `field:"cancelledAt"` // 取消时间
|
||||
FinishedAt uint64 `field:"finishedAt"` // 结束时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type UserOrderOperator struct {
|
||||
Id interface{} // 用户订单
|
||||
UserId interface{} // 用户ID
|
||||
Code interface{} // 订单号
|
||||
Type interface{} // 订单类型
|
||||
MethodId interface{} // 支付方式
|
||||
Status interface{} // 订单状态
|
||||
Amount interface{} // 金额
|
||||
Params interface{} // 附加参数
|
||||
ExpiredAt interface{} // 过期时间
|
||||
CreatedAt interface{} // 创建时间
|
||||
CancelledAt interface{} // 取消时间
|
||||
FinishedAt interface{} // 结束时间
|
||||
State interface{} // 状态
|
||||
}
|
||||
|
||||
func NewUserOrderOperator() *UserOrderOperator {
|
||||
return &UserOrderOperator{}
|
||||
}
|
||||
1
internal/db/models/accounts/user_order_model_ext.go
Normal file
1
internal/db/models/accounts/user_order_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
@@ -29,7 +29,7 @@ func init() {
|
||||
|
||||
// 创建认证信息
|
||||
func (this *ACMEAuthenticationDAO) CreateAuth(tx *dbs.Tx, taskId int64, domain string, token string, key string) error {
|
||||
op := NewACMEAuthenticationOperator()
|
||||
var op = NewACMEAuthenticationOperator()
|
||||
op.TaskId = taskId
|
||||
op.Domain = domain
|
||||
op.Token = token
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -169,7 +177,7 @@ func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId
|
||||
|
||||
// CreateACMETask 创建任务
|
||||
func (this *ACMETaskDAO) CreateACMETask(tx *dbs.Tx, adminId int64, userId int64, authType acmeutils.AuthType, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool, authURL string) (int64, error) {
|
||||
op := NewACMETaskOperator()
|
||||
var op = NewACMETaskOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.AuthType = authType
|
||||
@@ -204,7 +212,7 @@ func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId
|
||||
return errors.New("invalid acmeTaskId")
|
||||
}
|
||||
|
||||
op := NewACMETaskOperator()
|
||||
var op = NewACMETaskOperator()
|
||||
op.Id = acmeTaskId
|
||||
op.AcmeUserId = acmeUserId
|
||||
op.DnsProviderId = dnsProviderId
|
||||
@@ -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()
|
||||
@@ -240,7 +254,7 @@ func (this *ACMETaskDAO) UpdateACMETaskCert(tx *dbs.Tx, taskId int64, certId int
|
||||
return errors.New("invalid taskId")
|
||||
}
|
||||
|
||||
op := NewACMETaskOperator()
|
||||
var op = NewACMETaskOperator()
|
||||
op.Id = taskId
|
||||
op.CertId = certId
|
||||
err := this.Save(tx, op)
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func init() {
|
||||
|
||||
// 生成日志
|
||||
func (this *ACMETaskLogDAO) CreateACMETaskLog(tx *dbs.Tx, taskId int64, isOk bool, errMsg string) error {
|
||||
op := NewACMETaskLogOperator()
|
||||
var op = NewACMETaskLogOperator()
|
||||
op.TaskId = taskId
|
||||
op.Error = errMsg
|
||||
op.IsOk = isOk
|
||||
|
||||
@@ -83,7 +83,7 @@ func (this *ACMEUserDAO) CreateACMEUser(tx *dbs.Tx, adminId int64, userId int64,
|
||||
}
|
||||
privateKeyText := base64.StdEncoding.EncodeToString(privateKeyData)
|
||||
|
||||
op := NewACMEUserOperator()
|
||||
var op = NewACMEUserOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.ProviderCode = providerCode
|
||||
@@ -104,7 +104,7 @@ func (this *ACMEUserDAO) UpdateACMEUser(tx *dbs.Tx, acmeUserId int64, descriptio
|
||||
if acmeUserId <= 0 {
|
||||
return errors.New("invalid acmeUserId")
|
||||
}
|
||||
op := NewACMEUserOperator()
|
||||
var op = NewACMEUserOperator()
|
||||
op.Id = acmeUserId
|
||||
op.Description = description
|
||||
err := this.Save(tx, op)
|
||||
@@ -116,7 +116,7 @@ func (this *ACMEUserDAO) UpdateACMEUserRegistration(tx *dbs.Tx, acmeUserId int64
|
||||
if acmeUserId <= 0 {
|
||||
return errors.New("invalid acmeUserId")
|
||||
}
|
||||
op := NewACMEUserOperator()
|
||||
var op = NewACMEUserOperator()
|
||||
op.Id = acmeUserId
|
||||
op.Registration = registrationJSON
|
||||
err := this.Save(tx, op)
|
||||
|
||||
@@ -63,6 +63,19 @@ func (this *AdminDAO) FindEnabledAdmin(tx *dbs.Tx, id int64) (*Admin, error) {
|
||||
return result.(*Admin), err
|
||||
}
|
||||
|
||||
// FindBasicAdmin 查找管理员基本信息
|
||||
func (this *AdminDAO) FindBasicAdmin(tx *dbs.Tx, id int64) (*Admin, error) {
|
||||
result, err := this.Query(tx).
|
||||
Result("id", "username", "fullname").
|
||||
Pk(id).
|
||||
Attr("state", AdminStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*Admin), err
|
||||
}
|
||||
|
||||
// ExistEnabledAdmin 检查管理员是否存在
|
||||
func (this *AdminDAO) ExistEnabledAdmin(tx *dbs.Tx, adminId int64) (bool, error) {
|
||||
return this.Query(tx).
|
||||
@@ -115,7 +128,7 @@ func (this *AdminDAO) UpdateAdminPassword(tx *dbs.Tx, adminId int64, password st
|
||||
if adminId <= 0 {
|
||||
return errors.New("invalid adminId")
|
||||
}
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.Id = adminId
|
||||
op.Password = stringutil.Md5(password)
|
||||
err := this.Save(tx, op)
|
||||
@@ -124,7 +137,7 @@ func (this *AdminDAO) UpdateAdminPassword(tx *dbs.Tx, adminId int64, password st
|
||||
|
||||
// CreateAdmin 创建管理员
|
||||
func (this *AdminDAO) CreateAdmin(tx *dbs.Tx, username string, canLogin bool, password string, fullname string, isSuper bool, modulesJSON []byte) (int64, error) {
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.IsOn = true
|
||||
op.State = AdminStateEnabled
|
||||
op.Username = username
|
||||
@@ -149,7 +162,7 @@ func (this *AdminDAO) UpdateAdminInfo(tx *dbs.Tx, adminId int64, fullname string
|
||||
if adminId <= 0 {
|
||||
return errors.New("invalid adminId")
|
||||
}
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.Id = adminId
|
||||
op.Fullname = fullname
|
||||
err := this.Save(tx, op)
|
||||
@@ -161,7 +174,7 @@ func (this *AdminDAO) UpdateAdmin(tx *dbs.Tx, adminId int64, username string, ca
|
||||
if adminId <= 0 {
|
||||
return errors.New("invalid adminId")
|
||||
}
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.Id = adminId
|
||||
op.Fullname = fullname
|
||||
op.Username = username
|
||||
@@ -198,7 +211,7 @@ func (this *AdminDAO) UpdateAdminLogin(tx *dbs.Tx, adminId int64, username strin
|
||||
if adminId <= 0 {
|
||||
return errors.New("invalid adminId")
|
||||
}
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.Id = adminId
|
||||
op.Username = username
|
||||
if len(password) > 0 {
|
||||
@@ -213,7 +226,7 @@ func (this *AdminDAO) UpdateAdminModules(tx *dbs.Tx, adminId int64, allowModules
|
||||
if adminId <= 0 {
|
||||
return errors.New("invalid adminId")
|
||||
}
|
||||
op := NewAdminOperator()
|
||||
var op = NewAdminOperator()
|
||||
op.Id = adminId
|
||||
op.Modules = allowModulesJSON
|
||||
err := this.Save(tx, op)
|
||||
|
||||
@@ -14,23 +14,23 @@ type Admin struct {
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
Modules dbs.JSON `field:"modules"` // 允许的模块
|
||||
CanLogin uint8 `field:"canLogin"` // 是否可以登录
|
||||
CanLogin bool `field:"canLogin"` // 是否可以登录
|
||||
Theme string `field:"theme"` // 模板设置
|
||||
}
|
||||
|
||||
type AdminOperator struct {
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
Username interface{} // 用户名
|
||||
Password interface{} // 密码
|
||||
Fullname interface{} // 全名
|
||||
IsSuper interface{} // 是否为超级管理员
|
||||
CreatedAt interface{} // 创建时间
|
||||
UpdatedAt interface{} // 修改时间
|
||||
State interface{} // 状态
|
||||
Modules interface{} // 允许的模块
|
||||
CanLogin interface{} // 是否可以登录
|
||||
Theme interface{} // 模板设置
|
||||
Id any // ID
|
||||
IsOn any // 是否启用
|
||||
Username any // 用户名
|
||||
Password any // 密码
|
||||
Fullname any // 全名
|
||||
IsSuper any // 是否为超级管理员
|
||||
CreatedAt any // 创建时间
|
||||
UpdatedAt any // 修改时间
|
||||
State any // 状态
|
||||
Modules any // 允许的模块
|
||||
CanLogin any // 是否可以登录
|
||||
Theme any // 模板设置
|
||||
}
|
||||
|
||||
func NewAdminOperator() *AdminOperator {
|
||||
|
||||
@@ -56,7 +56,7 @@ func (this *APIAccessTokenDAO) GenerateAccessToken(tx *dbs.Tx, adminId int64, us
|
||||
token = rands.String(128) // TODO 增强安全性,将来使用 base64_encode(encrypt(salt+random)) 算法来代替
|
||||
expiresAt = time.Now().Unix() + 7200
|
||||
|
||||
op := NewAPIAccessTokenOperator()
|
||||
var op = NewAPIAccessTokenOperator()
|
||||
|
||||
if accessToken != nil {
|
||||
op.Id = accessToken.(*APIAccessToken).Id
|
||||
|
||||
@@ -134,7 +134,7 @@ func (this *APINodeDAO) CreateAPINode(tx *dbs.Tx, name string, description strin
|
||||
return
|
||||
}
|
||||
|
||||
op := NewAPINodeOperator()
|
||||
var op = NewAPINodeOperator()
|
||||
op.IsOn = isOn
|
||||
op.UniqueId = uniqueId
|
||||
op.Secret = secret
|
||||
|
||||
@@ -112,7 +112,7 @@ func (this *ApiTokenDAO) FindEnabledTokenWithRole(tx *dbs.Tx, role string) (*Api
|
||||
|
||||
// CreateAPIToken 保存API Token
|
||||
func (this *ApiTokenDAO) CreateAPIToken(tx *dbs.Tx, nodeId string, secret string, role nodeconfigs.NodeRole) error {
|
||||
op := NewApiTokenOperator()
|
||||
var op = NewApiTokenOperator()
|
||||
op.NodeId = nodeId
|
||||
op.Secret = secret
|
||||
op.Role = role
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AuthorityKeyDAO dbs.DAO
|
||||
@@ -33,63 +29,3 @@ func init() {
|
||||
_, _ = SharedAuthorityKeyDAO.IsPlus(nil)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateKey 设置Key
|
||||
func (this *AuthorityKeyDAO) UpdateKey(tx *dbs.Tx, value string, dayFrom string, dayTo string, hostname string, macAddresses []string, company string) error {
|
||||
one, err := this.Query(tx).
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op := NewAuthorityKeyOperator()
|
||||
if one != nil {
|
||||
op.Id = one.(*AuthorityKey).Id
|
||||
}
|
||||
op.Value = value
|
||||
op.DayFrom = dayFrom
|
||||
op.DayTo = dayTo
|
||||
op.Hostname = hostname
|
||||
|
||||
if len(macAddresses) == 0 {
|
||||
macAddresses = []string{}
|
||||
}
|
||||
macAddressesJSON, err := json.Marshal(macAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op.MacAddresses = macAddressesJSON
|
||||
op.Company = company
|
||||
op.UpdatedAt = time.Now().Unix()
|
||||
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
// ReadKey 读取Key
|
||||
func (this *AuthorityKeyDAO) ReadKey(tx *dbs.Tx) (key *AuthorityKey, err error) {
|
||||
one, err := this.Query(tx).
|
||||
AscPk().
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if one == nil {
|
||||
return nil, nil
|
||||
}
|
||||
key = one.(*AuthorityKey)
|
||||
|
||||
// 顺便更新相关变量
|
||||
if key.DayTo >= timeutil.Format("Y-m-d") {
|
||||
teaconst.IsPlus = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ResetKey 重置Key
|
||||
func (this *AuthorityKeyDAO) ResetKey(tx *dbs.Tx) error {
|
||||
_, err := this.Query(tx).
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package authority
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAuthorityKeyDAO_UpdateValue(t *testing.T) {
|
||||
err := NewAuthorityKeyDAO().UpdateKey(nil, "12345678", "", "", "", []string{}, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestAuthorityKeyDAO_ReadValue(t *testing.T) {
|
||||
value, err := NewAuthorityKeyDAO().ReadKey(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(value)
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (this *AuthorityNodeDAO) CreateAuthorityNode(tx *dbs.Tx, name string, descr
|
||||
return
|
||||
}
|
||||
|
||||
op := NewAuthorityNodeOperator()
|
||||
var op = NewAuthorityNodeOperator()
|
||||
op.IsOn = isOn
|
||||
op.UniqueId = uniqueId
|
||||
op.Secret = secret
|
||||
@@ -141,7 +141,7 @@ func (this *AuthorityNodeDAO) UpdateAuthorityNode(tx *dbs.Tx, nodeId int64, name
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
|
||||
op := NewAuthorityNodeOperator()
|
||||
var op = NewAuthorityNodeOperator()
|
||||
op.Id = nodeId
|
||||
op.Name = name
|
||||
op.Description = description
|
||||
|
||||
@@ -125,7 +125,7 @@ func (this *ClientBrowserDAO) CreateBrowser(tx *dbs.Tx, browserName string) (int
|
||||
return browserId, nil
|
||||
}
|
||||
|
||||
op := NewClientBrowserOperator()
|
||||
var op = NewClientBrowserOperator()
|
||||
op.Name = browserName
|
||||
codes := []string{browserName}
|
||||
codesJSON, err := json.Marshal(codes)
|
||||
|
||||
@@ -125,7 +125,7 @@ func (this *ClientSystemDAO) CreateSystem(tx *dbs.Tx, systemName string) (int64,
|
||||
return systemId, nil
|
||||
}
|
||||
|
||||
op := NewClientSystemOperator()
|
||||
var op = NewClientSystemOperator()
|
||||
op.Name = systemName
|
||||
|
||||
codes := []string{systemName}
|
||||
|
||||
@@ -109,7 +109,7 @@ func (this *DBNodeDAO) ListEnabledNodes(tx *dbs.Tx, offset int64, size int64) (r
|
||||
|
||||
// CreateDBNode 创建节点
|
||||
func (this *DBNodeDAO) CreateDBNode(tx *dbs.Tx, isOn bool, name string, description string, host string, port int32, database string, username string, password string, charset string) (int64, error) {
|
||||
op := NewDBNodeOperator()
|
||||
var op = NewDBNodeOperator()
|
||||
op.State = NodeStateEnabled
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -132,7 +132,7 @@ func (this *DBNodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, isOn bool, name stri
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
op := NewDBNodeOperator()
|
||||
var op = NewDBNodeOperator()
|
||||
op.Id = nodeId
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
|
||||
@@ -91,7 +91,7 @@ func (this *DNSDomainDAO) FindDNSDomainName(tx *dbs.Tx, id int64) (string, error
|
||||
|
||||
// CreateDomain 创建域名
|
||||
func (this *DNSDomainDAO) CreateDomain(tx *dbs.Tx, adminId int64, userId int64, providerId int64, name string) (int64, error) {
|
||||
op := NewDNSDomainOperator()
|
||||
var op = NewDNSDomainOperator()
|
||||
op.ProviderId = providerId
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
@@ -111,7 +111,7 @@ func (this *DNSDomainDAO) UpdateDomain(tx *dbs.Tx, domainId int64, name string,
|
||||
if domainId <= 0 {
|
||||
return errors.New("invalid domainId")
|
||||
}
|
||||
op := NewDNSDomainOperator()
|
||||
var op = NewDNSDomainOperator()
|
||||
op.Id = domainId
|
||||
op.Name = name
|
||||
op.IsOn = isOn
|
||||
@@ -146,7 +146,7 @@ func (this *DNSDomainDAO) UpdateDomainData(tx *dbs.Tx, domainId int64, data stri
|
||||
if domainId <= 0 {
|
||||
return errors.New("invalid domainId")
|
||||
}
|
||||
op := NewDNSDomainOperator()
|
||||
var op = NewDNSDomainOperator()
|
||||
op.Id = domainId
|
||||
op.Data = data
|
||||
err := this.Save(tx, op)
|
||||
@@ -158,7 +158,7 @@ func (this *DNSDomainDAO) UpdateDomainRecords(tx *dbs.Tx, domainId int64, record
|
||||
if domainId <= 0 {
|
||||
return errors.New("invalid domainId")
|
||||
}
|
||||
op := NewDNSDomainOperator()
|
||||
var op = NewDNSDomainOperator()
|
||||
op.Id = domainId
|
||||
op.Records = recordsJSON
|
||||
op.DataUpdatedAt = time.Now().Unix()
|
||||
@@ -171,7 +171,7 @@ func (this *DNSDomainDAO) UpdateDomainRoutes(tx *dbs.Tx, domainId int64, routesJ
|
||||
if domainId <= 0 {
|
||||
return errors.New("invalid domainId")
|
||||
}
|
||||
op := NewDNSDomainOperator()
|
||||
var op = NewDNSDomainOperator()
|
||||
op.Id = domainId
|
||||
op.Routes = routesJSON
|
||||
op.DataUpdatedAt = time.Now().Unix()
|
||||
|
||||
@@ -68,7 +68,7 @@ func (this *DNSProviderDAO) FindEnabledDNSProvider(tx *dbs.Tx, id int64) (*DNSPr
|
||||
|
||||
// CreateDNSProvider 创建服务商
|
||||
func (this *DNSProviderDAO) CreateDNSProvider(tx *dbs.Tx, adminId int64, userId int64, providerType string, name string, apiParamsJSON []byte) (int64, error) {
|
||||
op := NewDNSProviderOperator()
|
||||
var op = NewDNSProviderOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.Type = providerType
|
||||
@@ -90,7 +90,7 @@ func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, n
|
||||
return errors.New("invalid dnsProviderId")
|
||||
}
|
||||
|
||||
op := NewDNSProviderOperator()
|
||||
var op = NewDNSProviderOperator()
|
||||
op.Id = dnsProviderId
|
||||
op.Name = name
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
|
||||
if taskId <= 0 {
|
||||
return errors.New("invalid taskId")
|
||||
}
|
||||
op := NewDNSTaskOperator()
|
||||
var op = NewDNSTaskOperator()
|
||||
op.Id = taskId
|
||||
op.IsDone = true
|
||||
op.Error = err
|
||||
@@ -156,7 +156,7 @@ func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64) error {
|
||||
if taskId <= 0 {
|
||||
return errors.New("invalid taskId")
|
||||
}
|
||||
op := NewDNSTaskOperator()
|
||||
var op = NewDNSTaskOperator()
|
||||
op.Id = taskId
|
||||
op.IsDone = true
|
||||
op.IsOk = true
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 创建文件Chunk
|
||||
// CreateFileChunk 创建文件Chunk
|
||||
func (this *FileChunkDAO) CreateFileChunk(tx *dbs.Tx, fileId int64, data []byte) (int64, error) {
|
||||
op := NewFileChunkOperator()
|
||||
var op = NewFileChunkOperator()
|
||||
op.FileId = fileId
|
||||
op.Data = data
|
||||
err := this.Save(tx, op)
|
||||
@@ -41,7 +41,7 @@ func (this *FileChunkDAO) CreateFileChunk(tx *dbs.Tx, fileId int64, data []byte)
|
||||
return types.Int64(op.Id), nil
|
||||
}
|
||||
|
||||
// 列出所有的文件Chunk
|
||||
// FindAllFileChunks 列出所有的文件Chunk
|
||||
func (this *FileChunkDAO) FindAllFileChunks(tx *dbs.Tx, fileId int64) (result []*FileChunk, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Attr("fileId", fileId).
|
||||
@@ -51,7 +51,7 @@ func (this *FileChunkDAO) FindAllFileChunks(tx *dbs.Tx, fileId int64) (result []
|
||||
return
|
||||
}
|
||||
|
||||
// 读取文件的所有片段ID
|
||||
// FindAllFileChunkIds 读取文件的所有片段ID
|
||||
func (this *FileChunkDAO) FindAllFileChunkIds(tx *dbs.Tx, fileId int64) ([]int64, error) {
|
||||
ones, err := this.Query(tx).
|
||||
Attr("fileId", fileId).
|
||||
@@ -68,7 +68,7 @@ func (this *FileChunkDAO) FindAllFileChunkIds(tx *dbs.Tx, fileId int64) ([]int64
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 删除以前的文件
|
||||
// DeleteFileChunks 删除以前的文件
|
||||
func (this *FileChunkDAO) DeleteFileChunks(tx *dbs.Tx, fileId int64) error {
|
||||
if fileId <= 0 {
|
||||
return errors.New("invalid fileId")
|
||||
@@ -79,7 +79,7 @@ func (this *FileChunkDAO) DeleteFileChunks(tx *dbs.Tx, fileId int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据ID查找片段
|
||||
// FindFileChunk 根据ID查找片段
|
||||
func (this *FileChunkDAO) FindFileChunk(tx *dbs.Tx, chunkId int64) (*FileChunk, error) {
|
||||
one, err := this.Query(tx).
|
||||
Pk(chunkId).
|
||||
|
||||
@@ -65,7 +65,7 @@ func (this *FileDAO) FindEnabledFile(tx *dbs.Tx, id int64) (*File, error) {
|
||||
}
|
||||
|
||||
// CreateFile 创建文件
|
||||
func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, businessType, description string, filename string, size int64, isPublic bool) (int64, error) {
|
||||
func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, businessType string, description string, filename string, size int64, mimeType string, isPublic bool) (int64, error) {
|
||||
var op = NewFileOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
@@ -76,6 +76,7 @@ func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, busines
|
||||
op.Filename = filename
|
||||
op.IsPublic = isPublic
|
||||
op.Code = utils.Sha1RandomString()
|
||||
op.MimeType = mimeType
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -84,6 +85,21 @@ func (this *FileDAO) CreateFile(tx *dbs.Tx, adminId int64, userId int64, busines
|
||||
return types.Int64(op.Id), nil
|
||||
}
|
||||
|
||||
// CheckUserFile 检查用户ID
|
||||
func (this *FileDAO) CheckUserFile(tx *dbs.Tx, userId int64, fileId int64) error {
|
||||
b, err := this.Query(tx).
|
||||
Pk(fileId).
|
||||
Attr("userId", userId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !b {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateFileIsFinished 将文件置为已完成
|
||||
func (this *FileDAO) UpdateFileIsFinished(tx *dbs.Tx, fileId int64) error {
|
||||
_, err := this.Query(tx).
|
||||
|
||||
@@ -9,6 +9,7 @@ type File struct {
|
||||
Description string `field:"description"` // 文件描述
|
||||
Filename string `field:"filename"` // 文件名
|
||||
Size uint32 `field:"size"` // 文件尺寸
|
||||
MimeType string `field:"mimeType"` // Mime类型
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
Order uint32 `field:"order"` // 排序
|
||||
Type string `field:"type"` // 类型
|
||||
@@ -25,6 +26,7 @@ type FileOperator struct {
|
||||
Description interface{} // 文件描述
|
||||
Filename interface{} // 文件名
|
||||
Size interface{} // 文件尺寸
|
||||
MimeType interface{} // Mime类型
|
||||
CreatedAt interface{} // 创建时间
|
||||
Order interface{} // 排序
|
||||
Type interface{} // 类型
|
||||
|
||||
@@ -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,15 +86,21 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func NewHTTPAccessLogDAO() *HTTPAccessLogDAO {
|
||||
@@ -133,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{
|
||||
@@ -142,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
|
||||
@@ -157,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:
|
||||
@@ -169,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 写入单条访问日志
|
||||
@@ -768,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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ func (this *HTTPAccessLogPolicyDAO) CountAllEnabledPolicies(tx *dbs.Tx) (int64,
|
||||
func (this *HTTPAccessLogPolicyDAO) ListEnabledPolicies(tx *dbs.Tx, offset int64, size int64) (result []*HTTPAccessLogPolicy, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(HTTPAccessLogPolicyStateEnabled).
|
||||
Desc("isOn").
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
|
||||
@@ -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) {
|
||||
op := NewHTTPAuthPolicyOperator()
|
||||
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
|
||||
@@ -83,7 +84,7 @@ func (this *HTTPAuthPolicyDAO) UpdateHTTPAuthPolicy(tx *dbs.Tx, policyId int64,
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPAuthPolicyOperator()
|
||||
var op = NewHTTPAuthPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.Name = name
|
||||
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)
|
||||
|
||||
@@ -113,7 +113,7 @@ func (this *HTTPBrotliPolicyDAO) ComposeBrotliConfig(tx *dbs.Tx, policyId int64)
|
||||
|
||||
// CreatePolicy 创建策略
|
||||
func (this *HTTPBrotliPolicyDAO) CreatePolicy(tx *dbs.Tx, level int, minLengthJSON []byte, maxLengthJSON []byte, condsJSON []byte) (int64, error) {
|
||||
op := NewHTTPBrotliPolicyOperator()
|
||||
var op = NewHTTPBrotliPolicyOperator()
|
||||
op.State = HTTPBrotliPolicyStateEnabled
|
||||
op.IsOn = true
|
||||
op.Level = level
|
||||
@@ -138,7 +138,7 @@ func (this *HTTPBrotliPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, level
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPBrotliPolicyOperator()
|
||||
var op = NewHTTPBrotliPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.Level = level
|
||||
if len(minLengthJSON) > 0 {
|
||||
|
||||
@@ -97,7 +97,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
|
||||
|
||||
// CreateCachePolicy 创建缓存策略
|
||||
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
|
||||
op := NewHTTPCachePolicyOperator()
|
||||
var op = NewHTTPCachePolicyOperator()
|
||||
op.State = HTTPCachePolicyStateEnabled
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -209,7 +209,7 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
|
||||
op := NewHTTPCachePolicyOperator()
|
||||
var op = NewHTTPCachePolicyOperator()
|
||||
op.Id = policyId
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
|
||||
@@ -12,23 +12,23 @@ type HTTPCacheTask struct {
|
||||
Day string `field:"day"` // 创建日期YYYYMMDD
|
||||
IsDone bool `field:"isDone"` // 是否已完成
|
||||
IsOk bool `field:"isOk"` // 是否完全成功
|
||||
IsReady uint8 `field:"isReady"` // 是否已准备好
|
||||
IsReady bool `field:"isReady"` // 是否已准备好
|
||||
Description string `field:"description"` // 描述
|
||||
}
|
||||
|
||||
type HTTPCacheTaskOperator struct {
|
||||
Id interface{} // ID
|
||||
UserId interface{} // 用户ID
|
||||
Type interface{} // 任务类型:purge|fetch
|
||||
KeyType interface{} // Key类型
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
DoneAt interface{} // 完成时间
|
||||
Day interface{} // 创建日期YYYYMMDD
|
||||
IsDone interface{} // 是否已完成
|
||||
IsOk interface{} // 是否完全成功
|
||||
IsReady interface{} // 是否已准备好
|
||||
Description interface{} // 描述
|
||||
Id any // ID
|
||||
UserId any // 用户ID
|
||||
Type any // 任务类型:purge|fetch
|
||||
KeyType any // Key类型
|
||||
State any // 状态
|
||||
CreatedAt any // 创建时间
|
||||
DoneAt any // 完成时间
|
||||
Day any // 创建日期YYYYMMDD
|
||||
IsDone any // 是否已完成
|
||||
IsOk any // 是否完全成功
|
||||
IsReady any // 是否已准备好
|
||||
Description any // 描述
|
||||
}
|
||||
|
||||
func NewHTTPCacheTaskOperator() *HTTPCacheTaskOperator {
|
||||
|
||||
@@ -113,7 +113,7 @@ func (this *HTTPDeflatePolicyDAO) ComposeDeflateConfig(tx *dbs.Tx, policyId int6
|
||||
|
||||
// CreatePolicy 创建策略
|
||||
func (this *HTTPDeflatePolicyDAO) CreatePolicy(tx *dbs.Tx, level int, minLengthJSON []byte, maxLengthJSON []byte, condsJSON []byte) (int64, error) {
|
||||
op := NewHTTPDeflatePolicyOperator()
|
||||
var op = NewHTTPDeflatePolicyOperator()
|
||||
op.State = HTTPDeflatePolicyStateEnabled
|
||||
op.IsOn = true
|
||||
op.Level = level
|
||||
@@ -138,7 +138,7 @@ func (this *HTTPDeflatePolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, level
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPDeflatePolicyOperator()
|
||||
var op = NewHTTPDeflatePolicyOperator()
|
||||
op.Id = policyId
|
||||
op.Level = level
|
||||
if len(minLengthJSON) > 0 {
|
||||
|
||||
@@ -121,7 +121,7 @@ func (this *HTTPFastcgiDAO) ComposeFastcgiConfig(tx *dbs.Tx, fastcgiId int64) (*
|
||||
|
||||
// CreateFastcgi 创建Fastcgi
|
||||
func (this *HTTPFastcgiDAO) CreateFastcgi(tx *dbs.Tx, adminId int64, userId int64, isOn bool, address string, paramsJSON []byte, readTimeoutJSON []byte, connTimeoutJSON []byte, poolSize int32, pathInfoPattern string) (int64, error) {
|
||||
op := NewHTTPFastcgiOperator()
|
||||
var op = NewHTTPFastcgiOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.IsOn = isOn
|
||||
@@ -147,7 +147,7 @@ func (this *HTTPFastcgiDAO) UpdateFastcgi(tx *dbs.Tx, fastcgiId int64, isOn bool
|
||||
if fastcgiId <= 0 {
|
||||
return errors.New("invalid 'fastcgiId'")
|
||||
}
|
||||
op := NewHTTPFastcgiOperator()
|
||||
var op = NewHTTPFastcgiOperator()
|
||||
op.Id = fastcgiId
|
||||
op.IsOn = isOn
|
||||
op.Address = address
|
||||
|
||||
@@ -233,7 +233,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundAndOutbound(tx *db
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPFirewallPolicyOperator()
|
||||
var op = NewHTTPFirewallPolicyOperator()
|
||||
op.Id = policyId
|
||||
if len(inboundJSON) > 0 {
|
||||
op.Inbound = inboundJSON
|
||||
@@ -262,7 +262,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
op := NewHTTPFirewallPolicyOperator()
|
||||
var op = NewHTTPFirewallPolicyOperator()
|
||||
op.Id = policyId
|
||||
if len(inboundJSON) > 0 {
|
||||
op.Inbound = inboundJSON
|
||||
|
||||
@@ -116,7 +116,7 @@ func (this *HTTPFirewallRuleDAO) ComposeFirewallRule(tx *dbs.Tx, ruleId int64) (
|
||||
|
||||
// CreateOrUpdateRuleFromConfig 从配置中配置规则
|
||||
func (this *HTTPFirewallRuleDAO) CreateOrUpdateRuleFromConfig(tx *dbs.Tx, ruleConfig *firewallconfigs.HTTPFirewallRule) (int64, error) {
|
||||
op := NewHTTPFirewallRuleOperator()
|
||||
var op = NewHTTPFirewallRuleOperator()
|
||||
op.Id = ruleConfig.Id
|
||||
op.State = HTTPFirewallRuleStateEnabled
|
||||
op.IsOn = ruleConfig.IsOn
|
||||
|
||||
@@ -120,7 +120,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
|
||||
|
||||
// CreateGroupFromConfig 从配置中创建分组
|
||||
func (this *HTTPFirewallRuleGroupDAO) CreateGroupFromConfig(tx *dbs.Tx, groupConfig *firewallconfigs.HTTPFirewallRuleGroup) (int64, error) {
|
||||
op := NewHTTPFirewallRuleGroupOperator()
|
||||
var op = NewHTTPFirewallRuleGroupOperator()
|
||||
op.IsOn = groupConfig.IsOn
|
||||
op.Name = groupConfig.Name
|
||||
op.Description = groupConfig.Description
|
||||
@@ -166,7 +166,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroupIsOn(tx *dbs.Tx, groupId int64,
|
||||
|
||||
// CreateGroup 创建分组
|
||||
func (this *HTTPFirewallRuleGroupDAO) CreateGroup(tx *dbs.Tx, isOn bool, name string, code string, description string) (int64, error) {
|
||||
op := NewHTTPFirewallRuleGroupOperator()
|
||||
var op = NewHTTPFirewallRuleGroupOperator()
|
||||
op.State = HTTPFirewallRuleStateEnabled
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -184,7 +184,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroup(tx *dbs.Tx, groupId int64, isO
|
||||
if groupId <= 0 {
|
||||
return errors.New("invalid groupId")
|
||||
}
|
||||
op := NewHTTPFirewallRuleGroupOperator()
|
||||
var op = NewHTTPFirewallRuleGroupOperator()
|
||||
op.Id = groupId
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -202,7 +202,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroupSets(tx *dbs.Tx, groupId int64,
|
||||
if groupId <= 0 {
|
||||
return errors.New("invalid groupId")
|
||||
}
|
||||
op := NewHTTPFirewallRuleGroupOperator()
|
||||
var op = NewHTTPFirewallRuleGroupOperator()
|
||||
op.Id = groupId
|
||||
op.Sets = setRefsJSON
|
||||
err := this.Save(tx, op)
|
||||
|
||||
@@ -133,7 +133,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
|
||||
|
||||
// CreateOrUpdateSetFromConfig 从配置中创建规则集
|
||||
func (this *HTTPFirewallRuleSetDAO) CreateOrUpdateSetFromConfig(tx *dbs.Tx, setConfig *firewallconfigs.HTTPFirewallRuleSet) (int64, error) {
|
||||
op := NewHTTPFirewallRuleSetOperator()
|
||||
var op = NewHTTPFirewallRuleSetOperator()
|
||||
op.State = HTTPFirewallRuleSetStateEnabled
|
||||
op.Id = setConfig.Id
|
||||
op.IsOn = setConfig.IsOn
|
||||
|
||||
@@ -121,7 +121,7 @@ func (this *HTTPGzipDAO) ComposeGzipConfig(tx *dbs.Tx, gzipId int64) (*servercon
|
||||
|
||||
// CreateGzip 创建Gzip
|
||||
func (this *HTTPGzipDAO) CreateGzip(tx *dbs.Tx, level int, minLengthJSON []byte, maxLengthJSON []byte, condsJSON []byte) (int64, error) {
|
||||
op := NewHTTPGzipOperator()
|
||||
var op = NewHTTPGzipOperator()
|
||||
op.State = HTTPGzipStateEnabled
|
||||
op.IsOn = true
|
||||
op.Level = level
|
||||
@@ -146,7 +146,7 @@ func (this *HTTPGzipDAO) UpdateGzip(tx *dbs.Tx, gzipId int64, level int, minLeng
|
||||
if gzipId <= 0 {
|
||||
return errors.New("invalid gzipId")
|
||||
}
|
||||
op := NewHTTPGzipOperator()
|
||||
var op = NewHTTPGzipOperator()
|
||||
op.Id = gzipId
|
||||
op.Level = level
|
||||
if len(minLengthJSON) > 0 {
|
||||
|
||||
@@ -81,7 +81,7 @@ func (this *HTTPHeaderDAO) FindHTTPHeaderName(tx *dbs.Tx, id int64) (string, err
|
||||
|
||||
// CreateHeader 创建Header
|
||||
func (this *HTTPHeaderDAO) CreateHeader(tx *dbs.Tx, userId int64, name string, value string, status []int, disableRedirect bool, shouldAppend bool, shouldReplace bool, replaceValues []*shared.HTTPHeaderReplaceValue, methods []string, domains []string) (int64, error) {
|
||||
op := NewHTTPHeaderOperator()
|
||||
var op = NewHTTPHeaderOperator()
|
||||
op.UserId = userId
|
||||
op.State = HTTPHeaderStateEnabled
|
||||
op.IsOn = true
|
||||
@@ -156,7 +156,7 @@ func (this *HTTPHeaderDAO) UpdateHeader(tx *dbs.Tx, headerId int64, name string,
|
||||
return errors.New("invalid headerId")
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderOperator()
|
||||
var op = NewHTTPHeaderOperator()
|
||||
op.Id = headerId
|
||||
op.Name = name
|
||||
op.Value = value
|
||||
|
||||
@@ -77,7 +77,7 @@ func (this *HTTPHeaderPolicyDAO) FindEnabledHTTPHeaderPolicy(tx *dbs.Tx, id int6
|
||||
|
||||
// CreateHeaderPolicy 创建策略
|
||||
func (this *HTTPHeaderPolicyDAO) CreateHeaderPolicy(tx *dbs.Tx) (int64, error) {
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.IsOn = true
|
||||
op.State = HTTPHeaderPolicyStateEnabled
|
||||
err := this.Save(tx, op)
|
||||
@@ -93,7 +93,7 @@ func (this *HTTPHeaderPolicyDAO) UpdateAddingHeaders(tx *dbs.Tx, policyId int64,
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.AddHeaders = headersJSON
|
||||
err := this.Save(tx, op)
|
||||
@@ -109,7 +109,7 @@ func (this *HTTPHeaderPolicyDAO) UpdateSettingHeaders(tx *dbs.Tx, policyId int64
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.SetHeaders = headersJSON
|
||||
err := this.Save(tx, op)
|
||||
@@ -125,7 +125,7 @@ func (this *HTTPHeaderPolicyDAO) UpdateReplacingHeaders(tx *dbs.Tx, policyId int
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.ReplaceHeaders = headersJSON
|
||||
err := this.Save(tx, op)
|
||||
@@ -141,7 +141,7 @@ func (this *HTTPHeaderPolicyDAO) UpdateAddingTrailers(tx *dbs.Tx, policyId int64
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.AddTrailers = headersJSON
|
||||
err := this.Save(tx, op)
|
||||
@@ -162,7 +162,7 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
|
||||
return err
|
||||
}
|
||||
|
||||
op := NewHTTPHeaderPolicyOperator()
|
||||
var op = NewHTTPHeaderPolicyOperator()
|
||||
op.Id = policyId
|
||||
op.DeleteHeaders = string(namesJSON)
|
||||
err = this.Save(tx, op)
|
||||
|
||||
@@ -87,7 +87,7 @@ func (this *HTTPLocationDAO) FindHTTPLocationName(tx *dbs.Tx, id int64) (string,
|
||||
|
||||
// CreateLocation 创建路由规则
|
||||
func (this *HTTPLocationDAO) CreateLocation(tx *dbs.Tx, parentId int64, name string, pattern string, description string, isBreak bool, condsJSON []byte, domains []string) (int64, error) {
|
||||
op := NewHTTPLocationOperator()
|
||||
var op = NewHTTPLocationOperator()
|
||||
op.IsOn = true
|
||||
op.State = HTTPLocationStateEnabled
|
||||
op.ParentId = parentId
|
||||
@@ -121,7 +121,7 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
|
||||
if locationId <= 0 {
|
||||
return errors.New("invalid locationId")
|
||||
}
|
||||
op := NewHTTPLocationOperator()
|
||||
var op = NewHTTPLocationOperator()
|
||||
op.Id = locationId
|
||||
op.Name = name
|
||||
op.Pattern = pattern
|
||||
@@ -257,7 +257,7 @@ func (this *HTTPLocationDAO) UpdateLocationReverseProxy(tx *dbs.Tx, locationId i
|
||||
if locationId <= 0 {
|
||||
return errors.New("invalid locationId")
|
||||
}
|
||||
op := NewHTTPLocationOperator()
|
||||
var op = NewHTTPLocationOperator()
|
||||
op.Id = locationId
|
||||
op.ReverseProxy = JSONBytes(reverseProxyJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -281,7 +281,7 @@ func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, web
|
||||
if locationId <= 0 {
|
||||
return errors.New("invalid locationId")
|
||||
}
|
||||
op := NewHTTPLocationOperator()
|
||||
var op = NewHTTPLocationOperator()
|
||||
op.Id = locationId
|
||||
op.WebId = webId
|
||||
err := this.Save(tx, op)
|
||||
|
||||
@@ -78,7 +78,7 @@ func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, e
|
||||
|
||||
// CreatePage 创建Page
|
||||
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) (pageId int64, err error) {
|
||||
op := NewHTTPPageOperator()
|
||||
var op = NewHTTPPageOperator()
|
||||
op.UserId = userId
|
||||
op.IsOn = true
|
||||
op.State = HTTPPageStateEnabled
|
||||
@@ -108,7 +108,7 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
|
||||
return errors.New("invalid pageId")
|
||||
}
|
||||
|
||||
op := NewHTTPPageOperator()
|
||||
var op = NewHTTPPageOperator()
|
||||
op.Id = pageId
|
||||
op.IsOn = true
|
||||
op.State = HTTPPageStateEnabled
|
||||
|
||||
@@ -125,7 +125,7 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
|
||||
|
||||
// CreateRewriteRule 创建规则
|
||||
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
|
||||
op := NewHTTPRewriteRuleOperator()
|
||||
var op = NewHTTPRewriteRuleOperator()
|
||||
op.State = HTTPRewriteRuleStateEnabled
|
||||
op.IsOn = isOn
|
||||
|
||||
@@ -150,7 +150,7 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
|
||||
if rewriteRuleId <= 0 {
|
||||
return errors.New("invalid rewriteRuleId")
|
||||
}
|
||||
op := NewHTTPRewriteRuleOperator()
|
||||
var op = NewHTTPRewriteRuleOperator()
|
||||
op.Id = rewriteRuleId
|
||||
op.IsOn = isOn
|
||||
op.Pattern = pattern
|
||||
|
||||
@@ -466,7 +466,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
|
||||
|
||||
// CreateWeb 创建Web配置
|
||||
func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJSON []byte) (int64, error) {
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.State = HTTPWebStateEnabled
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
@@ -485,7 +485,7 @@ func (this *HTTPWebDAO) UpdateWeb(tx *dbs.Tx, webId int64, rootJSON []byte) erro
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Root = JSONBytes(rootJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -501,7 +501,7 @@ func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressio
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Compression = JSONBytes(compressionConfig)
|
||||
err := this.Save(tx, op)
|
||||
@@ -517,7 +517,7 @@ func (this *HTTPWebDAO) UpdateWebWebP(tx *dbs.Tx, webId int64, webpConfig []byte
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Webp = JSONBytes(webpConfig)
|
||||
err := this.Save(tx, op)
|
||||
@@ -548,7 +548,7 @@ func (this *HTTPWebDAO) UpdateWebCharset(tx *dbs.Tx, webId int64, charsetJSON []
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Charset = JSONBytes(charsetJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -564,7 +564,7 @@ func (this *HTTPWebDAO) UpdateWebRequestHeaderPolicy(tx *dbs.Tx, webId int64, he
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.RequestHeader = JSONBytes(headerPolicyJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -580,7 +580,7 @@ func (this *HTTPWebDAO) UpdateWebResponseHeaderPolicy(tx *dbs.Tx, webId int64, h
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.ResponseHeader = JSONBytes(headerPolicyJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -596,7 +596,7 @@ func (this *HTTPWebDAO) UpdateWebPages(tx *dbs.Tx, webId int64, pagesJSON []byte
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Pages = JSONBytes(pagesJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -612,7 +612,7 @@ func (this *HTTPWebDAO) UpdateWebShutdown(tx *dbs.Tx, webId int64, shutdownJSON
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Shutdown = JSONBytes(shutdownJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -628,7 +628,7 @@ func (this *HTTPWebDAO) UpdateWebAccessLogConfig(tx *dbs.Tx, webId int64, access
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.AccessLog = JSONBytes(accessLogJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -644,7 +644,7 @@ func (this *HTTPWebDAO) UpdateWebStat(tx *dbs.Tx, webId int64, statJSON []byte)
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Stat = JSONBytes(statJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -660,7 +660,7 @@ func (this *HTTPWebDAO) UpdateWebCache(tx *dbs.Tx, webId int64, cacheJSON []byte
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Cache = JSONBytes(cacheJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -676,7 +676,7 @@ func (this *HTTPWebDAO) UpdateWebFirewall(tx *dbs.Tx, webId int64, firewallJSON
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Firewall = JSONBytes(firewallJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -692,7 +692,7 @@ func (this *HTTPWebDAO) UpdateWebLocations(tx *dbs.Tx, webId int64, locationsJSO
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Locations = JSONBytes(locationsJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -708,7 +708,7 @@ func (this *HTTPWebDAO) UpdateWebRedirectToHTTPS(tx *dbs.Tx, webId int64, redire
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.RedirectToHttps = JSONBytes(redirectToHTTPSJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -724,7 +724,7 @@ func (this *HTTPWebDAO) UpdateWebsocket(tx *dbs.Tx, webId int64, websocketJSON [
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Websocket = JSONBytes(websocketJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -740,7 +740,7 @@ func (this *HTTPWebDAO) UpdateWebFastcgi(tx *dbs.Tx, webId int64, fastcgiJSON []
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Fastcgi = JSONBytes(fastcgiJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -756,7 +756,7 @@ func (this *HTTPWebDAO) UpdateWebRewriteRules(tx *dbs.Tx, webId int64, rewriteRu
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.RewriteRules = JSONBytes(rewriteRulesJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -772,7 +772,7 @@ func (this *HTTPWebDAO) UpdateWebAuth(tx *dbs.Tx, webId int64, authJSON []byte)
|
||||
if webId <= 0 {
|
||||
return errors.New("invalid webId")
|
||||
}
|
||||
op := NewHTTPWebOperator()
|
||||
var op = NewHTTPWebOperator()
|
||||
op.Id = webId
|
||||
op.Auth = JSONBytes(authJSON)
|
||||
err := this.Save(tx, op)
|
||||
@@ -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
|
||||
|
||||
@@ -110,7 +110,7 @@ func (this *HTTPWebsocketDAO) ComposeWebsocketConfig(tx *dbs.Tx, websocketId int
|
||||
|
||||
// CreateWebsocket 创建Websocket配置
|
||||
func (this *HTTPWebsocketDAO) CreateWebsocket(tx *dbs.Tx, handshakeTimeoutJSON []byte, allowAllOrigins bool, allowedOrigins []string, requestSameOrigin bool, requestOrigin string) (websocketId int64, err error) {
|
||||
op := NewHTTPWebsocketOperator()
|
||||
var op = NewHTTPWebsocketOperator()
|
||||
op.IsOn = true
|
||||
op.State = HTTPWebsocketStateEnabled
|
||||
if len(handshakeTimeoutJSON) > 0 {
|
||||
@@ -135,7 +135,7 @@ func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, han
|
||||
if websocketId <= 0 {
|
||||
return errors.New("invalid websocketId")
|
||||
}
|
||||
op := NewHTTPWebsocketOperator()
|
||||
var op = NewHTTPWebsocketOperator()
|
||||
op.Id = websocketId
|
||||
if len(handshakeTimeoutJSON) > 0 {
|
||||
op.HandshakeTimeout = handshakeTimeoutJSON
|
||||
|
||||
@@ -330,7 +330,7 @@ func (this *IPItemDAO) UpdateIPItem(tx *dbs.Tx, itemId int64, ipFrom string, ipT
|
||||
return err
|
||||
}
|
||||
|
||||
op := NewIPItemOperator()
|
||||
var op = NewIPItemOperator()
|
||||
op.Id = itemId
|
||||
op.IpFrom = ipFrom
|
||||
op.IpTo = ipTo
|
||||
|
||||
140
internal/db/models/ip_library_artifact_dao.go
Normal file
140
internal/db/models/ip_library_artifact_dao.go
Normal 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()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package nameservers
|
||||
package models_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
32
internal/db/models/ip_library_artifact_model.go
Normal file
32
internal/db/models/ip_library_artifact_model.go
Normal 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{}
|
||||
}
|
||||
1
internal/db/models/ip_library_artifact_model_ext.go
Normal file
1
internal/db/models/ip_library_artifact_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -33,7 +33,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 启用条目
|
||||
// EnableIPLibrary 启用条目
|
||||
func (this *IPLibraryDAO) EnableIPLibrary(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -42,7 +42,7 @@ func (this *IPLibraryDAO) EnableIPLibrary(tx *dbs.Tx, id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 禁用条目
|
||||
// DisableIPLibrary 禁用条目
|
||||
func (this *IPLibraryDAO) DisableIPLibrary(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -51,7 +51,7 @@ func (this *IPLibraryDAO) DisableIPLibrary(tx *dbs.Tx, id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找启用中的条目
|
||||
// FindEnabledIPLibrary 查找启用中的条目
|
||||
func (this *IPLibraryDAO) FindEnabledIPLibrary(tx *dbs.Tx, id int64) (*IPLibrary, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -63,7 +63,7 @@ func (this *IPLibraryDAO) FindEnabledIPLibrary(tx *dbs.Tx, id int64) (*IPLibrary
|
||||
return result.(*IPLibrary), err
|
||||
}
|
||||
|
||||
// 查找某个类型的IP库列表
|
||||
// FindAllEnabledIPLibrariesWithType 查找某个类型的IP库列表
|
||||
func (this *IPLibraryDAO) FindAllEnabledIPLibrariesWithType(tx *dbs.Tx, libraryType string) (result []*IPLibrary, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(IPLibraryStateEnabled).
|
||||
@@ -74,7 +74,7 @@ func (this *IPLibraryDAO) FindAllEnabledIPLibrariesWithType(tx *dbs.Tx, libraryT
|
||||
return
|
||||
}
|
||||
|
||||
// 查找某个类型的最新的IP库
|
||||
// FindLatestIPLibraryWithType 查找某个类型的最新的IP库
|
||||
func (this *IPLibraryDAO) FindLatestIPLibraryWithType(tx *dbs.Tx, libraryType string) (*IPLibrary, error) {
|
||||
one, err := this.Query(tx).
|
||||
State(IPLibraryStateEnabled).
|
||||
@@ -90,9 +90,9 @@ func (this *IPLibraryDAO) FindLatestIPLibraryWithType(tx *dbs.Tx, libraryType st
|
||||
return one.(*IPLibrary), nil
|
||||
}
|
||||
|
||||
// 创建新的IP库
|
||||
// CreateIPLibrary 创建新的IP库
|
||||
func (this *IPLibraryDAO) CreateIPLibrary(tx *dbs.Tx, libraryType string, fileId int64) (int64, error) {
|
||||
op := NewIPLibraryOperator()
|
||||
var op = NewIPLibraryOperator()
|
||||
op.Type = libraryType
|
||||
op.FileId = fileId
|
||||
op.State = IPLibraryStateEnabled
|
||||
|
||||
593
internal/db/models/ip_library_file_dao.go
Normal file
593
internal/db/models/ip_library_file_dao.go
Normal file
@@ -0,0 +1,593 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
||||
"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"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
IPLibraryFileStateEnabled = 1 // 已启用
|
||||
IPLibraryFileStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type IPLibraryFileDAO dbs.DAO
|
||||
|
||||
func NewIPLibraryFileDAO() *IPLibraryFileDAO {
|
||||
return dbs.NewDAO(&IPLibraryFileDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeIPLibraryFiles",
|
||||
Model: new(IPLibraryFile),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*IPLibraryFileDAO)
|
||||
}
|
||||
|
||||
var SharedIPLibraryFileDAO *IPLibraryFileDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedIPLibraryFileDAO = NewIPLibraryFileDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// EnableIPLibraryFile 启用条目
|
||||
func (this *IPLibraryFileDAO) EnableIPLibraryFile(tx *dbs.Tx, id uint64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", IPLibraryFileStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableIPLibraryFile 禁用条目
|
||||
func (this *IPLibraryFileDAO) DisableIPLibraryFile(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", IPLibraryFileStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledIPLibraryFile 查找启用中的条目
|
||||
func (this *IPLibraryFileDAO) FindEnabledIPLibraryFile(tx *dbs.Tx, id int64) (*IPLibraryFile, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
State(IPLibraryFileStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*IPLibraryFile), err
|
||||
}
|
||||
|
||||
// CreateLibraryFile 创建文件
|
||||
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 {
|
||||
emptyValues = []string{}
|
||||
}
|
||||
emptyValuesJSON, err := json.Marshal(emptyValues)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.EmptyValues = emptyValuesJSON
|
||||
|
||||
op.FileId = fileId
|
||||
|
||||
if countries == nil {
|
||||
countries = []string{}
|
||||
}
|
||||
countriesJSON, err := json.Marshal(countries)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Countries = countriesJSON
|
||||
|
||||
if provinces == nil {
|
||||
provinces = [][2]string{}
|
||||
}
|
||||
provincesJSON, err := json.Marshal(provinces)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Provinces = provincesJSON
|
||||
|
||||
if cities == nil {
|
||||
cities = [][3]string{}
|
||||
}
|
||||
citiesJSON, err := json.Marshal(cities)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Cities = citiesJSON
|
||||
|
||||
if towns == nil {
|
||||
towns = [][4]string{}
|
||||
}
|
||||
townsJSON, err := json.Marshal(towns)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Towns = townsJSON
|
||||
|
||||
if providers == nil {
|
||||
providers = []string{}
|
||||
}
|
||||
providersJSON, err := json.Marshal(providers)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Providers = providersJSON
|
||||
|
||||
op.IsFinished = false
|
||||
op.State = IPLibraryFileStateEnabled
|
||||
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).
|
||||
State(IPLibraryFileStateEnabled).
|
||||
Result("id", "fileId", "createdAt"). // 这里不需要其他信息
|
||||
Attr("isFinished", false).
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateLibraryFileIsFinished 设置文件为已完成
|
||||
func (this *IPLibraryFileDAO) UpdateLibraryFileIsFinished(tx *dbs.Tx, fileId int64) error {
|
||||
return this.Query(tx).
|
||||
Pk(fileId).
|
||||
Set("isFinished", true).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// FindLibraryFileCountries 获取IP库中的国家/地区
|
||||
func (this *IPLibraryFileDAO) FindLibraryFileCountries(tx *dbs.Tx, fileId int64) ([]string, error) {
|
||||
countriesJSON, err := this.Query(tx).
|
||||
Result("countries").
|
||||
Pk(fileId).
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsNull(countriesJSON) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
err = json.Unmarshal(countriesJSON, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindLibraryFileProvinces 获取IP库中的省份
|
||||
func (this *IPLibraryFileDAO) FindLibraryFileProvinces(tx *dbs.Tx, fileId int64) ([][2]string, error) {
|
||||
provincesJSON, err := this.Query(tx).
|
||||
Result("provinces").
|
||||
Pk(fileId).
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsNull(provincesJSON) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = [][2]string{}
|
||||
err = json.Unmarshal(provincesJSON, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindLibraryFileCities 获取IP库中的城市
|
||||
func (this *IPLibraryFileDAO) FindLibraryFileCities(tx *dbs.Tx, fileId int64) ([][3]string, error) {
|
||||
citiesJSON, err := this.Query(tx).
|
||||
Result("cities").
|
||||
Pk(fileId).
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsNull(citiesJSON) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = [][3]string{}
|
||||
err = json.Unmarshal(citiesJSON, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindLibraryFileTowns 获取IP库中的区县
|
||||
func (this *IPLibraryFileDAO) FindLibraryFileTowns(tx *dbs.Tx, fileId int64) ([][4]string, error) {
|
||||
townsJSON, err := this.Query(tx).
|
||||
Result("towns").
|
||||
Pk(fileId).
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsNull(townsJSON) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = [][4]string{}
|
||||
err = json.Unmarshal(townsJSON, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindLibraryFileProviders 获取IP库中的ISP运营商
|
||||
func (this *IPLibraryFileDAO) FindLibraryFileProviders(tx *dbs.Tx, fileId int64) ([]string, error) {
|
||||
providersJSON, err := this.Query(tx).
|
||||
Result("providers").
|
||||
Pk(fileId).
|
||||
FindJSONCol()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsNull(providersJSON) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
err = json.Unmarshal(providersJSON, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64) error {
|
||||
one, err := this.Query(tx).Pk(libraryFileId).Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if one == nil {
|
||||
return errors.New("the library file not found")
|
||||
}
|
||||
|
||||
var libraryFile = one.(*IPLibraryFile)
|
||||
template, err := iplibrary.NewTemplate(libraryFile.Template)
|
||||
if err != nil {
|
||||
return errors.New("create template from '" + libraryFile.Template + "' failed: " + err.Error())
|
||||
}
|
||||
|
||||
var fileId = int64(libraryFile.FileId)
|
||||
if fileId == 0 {
|
||||
return errors.New("the library file has not been uploaded yet")
|
||||
}
|
||||
|
||||
var dir = Tea.Root + "/data"
|
||||
stat, err := os.Stat(dir)
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = os.Mkdir(dir, 0777)
|
||||
if err != nil {
|
||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
||||
}
|
||||
} else {
|
||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
||||
}
|
||||
} else if !stat.IsDir() {
|
||||
_ = os.Remove(dir)
|
||||
|
||||
err = os.Mkdir(dir, 0777)
|
||||
if err != nil {
|
||||
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 删除以往生成的文件,但要考虑到文件正在被别的任务所使用
|
||||
|
||||
// 国家
|
||||
dbCountries, err := regions.SharedRegionCountryDAO.FindAllCountries(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var countries = []*iplibrary.Country{}
|
||||
for _, country := range dbCountries {
|
||||
countries = append(countries, &iplibrary.Country{
|
||||
Id: country.Id,
|
||||
Name: country.DisplayName(),
|
||||
Codes: country.AllCodes(),
|
||||
})
|
||||
}
|
||||
|
||||
// 省份
|
||||
dbProvinces, err := regions.SharedRegionProvinceDAO.FindAllEnabledProvinces(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var provinces = []*iplibrary.Province{}
|
||||
for _, province := range dbProvinces {
|
||||
provinces = append(provinces, &iplibrary.Province{
|
||||
Id: province.Id,
|
||||
Name: province.DisplayName(),
|
||||
Codes: province.AllCodes(),
|
||||
})
|
||||
}
|
||||
|
||||
// 城市
|
||||
dbCities, err := regions.SharedRegionCityDAO.FindAllEnabledCities(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cities = []*iplibrary.City{}
|
||||
for _, city := range dbCities {
|
||||
cities = append(cities, &iplibrary.City{
|
||||
Id: city.Id,
|
||||
Name: city.DisplayName(),
|
||||
Codes: city.AllCodes(),
|
||||
})
|
||||
}
|
||||
|
||||
// 区县
|
||||
dbTowns, err := regions.SharedRegionTownDAO.FindAllRegionTowns(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var towns = []*iplibrary.Town{}
|
||||
for _, town := range dbTowns {
|
||||
towns = append(towns, &iplibrary.Town{
|
||||
Id: town.Id,
|
||||
Name: town.DisplayName(),
|
||||
Codes: town.AllCodes(),
|
||||
})
|
||||
}
|
||||
|
||||
// ISP运营商
|
||||
dbProviders, err := regions.SharedRegionProviderDAO.FindAllEnabledProviders(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var providers = []*iplibrary.Provider{}
|
||||
for _, provider := range dbProviders {
|
||||
providers = append(providers, &iplibrary.Provider{
|
||||
Id: provider.Id,
|
||||
Name: provider.DisplayName(),
|
||||
Codes: provider.AllCodes(),
|
||||
})
|
||||
}
|
||||
|
||||
var libraryCode = utils.Sha1RandomString() // 每次都生成新的code
|
||||
var filePath = dir + "/" + this.composeFilename(libraryFileId, libraryCode)
|
||||
var meta = &iplibrary.Meta{
|
||||
Author: "", // 将来用户可以自行填写
|
||||
CreatedAt: time.Now().Unix(),
|
||||
Countries: countries,
|
||||
Provinces: provinces,
|
||||
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()
|
||||
if err != nil {
|
||||
return errors.New("write meta failed: " + err.Error())
|
||||
}
|
||||
|
||||
chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// countries etc ...
|
||||
var countryMap = map[string]int64{} // countryName => countryId
|
||||
for _, country := range dbCountries {
|
||||
for _, code := range country.AllCodes() {
|
||||
countryMap[code] = int64(country.Id)
|
||||
}
|
||||
}
|
||||
|
||||
var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
|
||||
for _, province := range dbProvinces {
|
||||
for _, code := range province.AllCodes() {
|
||||
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.Id)
|
||||
}
|
||||
}
|
||||
|
||||
var cityMap = map[string]int64{} // provinceId_cityName => cityId
|
||||
for _, city := range dbCities {
|
||||
for _, code := range city.AllCodes() {
|
||||
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.Id)
|
||||
}
|
||||
}
|
||||
|
||||
var townMap = map[string]int64{} // cityId_townName => townId
|
||||
for _, town := range dbTowns {
|
||||
for _, code := range town.AllCodes() {
|
||||
townMap[types.String(town.CityId)+"_"+code] = int64(town.Id)
|
||||
}
|
||||
}
|
||||
|
||||
var providerMap = map[string]int64{} // providerName => providerId
|
||||
for _, provider := range dbProviders {
|
||||
for _, code := range provider.AllCodes() {
|
||||
providerMap[code] = int64(provider.Id)
|
||||
}
|
||||
}
|
||||
|
||||
dataParser, err := iplibrary.NewParser(&iplibrary.ParserConfig{
|
||||
Template: template,
|
||||
EmptyValues: libraryFile.DecodeEmptyValues(),
|
||||
Iterator: func(values map[string]string) error {
|
||||
var ipFrom = values["ipFrom"]
|
||||
var ipTo = values["ipTo"]
|
||||
|
||||
var countryName = values["country"]
|
||||
var provinceName = values["province"]
|
||||
var cityName = values["city"]
|
||||
var townName = values["town"]
|
||||
var providerName = values["provider"]
|
||||
|
||||
var countryId = countryMap[countryName]
|
||||
var provinceId int64
|
||||
var cityId int64 = 0
|
||||
var townId int64 = 0
|
||||
var providerId = providerMap[providerName]
|
||||
|
||||
if countryId > 0 {
|
||||
provinceId = provinceMap[types.String(countryId)+"_"+provinceName]
|
||||
if provinceId > 0 {
|
||||
cityId = cityMap[types.String(provinceId)+"_"+cityName]
|
||||
if cityId > 0 {
|
||||
townId = townMap[types.String(cityId)+"_"+townName]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
|
||||
if err != nil {
|
||||
return errors.New("write failed: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, chunkId := range chunkIds {
|
||||
chunk, err := SharedFileChunkDAO.FindFileChunk(tx, chunkId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if chunk == nil {
|
||||
return errors.New("invalid chunk file, please upload again")
|
||||
}
|
||||
dataParser.Write(chunk.Data)
|
||||
err = dataParser.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 将生成的内容写入到文件
|
||||
stat, err = os.Stat(filePath)
|
||||
if err != nil {
|
||||
return errors.New("stat generated file failed: " + err.Error())
|
||||
}
|
||||
generatedFileId, err := SharedFileDAO.CreateFile(tx, 0, 0, "ipLibraryFile", "", libraryCode+".db", stat.Size(), "", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fp, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return errors.New("open generated file failed: " + err.Error())
|
||||
}
|
||||
var buf = make([]byte, 256*1024)
|
||||
for {
|
||||
n, err := fp.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = SharedFileChunkDAO.CreateFileChunk(tx, generatedFileId, buf[:n])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
err = SharedFileDAO.UpdateFileIsFinished(tx, generatedFileId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置code
|
||||
err = this.Query(tx).
|
||||
Pk(libraryFileId).
|
||||
Set("code", libraryCode).
|
||||
Set("isFinished", true).
|
||||
Set("generatedFileId", generatedFileId).
|
||||
Set("generatedAt", time.Now().Unix()).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 添加制品
|
||||
_, err = SharedIPLibraryArtifactDAO.CreateArtifact(tx, libraryFile.Name, generatedFileId, libraryFileId, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 组合IP库文件名
|
||||
func (this *IPLibraryFileDAO) composeFilename(libraryFileId int64, code string) string {
|
||||
return "ip-library-" + types.String(libraryFileId) + "-" + code + ".db"
|
||||
}
|
||||
19
internal/db/models/ip_library_file_dao_test.go
Normal file
19
internal/db/models/ip_library_file_dao_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIPLibraryFileDAO_GenerateIPLibrary(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := models.SharedIPLibraryFileDAO.GenerateIPLibrary(tx, 4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
46
internal/db/models/ip_library_file_model.go
Normal file
46
internal/db/models/ip_library_file_model.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package models
|
||||
|
||||
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"` // 空值列表
|
||||
GeneratedFileId uint64 `field:"generatedFileId"` // 生成的文件ID
|
||||
GeneratedAt uint64 `field:"generatedAt"` // 生成时间
|
||||
IsFinished bool `field:"isFinished"` // 是否已经完成
|
||||
Countries dbs.JSON `field:"countries"` // 国家/地区
|
||||
Provinces dbs.JSON `field:"provinces"` // 省份
|
||||
Cities dbs.JSON `field:"cities"` // 城市
|
||||
Towns dbs.JSON `field:"towns"` // 区县
|
||||
Providers dbs.JSON `field:"providers"` // ISP服务商
|
||||
Code string `field:"code"` // 文件代号
|
||||
CreatedAt uint64 `field:"createdAt"` // 上传时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type IPLibraryFileOperator struct {
|
||||
Id any // ID
|
||||
Name any // IP库名称
|
||||
FileId any // 原始文件ID
|
||||
Template any // 模板
|
||||
EmptyValues any // 空值列表
|
||||
GeneratedFileId any // 生成的文件ID
|
||||
GeneratedAt any // 生成时间
|
||||
IsFinished any // 是否已经完成
|
||||
Countries any // 国家/地区
|
||||
Provinces any // 省份
|
||||
Cities any // 城市
|
||||
Towns any // 区县
|
||||
Providers any // ISP服务商
|
||||
Code any // 文件代号
|
||||
CreatedAt any // 上传时间
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewIPLibraryFileOperator() *IPLibraryFileOperator {
|
||||
return &IPLibraryFileOperator{}
|
||||
}
|
||||
69
internal/db/models/ip_library_file_model_ext.go
Normal file
69
internal/db/models/ip_library_file_model_ext.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func (this *IPLibraryFile) DecodeCountries() []string {
|
||||
var countries = []string{}
|
||||
if IsNotNull(this.Countries) {
|
||||
err := json.Unmarshal(this.Countries, &countries)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return countries
|
||||
}
|
||||
|
||||
func (this *IPLibraryFile) DecodeProvinces() [][2]string {
|
||||
var provinces = [][2]string{}
|
||||
if IsNotNull(this.Provinces) {
|
||||
err := json.Unmarshal(this.Provinces, &provinces)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return provinces
|
||||
}
|
||||
|
||||
func (this *IPLibraryFile) DecodeCities() [][3]string {
|
||||
var cities = [][3]string{}
|
||||
if IsNotNull(this.Cities) {
|
||||
err := json.Unmarshal(this.Cities, &cities)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return cities
|
||||
}
|
||||
|
||||
func (this *IPLibraryFile) DecodeTowns() [][4]string {
|
||||
var towns = [][4]string{}
|
||||
if IsNotNull(this.Towns) {
|
||||
err := json.Unmarshal(this.Towns, &towns)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return towns
|
||||
}
|
||||
|
||||
func (this *IPLibraryFile) DecodeProviders() []string {
|
||||
var providers = []string{}
|
||||
if IsNotNull(this.Providers) {
|
||||
err := json.Unmarshal(this.Providers, &providers)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return providers
|
||||
}
|
||||
|
||||
func (this *IPLibraryFile) DecodeEmptyValues() []string {
|
||||
var result = []string{}
|
||||
if IsNotNull(this.EmptyValues) {
|
||||
err := json.Unmarshal(this.EmptyValues, &result)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,22 +1,26 @@
|
||||
package models
|
||||
|
||||
// IP库
|
||||
// IPLibrary IP库
|
||||
type IPLibrary struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
FileId uint32 `field:"fileId"` // 文件ID
|
||||
Type string `field:"type"` // 类型
|
||||
Name string `field:"name"` // 名称
|
||||
IsPublic bool `field:"isPublic"` // 是否公用
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
}
|
||||
|
||||
type IPLibraryOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
FileId interface{} // 文件ID
|
||||
Type interface{} // 类型
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
Id any // ID
|
||||
AdminId any // 管理员ID
|
||||
FileId any // 文件ID
|
||||
Type any // 类型
|
||||
Name any // 名称
|
||||
IsPublic any // 是否公用
|
||||
State any // 状态
|
||||
CreatedAt any // 创建时间
|
||||
}
|
||||
|
||||
func NewIPLibraryOperator() *IPLibraryOperator {
|
||||
|
||||
@@ -165,7 +165,7 @@ func (this *IPListDAO) UpdateIPList(tx *dbs.Tx, listId int64, name string, code
|
||||
if listId <= 0 {
|
||||
return errors.New("invalid listId")
|
||||
}
|
||||
op := NewIPListOperator()
|
||||
var op = NewIPListOperator()
|
||||
op.Id = listId
|
||||
op.Name = name
|
||||
op.Code = code
|
||||
|
||||
@@ -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"
|
||||
@@ -36,9 +37,9 @@ func init() {
|
||||
|
||||
// CreateLog 创建管理员日志
|
||||
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error {
|
||||
op := NewLogOperator()
|
||||
var op = NewLogOperator()
|
||||
op.Level = level
|
||||
op.Description = description
|
||||
op.Description = utils.LimitString(description, 1000)
|
||||
op.Action = action
|
||||
op.Ip = ip
|
||||
op.Type = adminType
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user