Compare commits

...

84 Commits

Author SHA1 Message Date
刘祥超
c66e28cb9d 减少带宽统计显示的空档期 2022-09-05 16:04:34 +08:00
刘祥超
e5109b24d4 版本修改为0.5.2.1 2022-09-05 16:02:55 +08:00
刘祥超
695b8482de 将版本修改为0.5.3 2022-09-05 11:03:12 +08:00
刘祥超
d0b908bcaa 自动添加firewalld使用异步 2022-09-04 06:36:22 +08:00
刘祥超
3de25d4fe1 优化代码 2022-09-03 22:23:16 +08:00
刘祥超
07194855bf 优化代码 2022-09-03 22:03:22 +08:00
刘祥超
d0f1eb13ee 优化节点活跃检测机制 2022-09-03 12:43:06 +08:00
刘祥超
a0930bfd74 远程安装节点出错时打印stderr 2022-08-30 11:40:01 +08:00
刘祥超
08cff8affc 可以通过用户API修改鉴权 2022-08-30 11:23:35 +08:00
刘祥超
02132e9262 用户系统也可以申请ACME证书 2022-08-28 20:02:13 +08:00
刘祥超
61b6a49885 增加修改全体用户功能API 2022-08-28 17:01:09 +08:00
刘祥超
896e54ebe8 提供按小时、按天查询带宽峰值的API 2022-08-28 15:56:16 +08:00
刘祥超
1b36bad60a 指标统计使用事务 2022-08-27 18:50:42 +08:00
刘祥超
fc14800d70 服务列表带宽使用新的算法 2022-08-27 18:39:00 +08:00
刘祥超
fa61f277e4 服务访问日志改成通过事务写入,以提升写入速度 2022-08-27 14:57:47 +08:00
刘祥超
9117309472 可以修改服务的CNAME 2022-08-26 19:51:21 +08:00
刘祥超
6bb2977d59 Ln节点可以指定访问IP 2022-08-25 20:37:10 +08:00
刘祥超
df9dce76cb 集群DNS设置中增加”包含Ln节点“选项 2022-08-25 19:18:30 +08:00
刘祥超
4cb9c85a1c 节点运行日志可以按照节点ID设置为已读 2022-08-25 18:26:52 +08:00
刘祥超
f4f5389ffb 请求限制API支持用户调用 2022-08-25 15:35:55 +08:00
刘祥超
5d336eb77d 优化代码 2022-08-23 21:42:05 +08:00
刘祥超
c552eb3b0e IP库增加制品管理/统计中相关区域名称可以显示别名 2022-08-23 19:40:17 +08:00
刘祥超
455952e9e4 提交SQL 2022-08-22 15:12:20 +08:00
刘祥超
7132401c7f NS节点基本的DDoS防护 2022-08-22 15:11:22 +08:00
刘祥超
a4dddfb139 优化代码 2022-08-22 11:02:16 +08:00
刘祥超
7ef32bad97 IP库改为手动初始化 2022-08-21 23:09:59 +08:00
刘祥超
732513a644 用户节点版本修改为0.4.1 2022-08-21 20:50:00 +08:00
刘祥超
756cf4a9ae 初步完成新版IP库 2022-08-21 20:38:34 +08:00
刘祥超
a15a630265 更新SQL 2022-08-20 19:57:25 +08:00
刘祥超
3fab1b8294 DNS节点版本号改为0.2.6 2022-08-20 15:27:02 +08:00
刘祥超
215635f429 版本修改为0.5.2 2022-08-17 18:58:20 +08:00
刘祥超
dbb1ae180b 版本修改为0.5.1 2022-08-15 19:38:40 +08:00
刘祥超
e8d4d01d85 改进一处日志 2022-08-15 15:17:09 +08:00
刘祥超
6593989a84 修复日志内容可能过长而无法存入数据库的问题 2022-08-15 15:05:47 +08:00
刘祥超
004e640321 修复升级数据库时主键可能冲突的问题 2022-08-15 00:02:38 +08:00
刘祥超
7ad315ae4b IP库管理阶段性提交(未完成) 2022-08-14 20:03:01 +08:00
刘祥超
ba938e5361 新版IP库管理阶段性提交(未完成) 2022-08-13 23:55:48 +08:00
刘祥超
9ddf02a0e6 更新TeaGo 2022-08-11 11:52:35 +08:00
刘祥超
ebcbd5690d 删除不必要的文件 2022-08-09 18:30:23 +08:00
刘祥超
bbca766fa4 删除不必要的文件 2022-08-09 17:35:35 +08:00
刘祥超
99c7819d3a 更新SQL 2022-08-07 19:04:16 +08:00
刘祥超
08bb3e66f8 修改版本号为0.5.0 2022-08-07 19:02:19 +08:00
刘祥超
9159820742 只有发送过离线通知的节点才会发送恢复在线通知 2022-08-07 17:28:54 +08:00
刘祥超
1a565b2ebb 优化代码/启用的日志策略排在最前面 2022-08-07 15:10:05 +08:00
刘祥超
98847c53ea 更新SQL 2022-08-06 20:31:28 +08:00
刘祥超
14bafc8f20 优化代码 2022-08-06 20:28:32 +08:00
刘祥超
58a5bd0092 优化代码 2022-08-05 21:05:34 +08:00
刘祥超
4f1ce52f6a 优化代码 2022-08-05 19:25:31 +08:00
刘祥超
14ba7f6899 优化访问日志策略测试时的失败提示 2022-08-05 19:11:21 +08:00
刘祥超
e582e37c06 优化代码 2022-08-05 14:45:56 +08:00
刘祥超
6a3fa9f0ca 删除不必要的文件 2022-08-05 14:40:42 +08:00
刘祥超
e0a9965fed 简化API 2022-08-04 19:36:25 +08:00
刘祥超
481fa8cd2d 增加查找使用某个证书的NS集群数量的API 2022-08-04 16:25:09 +08:00
刘祥超
95349dc457 允许用户标记上传文件状态 2022-08-04 16:01:07 +08:00
刘祥超
fc839f96d2 优化代码 2022-08-04 15:12:39 +08:00
刘祥超
0414cc02e8 优化代码 2022-08-04 11:41:42 +08:00
刘祥超
b8babaae39 更新SQL 2022-08-03 10:45:09 +08:00
刘祥超
285ce1b312 延长节点执行任务超时时间 2022-08-01 18:57:19 +08:00
刘祥超
c309da81ae 服务带宽API增加按月、按日查询接口 2022-08-01 15:40:57 +08:00
刘祥超
c325fde52b 更新SQL 2022-08-01 11:01:51 +08:00
刘祥超
0f69b45d25 修改用户节点版本号为0.4.0 2022-08-01 11:00:52 +08:00
刘祥超
e02084ba5d 增加用户订单相关表 2022-07-31 19:56:56 +08:00
刘祥超
642b23dbb7 优化代码 2022-07-30 16:28:28 +08:00
刘祥超
b1dc385c87 自动转换用户提交的域名为小写 2022-07-30 16:25:16 +08:00
刘祥超
89a69e3165 删除集群的时候同时删除相关节点运行日志 2022-07-28 09:47:01 +08:00
刘祥超
530954dd6c EdgeDNS:访问日志增加集群和记录类型筛选 2022-07-27 20:19:29 +08:00
刘祥超
33635f7a1b 智能DNS支持自定义端口 2022-07-27 16:56:17 +08:00
刘祥超
8ac964e805 优化远程安装程序 2022-07-27 08:35:15 +08:00
刘祥超
a1519baf0f 远程升级节点时,如果老的文件不存在,则不提示 2022-07-26 20:10:50 +08:00
刘祥超
e6e32a39bb 修改DNS节点版本为0.2.5 2022-07-26 11:15:22 +08:00
刘祥超
d828b7f8a4 修改版本号为0.4.11 2022-07-26 08:57:48 +08:00
刘祥超
07b377c2fb 用户状态发生变化时,同步服务状态 2022-07-24 17:13:05 +08:00
刘祥超
33a3795773 用户增加OTP认证设置 2022-07-24 16:14:56 +08:00
刘祥超
bddb3cae96 用户列表中显示实名审核状态 2022-07-24 11:57:42 +08:00
刘祥超
6a525c2b82 相关接口增加实名认证状态字段 2022-07-24 11:28:59 +08:00
刘祥超
3a137c1c3f 提交SQL 2022-07-24 10:08:40 +08:00
刘祥超
19867568a9 可以重置用户实名认证状态 2022-07-24 10:08:08 +08:00
刘祥超
c2600b911b 优化代码/实现基础的实名认证功能 2022-07-24 09:56:27 +08:00
刘祥超
fe511ae7e5 优化代码 2022-07-22 15:05:30 +08:00
刘祥超
876c631c85 优化代码 2022-07-22 14:35:17 +08:00
刘祥超
a4cc138ef3 API节点自动生成实例代号,用来外界查询多个API节点实例是否为同一个 2022-07-21 19:21:11 +08:00
刘祥超
3f9a7a8a49 升级gosock 2022-07-21 16:30:19 +08:00
刘祥超
09d8ef00c2 API节点状态中增加主程序位置信息 2022-07-21 15:23:08 +08:00
刘祥超
b4f77ddc63 修改版本为v0.4.10 2022-07-20 18:14:27 +08:00
350 changed files with 7623 additions and 12309 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
*_plus.go
*-plus.sh
*-plus.sh
*_plus_test.go

View File

@@ -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

View File

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

View File

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

View File

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

6
go.mod
View File

@@ -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
View File

@@ -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=

View File

@@ -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
})
}

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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 + "'")
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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);
?>

View File

@@ -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)

View File

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

View File

@@ -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,
}

View File

@@ -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)
}

View File

@@ -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版本号

View File

@@ -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()))))
)

View 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()
})
}

View File

@@ -1,4 +1,4 @@
package nameservers
package accounts_test
import (
_ "github.com/go-sql-driver/mysql"

View 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{}
}

View File

@@ -0,0 +1 @@
package accounts

View 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()
})
}

View File

@@ -1,4 +1,4 @@
package nameservers
package accounts_test
import (
_ "github.com/go-sql-driver/mysql"

View 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()
})
}

View File

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

View 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{}
}

View File

@@ -0,0 +1 @@
package accounts

View 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{}
}

View File

@@ -0,0 +1 @@
package accounts

View File

@@ -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

View File

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

View File

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

View File

@@ -107,7 +107,11 @@ func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) err
// CountAllEnabledACMETasks 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string) (int64, error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
var query = this.Query(tx)
if adminId > 0 {
query.Attr("adminId", adminId)
}
query.Attr("userId", userId) // 这个条件必须加上
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -138,7 +142,11 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, use
// ListEnabledACMETasks 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, offset int64, size int64) (result []*ACMETask, err error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
var query = this.Query(tx)
if adminId > 0 {
query.Attr("adminId", adminId)
}
query.Attr("userId", userId) // 这个条件必须加上
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -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,
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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}

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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).

View File

@@ -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).

View File

@@ -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{} // 类型

View File

@@ -39,9 +39,10 @@ var SharedHTTPAccessLogDAO *HTTPAccessLogDAO
var (
oldAccessLogQueue = make(chan *pb.HTTPAccessLog)
accessLogQueue = make(chan *pb.HTTPAccessLog, 10_000)
accessLogQueueMaxLength = 100_000
accessLogQueuePercent = 100 // 0-100
accessLogCountPerSecond = 10_000 // 0 表示不限制
accessLogQueueMaxLength = 100_000 //队列最大长度
accessLogQueuePercent = 100 // 0-100
accessLogCountPerSecond = 10_000 // 每秒钟写入条数,0 表示不限制
accessLogPerTx = 100 // 单事务写入条数
accessLogConfigJSON = []byte{}
accessLogQueueChanged = make(chan zero.Zero, 1)
@@ -85,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
}

View File

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

View File

@@ -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).

View File

@@ -68,8 +68,9 @@ func (this *HTTPAuthPolicyDAO) FindEnabledHTTPAuthPolicy(tx *dbs.Tx, id int64) (
}
// CreateHTTPAuthPolicy 创建策略
func (this *HTTPAuthPolicyDAO) CreateHTTPAuthPolicy(tx *dbs.Tx, name string, methodType string, paramsJSON []byte) (int64, error) {
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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -1,4 +1,4 @@
package nameservers
package models_test
import (
_ "github.com/go-sql-driver/mysql"

View File

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

View File

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

View File

@@ -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

View 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"
}

View 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)
}
}

View 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{}
}

View 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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -3,6 +3,7 @@ package models
import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -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