阶段性提交

This commit is contained in:
GoEdgeLab
2020-07-22 22:17:53 +08:00
parent a39aeb54c8
commit 9a751902f4
85 changed files with 3419 additions and 76 deletions

1
build/.gitignore vendored
View File

@@ -1 +0,0 @@
configs/api.yaml

2
build/configs/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
api.yaml
db.yaml

View File

@@ -0,0 +1,11 @@
default:
db: "dev"
prefix: ""
dbs:
dev:
driver: "mysql"
dsn: "root:123456@tcp(127.0.0.1:3306)/db_shield?charset=utf8mb4&timeout=30s"
prefix: "shield"
models:
package: internal/web/models

1
build/logs/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.log

View File

@@ -2,9 +2,17 @@ package main
import (
"github.com/TeaOSLab/EdgeAPI/internal/apis"
"github.com/TeaOSLab/EdgeAPI/internal/apps"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
_ "github.com/iwind/TeaGo/bootstrap"
)
func main() {
apis.NewAPINode().Start()
app := apps.NewAppCmd()
app.Version(teaconst.Version)
app.Product(teaconst.ProductName)
app.Usage(teaconst.ProcessName + " [start|stop|restart]")
app.Run(func() {
apis.NewAPINode().Start()
})
}

107
cmd/tt/main.go Normal file
View File

@@ -0,0 +1,107 @@
package main
import (
"bufio"
"bytes"
"fmt"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/cmd"
_ "github.com/iwind/TeaGo/dbs/commands"
"github.com/iwind/TeaGo/lists"
"os"
"path/filepath"
"time"
)
// TeaTool工具
func main() {
r := bufio.NewReader(os.Stdin)
lastCommand := ""
for {
time.Sleep(400 * time.Millisecond)
fmt.Print("> ")
line, _, err := r.ReadLine()
if err != nil {
continue
}
command := string(bytes.TrimSpace(line))
// 命令帮助
if len(command) == 0 || command == "help" || command == "h" || command == "?" || command == "/?" {
lastCommand = command
fmt.Println("TeaTool commands:")
commands := cmd.AllCommands()
// 对命令代码进行排序
codes := []string{}
for code := range commands {
codes = append(codes, code)
}
lists.Sort(codes, func(i int, j int) bool {
code1 := codes[i]
code2 := codes[j]
return code1 < code2
})
//输出
for _, code := range codes {
ptr := commands[code]
fmt.Println(" ", code+"\n\t\t"+ptr.Name())
}
continue
}
if command == "retry" || command == "!!" /** csh like **/ || command == "!-1" /** csh like **/ {
command = lastCommand
fmt.Println("retry '" + command + "'")
}
lastCommand = command
found := cmd.Try(cmd.ParseArgs(command))
if !found {
fmt.Println("command '" + command + "' not found")
}
}
}
// 重置Root
func init() {
webIsSet := false
if !Tea.IsTesting() {
exePath, err := os.Executable()
if err != nil {
exePath = os.Args[0]
}
link, err := filepath.EvalSymlinks(exePath)
if err == nil {
exePath = link
}
fullPath, err := filepath.Abs(exePath)
if err == nil {
Tea.UpdateRoot(filepath.Dir(filepath.Dir(fullPath)))
}
} else {
pwd, ok := os.LookupEnv("PWD")
if ok {
webIsSet = true
Tea.SetPublicDir(pwd + Tea.DS + "web" + Tea.DS + "public")
Tea.SetViewsDir(pwd + Tea.DS + "web" + Tea.DS + "views")
Tea.SetTmpDir(pwd + Tea.DS + "web" + Tea.DS + "tmp")
Tea.Root = pwd + Tea.DS + "build"
}
}
if !webIsSet {
Tea.SetPublicDir(Tea.Root + Tea.DS + "web" + Tea.DS + "public")
Tea.SetViewsDir(Tea.Root + Tea.DS + "web" + Tea.DS + "views")
Tea.SetTmpDir(Tea.Root + Tea.DS + "web" + Tea.DS + "tmp")
}
Tea.SetConfigDir(Tea.Root + Tea.DS + "configs")
_ = os.Setenv("GOPATH", filepath.Dir(Tea.Root))
}

5
go.mod
View File

@@ -3,9 +3,10 @@ module github.com/TeaOSLab/EdgeAPI
go 1.14
require (
github.com/go-sql-driver/mysql v1.5.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/golang/protobuf v1.4.1
github.com/iwind/TeaGo v0.0.0-20200720020412-96dbe21b81d4
github.com/golang/protobuf v1.4.2
github.com/iwind/TeaGo v0.0.0-20200722034406-6bf13920e40d
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect
google.golang.org/grpc v1.30.0

34
go.sum
View File

@@ -8,6 +8,11 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -23,6 +28,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -30,13 +37,24 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20200720020412-96dbe21b81d4 h1:893FbgV8PRV/rCqEAtpifgAmsIYTDrZruWHMWIw4+x8=
github.com/iwind/TeaGo v0.0.0-20200720020412-96dbe21b81d4/go.mod h1:taNzU+Tt7Axz5t1v8pEV7xRuioNJxbMeMAbDVQpxq20=
github.com/iwind/TeaGo v0.0.0-20200722010955-47dd648dc761 h1:70Iaf6iVF4CiH1P5Au3hqile/2Ea0XIkR4SPpdiaKI0=
github.com/iwind/TeaGo v0.0.0-20200722010955-47dd648dc761/go.mod h1:zjM7k+b+Jthhf0T0fKwuF0iy4TWb5SsU1gmKR2l+OmE=
github.com/iwind/TeaGo v0.0.0-20200722034406-6bf13920e40d h1:W//0gTbKQ44b3gHNz1/fMiKEu+mM5t5O3py4kJscSa0=
github.com/iwind/TeaGo v0.0.0-20200722034406-6bf13920e40d/go.mod h1:zjM7k+b+Jthhf0T0fKwuF0iy4TWb5SsU1gmKR2l+OmE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -47,19 +65,31 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -85,12 +115,16 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -3,6 +3,7 @@ package apis
import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/configs"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/admin"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/dns"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/log"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/monitor"
@@ -10,6 +11,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/rpc/provider"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/stat"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/user"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/iwind/TeaGo/logs"
"google.golang.org/grpc"
"net"
@@ -36,6 +38,9 @@ func (this *APINode) Start() {
}
sharedAPIConfig = config
// 设置rlimit
_ = utils.SetRLimit(1024 * 1024)
// 监听RPC服务
logs.Println("[API]start rpc: " + config.RPC.Listen)
err = this.listenRPC()
@@ -59,6 +64,7 @@ func (this *APINode) listenRPC() error {
provider.RegisterServiceServer(rpcServer, &provider.Service{})
stat.RegisterServiceServer(rpcServer, &stat.Service{})
user.RegisterServiceServer(rpcServer, &user.Service{})
admin.RegisterServiceServer(rpcServer, &admin.Service{})
err = rpcServer.Serve(listener)
if err != nil {
return errors.New("[API]start rpc failed: " + err.Error())

234
internal/apps/app_cmd.go Normal file
View File

@@ -0,0 +1,234 @@
package apps
import (
"fmt"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/logs"
"os"
"os/exec"
"runtime"
"strconv"
"time"
)
// App命令帮助
type AppCmd struct {
product string
version string
usage string
options []*CommandHelpOption
appendStrings []string
directives []*Directive
}
func NewAppCmd() *AppCmd {
return &AppCmd{}
}
type CommandHelpOption struct {
Code string
Description string
}
// 产品
func (this *AppCmd) Product(product string) *AppCmd {
this.product = product
return this
}
// 版本
func (this *AppCmd) Version(version string) *AppCmd {
this.version = version
return this
}
// 使用方法
func (this *AppCmd) Usage(usage string) *AppCmd {
this.usage = usage
return this
}
// 选项
func (this *AppCmd) Option(code string, description string) *AppCmd {
this.options = append(this.options, &CommandHelpOption{
Code: code,
Description: description,
})
return this
}
// 附加内容
func (this *AppCmd) Append(appendString string) *AppCmd {
this.appendStrings = append(this.appendStrings, appendString)
return this
}
// 打印
func (this *AppCmd) Print() {
fmt.Println(this.product + " v" + this.version)
usage := this.usage
fmt.Println("Usage:", "\n "+usage)
if len(this.options) > 0 {
fmt.Println("")
fmt.Println("Options:")
spaces := 20
max := 40
for _, option := range this.options {
l := len(option.Code)
if l < max && l > spaces {
spaces = l + 4
}
}
for _, option := range this.options {
if len(option.Code) > max {
fmt.Println("")
fmt.Println(" " + option.Code)
option.Code = ""
}
fmt.Printf(" %-"+strconv.Itoa(spaces)+"s%s\n", option.Code, ": "+option.Description)
}
}
if len(this.appendStrings) > 0 {
fmt.Println("")
for _, s := range this.appendStrings {
fmt.Println(s)
}
}
}
// 添加指令
func (this *AppCmd) On(arg string, callback func()) {
this.directives = append(this.directives, &Directive{
Arg: arg,
Callback: callback,
})
}
// 运行
func (this *AppCmd) Run(main func()) {
// 获取参数
args := os.Args[1:]
if len(args) > 0 {
switch args[0] {
case "-v", "version", "-version", "--version":
this.runVersion()
return
case "?", "help", "-help", "h", "-h":
this.runHelp()
return
case "start":
this.runStart()
return
case "stop":
this.runStop()
return
case "restart":
this.runRestart()
return
case "status":
this.runStatus()
return
}
// 查找指令
for _, directive := range this.directives {
if directive.Arg == args[0] {
directive.Callback()
return
}
}
fmt.Println("unknown command '" + args[0] + "'")
return
}
// 记录PID
_ = this.writePid()
// 日志
writer := new(LogWriter)
writer.Init()
logs.SetWriter(writer)
// 运行主函数
main()
}
// 版本号
func (this *AppCmd) runVersion() {
fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH+")")
}
// 帮助
func (this *AppCmd) runHelp() {
this.Print()
}
// 启动
func (this *AppCmd) runStart() {
proc := this.checkPid()
if proc != nil {
fmt.Println(this.product+" already started, pid:", proc.Pid)
return
}
cmd := exec.Command(os.Args[0])
err := cmd.Start()
if err != nil {
fmt.Println(this.product+" start failed:", err.Error())
return
}
fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid)
}
// 停止
func (this *AppCmd) runStop() {
proc := this.checkPid()
if proc == nil {
fmt.Println(this.product + " not started yet")
return
}
// 停止进程
_ = proc.Kill()
// 在Windows上经常不能及时释放资源
_ = DeletePid(Tea.Root + "/bin/pid")
fmt.Println(this.product+" stopped ok, pid:", proc.Pid)
}
// 重启
func (this *AppCmd) runRestart() {
this.runStop()
time.Sleep(1 * time.Second)
this.runStart()
}
// 状态
func (this *AppCmd) runStatus() {
proc := this.checkPid()
if proc == nil {
fmt.Println(this.product + " not started yet")
} else {
fmt.Println(this.product + " is running, pid: " + fmt.Sprintf("%d", proc.Pid))
}
}
// 检查PID
func (this *AppCmd) checkPid() *os.Process {
return CheckPid(Tea.Root + "/bin/pid")
}
// 写入PID
func (this *AppCmd) writePid() error {
return WritePid(Tea.Root + "/bin/pid")
}

View File

@@ -0,0 +1,6 @@
package apps
type Directive struct {
Arg string
Callback func()
}

View File

@@ -0,0 +1,17 @@
// +build !windows
package apps
import (
"os"
"syscall"
)
// lock file
func LockFile(fp *os.File) error {
return syscall.Flock(int(fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
}
func UnlockFile(fp *os.File) error {
return syscall.Flock(int(fp.Fd()), syscall.LOCK_UN)
}

View File

@@ -0,0 +1,17 @@
// +build windows
package apps
import (
"errors"
"os"
)
// lock file
func LockFile(fp *os.File) error {
return errors.New("not implemented on windows")
}
func UnlockFile(fp *os.File) error {
return errors.New("not implemented on windows")
}

View File

@@ -0,0 +1,51 @@
package apps
import (
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/utils/time"
"log"
)
type LogWriter struct {
fileAppender *files.Appender
}
func (this *LogWriter) Init() {
// 创建目录
dir := files.NewFile(Tea.LogDir())
if !dir.Exists() {
err := dir.Mkdir()
if err != nil {
log.Println("[error]" + err.Error())
}
}
logFile := files.NewFile(Tea.LogFile("run.log"))
// 打开要写入的日志文件
appender, err := logFile.Appender()
if err != nil {
logs.Error(err)
} else {
this.fileAppender = appender
}
}
func (this *LogWriter) Write(message string) {
log.Println(message)
if this.fileAppender != nil {
_, err := this.fileAppender.AppendString(timeutil.Format("Y/m/d H:i:s ") + message + "\n")
if err != nil {
log.Println("[error]" + err.Error())
}
}
}
func (this *LogWriter) Close() {
if this.fileAppender != nil {
_ = this.fileAppender.Close()
}
}

113
internal/apps/pid.go Normal file
View File

@@ -0,0 +1,113 @@
package apps
import (
"fmt"
"github.com/iwind/TeaGo/types"
"io/ioutil"
"os"
"runtime"
)
var pidFileList = []*os.File{}
// 检查Pid
func CheckPid(path string) *os.Process {
// windows上打开的文件是不能删除的
if runtime.GOOS == "windows" {
if os.Remove(path) == nil {
return nil
}
}
file, err := os.Open(path)
if err != nil {
return nil
}
defer func() {
_ = file.Close()
}()
// 是否能取得Lock
err = LockFile(file)
if err == nil {
_ = UnlockFile(file)
return nil
}
pidBytes, err := ioutil.ReadAll(file)
if err != nil {
return nil
}
pid := types.Int(string(pidBytes))
if pid <= 0 {
return nil
}
proc, _ := os.FindProcess(pid)
return proc
}
// 写入Pid
func WritePid(path string) error {
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
if err != nil {
return err
}
if runtime.GOOS != "windows" {
err = LockFile(fp)
if err != nil {
return err
}
}
pidFileList = append(pidFileList, fp) // hold the file pointers
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getpid()))
if err != nil {
return err
}
return nil
}
// 写入Ppid
func WritePpid(path string) error {
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
if err != nil {
return err
}
if runtime.GOOS != "windows" {
err = LockFile(fp)
if err != nil {
return err
}
}
pidFileList = append(pidFileList, fp) // hold the file pointers
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getppid()))
if err != nil {
return err
}
return nil
}
// 删除Pid
func DeletePid(path string) error {
_, err := os.Stat(path)
if err != nil {
if !os.IsNotExist(err) {
return nil
}
return err
}
for _, fp := range pidFileList {
_ = UnlockFile(fp)
_ = fp.Close()
}
return os.Remove(path)
}

16
internal/const/const.go Normal file
View File

@@ -0,0 +1,16 @@
package teaconst
const (
Version = "0.0.1"
ProductName = "Edge API"
ProcessName = "edge-api"
ProductNameZH = "Edge"
Role = "api"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
EncryptMethod = "aes-256-cfb"
ErrServer = "服务器出了点小问题,请稍后重试"
)

View File

@@ -0,0 +1,84 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
AdminStateEnabled = 1 // 已启用
AdminStateDisabled = 0 // 已禁用
)
type AdminDAO dbs.DAO
func NewAdminDAO() *AdminDAO {
return dbs.NewDAO(&AdminDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeAdmins",
Model: new(Admin),
PkName: "id",
},
}).(*AdminDAO)
}
var SharedAdminDAO = NewAdminDAO()
// 启用条目
func (this *AdminDAO) EnableAdmin(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", AdminStateEnabled).
Update()
}
// 禁用条目
func (this *AdminDAO) DisableAdmin(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", AdminStateDisabled).
Update()
}
// 查找启用中的条目
func (this *AdminDAO) FindEnabledAdmin(id uint32) (*Admin, error) {
result, err := this.Query().
Pk(id).
Attr("state", AdminStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Admin), err
}
// 检查管理员是否存在
func (this *AdminDAO) ExistEnabledAdmin(adminId int) (bool, error) {
return this.Query().
Pk(adminId).
State(AdminStateEnabled).
Exist()
}
// 获取管理员名称
func (this *AdminDAO) FindAdminFullname(adminId int) (string, error) {
return this.Query().
Pk(adminId).
Result("fullname").
FindStringCol("")
}
// 检查用户名、密码
func (this *AdminDAO) CheckAdminPassword(username string, encryptedPassword string) (int, error) {
if len(username) == 0 || len(encryptedPassword) == 0 {
return 0, nil
}
return this.Query().
Attr("username", username).
Attr("password", encryptedPassword).
Attr("state", AdminStateEnabled).
ResultPk().
FindIntCol(0)
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,28 @@
package models
// 管理员
type Admin struct {
Id uint32 `field:"id"` // ID
Username string `field:"username"` // 用户名
Password string `field:"password"` // 密码
Fullname string `field:"fullname"` // 全名
IsSuper uint8 `field:"isSuper"` // 是否为超级管理员
CreatedAt uint32 `field:"createdAt"` // 创建时间
UpdatedAt uint32 `field:"updatedAt"` // 修改时间
State uint8 `field:"state"` // 状态
}
type AdminOperator struct {
Id interface{} // ID
Username interface{} // 用户名
Password interface{} // 密码
Fullname interface{} // 全名
IsSuper interface{} // 是否为超级管理员
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
State interface{} // 状态
}
func NewAdminOperator() *AdminOperator {
return &AdminOperator{}
}

View File

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

View File

@@ -0,0 +1,68 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
ApiTokenStateEnabled = 1 // 已启用
ApiTokenStateDisabled = 0 // 已禁用
)
type ApiTokenDAO dbs.DAO
func NewApiTokenDAO() *ApiTokenDAO {
return dbs.NewDAO(&ApiTokenDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeApiTokens",
Model: new(ApiToken),
PkName: "id",
},
}).(*ApiTokenDAO)
}
var SharedApiTokenDAO = NewApiTokenDAO()
// 启用条目
func (this *ApiTokenDAO) EnableApiToken(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ApiTokenStateEnabled).
Update()
}
// 禁用条目
func (this *ApiTokenDAO) DisableApiToken(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ApiTokenStateDisabled).
Update()
}
// 查找启用中的条目
func (this *ApiTokenDAO) FindEnabledApiToken(id uint32) (*ApiToken, error) {
result, err := this.Query().
Pk(id).
Attr("state", ApiTokenStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*ApiToken), err
}
// 获取节点Token信息
// TODO 需要添加缓存
func (this *ApiTokenDAO) FindEnabledTokenWithNode(nodeId string) (*ApiToken, error) {
one, err := this.Query().
Attr("nodeId", nodeId).
State(ApiTokenStateEnabled).
Find()
if one != nil {
return one.(*ApiToken), nil
}
return nil, err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,22 @@
package models
// API令牌管理
type ApiToken struct {
Id uint32 `field:"id"` // ID
NodeId string `field:"nodeId"` // 节点ID
Secret string `field:"secret"` // 节点密钥
Role string `field:"role"` // 节点角色
State uint8 `field:"state"` // 状态
}
type ApiTokenOperator struct {
Id interface{} // ID
NodeId interface{} // 节点ID
Secret interface{} // 节点密钥
Role interface{} // 节点角色
State interface{} // 状态
}
func NewApiTokenOperator() *ApiTokenOperator {
return &ApiTokenOperator{}
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -0,0 +1,31 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
type LogDAO dbs.DAO
func NewLogDAO() *LogDAO {
return dbs.NewDAO(&LogDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeLogs",
Model: new(Log),
PkName: "id",
},
}).(*LogDAO)
}
var SharedLogDAO = NewLogDAO()
// 创建管理员日志
func (this *LogDAO) CreateAdminLog(adminId int, level string, description string, action string, ip string) error {
op := NewLogOperator()
op.AdminId, op.Level, op.Description, op.Action, op.Ip = adminId, level, description, action, ip
op.Type = LogTypeAdmin
_, err := this.Save(op)
return err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,32 @@
package models
// 操作日志
type Log struct {
Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别
Description string `field:"description"` // 描述
CreatedAt uint32 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user
}
type LogOperator struct {
Id interface{} // ID
Level interface{} // 级别
Description interface{} // 描述
CreatedAt interface{} // 创建时间
Action interface{} // 动作
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
ProviderId interface{} // 供应商ID
Ip interface{} // IP地址
Type interface{} // 类型admin, user
}
func NewLogOperator() *LogOperator {
return &LogOperator{}
}

View File

@@ -0,0 +1,74 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeClusterStateEnabled = 1 // 已启用
NodeClusterStateDisabled = 0 // 已禁用
)
type NodeClusterDAO dbs.DAO
func NewNodeClusterDAO() *NodeClusterDAO {
return dbs.NewDAO(&NodeClusterDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeClusters",
Model: new(NodeCluster),
PkName: "id",
},
}).(*NodeClusterDAO)
}
var SharedNodeClusterDAO = NewNodeClusterDAO()
// 启用条目
func (this *NodeClusterDAO) EnableNodeCluster(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeClusterStateEnabled).
Update()
}
// 禁用条目
func (this *NodeClusterDAO) DisableNodeCluster(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeClusterStateDisabled).
Update()
}
// 查找启用中的条目
func (this *NodeClusterDAO) FindEnabledNodeCluster(id uint32) (*NodeCluster, error) {
result, err := this.Query().
Pk(id).
Attr("state", NodeClusterStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeCluster), err
}
// 根据主键查找名称
func (this *NodeClusterDAO) FindNodeClusterName(id uint32) (string, error) {
return this.Query().
Pk(id).
Result("name").
FindStringCol("")
}
// 查找所有可用的集群
func (this *NodeClusterDAO) FindAllEnableClusters() (result []*NodeCluster, err error) {
_, err = this.Query().
State(NodeClusterStateEnabled).
Slice(&result).
Desc("order").
DescPk().
FindAll()
return
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,22 @@
package models
// 节点集群
type NodeCluster struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
Order uint32 `field:"order"` // 排序
CreatedAt uint32 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
}
type NodeClusterOperator struct {
Id interface{} // ID
Name interface{} // 名称
Order interface{} // 排序
CreatedAt interface{} // 创建时间
State interface{} // 状态
}
func NewNodeClusterOperator() *NodeClusterOperator {
return &NodeClusterOperator{}
}

View File

@@ -0,0 +1,64 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeStateEnabled = 1 // 已启用
NodeStateDisabled = 0 // 已禁用
)
type NodeDAO dbs.DAO
func NewNodeDAO() *NodeDAO {
return dbs.NewDAO(&NodeDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodes",
Model: new(Node),
PkName: "id",
},
}).(*NodeDAO)
}
var SharedNodeDAO = NewNodeDAO()
// 启用条目
func (this *NodeDAO) EnableNode(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeStateEnabled).
Update()
}
// 禁用条目
func (this *NodeDAO) DisableNode(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeStateDisabled).
Update()
}
// 查找启用中的条目
func (this *NodeDAO) FindEnabledNode(id uint32) (*Node, error) {
result, err := this.Query().
Pk(id).
Attr("state", NodeStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Node), err
}
// 根据主键查找名称
func (this *NodeDAO) FindNodeName(id uint32) (string, error) {
name, err := this.Query().
Pk(id).
Result("name").
FindCol("")
return name.(string), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,64 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeGrantStateEnabled = 1 // 已启用
NodeGrantStateDisabled = 0 // 已禁用
)
type NodeGrantDAO dbs.DAO
func NewNodeGrantDAO() *NodeGrantDAO {
return dbs.NewDAO(&NodeGrantDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeGrants",
Model: new(NodeGrant),
PkName: "id",
},
}).(*NodeGrantDAO)
}
var SharedNodeGrantDAO = NewNodeGrantDAO()
// 启用条目
func (this *NodeGrantDAO) EnableNodeGrant(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeGrantStateEnabled).
Update()
}
// 禁用条目
func (this *NodeGrantDAO) DisableNodeGrant(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeGrantStateDisabled).
Update()
}
// 查找启用中的条目
func (this *NodeGrantDAO) FindEnabledNodeGrant(id uint32) (*NodeGrant, error) {
result, err := this.Query().
Pk(id).
Attr("state", NodeGrantStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeGrant), err
}
// 根据主键查找名称
func (this *NodeGrantDAO) FindNodeGrantName(id uint32) (string, error) {
name, err := this.Query().
Pk(id).
Result("name").
FindCol("")
return name.(string), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,30 @@
package models
//
type NodeGrant struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
Username string `field:"username"` // 用户名
Password string `field:"password"` // 密码
Su uint8 `field:"su"` // 是否需要su
PrivateKey string `field:"privateKey"` // 密钥
Description string `field:"description"` // 备注
NodeId uint32 `field:"nodeId"` // 专有节点
State uint8 `field:"state"` // 状态
}
type NodeGrantOperator struct {
Id interface{} // ID
Name interface{} // 名称
Username interface{} // 用户名
Password interface{} // 密码
Su interface{} // 是否需要su
PrivateKey interface{} // 密钥
Description interface{} // 备注
NodeId interface{} // 专有节点
State interface{} // 状态
}
func NewNodeGrantOperator() *NodeGrantOperator {
return &NodeGrantOperator{}
}

View File

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

View File

@@ -0,0 +1,64 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeGroupStateEnabled = 1 // 已启用
NodeGroupStateDisabled = 0 // 已禁用
)
type NodeGroupDAO dbs.DAO
func NewNodeGroupDAO() *NodeGroupDAO {
return dbs.NewDAO(&NodeGroupDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeGroups",
Model: new(NodeGroup),
PkName: "id",
},
}).(*NodeGroupDAO)
}
var SharedNodeGroupDAO = NewNodeGroupDAO()
// 启用条目
func (this *NodeGroupDAO) EnableNodeGroup(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeGroupStateEnabled).
Update()
}
// 禁用条目
func (this *NodeGroupDAO) DisableNodeGroup(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeGroupStateDisabled).
Update()
}
// 查找启用中的条目
func (this *NodeGroupDAO) FindEnabledNodeGroup(id uint32) (*NodeGroup, error) {
result, err := this.Query().
Pk(id).
Attr("state", NodeGroupStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeGroup), err
}
// 根据主键查找名称
func (this *NodeGroupDAO) FindNodeGroupName(id uint32) (string, error) {
name, err := this.Query().
Pk(id).
Result("name").
FindCol("")
return name.(string), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,22 @@
package models
// 节点分组
type NodeGroup struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
Order uint32 `field:"order"` // 排序
CreatedAt uint32 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
}
type NodeGroupOperator struct {
Id interface{} // ID
Name interface{} // 名称
Order interface{} // 排序
CreatedAt interface{} // 创建时间
State interface{} // 状态
}
func NewNodeGroupOperator() *NodeGroupOperator {
return &NodeGroupOperator{}
}

View File

@@ -0,0 +1,64 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeLoginStateEnabled = 1 // 已启用
NodeLoginStateDisabled = 0 // 已禁用
)
type NodeLoginDAO dbs.DAO
func NewNodeLoginDAO() *NodeLoginDAO {
return dbs.NewDAO(&NodeLoginDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeLogins",
Model: new(NodeLogin),
PkName: "id",
},
}).(*NodeLoginDAO)
}
var SharedNodeLoginDAO = NewNodeLoginDAO()
// 启用条目
func (this *NodeLoginDAO) EnableNodeLogin(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeLoginStateEnabled).
Update()
}
// 禁用条目
func (this *NodeLoginDAO) DisableNodeLogin(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", NodeLoginStateDisabled).
Update()
}
// 查找启用中的条目
func (this *NodeLoginDAO) FindEnabledNodeLogin(id uint32) (*NodeLogin, error) {
result, err := this.Query().
Pk(id).
Attr("state", NodeLoginStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeLogin), err
}
// 根据主键查找名称
func (this *NodeLoginDAO) FindNodeLoginName(id uint32) (string, error) {
name, err := this.Query().
Pk(id).
Result("name").
FindCol("")
return name.(string), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,24 @@
package models
//
type NodeLogin struct {
Id uint32 `field:"id"` // ID
NodeId uint32 `field:"nodeId"` // 节点ID
Name string `field:"name"` // 名称
Type string `field:"type"` // 类型ssh,agent
Params string `field:"params"` // 配置参数
State uint8 `field:"state"` // 状态
}
type NodeLoginOperator struct {
Id interface{} // ID
NodeId interface{} // 节点ID
Name interface{} // 名称
Type interface{} // 类型ssh,agent
Params interface{} // 配置参数
State interface{} // 状态
}
func NewNodeLoginOperator() *NodeLoginOperator {
return &NodeLoginOperator{}
}

View File

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

View File

@@ -0,0 +1,34 @@
package models
// 节点
type Node struct {
Id uint32 `field:"id"` // ID
NodeId string `field:"nodeId"` // 节点ID
Secret string `field:"secret"` // 密钥
Name string `field:"name"` // 节点名
Code string `field:"code"` // 代号
ClusterId uint32 `field:"clusterId"` // 集群ID
RegionId uint32 `field:"regionId"` // 区域ID
GroupId uint32 `field:"groupId"` // 分组ID
CreatedAt uint32 `field:"createdAt"` // 创建时间
Status string `field:"status"` // 最新的状态
State uint8 `field:"state"` // 状态
}
type NodeOperator struct {
Id interface{} // ID
NodeId interface{} // 节点ID
Secret interface{} // 密钥
Name interface{} // 节点名
Code interface{} // 代号
ClusterId interface{} // 集群ID
RegionId interface{} // 区域ID
GroupId interface{} // 分组ID
CreatedAt interface{} // 创建时间
Status interface{} // 最新的状态
State interface{} // 状态
}
func NewNodeOperator() *NodeOperator {
return &NodeOperator{}
}

View File

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

View File

@@ -0,0 +1,11 @@
package models
const (
LevelDebug = "debug"
LevelInfo = "info"
LevelWarning = "warning"
LevelError = "error"
LogTypeAdmin = "admin"
LogTypeUser = "user"
)

View File

@@ -0,0 +1,55 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
ProviderStateEnabled = 1 // 已启用
ProviderStateDisabled = 0 // 已禁用
)
type ProviderDAO dbs.DAO
func NewProviderDAO() *ProviderDAO {
return dbs.NewDAO(&ProviderDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeProviders",
Model: new(Provider),
PkName: "id",
},
}).(*ProviderDAO)
}
var SharedProviderDAO = NewProviderDAO()
// 启用条目
func (this *ProviderDAO) EnableProvider(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ProviderStateEnabled).
Update()
}
// 禁用条目
func (this *ProviderDAO) DisableProvider(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ProviderStateDisabled).
Update()
}
// 查找启用中的条目
func (this *ProviderDAO) FindEnabledProvider(id uint32) (*Provider, error) {
result, err := this.Query().
Pk(id).
Attr("state", ProviderStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Provider), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,26 @@
package models
// 供应商
type Provider struct {
Id uint32 `field:"id"` // ID
Username string `field:"username"` // 用户名
Password string `field:"password"` // 密码
Fullname string `field:"fullname"` // 真实姓名
CreatedAt uint32 `field:"createdAt"` // 创建时间
UpdatedAt uint32 `field:"updatedAt"` // 修改时间
State uint8 `field:"state"` // 状态
}
type ProviderOperator struct {
Id interface{} // ID
Username interface{} // 用户名
Password interface{} // 密码
Fullname interface{} // 真实姓名
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
State interface{} // 状态
}
func NewProviderOperator() *ProviderOperator {
return &ProviderOperator{}
}

View File

@@ -0,0 +1,55 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
ServerStateEnabled = 1 // 已启用
ServerStateDisabled = 0 // 已禁用
)
type ServerDAO dbs.DAO
func NewServerDAO() *ServerDAO {
return dbs.NewDAO(&ServerDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeServers",
Model: new(Server),
PkName: "id",
},
}).(*ServerDAO)
}
var SharedServerDAO = NewServerDAO()
// 启用条目
func (this *ServerDAO) EnableServer(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ServerStateEnabled).
Update()
}
// 禁用条目
func (this *ServerDAO) DisableServer(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ServerStateDisabled).
Update()
}
// 查找启用中的条目
func (this *ServerDAO) FindEnabledServer(id uint32) (*Server, error) {
result, err := this.Query().
Pk(id).
Attr("state", ServerStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Server), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,64 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
ServerGroupStateEnabled = 1 // 已启用
ServerGroupStateDisabled = 0 // 已禁用
)
type ServerGroupDAO dbs.DAO
func NewServerGroupDAO() *ServerGroupDAO {
return dbs.NewDAO(&ServerGroupDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeServerGroups",
Model: new(ServerGroup),
PkName: "id",
},
}).(*ServerGroupDAO)
}
var SharedServerGroupDAO = NewServerGroupDAO()
// 启用条目
func (this *ServerGroupDAO) EnableServerGroup(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ServerGroupStateEnabled).
Update()
}
// 禁用条目
func (this *ServerGroupDAO) DisableServerGroup(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", ServerGroupStateDisabled).
Update()
}
// 查找启用中的条目
func (this *ServerGroupDAO) FindEnabledServerGroup(id uint32) (*ServerGroup, error) {
result, err := this.Query().
Pk(id).
Attr("state", ServerGroupStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*ServerGroup), err
}
// 根据主键查找名称
func (this *ServerGroupDAO) FindServerGroupName(id uint32) (string, error) {
name, err := this.Query().
Pk(id).
Result("name").
FindCol("")
return name.(string), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,26 @@
package models
// 服务分组
type ServerGroup struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
Name string `field:"name"` // 名称
Order uint32 `field:"order"` // 排序
CreatedAt uint32 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
}
type ServerGroupOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
Name interface{} // 名称
Order interface{} // 排序
CreatedAt interface{} // 创建时间
State interface{} // 状态
}
func NewServerGroupOperator() *ServerGroupOperator {
return &ServerGroupOperator{}
}

View File

@@ -0,0 +1,32 @@
package models
// 服务
type Server struct {
Id uint32 `field:"id"` // ID
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
GroupIds string `field:"groupIds"` // 分组ID列表
Config string `field:"config"` // 服务配置,自动生成
IncludeNodes string `field:"includeNodes"` // 部署条件
ExcludeNodes string `field:"excludeNodes"` // 节点排除条件
Version uint32 `field:"version"` // 版本号
CreatedAt uint32 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
}
type ServerOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
GroupIds interface{} // 分组ID列表
Config interface{} // 服务配置,自动生成
IncludeNodes interface{} // 部署条件
ExcludeNodes interface{} // 节点排除条件
Version interface{} // 版本号
CreatedAt interface{} // 创建时间
State interface{} // 状态
}
func NewServerOperator() *ServerOperator {
return &ServerOperator{}
}

View File

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

View File

@@ -0,0 +1,55 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
UserStateEnabled = 1 // 已启用
UserStateDisabled = 0 // 已禁用
)
type UserDAO dbs.DAO
func NewUserDAO() *UserDAO {
return dbs.NewDAO(&UserDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeUsers",
Model: new(User),
PkName: "id",
},
}).(*UserDAO)
}
var SharedUserDAO = NewUserDAO()
// 启用条目
func (this *UserDAO) EnableUser(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", UserStateEnabled).
Update()
}
// 禁用条目
func (this *UserDAO) DisableUser(id uint32) (rowsAffected int64, err error) {
return this.Query().
Pk(id).
Set("state", UserStateDisabled).
Update()
}
// 查找启用中的条目
func (this *UserDAO) FindEnabledUser(id uint32) (*User, error) {
result, err := this.Query().
Pk(id).
Attr("state", UserStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*User), err
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,26 @@
package models
//
type User struct {
Id uint32 `field:"id"` // ID
Username string `field:"username"` // 用户名
Password string `field:"password"` // 密码
Fullname string `field:"fullname"` // 真实姓名
CreatedAt uint32 `field:"createdAt"` // 创建时间
UpdatedAt uint32 `field:"updatedAt"` // 修改时间
State uint8 `field:"state"` // 状态
}
type UserOperator struct {
Id interface{} // ID
Username interface{} // 用户名
Password interface{} // 密码
Fullname interface{} // 真实姓名
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
State interface{} // 状态
}
func NewUserOperator() *UserOperator {
return &UserOperator{}
}

View File

@@ -0,0 +1,41 @@
package encrypt
import (
"github.com/iwind/TeaGo/logs"
)
const (
MagicKey = "f1c8eafb543f03023e97b7be864a4e9b"
)
// 加密特殊信息
func MagicKeyEncode(data []byte) []byte {
method, err := NewMethodInstance("aes-256-cfb", MagicKey, MagicKey[:16])
if err != nil {
logs.Println("[MagicKeyEncode]" + err.Error())
return data
}
dst, err := method.Encrypt(data)
if err != nil {
logs.Println("[MagicKeyEncode]" + err.Error())
return data
}
return dst
}
// 解密特殊信息
func MagicKeyDecode(data []byte) []byte {
method, err := NewMethodInstance("aes-256-cfb", MagicKey, MagicKey[:16])
if err != nil {
logs.Println("[MagicKeyEncode]" + err.Error())
return data
}
src, err := method.Decrypt(data)
if err != nil {
logs.Println("[MagicKeyEncode]" + err.Error())
return data
}
return src
}

View File

@@ -0,0 +1,11 @@
package encrypt
import "testing"
func TestMagicKeyEncode(t *testing.T) {
dst := MagicKeyEncode([]byte("Hello,World"))
t.Log("dst:", string(dst))
src := MagicKeyDecode(dst)
t.Log("src:", string(src))
}

View File

@@ -0,0 +1,12 @@
package encrypt
type MethodInterface interface {
// 初始化
Init(key []byte, iv []byte) error
// 加密
Encrypt(src []byte) (dst []byte, err error)
// 解密
Decrypt(dst []byte) (src []byte, err error)
}

View File

@@ -0,0 +1,73 @@
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
)
type AES128CFBMethod struct {
iv []byte
block cipher.Block
}
func (this *AES128CFBMethod) Init(key, iv []byte) error {
// 判断key是否为32长度
l := len(key)
if l > 16 {
key = key[:16]
} else if l < 16 {
key = append(key, bytes.Repeat([]byte{' '}, 16-l)...)
}
// 判断iv长度
l2 := len(iv)
if l2 > aes.BlockSize {
iv = iv[:aes.BlockSize]
} else if l2 < aes.BlockSize {
iv = append(iv, bytes.Repeat([]byte{' '}, aes.BlockSize-l2)...)
}
this.iv = iv
// block
block, err := aes.NewCipher(key)
if err != nil {
return err
}
this.block = block
return nil
}
func (this *AES128CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
if len(src) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
dst = make([]byte, len(src))
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
encrypter.XORKeyStream(dst, src)
return
}
func (this *AES128CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
if len(dst) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
src = make([]byte, len(dst))
encrypter := cipher.NewCFBDecrypter(this.block, this.iv)
encrypter.XORKeyStream(src, dst)
return
}

View File

@@ -0,0 +1,92 @@
package encrypt
import (
"runtime"
"strings"
"testing"
)
func TestAES128CFBMethod_Encrypt(t *testing.T) {
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
if err != nil {
t.Fatal(err)
}
src := []byte("Hello, World")
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
dst = dst[:len(src)]
t.Log("dst:", string(dst))
src = make([]byte, len(src))
src, err = method.Decrypt(dst)
if err != nil {
t.Fatal(err)
}
t.Log("src:", string(src))
}
func TestAES128CFBMethod_Encrypt2(t *testing.T) {
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
if err != nil {
t.Fatal(err)
}
sources := [][]byte{}
{
a := []byte{1}
_, err = method.Encrypt(a)
if err != nil {
t.Fatal(err)
}
}
for i := 0; i < 10; i++ {
src := []byte(strings.Repeat("Hello", 1))
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
sources = append(sources, dst)
}
{
a := []byte{1}
_, err = method.Decrypt(a)
if err != nil {
t.Fatal(err)
}
}
for _, dst := range sources {
dst2 := append([]byte{}, dst...)
src2 := make([]byte, len(dst2))
src2, err := method.Decrypt(dst2)
if err != nil {
t.Fatal(err)
}
t.Log(string(src2))
}
}
func BenchmarkAES128CFBMethod_Encrypt(b *testing.B) {
runtime.GOMAXPROCS(1)
method, err := NewMethodInstance("aes-128-cfb", "abc", "123")
if err != nil {
b.Fatal(err)
}
src := []byte(strings.Repeat("Hello", 1024))
for i := 0; i < b.N; i++ {
dst, err := method.Encrypt(src)
if err != nil {
b.Fatal(err)
}
_ = dst
}
}

View File

@@ -0,0 +1,74 @@
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
)
type AES192CFBMethod struct {
block cipher.Block
iv []byte
}
func (this *AES192CFBMethod) Init(key, iv []byte) error {
// 判断key是否为24长度
l := len(key)
if l > 24 {
key = key[:24]
} else if l < 24 {
key = append(key, bytes.Repeat([]byte{' '}, 24-l)...)
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
this.block = block
// 判断iv长度
l2 := len(iv)
if l2 > aes.BlockSize {
iv = iv[:aes.BlockSize]
} else if l2 < aes.BlockSize {
iv = append(iv, bytes.Repeat([]byte{' '}, aes.BlockSize-l2)...)
}
this.iv = iv
return nil
}
func (this *AES192CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
if len(src) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
dst = make([]byte, len(src))
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
encrypter.XORKeyStream(dst, src)
return
}
func (this *AES192CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
if len(dst) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
src = make([]byte, len(dst))
decrypter := cipher.NewCFBDecrypter(this.block, this.iv)
decrypter.XORKeyStream(src, dst)
return
}

View File

@@ -0,0 +1,45 @@
package encrypt
import (
"runtime"
"strings"
"testing"
)
func TestAES192CFBMethod_Encrypt(t *testing.T) {
method, err := NewMethodInstance("aes-192-cfb", "abc", "123")
if err != nil {
t.Fatal(err)
}
src := []byte("Hello, World")
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
dst = dst[:len(src)]
t.Log("dst:", string(dst))
src, err = method.Decrypt(dst)
if err != nil {
t.Fatal(err)
}
t.Log("src:", string(src))
}
func BenchmarkAES192CFBMethod_Encrypt(b *testing.B) {
runtime.GOMAXPROCS(1)
method, err := NewMethodInstance("aes-192-cfb", "abc", "123")
if err != nil {
b.Fatal(err)
}
src := []byte(strings.Repeat("Hello", 1024))
for i := 0; i < b.N; i++ {
dst, err := method.Encrypt(src)
if err != nil {
b.Fatal(err)
}
_ = dst
}
}

View File

@@ -0,0 +1,72 @@
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
)
type AES256CFBMethod struct {
block cipher.Block
iv []byte
}
func (this *AES256CFBMethod) Init(key, iv []byte) error {
// 判断key是否为32长度
l := len(key)
if l > 32 {
key = key[:32]
} else if l < 32 {
key = append(key, bytes.Repeat([]byte{' '}, 32-l)...)
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
this.block = block
// 判断iv长度
l2 := len(iv)
if l2 > aes.BlockSize {
iv = iv[:aes.BlockSize]
} else if l2 < aes.BlockSize {
iv = append(iv, bytes.Repeat([]byte{' '}, aes.BlockSize-l2)...)
}
this.iv = iv
return nil
}
func (this *AES256CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
if len(src) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
dst = make([]byte, len(src))
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
encrypter.XORKeyStream(dst, src)
return
}
func (this *AES256CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
if len(dst) == 0 {
return
}
defer func() {
err = RecoverMethodPanic(recover())
}()
src = make([]byte, len(dst))
decrypter := cipher.NewCFBDecrypter(this.block, this.iv)
decrypter.XORKeyStream(src, dst)
return
}

View File

@@ -0,0 +1,42 @@
package encrypt
import "testing"
func TestAES256CFBMethod_Encrypt(t *testing.T) {
method, err := NewMethodInstance("aes-256-cfb", "abc", "123")
if err != nil {
t.Fatal(err)
}
src := []byte("Hello, World")
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
dst = dst[:len(src)]
t.Log("dst:", string(dst))
src, err = method.Decrypt(dst)
if err != nil {
t.Fatal(err)
}
t.Log("src:", string(src))
}
func TestAES256CFBMethod_Encrypt2(t *testing.T) {
method, err := NewMethodInstance("aes-256-cfb", "abc", "123")
if err != nil {
t.Fatal(err)
}
src := []byte("Hello, World")
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
t.Log("dst:", string(dst))
src, err = method.Decrypt(dst)
if err != nil {
t.Fatal(err)
}
t.Log("src:", string(src))
}

View File

@@ -0,0 +1,26 @@
package encrypt
type RawMethod struct {
}
func (this *RawMethod) Init(key, iv []byte) error {
return nil
}
func (this *RawMethod) Encrypt(src []byte) (dst []byte, err error) {
if len(src) == 0 {
return
}
dst = make([]byte, len(src))
copy(dst, src)
return
}
func (this *RawMethod) Decrypt(dst []byte) (src []byte, err error) {
if len(dst) == 0 {
return
}
src = make([]byte, len(dst))
copy(src, dst)
return
}

View File

@@ -0,0 +1,23 @@
package encrypt
import "testing"
func TestRawMethod_Encrypt(t *testing.T) {
method, err := NewMethodInstance("raw", "abc", "123")
if err != nil {
t.Fatal(err)
}
src := []byte("Hello, World")
dst, err := method.Encrypt(src)
if err != nil {
t.Fatal(err)
}
dst = dst[:len(src)]
t.Log("dst:", string(dst))
src, err = method.Decrypt(dst)
if err != nil {
t.Fatal(err)
}
t.Log("src:", string(src))
}

View File

@@ -0,0 +1,43 @@
package encrypt
import (
"errors"
"reflect"
)
var methods = map[string]reflect.Type{
"raw": reflect.TypeOf(new(RawMethod)).Elem(),
"aes-128-cfb": reflect.TypeOf(new(AES128CFBMethod)).Elem(),
"aes-192-cfb": reflect.TypeOf(new(AES192CFBMethod)).Elem(),
"aes-256-cfb": reflect.TypeOf(new(AES256CFBMethod)).Elem(),
}
func NewMethodInstance(method string, key string, iv string) (MethodInterface, error) {
valueType, ok := methods[method]
if !ok {
return nil, errors.New("method '" + method + "' not found")
}
instance, ok := reflect.New(valueType).Interface().(MethodInterface)
if !ok {
return nil, errors.New("method '" + method + "' must implement MethodInterface")
}
err := instance.Init([]byte(key), []byte(iv))
return instance, err
}
func RecoverMethodPanic(err interface{}) error {
if err != nil {
s, ok := err.(string)
if ok {
return errors.New(s)
}
e, ok := err.(error)
if ok {
return e
}
return errors.New("unknown error")
}
return nil
}

View File

@@ -0,0 +1,8 @@
package encrypt
import "testing"
func TestFindMethodInstance(t *testing.T) {
t.Log(NewMethodInstance("a", "b", ""))
t.Log(NewMethodInstance("aes-256-cfb", "123456", ""))
}

View File

@@ -0,0 +1,181 @@
package admin
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/encrypt"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/iwind/TeaGo/maps"
"google.golang.org/grpc/metadata"
"time"
)
type Service struct {
debug bool
}
func (this *Service) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
_, err := this.validateRequest(ctx)
if err != nil {
return nil, err
}
if len(req.Username) == 0 || len(req.Password) == 0 {
return &LoginResponse{
AdminId: 0,
IsOk: false,
Message: "请输入正确的用户名密码",
}, nil
}
adminId, err := models.SharedAdminDAO.CheckAdminPassword(req.Username, req.Password)
if err != nil {
utils.PrintError(err)
return nil, err
}
if adminId <= 0 {
return &LoginResponse{
AdminId: 0,
IsOk: false,
Message: "请输入正确的用户名密码",
}, nil
}
return &LoginResponse{
AdminId: int64(adminId),
IsOk: true,
}, nil
}
func (this *Service) CreateLog(ctx context.Context, req *CreateLogRequest) (*CreateLogResponse, error) {
adminId, err := this.validateAdminRequest(ctx)
if err != nil {
return nil, err
}
err = models.SharedLogDAO.CreateAdminLog(adminId, req.Level, req.Description, req.Action, req.Ip)
return &CreateLogResponse{
IsOk: err != nil,
}, err
}
func (this *Service) CheckAdminExists(ctx context.Context, req *CheckAdminExistsRequest) (*CheckAdminExistsResponse, error) {
_, err := this.validateRequest(ctx)
if err != nil {
return nil, err
}
if req.AdminId <= 0 {
return &CheckAdminExistsResponse{
IsOk: false,
}, nil
}
ok, err := models.SharedAdminDAO.ExistEnabledAdmin(int(req.AdminId))
if err != nil {
return nil, err
}
return &CheckAdminExistsResponse{
IsOk: ok,
}, nil
}
func (this *Service) FindAdminFullname(ctx context.Context, req *FindAdminNameRequest) (*FindAdminNameResponse, error) {
_, err := this.validateRequest(ctx)
if err != nil {
return nil, err
}
fullname, err := models.SharedAdminDAO.FindAdminFullname(int(req.AdminId))
if err != nil {
utils.PrintError(err)
return nil, err
}
return &FindAdminNameResponse{
Fullname: fullname,
}, nil
}
func (this *Service) validateRequest(ctx context.Context) (adminId int, err error) {
var md metadata.MD
var ok bool
if this.debug {
md, ok = metadata.FromOutgoingContext(ctx)
} else {
md, ok = metadata.FromIncomingContext(ctx)
}
if !ok {
return 0, errors.New("context: need 'nodeId'")
}
nodeIds := md.Get("nodeid")
if len(nodeIds) == 0 || len(nodeIds[0]) == 0 {
return 0, errors.New("context: need 'nodeId'")
}
nodeId := nodeIds[0]
// 获取Node信息
apiToken, err := models.SharedApiTokenDAO.FindEnabledTokenWithNode(nodeId)
if err != nil {
utils.PrintError(err)
return 0, err
}
if apiToken == nil {
return 0, errors.New("can not find token from node id: " + err.Error())
}
tokens := md.Get("token")
if len(tokens) == 0 || len(tokens[0]) == 0 {
return 0, errors.New("context: need 'token'")
}
token := tokens[0]
data, err := base64.StdEncoding.DecodeString(token)
if err != nil {
return 0, err
}
method, err := encrypt.NewMethodInstance(teaconst.EncryptMethod, apiToken.Secret, nodeId)
if err != nil {
utils.PrintError(err)
return 0, err
}
data, err = method.Decrypt(data)
if err != nil {
return 0, err
}
if len(data) == 0 {
return 0, errors.New("invalid token")
}
m := maps.Map{}
err = json.Unmarshal(data, &m)
if err != nil {
return 0, errors.New("decode token error: " + err.Error())
}
timestamp := m.GetInt64("timestamp")
if time.Now().Unix()-timestamp > 600 {
// 请求超过10分钟认为超时
return 0, errors.New("authenticate timeout")
}
adminId = m.GetInt("adminId")
return
}
func (this *Service) validateAdminRequest(ctx context.Context) (adminId int, err error) {
adminId, err = this.validateRequest(ctx)
if err != nil {
return 0, err
}
if adminId <= 0 {
return 0, errors.New("invalid admin id")
}
return
}

View File

@@ -33,6 +33,9 @@ type LoginRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *LoginRequest) Reset() {
@@ -67,10 +70,28 @@ func (*LoginRequest) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{0}
}
func (x *LoginRequest) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *LoginRequest) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type LoginResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AdminId int64 `protobuf:"varint,1,opt,name=adminId,proto3" json:"adminId,omitempty"`
IsOk bool `protobuf:"varint,2,opt,name=isOk,proto3" json:"isOk,omitempty"`
Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *LoginResponse) Reset() {
@@ -105,19 +126,400 @@ func (*LoginResponse) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{1}
}
func (x *LoginResponse) GetAdminId() int64 {
if x != nil {
return x.AdminId
}
return 0
}
func (x *LoginResponse) GetIsOk() bool {
if x != nil {
return x.IsOk
}
return false
}
func (x *LoginResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type CreateLogRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Level string `protobuf:"bytes,1,opt,name=level,proto3" json:"level,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Action string `protobuf:"bytes,3,opt,name=action,proto3" json:"action,omitempty"`
Ip string `protobuf:"bytes,4,opt,name=ip,proto3" json:"ip,omitempty"`
}
func (x *CreateLogRequest) Reset() {
*x = CreateLogRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateLogRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateLogRequest) ProtoMessage() {}
func (x *CreateLogRequest) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreateLogRequest.ProtoReflect.Descriptor instead.
func (*CreateLogRequest) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{2}
}
func (x *CreateLogRequest) GetLevel() string {
if x != nil {
return x.Level
}
return ""
}
func (x *CreateLogRequest) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *CreateLogRequest) GetAction() string {
if x != nil {
return x.Action
}
return ""
}
func (x *CreateLogRequest) GetIp() string {
if x != nil {
return x.Ip
}
return ""
}
type CreateLogResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsOk bool `protobuf:"varint,1,opt,name=isOk,proto3" json:"isOk,omitempty"`
}
func (x *CreateLogResponse) Reset() {
*x = CreateLogResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateLogResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateLogResponse) ProtoMessage() {}
func (x *CreateLogResponse) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreateLogResponse.ProtoReflect.Descriptor instead.
func (*CreateLogResponse) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{3}
}
func (x *CreateLogResponse) GetIsOk() bool {
if x != nil {
return x.IsOk
}
return false
}
type CheckAdminExistsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AdminId int64 `protobuf:"varint,1,opt,name=adminId,proto3" json:"adminId,omitempty"`
}
func (x *CheckAdminExistsRequest) Reset() {
*x = CheckAdminExistsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CheckAdminExistsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckAdminExistsRequest) ProtoMessage() {}
func (x *CheckAdminExistsRequest) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckAdminExistsRequest.ProtoReflect.Descriptor instead.
func (*CheckAdminExistsRequest) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{4}
}
func (x *CheckAdminExistsRequest) GetAdminId() int64 {
if x != nil {
return x.AdminId
}
return 0
}
type CheckAdminExistsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsOk bool `protobuf:"varint,1,opt,name=isOk,proto3" json:"isOk,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *CheckAdminExistsResponse) Reset() {
*x = CheckAdminExistsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CheckAdminExistsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckAdminExistsResponse) ProtoMessage() {}
func (x *CheckAdminExistsResponse) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckAdminExistsResponse.ProtoReflect.Descriptor instead.
func (*CheckAdminExistsResponse) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{5}
}
func (x *CheckAdminExistsResponse) GetIsOk() bool {
if x != nil {
return x.IsOk
}
return false
}
func (x *CheckAdminExistsResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type FindAdminNameRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AdminId int64 `protobuf:"varint,1,opt,name=adminId,proto3" json:"adminId,omitempty"`
}
func (x *FindAdminNameRequest) Reset() {
*x = FindAdminNameRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FindAdminNameRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FindAdminNameRequest) ProtoMessage() {}
func (x *FindAdminNameRequest) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FindAdminNameRequest.ProtoReflect.Descriptor instead.
func (*FindAdminNameRequest) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{6}
}
func (x *FindAdminNameRequest) GetAdminId() int64 {
if x != nil {
return x.AdminId
}
return 0
}
type FindAdminNameResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Fullname string `protobuf:"bytes,1,opt,name=fullname,proto3" json:"fullname,omitempty"`
}
func (x *FindAdminNameResponse) Reset() {
*x = FindAdminNameResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_admin_service_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FindAdminNameResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FindAdminNameResponse) ProtoMessage() {}
func (x *FindAdminNameResponse) ProtoReflect() protoreflect.Message {
mi := &file_admin_service_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FindAdminNameResponse.ProtoReflect.Descriptor instead.
func (*FindAdminNameResponse) Descriptor() ([]byte, []int) {
return file_admin_service_proto_rawDescGZIP(), []int{7}
}
func (x *FindAdminNameResponse) GetFullname() string {
if x != nil {
return x.Fullname
}
return ""
}
var File_admin_service_proto protoreflect.FileDescriptor
var file_admin_service_proto_rawDesc = []byte{
0x0a, 0x13, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x22, 0x0e, 0x0a, 0x0c,
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0f, 0x0a, 0x0d,
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x3f, 0x0a,
0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69,
0x6e, 0x12, 0x13, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c,
0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09,
0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x22, 0x46, 0x0a, 0x0c,
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x22, 0x57, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x12,
0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69,
0x73, 0x4f, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x72, 0x0a,
0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x70, 0x22, 0x27, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x18, 0x01,
0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x22, 0x33, 0x0a, 0x17, 0x43, 0x68,
0x65, 0x63, 0x6b, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x22,
0x48, 0x0a, 0x18, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x45, 0x78, 0x69,
0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69,
0x73, 0x4f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x12,
0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x30, 0x0a, 0x14, 0x46, 0x69, 0x6e,
0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x64, 0x22, 0x33, 0x0a, 0x15, 0x46,
0x69, 0x6e, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
0x32, 0xaa, 0x02, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x05,
0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x13, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f,
0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x64, 0x6d,
0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x40, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x12,
0x17, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f,
0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x64, 0x6d,
0x69, 0x6e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x45, 0x78, 0x69, 0x73, 0x74,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x45, 0x78, 0x69, 0x73, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x66,
0x69, 0x6e, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x46, 0x75, 0x6c, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x1b, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x6d,
0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,
0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4e,
0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a,
0x07, 0x2e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -132,16 +534,28 @@ func file_admin_service_proto_rawDescGZIP() []byte {
return file_admin_service_proto_rawDescData
}
var file_admin_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_admin_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_admin_service_proto_goTypes = []interface{}{
(*LoginRequest)(nil), // 0: admin.LoginRequest
(*LoginResponse)(nil), // 1: admin.LoginResponse
(*LoginRequest)(nil), // 0: admin.LoginRequest
(*LoginResponse)(nil), // 1: admin.LoginResponse
(*CreateLogRequest)(nil), // 2: admin.CreateLogRequest
(*CreateLogResponse)(nil), // 3: admin.CreateLogResponse
(*CheckAdminExistsRequest)(nil), // 4: admin.CheckAdminExistsRequest
(*CheckAdminExistsResponse)(nil), // 5: admin.CheckAdminExistsResponse
(*FindAdminNameRequest)(nil), // 6: admin.FindAdminNameRequest
(*FindAdminNameResponse)(nil), // 7: admin.FindAdminNameResponse
}
var file_admin_service_proto_depIdxs = []int32{
0, // 0: admin.Service.login:input_type -> admin.LoginRequest
1, // 1: admin.Service.login:output_type -> admin.LoginResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
2, // 1: admin.Service.createLog:input_type -> admin.CreateLogRequest
4, // 2: admin.Service.checkAdminExists:input_type -> admin.CheckAdminExistsRequest
6, // 3: admin.Service.findAdminFullname:input_type -> admin.FindAdminNameRequest
1, // 4: admin.Service.login:output_type -> admin.LoginResponse
3, // 5: admin.Service.createLog:output_type -> admin.CreateLogResponse
5, // 6: admin.Service.checkAdminExists:output_type -> admin.CheckAdminExistsResponse
7, // 7: admin.Service.findAdminFullname:output_type -> admin.FindAdminNameResponse
4, // [4:8] is the sub-list for method output_type
0, // [0:4] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
@@ -177,6 +591,78 @@ func file_admin_service_proto_init() {
return nil
}
}
file_admin_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CreateLogRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_admin_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CreateLogResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_admin_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CheckAdminExistsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_admin_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CheckAdminExistsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_admin_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FindAdminNameRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_admin_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FindAdminNameResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -184,7 +670,7 @@ func file_admin_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_admin_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
@@ -210,7 +696,14 @@ const _ = grpc.SupportPackageIsVersion6
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ServiceClient interface {
// 登录
Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
// 创建操作日志
CreateLog(ctx context.Context, in *CreateLogRequest, opts ...grpc.CallOption) (*CreateLogResponse, error)
// 检查管理员是否存在
CheckAdminExists(ctx context.Context, in *CheckAdminExistsRequest, opts ...grpc.CallOption) (*CheckAdminExistsResponse, error)
// 获取管理员名称
FindAdminFullname(ctx context.Context, in *FindAdminNameRequest, opts ...grpc.CallOption) (*FindAdminNameResponse, error)
}
type serviceClient struct {
@@ -230,9 +723,43 @@ func (c *serviceClient) Login(ctx context.Context, in *LoginRequest, opts ...grp
return out, nil
}
func (c *serviceClient) CreateLog(ctx context.Context, in *CreateLogRequest, opts ...grpc.CallOption) (*CreateLogResponse, error) {
out := new(CreateLogResponse)
err := c.cc.Invoke(ctx, "/admin.Service/createLog", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *serviceClient) CheckAdminExists(ctx context.Context, in *CheckAdminExistsRequest, opts ...grpc.CallOption) (*CheckAdminExistsResponse, error) {
out := new(CheckAdminExistsResponse)
err := c.cc.Invoke(ctx, "/admin.Service/checkAdminExists", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *serviceClient) FindAdminFullname(ctx context.Context, in *FindAdminNameRequest, opts ...grpc.CallOption) (*FindAdminNameResponse, error) {
out := new(FindAdminNameResponse)
err := c.cc.Invoke(ctx, "/admin.Service/findAdminFullname", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ServiceServer is the server API for Service service.
type ServiceServer interface {
// 登录
Login(context.Context, *LoginRequest) (*LoginResponse, error)
// 创建操作日志
CreateLog(context.Context, *CreateLogRequest) (*CreateLogResponse, error)
// 检查管理员是否存在
CheckAdminExists(context.Context, *CheckAdminExistsRequest) (*CheckAdminExistsResponse, error)
// 获取管理员名称
FindAdminFullname(context.Context, *FindAdminNameRequest) (*FindAdminNameResponse, error)
}
// UnimplementedServiceServer can be embedded to have forward compatible implementations.
@@ -242,6 +769,15 @@ type UnimplementedServiceServer struct {
func (*UnimplementedServiceServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (*UnimplementedServiceServer) CreateLog(context.Context, *CreateLogRequest) (*CreateLogResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateLog not implemented")
}
func (*UnimplementedServiceServer) CheckAdminExists(context.Context, *CheckAdminExistsRequest) (*CheckAdminExistsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CheckAdminExists not implemented")
}
func (*UnimplementedServiceServer) FindAdminFullname(context.Context, *FindAdminNameRequest) (*FindAdminNameResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FindAdminFullname not implemented")
}
func RegisterServiceServer(s *grpc.Server, srv ServiceServer) {
s.RegisterService(&_Service_serviceDesc, srv)
@@ -265,6 +801,60 @@ func _Service_Login_Handler(srv interface{}, ctx context.Context, dec func(inter
return interceptor(ctx, in, info, handler)
}
func _Service_CreateLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateLogRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).CreateLog(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/admin.Service/CreateLog",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).CreateLog(ctx, req.(*CreateLogRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Service_CheckAdminExists_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CheckAdminExistsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).CheckAdminExists(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/admin.Service/CheckAdminExists",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).CheckAdminExists(ctx, req.(*CheckAdminExistsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Service_FindAdminFullname_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FindAdminNameRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).FindAdminFullname(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/admin.Service/FindAdminFullname",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).FindAdminFullname(ctx, req.(*FindAdminNameRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Service_serviceDesc = grpc.ServiceDesc{
ServiceName: "admin.Service",
HandlerType: (*ServiceServer)(nil),
@@ -273,6 +863,18 @@ var _Service_serviceDesc = grpc.ServiceDesc{
MethodName: "login",
Handler: _Service_Login_Handler,
},
{
MethodName: "createLog",
Handler: _Service_CreateLog_Handler,
},
{
MethodName: "checkAdminExists",
Handler: _Service_CheckAdminExists_Handler,
},
{
MethodName: "findAdminFullname",
Handler: _Service_FindAdminFullname_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "admin/service.proto",

View File

@@ -1,18 +1,64 @@
syntax = "proto3";
option go_package = "./admin";
package admin;
option go_package = "./admin";
service Service {
// 登录
rpc login (LoginRequest) returns (LoginResponse) {
}
// 创建操作日志
rpc createLog (CreateLogRequest) returns (CreateLogResponse) {
}
// 检查管理员是否存在
rpc checkAdminExists (CheckAdminExistsRequest) returns (CheckAdminExistsResponse) {
}
// 获取管理员名称
rpc findAdminFullname (FindAdminNameRequest) returns (FindAdminNameResponse) {
}
}
message LoginRequest {
string username = 1;
string password = 2;
}
message LoginResponse {
int64 adminId = 1;
bool isOk = 2;
string message = 3;
}
}
message CreateLogRequest {
string level = 1;
string description = 2;
string action = 3;
string ip = 4;
}
message CreateLogResponse {
bool isOk = 1;
}
message CheckAdminExistsRequest {
int64 adminId = 1;
}
message CheckAdminExistsResponse {
bool isOk = 1;
string message = 2;
}
message FindAdminNameRequest {
int64 adminId = 1;
}
message FindAdminNameResponse {
string fullname = 1;
}

View File

@@ -0,0 +1,68 @@
package admin
import (
"context"
"encoding/base64"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/encrypt"
"github.com/iwind/TeaGo/assert"
"github.com/iwind/TeaGo/maps"
stringutil "github.com/iwind/TeaGo/utils/string"
"google.golang.org/grpc/metadata"
"testing"
"time"
)
func TestService_Login(t *testing.T) {
a := assert.NewAssertion(t)
service := &Service{
debug: true,
}
resp, err := service.Login(testCtx(t), &LoginRequest{
Username: "admin",
Password: stringutil.Md5("123456"),
})
if err != nil {
t.Fatal(err)
}
a.LogJSON(resp)
}
func TestService_CreateLog(t *testing.T) {
service := &Service{debug: true}
resp, err := service.CreateLog(testCtx(t), &CreateLogRequest{
Level: "info",
Description: "这是一个测试日志",
Action: "/login",
Ip: "127.0.0.1",
})
if err != nil {
t.Fatal(err)
}
t.Log(resp)
}
func testCtx(t *testing.T) context.Context {
ctx := context.Background()
nodeId := "H6sjDf779jimnVPnBFSgZxvr6Ca0wQ0z"
token := maps.Map{
"timestamp": time.Now().Unix(),
"adminId": 1,
}
data := token.AsJSON()
method, err := encrypt.NewMethodInstance(teaconst.EncryptMethod, "hMHjmEng0SIcT3yiA3HIoUjogwAC9cur", nodeId)
if err != nil {
t.Fatal(err)
}
data, err = method.Encrypt(data)
if err != nil {
t.Fatal(err)
}
tokenString := base64.StdEncoding.EncodeToString(data)
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", nodeId, "token", tokenString)
return ctx
}

View File

@@ -8,7 +8,9 @@ import (
type Service struct {
}
func (this *Service) Node(context.Context, *NodeRequest) (*NodeResponse, error) {
func (this *Service) Config(ctx context.Context, req *ConfigRequest) (*ConfigResponse, error) {
logs.Println("you called me")
return &NodeResponse{}, nil
return &ConfigResponse{
Id: req.NodeId,
}, nil
}

View File

@@ -29,14 +29,16 @@ const (
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type NodeRequest struct {
type ConfigRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NodeId string `protobuf:"bytes,1,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
}
func (x *NodeRequest) Reset() {
*x = NodeRequest{}
func (x *ConfigRequest) Reset() {
*x = ConfigRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_node_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -44,13 +46,13 @@ func (x *NodeRequest) Reset() {
}
}
func (x *NodeRequest) String() string {
func (x *ConfigRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeRequest) ProtoMessage() {}
func (*ConfigRequest) ProtoMessage() {}
func (x *NodeRequest) ProtoReflect() protoreflect.Message {
func (x *ConfigRequest) ProtoReflect() protoreflect.Message {
mi := &file_node_service_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -62,19 +64,28 @@ func (x *NodeRequest) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use NodeRequest.ProtoReflect.Descriptor instead.
func (*NodeRequest) Descriptor() ([]byte, []int) {
// Deprecated: Use ConfigRequest.ProtoReflect.Descriptor instead.
func (*ConfigRequest) Descriptor() ([]byte, []int) {
return file_node_service_proto_rawDescGZIP(), []int{0}
}
type NodeResponse struct {
func (x *ConfigRequest) GetNodeId() string {
if x != nil {
return x.NodeId
}
return ""
}
type ConfigResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *NodeResponse) Reset() {
*x = NodeResponse{}
func (x *ConfigResponse) Reset() {
*x = ConfigResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_node_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -82,13 +93,13 @@ func (x *NodeResponse) Reset() {
}
}
func (x *NodeResponse) String() string {
func (x *ConfigResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeResponse) ProtoMessage() {}
func (*ConfigResponse) ProtoMessage() {}
func (x *NodeResponse) ProtoReflect() protoreflect.Message {
func (x *ConfigResponse) ProtoReflect() protoreflect.Message {
mi := &file_node_service_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -100,23 +111,33 @@ func (x *NodeResponse) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use NodeResponse.ProtoReflect.Descriptor instead.
func (*NodeResponse) Descriptor() ([]byte, []int) {
// Deprecated: Use ConfigResponse.ProtoReflect.Descriptor instead.
func (*ConfigResponse) Descriptor() ([]byte, []int) {
return file_node_service_proto_rawDescGZIP(), []int{1}
}
func (x *ConfigResponse) GetId() string {
if x != nil {
return x.Id
}
return ""
}
var File_node_service_proto protoreflect.FileDescriptor
var file_node_service_proto_rawDesc = []byte{
0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x0d, 0x0a, 0x0b, 0x4e, 0x6f,
0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x4e, 0x6f, 0x64,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x3a, 0x0a, 0x07, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x11, 0x2e, 0x6e,
0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x27, 0x0a, 0x0d, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e,
0x6f, 0x64, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64,
0x65, 0x49, 0x64, 0x22, 0x20, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x40, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x13, 0x2e, 0x6e, 0x6f, 0x64,
0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x6e, 0x6f, 0x64,
0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -133,12 +154,12 @@ func file_node_service_proto_rawDescGZIP() []byte {
var file_node_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_node_service_proto_goTypes = []interface{}{
(*NodeRequest)(nil), // 0: node.NodeRequest
(*NodeResponse)(nil), // 1: node.NodeResponse
(*ConfigRequest)(nil), // 0: node.ConfigRequest
(*ConfigResponse)(nil), // 1: node.ConfigResponse
}
var file_node_service_proto_depIdxs = []int32{
0, // 0: node.Service.node:input_type -> node.NodeRequest
1, // 1: node.Service.node:output_type -> node.NodeResponse
0, // 0: node.Service.config:input_type -> node.ConfigRequest
1, // 1: node.Service.config:output_type -> node.ConfigResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
@@ -153,7 +174,7 @@ func file_node_service_proto_init() {
}
if !protoimpl.UnsafeEnabled {
file_node_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeRequest); i {
switch v := v.(*ConfigRequest); i {
case 0:
return &v.state
case 1:
@@ -165,7 +186,7 @@ func file_node_service_proto_init() {
}
}
file_node_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeResponse); i {
switch v := v.(*ConfigResponse); i {
case 0:
return &v.state
case 1:
@@ -209,7 +230,7 @@ const _ = grpc.SupportPackageIsVersion6
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ServiceClient interface {
Node(ctx context.Context, in *NodeRequest, opts ...grpc.CallOption) (*NodeResponse, error)
Config(ctx context.Context, in *ConfigRequest, opts ...grpc.CallOption) (*ConfigResponse, error)
}
type serviceClient struct {
@@ -220,9 +241,9 @@ func NewServiceClient(cc grpc.ClientConnInterface) ServiceClient {
return &serviceClient{cc}
}
func (c *serviceClient) Node(ctx context.Context, in *NodeRequest, opts ...grpc.CallOption) (*NodeResponse, error) {
out := new(NodeResponse)
err := c.cc.Invoke(ctx, "/node.Service/node", in, out, opts...)
func (c *serviceClient) Config(ctx context.Context, in *ConfigRequest, opts ...grpc.CallOption) (*ConfigResponse, error) {
out := new(ConfigResponse)
err := c.cc.Invoke(ctx, "/node.Service/config", in, out, opts...)
if err != nil {
return nil, err
}
@@ -231,35 +252,35 @@ func (c *serviceClient) Node(ctx context.Context, in *NodeRequest, opts ...grpc.
// ServiceServer is the server API for Service service.
type ServiceServer interface {
Node(context.Context, *NodeRequest) (*NodeResponse, error)
Config(context.Context, *ConfigRequest) (*ConfigResponse, error)
}
// UnimplementedServiceServer can be embedded to have forward compatible implementations.
type UnimplementedServiceServer struct {
}
func (*UnimplementedServiceServer) Node(context.Context, *NodeRequest) (*NodeResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Node not implemented")
func (*UnimplementedServiceServer) Config(context.Context, *ConfigRequest) (*ConfigResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Config not implemented")
}
func RegisterServiceServer(s *grpc.Server, srv ServiceServer) {
s.RegisterService(&_Service_serviceDesc, srv)
}
func _Service_Node_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeRequest)
func _Service_Config_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ConfigRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).Node(ctx, in)
return srv.(ServiceServer).Config(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/node.Service/Node",
FullMethod: "/node.Service/Config",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).Node(ctx, req.(*NodeRequest))
return srv.(ServiceServer).Config(ctx, req.(*ConfigRequest))
}
return interceptor(ctx, in, info, handler)
}
@@ -269,8 +290,8 @@ var _Service_serviceDesc = grpc.ServiceDesc{
HandlerType: (*ServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "node",
Handler: _Service_Node_Handler,
MethodName: "config",
Handler: _Service_Config_Handler,
},
},
Streams: []grpc.StreamDesc{},

View File

@@ -5,15 +5,15 @@ package node;
option go_package = "./node";
service Service {
rpc node (NodeRequest) returns (NodeResponse) {
rpc config (ConfigRequest) returns (ConfigResponse) {
}
}
message NodeRequest {
message ConfigRequest {
string nodeId = 1;
}
message NodeResponse {
message ConfigResponse {
string id = 1;
}

View File

@@ -3,6 +3,7 @@ package tests
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/admin"
nodepb "github.com/TeaOSLab/EdgeAPI/internal/rpc/node"
pb "github.com/TeaOSLab/EdgeAPI/internal/tests/helloworld"
"google.golang.org/grpc"
@@ -42,6 +43,7 @@ func TestTCPServer(t *testing.T) {
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
nodepb.RegisterServiceServer(s, &nodepb.Service{})
admin.RegisterServiceServer(s, &admin.Service{})
err = s.Serve(listener)
if err != nil {
@@ -89,7 +91,7 @@ func TestTCPClient_Node(t *testing.T) {
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx, "name", "liu", "age", "20")
reply, err := c.Node(ctx, &nodepb.NodeRequest{
reply, err := c.Config(ctx, &nodepb.ConfigRequest{
})
if err != nil {
t.Fatal(err)

View File

@@ -0,0 +1,10 @@
package tests
import (
"github.com/iwind/TeaGo/rands"
"testing"
)
func TestRandString(t *testing.T) {
t.Log(rands.HexString(32))
}

8
internal/utils/errors.go Normal file
View File

@@ -0,0 +1,8 @@
package utils
import "github.com/iwind/TeaGo/logs"
func PrintError(err error) {
// TODO 记录调用的文件名、行数
logs.Println("[ERROR]" + err.Error())
}

View File

@@ -0,0 +1,29 @@
// +build darwin
package utils
import (
"syscall"
)
// set resource limit
func SetRLimit(limit uint64) error {
rLimit := &syscall.Rlimit{}
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rLimit)
if err != nil {
return err
}
if rLimit.Cur < limit {
rLimit.Cur = limit
}
if rLimit.Max < limit {
rLimit.Max = limit
}
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, rLimit)
}
// set best resource limit value
func SetSuitableRLimit() {
SetRLimit(4096 * 100) // 1M=100Files
}

View File

@@ -0,0 +1,29 @@
// +build linux
package utils
import (
"syscall"
)
// set resource limit
func SetRLimit(limit uint64) error {
rLimit := &syscall.Rlimit{}
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rLimit)
if err != nil {
return err
}
if rLimit.Cur < limit {
rLimit.Cur = limit
}
if rLimit.Max < limit {
rLimit.Max = limit
}
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, rLimit)
}
// set best resource limit value
func SetSuitableRLimit() {
SetRLimit(4096 * 100) // 1M=100Files
}

View File

@@ -0,0 +1,13 @@
// +build !linux,!darwin
package utils
// set resource limit
func SetRLimit(limit uint64) error {
return nil
}
// set best resource limit value
func SetSuitableRLimit() {
}