mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2026-02-11 21:25:37 +08:00
阶段性提交
This commit is contained in:
234
internal/apps/app_cmd.go
Normal file
234
internal/apps/app_cmd.go
Normal 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")
|
||||
}
|
||||
6
internal/apps/directive.go
Normal file
6
internal/apps/directive.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package apps
|
||||
|
||||
type Directive struct {
|
||||
Arg string
|
||||
Callback func()
|
||||
}
|
||||
17
internal/apps/file_others.go
Normal file
17
internal/apps/file_others.go
Normal 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)
|
||||
}
|
||||
17
internal/apps/file_windows.go
Normal file
17
internal/apps/file_windows.go
Normal 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")
|
||||
}
|
||||
51
internal/apps/log_writer.go
Normal file
51
internal/apps/log_writer.go
Normal 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
113
internal/apps/pid.go
Normal 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)
|
||||
}
|
||||
@@ -10,6 +10,8 @@ type APIConfig struct {
|
||||
RPC struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
} `yaml:"rpc"`
|
||||
NodeId string `yaml:"nodeId"`
|
||||
Secret string `yaml:"secret"`
|
||||
}
|
||||
|
||||
func LoadAPIConfig() (*APIConfig, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"io/ioutil"
|
||||
@@ -9,10 +10,13 @@ import (
|
||||
var sharedNodeConfig *NodeConfig = nil
|
||||
|
||||
type NodeConfig struct {
|
||||
Id string `yaml:"id"`
|
||||
Servers []*ServerConfig `yaml:"servers"`
|
||||
Id string `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Servers []*serverconfigs.ServerConfig `yaml:"servers" json:"servers"`
|
||||
Version int `yaml:"version" json:"version"`
|
||||
}
|
||||
|
||||
// 取得当前节点配置单例
|
||||
func SharedNodeConfig() (*NodeConfig, error) {
|
||||
sharedLocker.Lock()
|
||||
defer sharedLocker.Unlock()
|
||||
@@ -36,9 +40,19 @@ func SharedNodeConfig() (*NodeConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// 刷新当前节点配置
|
||||
func ReloadNodeConfig() error {
|
||||
sharedLocker.Lock()
|
||||
sharedNodeConfig = nil
|
||||
sharedLocker.Unlock()
|
||||
|
||||
_, err := SharedNodeConfig()
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据网络地址和协议分组
|
||||
func (this *NodeConfig) AvailableGroups() []*ServerGroup {
|
||||
groupMapping := map[string]*ServerGroup{} // protocol://addr => Server Group
|
||||
func (this *NodeConfig) AvailableGroups() []*serverconfigs.ServerGroup {
|
||||
groupMapping := map[string]*serverconfigs.ServerGroup{} // protocol://addr => Server Group
|
||||
for _, server := range this.Servers {
|
||||
if !server.IsOn {
|
||||
continue
|
||||
@@ -48,15 +62,39 @@ func (this *NodeConfig) AvailableGroups() []*ServerGroup {
|
||||
if ok {
|
||||
group.Add(server)
|
||||
} else {
|
||||
group = NewServerGroup(addr)
|
||||
group = serverconfigs.NewServerGroup(addr)
|
||||
group.Add(server)
|
||||
}
|
||||
groupMapping[addr] = group
|
||||
}
|
||||
}
|
||||
result := []*ServerGroup{}
|
||||
result := []*serverconfigs.ServerGroup{}
|
||||
for _, group := range groupMapping {
|
||||
result = append(result, group)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *NodeConfig) Init() error {
|
||||
for _, server := range this.Servers {
|
||||
err := server.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 写入到文件
|
||||
func (this *NodeConfig) Save() error {
|
||||
sharedLocker.Lock()
|
||||
defer sharedLocker.Unlock()
|
||||
|
||||
data, err := yaml.Marshal(this)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(Tea.ConfigFile("node.yaml"), data, 0777)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"testing"
|
||||
@@ -27,18 +28,37 @@ func TestSharedNodeConfig(t *testing.T) {
|
||||
|
||||
func TestNodeConfig_Groups(t *testing.T) {
|
||||
config := &NodeConfig{}
|
||||
config.Servers = []*ServerConfig{
|
||||
config.Servers = []*serverconfigs.ServerConfig{
|
||||
{
|
||||
IsOn: true,
|
||||
HTTP: &HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{"127.0.0.1:1234", ":8080"},
|
||||
HTTP: &serverconfigs.HTTPProtocolConfig{
|
||||
BaseProtocol: serverconfigs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTP,
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "1234",
|
||||
},
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTP,
|
||||
PortRange: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
HTTP: &HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{":8080"},
|
||||
HTTP: &serverconfigs.HTTPProtocolConfig{
|
||||
BaseProtocol: serverconfigs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTP,
|
||||
PortRange: "8080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package configs
|
||||
|
||||
type OriginServerConfig struct {
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package configs
|
||||
|
||||
type HTTPProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
IPVersion IPVersion `yaml:"ipVersion"` // 4, 6
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *HTTPProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
switch this.IPVersion {
|
||||
case IPv4:
|
||||
result = append(result, ProtocolHTTP4+"://"+listen)
|
||||
case IPv6:
|
||||
result = append(result, ProtocolHTTP6+"://"+listen)
|
||||
default:
|
||||
result = append(result, ProtocolHTTP+"://"+listen)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package configs
|
||||
|
||||
type HTTPSProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
IPVersion string `yaml:"ipVersion"` // 4, 6
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *HTTPSProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
switch this.IPVersion {
|
||||
case IPv4:
|
||||
result = append(result, ProtocolHTTPS4+"://"+listen)
|
||||
case IPv6:
|
||||
result = append(result, ProtocolHTTPS6+"://"+listen)
|
||||
default:
|
||||
result = append(result, ProtocolHTTPS+"://"+listen)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package configs
|
||||
|
||||
type TCPProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
IPVersion IPVersion `yaml:"ipVersion"` // 4, 6
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *TCPProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
switch this.IPVersion {
|
||||
case IPv4:
|
||||
result = append(result, ProtocolTCP4+"://"+listen)
|
||||
case IPv6:
|
||||
result = append(result, ProtocolTCP6+"://"+listen)
|
||||
default:
|
||||
result = append(result, ProtocolTCP+"://"+listen)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package configs
|
||||
|
||||
type TLSProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
IPVersion string `yaml:"ipVersion"` // 4, 6
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *TLSProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
switch this.IPVersion {
|
||||
case IPv4:
|
||||
result = append(result, ProtocolTLS4+"://"+listen)
|
||||
case IPv6:
|
||||
result = append(result, ProtocolTLS6+"://"+listen)
|
||||
default:
|
||||
result = append(result, ProtocolTLS+"://"+listen)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package configs
|
||||
|
||||
type UDPProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *UDPProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
result = append(result, ProtocolUDP+"://"+listen)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package configs
|
||||
|
||||
type UnixProtocolConfig struct {
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
Listen []string `yaml:"listen" json:"listen"` // 监听地址
|
||||
}
|
||||
|
||||
func (this *UnixProtocolConfig) Addresses() []string {
|
||||
result := []string{}
|
||||
for _, listen := range this.Listen {
|
||||
result = append(result, ProtocolUnix+":"+listen)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package configs
|
||||
|
||||
type ServerConfig struct {
|
||||
Id string `yaml:"id"` // ID
|
||||
IsOn bool `yaml:"isOn"` // 是否开启
|
||||
Components []*ComponentConfig `yaml:"components"` // 组件
|
||||
Filters []*FilterConfig `yaml:"filters"` // 过滤器
|
||||
Name string `yaml:"name"` // 名称
|
||||
Description string `yaml:"description"` // 描述
|
||||
ServerNames []string `yaml:"serverNames"` // 域名
|
||||
|
||||
// 协议
|
||||
HTTP *HTTPProtocolConfig `yaml:"http"` // HTTP配置
|
||||
HTTPS *HTTPSProtocolConfig `yaml:"https"` // HTTPS配置
|
||||
TCP *TCPProtocolConfig `yaml:"tcp"` // TCP配置
|
||||
TLS *TLSProtocolConfig `yaml:"tls"` // TLS配置
|
||||
Unix *UnixProtocolConfig `yaml:"unix"` // Unix配置
|
||||
UDP *UDPProtocolConfig `yaml:"udp"` // UDP配置
|
||||
|
||||
// Web配置
|
||||
Web *WebConfig `yaml:"web"`
|
||||
}
|
||||
|
||||
func NewServerConfig() *ServerConfig {
|
||||
return &ServerConfig{}
|
||||
}
|
||||
|
||||
func (this *ServerConfig) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) FullAddresses() []string {
|
||||
result := []Protocol{}
|
||||
if this.HTTP != nil && this.HTTP.IsOn {
|
||||
result = append(result, this.HTTP.Addresses()...)
|
||||
}
|
||||
if this.HTTPS != nil && this.HTTPS.IsOn {
|
||||
result = append(result, this.HTTPS.Addresses()...)
|
||||
}
|
||||
if this.TCP != nil && this.TCP.IsOn {
|
||||
result = append(result, this.TCP.Addresses()...)
|
||||
}
|
||||
if this.TLS != nil && this.TLS.IsOn {
|
||||
result = append(result, this.TLS.Addresses()...)
|
||||
}
|
||||
if this.Unix != nil && this.Unix.IsOn {
|
||||
result = append(result, this.Unix.Addresses()...)
|
||||
}
|
||||
if this.UDP != nil && this.UDP.IsOn {
|
||||
result = append(result, this.UDP.Addresses()...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package configs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestServerConfig_Protocols(t *testing.T) {
|
||||
{
|
||||
server := NewServerConfig()
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
server := NewServerConfig()
|
||||
server.HTTP = &HTTPProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
server.HTTPS = &HTTPSProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
server.TCP = &TCPProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
server.TLS = &TLSProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
server.Unix = &UnixProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
server.UDP = &UDPProtocolConfig{IsOn: true, Listen: []string{"127.0.0.1:1234"}}
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package configs
|
||||
|
||||
import "strings"
|
||||
|
||||
type ServerGroup struct {
|
||||
fullAddr string
|
||||
Servers []*ServerConfig
|
||||
}
|
||||
|
||||
func NewServerGroup(fullAddr string) *ServerGroup {
|
||||
return &ServerGroup{fullAddr: fullAddr}
|
||||
}
|
||||
|
||||
// 添加服务
|
||||
func (this *ServerGroup) Add(server *ServerConfig) {
|
||||
this.Servers = append(this.Servers, server)
|
||||
}
|
||||
|
||||
// 获取完整的地址
|
||||
func (this *ServerGroup) FullAddr() string {
|
||||
return this.fullAddr
|
||||
}
|
||||
|
||||
// 获取当前分组的协议
|
||||
func (this *ServerGroup) Protocol() Protocol {
|
||||
for _, p := range AllProtocols() {
|
||||
if strings.HasPrefix(this.fullAddr, p+":") {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return ProtocolHTTP
|
||||
}
|
||||
|
||||
// 获取当前分组的地址
|
||||
func (this *ServerGroup) Addr() string {
|
||||
protocol := this.Protocol()
|
||||
if protocol == ProtocolUnix {
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+":")
|
||||
}
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+"://")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
type ComponentConfig struct {
|
||||
}
|
||||
20
internal/configs/serverconfigs/configutils/copy.go
Normal file
20
internal/configs/serverconfigs/configutils/copy.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 拷贝同类型struct指针对象中的字段
|
||||
func CopyStructObject(destPtr, sourcePtr interface{}) {
|
||||
value := reflect.ValueOf(destPtr)
|
||||
value2 := reflect.ValueOf(sourcePtr)
|
||||
|
||||
countFields := value2.Elem().NumField()
|
||||
for i := 0; i < countFields; i++ {
|
||||
v := value2.Elem().Field(i)
|
||||
if !v.IsValid() || !v.CanSet() {
|
||||
continue
|
||||
}
|
||||
value.Elem().Field(i).Set(v)
|
||||
}
|
||||
}
|
||||
28
internal/configs/serverconfigs/configutils/copy_test.go
Normal file
28
internal/configs/serverconfigs/configutils/copy_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCopyStructObject(t *testing.T) {
|
||||
type Book struct {
|
||||
Name string
|
||||
Price int
|
||||
Year int
|
||||
Author string
|
||||
press string
|
||||
}
|
||||
|
||||
book1 := &Book{
|
||||
Name: "Hello Golang",
|
||||
Price: 100,
|
||||
Year: 2020,
|
||||
Author: "Liu",
|
||||
press: "Beijing",
|
||||
}
|
||||
book2 := new(Book)
|
||||
CopyStructObject(book2, book1)
|
||||
logs.PrintAsJSON(book2, t)
|
||||
logs.PrintAsJSON(book1, t)
|
||||
}
|
||||
59
internal/configs/serverconfigs/configutils/domain.go
Normal file
59
internal/configs/serverconfigs/configutils/domain.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 从一组规则中匹配域名
|
||||
// 支持的格式:example.com, www.example.com, .example.com, *.example.com, ~(\d+).example.com
|
||||
// 更多参考:http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
|
||||
func MatchDomains(patterns []string, domain string) (isMatched bool) {
|
||||
if len(patterns) == 0 {
|
||||
return
|
||||
}
|
||||
for _, pattern := range patterns {
|
||||
if matchDomain(pattern, domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 匹配单个域名规则
|
||||
func matchDomain(pattern string, domain string) (isMatched bool) {
|
||||
if len(pattern) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 正则表达式
|
||||
if pattern[0] == '~' {
|
||||
reg, err := stringutil.RegexpCompile(strings.TrimSpace(pattern[1:]))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return false
|
||||
}
|
||||
return reg.MatchString(domain)
|
||||
}
|
||||
|
||||
if pattern[0] == '.' {
|
||||
return strings.HasSuffix(domain, pattern)
|
||||
}
|
||||
|
||||
// 其他匹配
|
||||
patternPieces := strings.Split(pattern, ".")
|
||||
domainPieces := strings.Split(domain, ".")
|
||||
if len(patternPieces) != len(domainPieces) {
|
||||
return
|
||||
}
|
||||
isMatched = true
|
||||
for index, patternPiece := range patternPieces {
|
||||
if patternPiece == "" || patternPiece == "*" || patternPiece == domainPieces[index] {
|
||||
continue
|
||||
}
|
||||
isMatched = false
|
||||
break
|
||||
}
|
||||
return isMatched
|
||||
}
|
||||
79
internal/configs/serverconfigs/configutils/domain_test.go
Normal file
79
internal/configs/serverconfigs/configutils/domain_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchDomain(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
{
|
||||
ok := MatchDomains([]string{}, "example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"example.com"}, "example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"www.example.com"}, "example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "a.www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{".example.com"}, "a.www.example123.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"*.example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"*.*.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"www.*.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"gallery.*.com"}, "www.example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~\\w+.example.com"}, "www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~\\w+.example.com"}, "a.www.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "www.example.com")
|
||||
a.IsFalse(ok)
|
||||
}
|
||||
|
||||
{
|
||||
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "123.example.com")
|
||||
a.IsTrue(ok)
|
||||
}
|
||||
}
|
||||
11
internal/configs/serverconfigs/configutils/log.go
Normal file
11
internal/configs/serverconfigs/configutils/log.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package configutils
|
||||
|
||||
import "github.com/iwind/TeaGo/logs"
|
||||
|
||||
// 记录错误
|
||||
func LogError(arg ...interface{}) {
|
||||
if len(arg) == 0 {
|
||||
return
|
||||
}
|
||||
logs.Println(arg...)
|
||||
}
|
||||
25
internal/configs/serverconfigs/configutils/match.go
Normal file
25
internal/configs/serverconfigs/configutils/match.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var whitespaceReg = regexp.MustCompile(`\s+`)
|
||||
|
||||
// 关键词匹配
|
||||
func MatchKeyword(source, keyword string) bool {
|
||||
if len(keyword) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
pieces := whitespaceReg.Split(keyword, -1)
|
||||
source = strings.ToLower(source)
|
||||
for _, piece := range pieces {
|
||||
if strings.Index(source, strings.ToLower(piece)) > -1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
13
internal/configs/serverconfigs/configutils/match_test.go
Normal file
13
internal/configs/serverconfigs/configutils/match_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchKeyword(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
a.IsTrue(MatchKeyword("a b c", "a"))
|
||||
a.IsFalse(MatchKeyword("a b c", ""))
|
||||
a.IsTrue(MatchKeyword("abc", "BC"))
|
||||
}
|
||||
14
internal/configs/serverconfigs/configutils/yaml.go
Normal file
14
internal/configs/serverconfigs/configutils/yaml.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package configutils
|
||||
|
||||
import (
|
||||
"github.com/go-yaml/yaml"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func UnmarshalYamlFile(file string, ptr interface{}) error {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return yaml.Unmarshal(data, ptr)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
type FilterConfig struct {
|
||||
}
|
||||
43
internal/configs/serverconfigs/global_config.go
Normal file
43
internal/configs/serverconfigs/global_config.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
)
|
||||
|
||||
var globalConfig *GlobalConfig = nil
|
||||
var globalConfigFile = "global.yaml"
|
||||
|
||||
// 全局设置
|
||||
type GlobalConfig struct {
|
||||
HTTPAll struct {
|
||||
MatchDomainStrictly bool `yaml:"matchDomainStrictly"`
|
||||
} `yaml:"httpAll"`
|
||||
HTTP struct{} `yaml:"http"`
|
||||
HTTPS struct{} `yaml:"https"`
|
||||
TCPAll struct{} `yaml:"tcpAll"`
|
||||
TCP struct{} `yaml:"tcp"`
|
||||
TLS struct{} `yaml:"tls"`
|
||||
Unix struct{} `yaml:"unix"`
|
||||
UDP struct{} `yaml:"udp"`
|
||||
}
|
||||
|
||||
func SharedGlobalConfig() *GlobalConfig {
|
||||
shared.Locker.Lock()
|
||||
defer shared.Locker.Unlock()
|
||||
|
||||
if globalConfig != nil {
|
||||
return globalConfig
|
||||
}
|
||||
|
||||
err := configutils.UnmarshalYamlFile(globalConfigFile, globalConfig)
|
||||
if err != nil {
|
||||
configutils.LogError("[SharedGlobalConfig]" + err.Error())
|
||||
globalConfig = &GlobalConfig{}
|
||||
}
|
||||
return globalConfig
|
||||
}
|
||||
|
||||
func (this *GlobalConfig) Init() error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
type IPVersion = string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
type LocationConfig struct {
|
||||
}
|
||||
70
internal/configs/serverconfigs/network_address_config.go
Normal file
70
internal/configs/serverconfigs/network_address_config.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var regexpSinglePort = regexp.MustCompile(`^\d+$`)
|
||||
|
||||
// 网络地址配置
|
||||
type NetworkAddressConfig struct {
|
||||
Protocol string `yaml:"protocol" json:"protocol"` // 协议,http、tcp、tcp4、tcp6、unix、udp等
|
||||
Host string `yaml:"host" json:"host"` // 主机地址或主机名
|
||||
PortRange string `yaml:"portRange" json:"portRange"` // 端口范围,支持 8080、8080-8090、8080:8090
|
||||
|
||||
minPort int
|
||||
maxPort int
|
||||
}
|
||||
|
||||
func (this *NetworkAddressConfig) Init() error {
|
||||
// 8080
|
||||
if regexpSinglePort.MatchString(this.PortRange) {
|
||||
this.minPort = types.Int(this.PortRange)
|
||||
this.maxPort = this.minPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8080:8090
|
||||
if strings.Contains(this.PortRange, ":") {
|
||||
pieces := strings.SplitN(this.PortRange, ":", 2)
|
||||
minPort := types.Int(pieces[0])
|
||||
maxPort := types.Int(pieces[1])
|
||||
if minPort > maxPort {
|
||||
minPort, maxPort = maxPort, minPort
|
||||
}
|
||||
this.minPort = minPort
|
||||
this.maxPort = maxPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8080-8090
|
||||
if strings.Contains(this.PortRange, "-") {
|
||||
pieces := strings.SplitN(this.PortRange, "-", 2)
|
||||
minPort := types.Int(pieces[0])
|
||||
maxPort := types.Int(pieces[1])
|
||||
if minPort > maxPort {
|
||||
minPort, maxPort = maxPort, minPort
|
||||
}
|
||||
this.minPort = minPort
|
||||
this.maxPort = maxPort
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *NetworkAddressConfig) FullAddresses() []string {
|
||||
if this.Protocol == ProtocolUnix {
|
||||
return []string{this.Protocol + ":" + this.Host}
|
||||
}
|
||||
|
||||
result := []string{}
|
||||
for i := this.minPort; i <= this.maxPort; i++ {
|
||||
host := this.Host
|
||||
result = append(result, this.Protocol+"://"+host+":"+strconv.Itoa(i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package serverconfigs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNetworkAddressConfig_FullAddresses(t *testing.T) {
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080:8090",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080-8090",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
addr := &NetworkAddressConfig{
|
||||
Protocol: "http",
|
||||
Host: "127.0.0.1",
|
||||
PortRange: "8080-8070",
|
||||
}
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addr.FullAddresses())
|
||||
}
|
||||
}
|
||||
10
internal/configs/serverconfigs/origin_server_config.go
Normal file
10
internal/configs/serverconfigs/origin_server_config.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package serverconfigs
|
||||
|
||||
// 源站服务配置
|
||||
type OriginServerConfig struct {
|
||||
Id string `yaml:"id" json:"id"` // ID
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
|
||||
Name string `yaml:"name" json:"name"` // 名称 TODO
|
||||
Addr *NetworkAddressConfig `yaml:"addr" json:"addr"` // 地址
|
||||
Description string `yaml:"description" json:"description"` // 描述 TODO
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package serverconfigs
|
||||
|
||||
// TODO 需要实现
|
||||
type OriginServerGroupConfig struct {
|
||||
Origins []*OriginServerConfig `yaml:"origins" json:"origins"` // 源站列表
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
type Protocol = string
|
||||
|
||||
32
internal/configs/serverconfigs/protocol_base.go
Normal file
32
internal/configs/serverconfigs/protocol_base.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package serverconfigs
|
||||
|
||||
// 协议基础数据结构
|
||||
type BaseProtocol struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
Listen []*NetworkAddressConfig `yaml:"listen" json:"listen"` // 绑定的网络地址
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *BaseProtocol) InitBase() error {
|
||||
for _, addr := range this.Listen {
|
||||
err := addr.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取完整的地址列表
|
||||
func (this *BaseProtocol) FullAddresses() []string {
|
||||
result := []string{}
|
||||
for _, addr := range this.Listen {
|
||||
result = append(result, addr.FullAddresses()...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 添加地址
|
||||
func (this *BaseProtocol) AddListen(addr ...*NetworkAddressConfig) {
|
||||
this.Listen = append(this.Listen, addr...)
|
||||
}
|
||||
14
internal/configs/serverconfigs/protocol_http_config.go
Normal file
14
internal/configs/serverconfigs/protocol_http_config.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package serverconfigs
|
||||
|
||||
type HTTPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *HTTPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
24
internal/configs/serverconfigs/protocol_https_config.go
Normal file
24
internal/configs/serverconfigs/protocol_https_config.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
|
||||
// TLS Version
|
||||
type TLSVersion = string
|
||||
|
||||
// Cipher Suites
|
||||
type TLSCipherSuite = string
|
||||
|
||||
type HTTPSProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
|
||||
SSL *sslconfigs.SSLConfig `yaml:"ssl"`
|
||||
}
|
||||
|
||||
func (this *HTTPSProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
14
internal/configs/serverconfigs/protocol_tcp_config.go
Normal file
14
internal/configs/serverconfigs/protocol_tcp_config.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package serverconfigs
|
||||
|
||||
type TCPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *TCPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
18
internal/configs/serverconfigs/protocol_tls_config.go
Normal file
18
internal/configs/serverconfigs/protocol_tls_config.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
|
||||
type TLSProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
|
||||
SSL *sslconfigs.SSLConfig `yaml:"ssl"`
|
||||
}
|
||||
|
||||
func (this *TLSProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
14
internal/configs/serverconfigs/protocol_udp_config.go
Normal file
14
internal/configs/serverconfigs/protocol_udp_config.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package serverconfigs
|
||||
|
||||
type UDPProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *UDPProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
14
internal/configs/serverconfigs/protocol_unix_config.go
Normal file
14
internal/configs/serverconfigs/protocol_unix_config.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package serverconfigs
|
||||
|
||||
type UnixProtocolConfig struct {
|
||||
BaseProtocol `yaml:",inline"`
|
||||
}
|
||||
|
||||
func (this *UnixProtocolConfig) Init() error {
|
||||
err := this.InitBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
6
internal/configs/serverconfigs/reverse_proxy_config.go
Normal file
6
internal/configs/serverconfigs/reverse_proxy_config.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package serverconfigs
|
||||
|
||||
type ReverseProxyConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
|
||||
Origins []*OriginServerConfig `yaml:"origins" json:"origins"` // 源站列表
|
||||
}
|
||||
178
internal/configs/serverconfigs/server_config.go
Normal file
178
internal/configs/serverconfigs/server_config.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
Id string `yaml:"id" json:"id"` // ID
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
Components []*ComponentConfig `yaml:"components" json:"components"` // 组件
|
||||
Filters []*FilterConfig `yaml:"filters" json:"filters"` // 过滤器
|
||||
Name string `yaml:"name" json:"name"` // 名称
|
||||
Description string `yaml:"description" json:"description"` // 描述
|
||||
ServerNames []*ServerNameConfig `yaml:"serverNames" json:"serverNames"` // 域名
|
||||
|
||||
// 前端协议
|
||||
HTTP *HTTPProtocolConfig `yaml:"http" json:"http"` // HTTP配置
|
||||
HTTPS *HTTPSProtocolConfig `yaml:"https" json:"https"` // HTTPS配置
|
||||
TCP *TCPProtocolConfig `yaml:"tcp" json:"tcp"` // TCP配置
|
||||
TLS *TLSProtocolConfig `yaml:"tls" json:"tls"` // TLS配置
|
||||
Unix *UnixProtocolConfig `yaml:"unix" json:"unix"` // Unix配置
|
||||
UDP *UDPProtocolConfig `yaml:"udp" json:"udp"` // UDP配置
|
||||
|
||||
// Web配置
|
||||
Web *WebConfig `yaml:"web" json:"web"`
|
||||
|
||||
// 反向代理配置
|
||||
ReverseProxy *ReverseProxyConfig `yaml:"reverseProxy" json:"reverseProxy"`
|
||||
}
|
||||
|
||||
func NewServerConfig() *ServerConfig {
|
||||
return &ServerConfig{}
|
||||
}
|
||||
|
||||
func (this *ServerConfig) Init() error {
|
||||
if this.HTTP != nil {
|
||||
err := this.HTTP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.HTTPS != nil {
|
||||
err := this.HTTPS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.TCP != nil {
|
||||
err := this.TCP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.TLS != nil {
|
||||
err := this.TLS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.Unix != nil {
|
||||
err := this.Unix.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.UDP != nil {
|
||||
err := this.UDP.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) FullAddresses() []string {
|
||||
result := []Protocol{}
|
||||
if this.HTTP != nil && this.HTTP.IsOn {
|
||||
result = append(result, this.HTTP.FullAddresses()...)
|
||||
}
|
||||
if this.HTTPS != nil && this.HTTPS.IsOn {
|
||||
result = append(result, this.HTTPS.FullAddresses()...)
|
||||
}
|
||||
if this.TCP != nil && this.TCP.IsOn {
|
||||
result = append(result, this.TCP.FullAddresses()...)
|
||||
}
|
||||
if this.TLS != nil && this.TLS.IsOn {
|
||||
result = append(result, this.TLS.FullAddresses()...)
|
||||
}
|
||||
if this.Unix != nil && this.Unix.IsOn {
|
||||
result = append(result, this.Unix.FullAddresses()...)
|
||||
}
|
||||
if this.UDP != nil && this.UDP.IsOn {
|
||||
result = append(result, this.UDP.FullAddresses()...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *ServerConfig) Listen() []*NetworkAddressConfig {
|
||||
result := []*NetworkAddressConfig{}
|
||||
if this.HTTP != nil {
|
||||
result = append(result, this.HTTP.Listen...)
|
||||
}
|
||||
if this.HTTPS != nil {
|
||||
result = append(result, this.HTTPS.Listen...)
|
||||
}
|
||||
if this.TCP != nil {
|
||||
result = append(result, this.TCP.Listen...)
|
||||
}
|
||||
if this.TLS != nil {
|
||||
result = append(result, this.TLS.Listen...)
|
||||
}
|
||||
if this.Unix != nil {
|
||||
result = append(result, this.Unix.Listen...)
|
||||
}
|
||||
if this.UDP != nil {
|
||||
result = append(result, this.UDP.Listen...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *ServerConfig) AsJSON() ([]byte, error) {
|
||||
return json.Marshal(this)
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsHTTP() bool {
|
||||
return this.HTTP != nil || this.HTTPS != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsTCP() bool {
|
||||
return this.TCP != nil || this.TLS != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsUnix() bool {
|
||||
return this.Unix != nil
|
||||
}
|
||||
|
||||
func (this *ServerConfig) IsUDP() bool {
|
||||
return this.UDP != nil
|
||||
}
|
||||
|
||||
// 判断是否和域名匹配
|
||||
func (this *ServerConfig) MatchName(name string) bool {
|
||||
for _, serverName := range this.ServerNames {
|
||||
if serverName.Match(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断是否严格匹配
|
||||
func (this *ServerConfig) MatchNameStrictly(name string) bool {
|
||||
for _, serverName := range this.ServerNames {
|
||||
if serverName.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SSL信息
|
||||
func (this *ServerConfig) SSLConfig() *sslconfigs.SSLConfig {
|
||||
if this.HTTPS != nil {
|
||||
return this.HTTPS.SSL
|
||||
}
|
||||
if this.TLS != nil {
|
||||
return this.TLS.SSL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
74
internal/configs/serverconfigs/server_config_test.go
Normal file
74
internal/configs/serverconfigs/server_config_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package serverconfigs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestServerConfig_Protocols(t *testing.T) {
|
||||
{
|
||||
server := NewServerConfig()
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
|
||||
{
|
||||
server := NewServerConfig()
|
||||
server.HTTP = &HTTPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolHTTP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.HTTPS = &HTTPSProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolUnix,
|
||||
Host: "/hello.sock",
|
||||
PortRange: "1235",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.TCP = &TCPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolHTTPS,
|
||||
PortRange: "1236",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.TLS = &TLSProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolTCP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.Unix = &UnixProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolTLS,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
server.UDP = &UDPProtocolConfig{BaseProtocol: BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*NetworkAddressConfig{
|
||||
{
|
||||
Protocol: ProtocolUDP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
}}
|
||||
err := server.Init()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(server.FullAddresses())
|
||||
}
|
||||
}
|
||||
85
internal/configs/serverconfigs/server_group.go
Normal file
85
internal/configs/serverconfigs/server_group.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package serverconfigs
|
||||
|
||||
import "strings"
|
||||
|
||||
type ServerGroup struct {
|
||||
fullAddr string
|
||||
Servers []*ServerConfig
|
||||
}
|
||||
|
||||
func NewServerGroup(fullAddr string) *ServerGroup {
|
||||
return &ServerGroup{fullAddr: fullAddr}
|
||||
}
|
||||
|
||||
// 添加服务
|
||||
func (this *ServerGroup) Add(server *ServerConfig) {
|
||||
this.Servers = append(this.Servers, server)
|
||||
}
|
||||
|
||||
// 获取完整的地址
|
||||
func (this *ServerGroup) FullAddr() string {
|
||||
return this.fullAddr
|
||||
}
|
||||
|
||||
// 获取当前分组的协议
|
||||
func (this *ServerGroup) Protocol() Protocol {
|
||||
for _, p := range AllProtocols() {
|
||||
if strings.HasPrefix(this.fullAddr, p+":") {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return ProtocolHTTP
|
||||
}
|
||||
|
||||
// 获取当前分组的地址
|
||||
func (this *ServerGroup) Addr() string {
|
||||
protocol := this.Protocol()
|
||||
if protocol == ProtocolUnix {
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+":")
|
||||
}
|
||||
return strings.TrimPrefix(this.fullAddr, protocol+"://")
|
||||
}
|
||||
|
||||
// 判断当前分组是否为HTTP
|
||||
func (this *ServerGroup) IsHTTP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolHTTP || p == ProtocolHTTP4 || p == ProtocolHTTP6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为HTTPS
|
||||
func (this *ServerGroup) IsHTTPS() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolHTTPS || p == ProtocolHTTPS4 || p == ProtocolHTTPS6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为TCP
|
||||
func (this *ServerGroup) IsTCP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolTCP || p == ProtocolTCP4 || p == ProtocolTCP6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为TLS
|
||||
func (this *ServerGroup) IsTLS() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolTLS || p == ProtocolTLS4 || p == ProtocolTLS6
|
||||
}
|
||||
|
||||
// 判断当前分组是否为Unix
|
||||
func (this *ServerGroup) IsUnix() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolUnix
|
||||
}
|
||||
|
||||
// 判断当前分组是否为UDP
|
||||
func (this *ServerGroup) IsUDP() bool {
|
||||
p := this.Protocol()
|
||||
return p == ProtocolUDP
|
||||
}
|
||||
|
||||
// 获取第一个Server
|
||||
func (this *ServerGroup) FirstServer() *ServerConfig {
|
||||
if len(this.Servers) > 0 {
|
||||
return this.Servers[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package configs
|
||||
package serverconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
23
internal/configs/serverconfigs/server_name_config.go
Normal file
23
internal/configs/serverconfigs/server_name_config.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
|
||||
type ServerNameType = string
|
||||
|
||||
const (
|
||||
ServerNameTypeFull = "full" // 完整的域名,包含通配符等
|
||||
ServerNameTypePrefix = "prefix" // 前缀
|
||||
ServerNameTypeSuffix = "suffix" // 后缀
|
||||
ServerNameTypeMatch = "match" // 正则匹配
|
||||
)
|
||||
|
||||
// 主机名(域名)配置
|
||||
type ServerNameConfig struct {
|
||||
Name string `yaml:"name" json:"name"` // 名称
|
||||
Type string `yaml:"type" json:"type"` // 类型
|
||||
}
|
||||
|
||||
// 判断主机名是否匹配
|
||||
func (this *ServerNameConfig) Match(name string) bool {
|
||||
return configutils.MatchDomains([]string{this.Name}, name)
|
||||
}
|
||||
21
internal/configs/serverconfigs/shared/locker.go
Normal file
21
internal/configs/serverconfigs/shared/locker.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var Locker = new(FileLocker)
|
||||
|
||||
// global file modify locker
|
||||
type FileLocker struct {
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
// lock
|
||||
func (this *FileLocker) Lock() {
|
||||
this.locker.Lock()
|
||||
}
|
||||
|
||||
func (this *FileLocker) Unlock() {
|
||||
this.locker.Unlock()
|
||||
}
|
||||
207
internal/configs/serverconfigs/sslconfigs/ssl.go
Normal file
207
internal/configs/serverconfigs/sslconfigs/ssl.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TLS Version
|
||||
type TLSVersion = string
|
||||
|
||||
// Cipher Suites
|
||||
type TLSCipherSuite = string
|
||||
|
||||
// SSL配置
|
||||
type SSLConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
||||
|
||||
Certs []*SSLCertConfig `yaml:"certs" json:"certs"`
|
||||
ClientAuthType SSLClientAuthType `yaml:"clientAuthType" json:"clientAuthType"` // 客户端认证类型
|
||||
ClientCACertIds []string `yaml:"clientCACertIds" json:"clientCACertIds"` // 客户端认证CA
|
||||
|
||||
Listen []string `yaml:"listen" json:"listen"` // 网络地址
|
||||
MinVersion TLSVersion `yaml:"minVersion" json:"minVersion"` // 支持的最小版本
|
||||
CipherSuites []TLSCipherSuite `yaml:"cipherSuites" json:"cipherSuites"` // 加密算法套件
|
||||
|
||||
HSTS *HSTSConfig `yaml:"hsts2" json:"hsts"` // HSTS配置,yaml之所以使用hsts2,是因为要和以前的版本分开
|
||||
HTTP2Disabled bool `yaml:"http2Disabled" json:"http2Disabled"` // 是否禁用HTTP2
|
||||
|
||||
nameMapping map[string]*tls.Certificate // dnsName => cert
|
||||
|
||||
minVersion uint16
|
||||
cipherSuites []uint16
|
||||
|
||||
clientCAPool *x509.CertPool
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewSSLConfig() *SSLConfig {
|
||||
return &SSLConfig{}
|
||||
}
|
||||
|
||||
// 校验配置
|
||||
func (this *SSLConfig) Init() error {
|
||||
if !this.IsOn {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(this.Certs) == 0 {
|
||||
return errors.New("no certificates in https config")
|
||||
}
|
||||
|
||||
for _, cert := range this.Certs {
|
||||
err := cert.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.Listen == nil {
|
||||
this.Listen = []string{}
|
||||
} else {
|
||||
for index, addr := range this.Listen {
|
||||
_, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
this.Listen[index] = strings.TrimSuffix(addr, ":") + ":443"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// min version
|
||||
this.convertMinVersion()
|
||||
|
||||
// cipher suite categories
|
||||
this.initCipherSuites()
|
||||
|
||||
// hsts
|
||||
if this.HSTS != nil {
|
||||
err := this.HSTS.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// CA证书
|
||||
if len(this.ClientCACertIds) > 0 && this.ClientAuthType != SSLClientAuthTypeNoClientCert {
|
||||
this.clientCAPool = x509.NewCertPool()
|
||||
list := SharedSSLCertList()
|
||||
for _, certId := range this.ClientCACertIds {
|
||||
cert := list.FindCert(certId)
|
||||
if cert == nil {
|
||||
continue
|
||||
}
|
||||
if !cert.On {
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadFile(cert.FullCertPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.clientCAPool.AppendCertsFromPEM(data)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 取得最小版本
|
||||
func (this *SSLConfig) TLSMinVersion() uint16 {
|
||||
return this.minVersion
|
||||
}
|
||||
|
||||
// 套件
|
||||
func (this *SSLConfig) TLSCipherSuites() []uint16 {
|
||||
return this.cipherSuites
|
||||
}
|
||||
|
||||
// 校验是否匹配某个域名
|
||||
func (this *SSLConfig) MatchDomain(domain string) (cert *tls.Certificate, ok bool) {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.MatchDomain(domain) {
|
||||
return cert.CertObject(), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// 取得第一个证书
|
||||
func (this *SSLConfig) FirstCert() *tls.Certificate {
|
||||
for _, cert := range this.Certs {
|
||||
return cert.CertObject()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否包含某个证书或密钥路径
|
||||
func (this *SSLConfig) ContainsFile(file string) bool {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.CertFile == file || cert.KeyFile == file {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除证书文件
|
||||
func (this *SSLConfig) DeleteFiles() error {
|
||||
var resultErr error = nil
|
||||
|
||||
for _, cert := range this.Certs {
|
||||
err := cert.DeleteFiles()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// 查找单个证书配置
|
||||
func (this *SSLConfig) FindCert(certId string) *SSLCertConfig {
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加证书
|
||||
func (this *SSLConfig) AddCert(cert *SSLCertConfig) {
|
||||
this.Certs = append(this.Certs, cert)
|
||||
}
|
||||
|
||||
// CA证书Pool,用于TLS对客户端进行认证
|
||||
func (this *SSLConfig) CAPool() *x509.CertPool {
|
||||
return this.clientCAPool
|
||||
}
|
||||
|
||||
// 分解所有监听地址
|
||||
func (this *SSLConfig) ParseListenAddresses() []string {
|
||||
result := []string{}
|
||||
var reg = regexp.MustCompile(`\[\s*(\d+)\s*[,:-]\s*(\d+)\s*]$`)
|
||||
for _, addr := range this.Listen {
|
||||
match := reg.FindStringSubmatch(addr)
|
||||
if len(match) == 0 {
|
||||
result = append(result, addr)
|
||||
} else {
|
||||
min := types.Int(match[1])
|
||||
max := types.Int(match[2])
|
||||
if min > max {
|
||||
min, max = max, min
|
||||
}
|
||||
for i := min; i <= max; i++ {
|
||||
newAddr := reg.ReplaceAllString(addr, ":"+strconv.Itoa(i))
|
||||
result = append(result, newAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
75
internal/configs/serverconfigs/sslconfigs/ssl_auth.go
Normal file
75
internal/configs/serverconfigs/sslconfigs/ssl_auth.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 认证类型
|
||||
type SSLClientAuthType = int
|
||||
|
||||
const (
|
||||
SSLClientAuthTypeNoClientCert SSLClientAuthType = 0
|
||||
SSLClientAuthTypeRequestClientCert SSLClientAuthType = 1
|
||||
SSLClientAuthTypeRequireAnyClientCert SSLClientAuthType = 2
|
||||
SSLClientAuthTypeVerifyClientCertIfGiven SSLClientAuthType = 3
|
||||
SSLClientAuthTypeRequireAndVerifyClientCert SSLClientAuthType = 4
|
||||
)
|
||||
|
||||
// 所有的客户端认证类型
|
||||
func AllSSLClientAuthTypes() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"name": "不需要客户端证书",
|
||||
"type": SSLClientAuthTypeNoClientCert,
|
||||
"requireCA": false,
|
||||
},
|
||||
{
|
||||
"name": "请求客户端证书",
|
||||
"type": SSLClientAuthTypeRequestClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "需要客户端证书,但不校验",
|
||||
"type": SSLClientAuthTypeRequireAnyClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "有客户端证书的时候才校验",
|
||||
"type": SSLClientAuthTypeVerifyClientCertIfGiven,
|
||||
"requireCA": true,
|
||||
},
|
||||
{
|
||||
"name": "校验客户端提供的证书",
|
||||
"type": SSLClientAuthTypeRequireAndVerifyClientCert,
|
||||
"requireCA": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 查找单个认证方式的名称
|
||||
func FindSSLClientAuthTypeName(authType SSLClientAuthType) string {
|
||||
for _, m := range AllSSLClientAuthTypes() {
|
||||
if m.GetInt("type") == authType {
|
||||
return m.GetString("name")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 认证类型和tls包内类型的映射
|
||||
func GoSSLClientAuthType(authType SSLClientAuthType) tls.ClientAuthType {
|
||||
switch authType {
|
||||
case SSLClientAuthTypeNoClientCert:
|
||||
return tls.NoClientCert
|
||||
case SSLClientAuthTypeRequestClientCert:
|
||||
return tls.RequestClientCert
|
||||
case SSLClientAuthTypeRequireAnyClientCert:
|
||||
return tls.RequireAnyClientCert
|
||||
case SSLClientAuthTypeVerifyClientCertIfGiven:
|
||||
return tls.VerifyClientCertIfGiven
|
||||
case SSLClientAuthTypeRequireAndVerifyClientCert:
|
||||
return tls.RequireAndVerifyClientCert
|
||||
}
|
||||
return tls.NoClientCert
|
||||
}
|
||||
271
internal/configs/serverconfigs/sslconfigs/ssl_cert.go
Normal file
271
internal/configs/serverconfigs/sslconfigs/ssl_cert.go
Normal file
@@ -0,0 +1,271 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSL证书
|
||||
type SSLCertConfig struct {
|
||||
Id string `yaml:"id" json:"id"`
|
||||
On bool `yaml:"on" json:"on"`
|
||||
Description string `yaml:"description" json:"description"` // 说明
|
||||
CertFile string `yaml:"certFile" json:"certFile"`
|
||||
KeyFile string `yaml:"keyFile" json:"keyFile"`
|
||||
IsLocal bool `yaml:"isLocal" json:"isLocal"` // 是否为本地文件
|
||||
TaskId string `yaml:"taskId" json:"taskId"` // 生成证书任务ID
|
||||
IsShared bool `yaml:"isShared" json:"isShared"` // 是否为公用组件
|
||||
ServerName string `yaml:"serverName" json:"serverName"` // 证书使用的主机名,在请求TLS服务器时需要
|
||||
IsCA bool `yaml:"isCA" json:"isCA"` // 是否为CA证书
|
||||
|
||||
dnsNames []string
|
||||
cert *tls.Certificate
|
||||
timeBefore time.Time
|
||||
timeAfter time.Time
|
||||
issuer pkix.Name
|
||||
}
|
||||
|
||||
// 获取新的SSL证书
|
||||
func NewSSLCertConfig(certFile string, keyFile string) *SSLCertConfig {
|
||||
return &SSLCertConfig{
|
||||
On: true,
|
||||
Id: stringutil.Rand(16),
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
}
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *SSLCertConfig) Init() error {
|
||||
if this.IsShared {
|
||||
shared := this.FindShared()
|
||||
if shared == nil {
|
||||
return errors.New("the shared cert has been deleted")
|
||||
}
|
||||
|
||||
// 拷贝之前需要保留的
|
||||
serverName := this.ServerName
|
||||
|
||||
// copy
|
||||
configutils.CopyStructObject(this, shared)
|
||||
this.ServerName = serverName
|
||||
}
|
||||
|
||||
this.dnsNames = []string{}
|
||||
|
||||
if len(this.CertFile) == 0 {
|
||||
return errors.New("cert file should not be empty")
|
||||
}
|
||||
|
||||
// 分析证书
|
||||
if this.IsCA { // CA证书
|
||||
data, err := ioutil.ReadFile(this.FullCertPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
index := -1
|
||||
this.cert = &tls.Certificate{
|
||||
Certificate: [][]byte{},
|
||||
}
|
||||
for {
|
||||
index++
|
||||
|
||||
block, rest := pem.Decode(data)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
break
|
||||
}
|
||||
this.cert.Certificate = append(this.cert.Certificate, block.Bytes)
|
||||
data = rest
|
||||
c, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
return errors.New("no available certificates in file")
|
||||
}
|
||||
|
||||
dnsNames := c.DNSNames
|
||||
if len(dnsNames) > 0 {
|
||||
for _, dnsName := range dnsNames {
|
||||
if !lists.ContainsString(this.dnsNames, dnsName) {
|
||||
this.dnsNames = append(this.dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
this.timeBefore = c.NotBefore
|
||||
this.timeAfter = c.NotAfter
|
||||
this.issuer = c.Issuer
|
||||
}
|
||||
}
|
||||
} else { // 证书+私钥
|
||||
if len(this.KeyFile) == 0 {
|
||||
return errors.New("key file should not be empty")
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(this.FullCertPath(), this.FullKeyPath())
|
||||
if err != nil {
|
||||
return errors.New("load certificate '" + this.CertFile + "', '" + this.KeyFile + "' failed:" + err.Error())
|
||||
}
|
||||
|
||||
for index, data := range cert.Certificate {
|
||||
c, err := x509.ParseCertificate(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
dnsNames := c.DNSNames
|
||||
if len(dnsNames) > 0 {
|
||||
for _, dnsName := range dnsNames {
|
||||
if !lists.ContainsString(this.dnsNames, dnsName) {
|
||||
this.dnsNames = append(this.dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
this.timeBefore = c.NotBefore
|
||||
this.timeAfter = c.NotAfter
|
||||
this.issuer = c.Issuer
|
||||
}
|
||||
}
|
||||
|
||||
this.cert = &cert
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查找共享的证书
|
||||
func (this *SSLCertConfig) FindShared() *SSLCertConfig {
|
||||
if !this.IsShared {
|
||||
return nil
|
||||
}
|
||||
return SharedSSLCertList().FindCert(this.Id)
|
||||
}
|
||||
|
||||
// 证书文件路径
|
||||
func (this *SSLCertConfig) FullCertPath() string {
|
||||
if len(this.CertFile) == 0 {
|
||||
return ""
|
||||
}
|
||||
if !strings.ContainsAny(this.CertFile, "/\\") {
|
||||
return Tea.ConfigFile(this.CertFile)
|
||||
}
|
||||
return this.CertFile
|
||||
}
|
||||
|
||||
// 密钥文件路径
|
||||
func (this *SSLCertConfig) FullKeyPath() string {
|
||||
if len(this.KeyFile) == 0 {
|
||||
return ""
|
||||
}
|
||||
if !strings.ContainsAny(this.KeyFile, "/\\") {
|
||||
return Tea.ConfigFile(this.KeyFile)
|
||||
}
|
||||
return this.KeyFile
|
||||
}
|
||||
|
||||
// 校验是否匹配某个域名
|
||||
func (this *SSLCertConfig) MatchDomain(domain string) bool {
|
||||
if len(this.dnsNames) == 0 {
|
||||
return false
|
||||
}
|
||||
return configutils.MatchDomains(this.dnsNames, domain)
|
||||
}
|
||||
|
||||
// 证书中的域名
|
||||
func (this *SSLCertConfig) DNSNames() []string {
|
||||
return this.dnsNames
|
||||
}
|
||||
|
||||
// 获取证书对象
|
||||
func (this *SSLCertConfig) CertObject() *tls.Certificate {
|
||||
return this.cert
|
||||
}
|
||||
|
||||
// 开始时间
|
||||
func (this *SSLCertConfig) TimeBefore() time.Time {
|
||||
return this.timeBefore
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
func (this *SSLCertConfig) TimeAfter() time.Time {
|
||||
return this.timeAfter
|
||||
}
|
||||
|
||||
// 发行信息
|
||||
func (this *SSLCertConfig) Issuer() pkix.Name {
|
||||
return this.issuer
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
func (this *SSLCertConfig) DeleteFiles() error {
|
||||
if this.IsLocal {
|
||||
return nil
|
||||
}
|
||||
|
||||
var resultErr error = nil
|
||||
if len(this.CertFile) > 0 && !strings.ContainsAny(this.CertFile, "/\\") {
|
||||
err := files.NewFile(this.FullCertPath()).Delete()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
|
||||
if len(this.KeyFile) > 0 && !strings.ContainsAny(this.KeyFile, "/\\") {
|
||||
err := files.NewFile(this.FullKeyPath()).Delete()
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
}
|
||||
}
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// 读取证书文件
|
||||
func (this *SSLCertConfig) ReadCert() ([]byte, error) {
|
||||
if len(this.CertFile) == 0 {
|
||||
return nil, errors.New("cert file should not be empty")
|
||||
}
|
||||
|
||||
if this.IsLocal {
|
||||
return ioutil.ReadFile(this.CertFile)
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(Tea.ConfigFile(this.CertFile))
|
||||
}
|
||||
|
||||
// 读取密钥文件
|
||||
func (this *SSLCertConfig) ReadKey() ([]byte, error) {
|
||||
if len(this.KeyFile) == 0 {
|
||||
return nil, errors.New("key file should not be empty")
|
||||
}
|
||||
|
||||
if this.IsLocal {
|
||||
return ioutil.ReadFile(this.KeyFile)
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(Tea.ConfigFile(this.KeyFile))
|
||||
}
|
||||
|
||||
// 匹配关键词
|
||||
func (this *SSLCertConfig) MatchKeyword(keyword string) (matched bool, name string, tags []string) {
|
||||
if configutils.MatchKeyword(this.Description, keyword) {
|
||||
matched = true
|
||||
name = this.Description
|
||||
}
|
||||
return
|
||||
}
|
||||
86
internal/configs/serverconfigs/sslconfigs/ssl_cert_list.go
Normal file
86
internal/configs/serverconfigs/sslconfigs/ssl_cert_list.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
sslCertListFilename = "ssl.certs.conf"
|
||||
)
|
||||
|
||||
// 获取证书列表实例
|
||||
// 一定会返回不为nil的值
|
||||
func SharedSSLCertList() *SSLCertList {
|
||||
data, err := ioutil.ReadFile(Tea.ConfigFile(sslCertListFilename))
|
||||
if err != nil {
|
||||
return NewSSLCertList()
|
||||
}
|
||||
|
||||
list := &SSLCertList{}
|
||||
err = yaml.Unmarshal(data, list)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return NewSSLCertList()
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// 公共的SSL证书列表
|
||||
type SSLCertList struct {
|
||||
Certs []*SSLCertConfig `yaml:"certs" json:"certs"` // 证书
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewSSLCertList() *SSLCertList {
|
||||
return &SSLCertList{
|
||||
Certs: []*SSLCertConfig{},
|
||||
}
|
||||
}
|
||||
|
||||
// 添加证书
|
||||
func (this *SSLCertList) AddCert(cert *SSLCertConfig) {
|
||||
this.Certs = append(this.Certs, cert)
|
||||
}
|
||||
|
||||
// 删除证书
|
||||
func (this *SSLCertList) RemoveCert(certId string) {
|
||||
result := []*SSLCertConfig{}
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
continue
|
||||
}
|
||||
result = append(result, cert)
|
||||
}
|
||||
this.Certs = result
|
||||
}
|
||||
|
||||
// 查找证书
|
||||
func (this *SSLCertList) FindCert(certId string) *SSLCertConfig {
|
||||
if len(certId) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, cert := range this.Certs {
|
||||
if cert.Id == certId {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 保存
|
||||
func (this *SSLCertList) Save() error {
|
||||
shared.Locker.Lock()
|
||||
defer shared.Locker.Unlock()
|
||||
|
||||
data, err := yaml.Marshal(this)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(Tea.ConfigFile(sslCertListFilename), data, 0777)
|
||||
}
|
||||
124
internal/configs/serverconfigs/sslconfigs/ssl_go_1.11.go
Normal file
124
internal/configs/serverconfigs/sslconfigs/ssl_go_1.11.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// +build !go1.12
|
||||
|
||||
package sslconfigs
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
var AllTlsVersions = []TLSVersion{"SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2"}
|
||||
|
||||
var AllTLSCipherSuites = []TLSCipherSuite{
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
}
|
||||
|
||||
var TLSModernCipherSuites = []string{
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
}
|
||||
|
||||
var TLSIntermediateCipherSuites = []string{
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
}
|
||||
|
||||
func (this *SSLConfig) convertMinVersion() {
|
||||
switch this.MinVersion {
|
||||
case "SSL 3.0":
|
||||
this.minVersion = tls.VersionSSL30
|
||||
case "TLS 1.0":
|
||||
this.minVersion = tls.VersionTLS10
|
||||
case "TLS 1.1":
|
||||
this.minVersion = tls.VersionTLS11
|
||||
case "TLS 1.2":
|
||||
this.minVersion = tls.VersionTLS12
|
||||
default:
|
||||
this.minVersion = tls.VersionTLS10
|
||||
}
|
||||
}
|
||||
|
||||
func (this *SSLConfig) initCipherSuites() {
|
||||
// cipher suites
|
||||
suites := []uint16{}
|
||||
for _, suite := range this.CipherSuites {
|
||||
switch suite {
|
||||
case "TLS_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
|
||||
}
|
||||
}
|
||||
this.cipherSuites = suites
|
||||
}
|
||||
148
internal/configs/serverconfigs/sslconfigs/ssl_go_1.12.go
Normal file
148
internal/configs/serverconfigs/sslconfigs/ssl_go_1.12.go
Normal file
@@ -0,0 +1,148 @@
|
||||
// +build go1.12
|
||||
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"os"
|
||||
)
|
||||
|
||||
var AllTlsVersions = []TLSVersion{"SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2", "TLS 1.3"}
|
||||
|
||||
var AllTLSCipherSuites = []TLSCipherSuite{
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
}
|
||||
|
||||
var TLSModernCipherSuites = []string{
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
}
|
||||
|
||||
var TLSIntermediateCipherSuites = []string{
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
}
|
||||
|
||||
func (this *SSLConfig) convertMinVersion() {
|
||||
switch this.MinVersion {
|
||||
case "SSL 3.0":
|
||||
this.minVersion = tls.VersionSSL30
|
||||
case "TLS 1.0":
|
||||
this.minVersion = tls.VersionTLS10
|
||||
case "TLS 1.1":
|
||||
this.minVersion = tls.VersionTLS11
|
||||
case "TLS 1.2":
|
||||
this.minVersion = tls.VersionTLS12
|
||||
case "TLS 1.3":
|
||||
this.minVersion = tls.VersionTLS13
|
||||
|
||||
os.Setenv("GODEBUG", "tls13=1") // TODO should be removed in go 1.14, in go 1.12 tls IS NOT FULL IMPLEMENTED YET
|
||||
default:
|
||||
this.minVersion = tls.VersionTLS10
|
||||
}
|
||||
}
|
||||
|
||||
func (this *SSLConfig) initCipherSuites() {
|
||||
// cipher suites
|
||||
suites := []uint16{}
|
||||
for _, suite := range this.CipherSuites {
|
||||
switch suite {
|
||||
case "TLS_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_RC4_128_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
case "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
|
||||
case "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
|
||||
suites = append(suites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
|
||||
case "TLS_AES_128_GCM_SHA256":
|
||||
suites = append(suites, tls.TLS_AES_128_GCM_SHA256)
|
||||
case "TLS_AES_256_GCM_SHA384":
|
||||
suites = append(suites, tls.TLS_AES_256_GCM_SHA384)
|
||||
case "TLS_CHACHA20_POLY1305_SHA256":
|
||||
suites = append(suites, tls.TLS_CHACHA20_POLY1305_SHA256)
|
||||
}
|
||||
}
|
||||
this.cipherSuites = suites
|
||||
}
|
||||
63
internal/configs/serverconfigs/sslconfigs/ssl_hsts.go
Normal file
63
internal/configs/serverconfigs/sslconfigs/ssl_hsts.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/configutils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HSTS设置
|
||||
// 参考: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
||||
type HSTSConfig struct {
|
||||
On bool `yaml:"on" json:"on"`
|
||||
MaxAge int `yaml:"maxAge" json:"maxAge"` // 单位秒
|
||||
IncludeSubDomains bool `yaml:"includeSubDomains" json:"includeSubDomains"`
|
||||
Preload bool `yaml:"preload" json:"preload"`
|
||||
Domains []string `yaml:"domains" json:"domains"`
|
||||
|
||||
hasDomains bool
|
||||
headerValue string
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *HSTSConfig) Init() error {
|
||||
this.hasDomains = len(this.Domains) > 0
|
||||
this.headerValue = this.asHeaderValue()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否匹配域名
|
||||
func (this *HSTSConfig) Match(domain string) bool {
|
||||
if !this.hasDomains {
|
||||
return true
|
||||
}
|
||||
return configutils.MatchDomains(this.Domains, domain)
|
||||
}
|
||||
|
||||
// Header Key
|
||||
func (this *HSTSConfig) HeaderKey() string {
|
||||
return "Strict-Transport-Security"
|
||||
}
|
||||
|
||||
// 取得当前的Header值
|
||||
func (this *HSTSConfig) HeaderValue() string {
|
||||
return this.headerValue
|
||||
}
|
||||
|
||||
// 转换为Header值
|
||||
func (this *HSTSConfig) asHeaderValue() string {
|
||||
b := strings.Builder{}
|
||||
b.WriteString("max-age=")
|
||||
if this.MaxAge > 0 {
|
||||
b.WriteString(strconv.Itoa(this.MaxAge))
|
||||
} else {
|
||||
b.WriteString("31536000") // 1 year
|
||||
}
|
||||
if this.IncludeSubDomains {
|
||||
b.WriteString("; includeSubDomains")
|
||||
}
|
||||
if this.Preload {
|
||||
b.WriteString("; preload")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
39
internal/configs/serverconfigs/sslconfigs/ssl_hsts_test.go
Normal file
39
internal/configs/serverconfigs/sslconfigs/ssl_hsts_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHSTSConfig(t *testing.T) {
|
||||
h := &HSTSConfig{}
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.IncludeSubDomains = true
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.Preload = true
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.IncludeSubDomains = false
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
h.MaxAge = 86400
|
||||
h.Init()
|
||||
t.Log(h.HeaderValue())
|
||||
|
||||
a := assert.NewAssertion(t)
|
||||
a.IsTrue(h.Match("abc.com"))
|
||||
|
||||
h.Domains = []string{"abc.com"}
|
||||
h.Init()
|
||||
a.IsTrue(h.Match("abc.com"))
|
||||
|
||||
h.Domains = []string{"1.abc.com"}
|
||||
h.Init()
|
||||
a.IsFalse(h.Match("abc.com"))
|
||||
}
|
||||
10
internal/configs/serverconfigs/web_config.go
Normal file
10
internal/configs/serverconfigs/web_config.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package serverconfigs
|
||||
|
||||
type WebConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
|
||||
Locations []*LocationConfig `yaml:"locations" json:"locations"` // 路径规则 TODO
|
||||
|
||||
// 本地静态资源配置
|
||||
Root string `yaml:"root" json:"root"` // 资源根目录 TODO
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package configs
|
||||
|
||||
type WebConfig struct {
|
||||
Locations []*LocationConfig `yaml:"locations"` // 路径规则
|
||||
|
||||
// 本地静态资源配置
|
||||
Root string `yaml:"root" json:"root"` // 资源根目录
|
||||
}
|
||||
13
internal/const/const.go
Normal file
13
internal/const/const.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.0.1"
|
||||
|
||||
ProductName = "Edge Node"
|
||||
ProcessName = "edge-node"
|
||||
|
||||
Role = "node"
|
||||
|
||||
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
|
||||
EncryptMethod = "aes-256-cfb"
|
||||
)
|
||||
41
internal/encrypt/magic_key.go
Normal file
41
internal/encrypt/magic_key.go
Normal 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
|
||||
}
|
||||
11
internal/encrypt/magic_key_test.go
Normal file
11
internal/encrypt/magic_key_test.go
Normal 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))
|
||||
}
|
||||
12
internal/encrypt/method.go
Normal file
12
internal/encrypt/method.go
Normal 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)
|
||||
}
|
||||
73
internal/encrypt/method_aes_128_cfb.go
Normal file
73
internal/encrypt/method_aes_128_cfb.go
Normal 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
|
||||
}
|
||||
92
internal/encrypt/method_aes_128_cfb_test.go
Normal file
92
internal/encrypt/method_aes_128_cfb_test.go
Normal 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
|
||||
}
|
||||
}
|
||||
74
internal/encrypt/method_aes_192_cfb.go
Normal file
74
internal/encrypt/method_aes_192_cfb.go
Normal 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
|
||||
}
|
||||
45
internal/encrypt/method_aes_192_cfb_test.go
Normal file
45
internal/encrypt/method_aes_192_cfb_test.go
Normal 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
|
||||
}
|
||||
}
|
||||
72
internal/encrypt/method_aes_256_cfb.go
Normal file
72
internal/encrypt/method_aes_256_cfb.go
Normal 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
|
||||
}
|
||||
42
internal/encrypt/method_aes_256_cfb_test.go
Normal file
42
internal/encrypt/method_aes_256_cfb_test.go
Normal 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))
|
||||
}
|
||||
26
internal/encrypt/method_raw.go
Normal file
26
internal/encrypt/method_raw.go
Normal 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
|
||||
}
|
||||
23
internal/encrypt/method_raw_test.go
Normal file
23
internal/encrypt/method_raw_test.go
Normal 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))
|
||||
}
|
||||
43
internal/encrypt/method_utils.go
Normal file
43
internal/encrypt/method_utils.go
Normal 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
|
||||
}
|
||||
8
internal/encrypt/method_utils_test.go
Normal file
8
internal/encrypt/method_utils_test.go
Normal 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", ""))
|
||||
}
|
||||
@@ -3,17 +3,16 @@ package nodes
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
group *configs.ServerGroup
|
||||
group *serverconfigs.ServerGroup
|
||||
isListening bool
|
||||
listener interface{} // 监听器
|
||||
listener ListenerImpl // 监听器
|
||||
|
||||
locker sync.RWMutex
|
||||
}
|
||||
@@ -22,7 +21,7 @@ func NewListener() *Listener {
|
||||
return &Listener{}
|
||||
}
|
||||
|
||||
func (this *Listener) Reload(group *configs.ServerGroup) {
|
||||
func (this *Listener) Reload(group *serverconfigs.ServerGroup) {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
this.group = group
|
||||
@@ -40,78 +39,67 @@ func (this *Listener) Listen() error {
|
||||
return nil
|
||||
}
|
||||
protocol := this.group.Protocol()
|
||||
switch protocol {
|
||||
case configs.ProtocolHTTP, configs.ProtocolHTTP4, configs.ProtocolHTTP6:
|
||||
return this.listenHTTP()
|
||||
case configs.ProtocolHTTPS, configs.ProtocolHTTPS4, configs.ProtocolHTTPS6:
|
||||
return this.ListenHTTPS()
|
||||
case configs.ProtocolTCP, configs.ProtocolTCP4, configs.ProtocolTCP6:
|
||||
return this.listenTCP()
|
||||
case configs.ProtocolTLS, configs.ProtocolTLS4, configs.ProtocolTLS6:
|
||||
return this.listenTLS()
|
||||
case configs.ProtocolUnix:
|
||||
return this.listenUnix()
|
||||
case configs.ProtocolUDP:
|
||||
return this.listenUDP()
|
||||
default:
|
||||
return errors.New("unknown protocol '" + protocol + "'")
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Listener) Close() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) listenHTTP() error {
|
||||
listener, err := this.createListener()
|
||||
netListener, err := this.createListener()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
_, _ = writer.Write([]byte("Hello, World"))
|
||||
})
|
||||
server := &http.Server{
|
||||
Addr: this.group.Addr(),
|
||||
Handler: mux,
|
||||
switch protocol {
|
||||
case serverconfigs.ProtocolHTTP, serverconfigs.ProtocolHTTP4, serverconfigs.ProtocolHTTP6:
|
||||
this.listener = &HTTPListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
case serverconfigs.ProtocolHTTPS, serverconfigs.ProtocolHTTPS4, serverconfigs.ProtocolHTTPS6:
|
||||
this.listener = &HTTPListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
case serverconfigs.ProtocolTCP, serverconfigs.ProtocolTCP4, serverconfigs.ProtocolTCP6:
|
||||
this.listener = &TCPListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
case serverconfigs.ProtocolTLS, serverconfigs.ProtocolTLS4, serverconfigs.ProtocolTLS6:
|
||||
this.listener = &TCPListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
case serverconfigs.ProtocolUnix:
|
||||
this.listener = &UnixListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
case serverconfigs.ProtocolUDP:
|
||||
this.listener = &UDPListener{
|
||||
Group: this.group,
|
||||
Listener: netListener,
|
||||
}
|
||||
default:
|
||||
return errors.New("unknown protocol '" + protocol + "'")
|
||||
}
|
||||
|
||||
this.listener.Init()
|
||||
|
||||
go func() {
|
||||
err = server.Serve(listener)
|
||||
err := this.listener.Serve()
|
||||
if err != nil {
|
||||
logs.Println("[LISTENER]" + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) ListenHTTPS() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) listenTCP() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) listenTLS() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) listenUnix() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Listener) listenUDP() error {
|
||||
// TODO 需要实现
|
||||
return nil
|
||||
func (this *Listener) Close() error {
|
||||
if this.listener == nil {
|
||||
return nil
|
||||
}
|
||||
return this.listener.Close()
|
||||
}
|
||||
|
||||
// 创建监听器
|
||||
func (this *Listener) createListener() (net.Listener, error) {
|
||||
listenConfig := net.ListenConfig{
|
||||
Control: nil,
|
||||
@@ -119,9 +107,9 @@ func (this *Listener) createListener() (net.Listener, error) {
|
||||
}
|
||||
|
||||
switch this.group.Protocol() {
|
||||
case configs.ProtocolHTTP4, configs.ProtocolHTTPS4, configs.ProtocolTLS4:
|
||||
case serverconfigs.ProtocolHTTP4, serverconfigs.ProtocolHTTPS4, serverconfigs.ProtocolTLS4:
|
||||
return listenConfig.Listen(context.Background(), "tcp4", this.group.Addr())
|
||||
case configs.ProtocolHTTP6, configs.ProtocolHTTPS6, configs.ProtocolTLS6:
|
||||
case serverconfigs.ProtocolHTTP6, serverconfigs.ProtocolHTTPS6, serverconfigs.ProtocolTLS6:
|
||||
return listenConfig.Listen(context.Background(), "tcp6", this.group.Addr())
|
||||
}
|
||||
|
||||
|
||||
195
internal/nodes/listener_base.go
Normal file
195
internal/nodes/listener_base.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs/sslconfigs"
|
||||
http2 "golang.org/x/net/http2"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type BaseListener struct {
|
||||
serversLocker sync.RWMutex
|
||||
namedServersLocker sync.RWMutex
|
||||
namedServers map[string]*NamedServer // 域名 => server
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *BaseListener) Init() {
|
||||
this.namedServers = map[string]*NamedServer{}
|
||||
}
|
||||
|
||||
// 构造TLS配置
|
||||
func (this *BaseListener) buildTLSConfig(group *serverconfigs.ServerGroup) *tls.Config {
|
||||
return &tls.Config{
|
||||
Certificates: nil,
|
||||
GetConfigForClient: func(info *tls.ClientHelloInfo) (config *tls.Config, e error) {
|
||||
ssl, _, err := this.matchSSL(group, info.ServerName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cipherSuites := ssl.TLSCipherSuites()
|
||||
if len(cipherSuites) == 0 {
|
||||
cipherSuites = nil
|
||||
}
|
||||
|
||||
nextProto := []string{}
|
||||
if !ssl.HTTP2Disabled {
|
||||
nextProto = []string{http2.NextProtoTLS}
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: nil,
|
||||
MinVersion: ssl.TLSMinVersion(),
|
||||
CipherSuites: cipherSuites,
|
||||
GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, e error) {
|
||||
_, cert, err := this.matchSSL(group, info.ServerName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert == nil {
|
||||
return nil, errors.New("[proxy]no certs found for '" + info.ServerName + "'")
|
||||
}
|
||||
return cert, nil
|
||||
},
|
||||
ClientAuth: sslconfigs.GoSSLClientAuthType(ssl.ClientAuthType),
|
||||
ClientCAs: ssl.CAPool(),
|
||||
|
||||
NextProtos: nextProto,
|
||||
}, nil
|
||||
},
|
||||
GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, e error) {
|
||||
_, cert, err := this.matchSSL(group, info.ServerName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert == nil {
|
||||
return nil, errors.New("[proxy]no certs found for '" + info.ServerName + "'")
|
||||
}
|
||||
return cert, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 根据域名匹配证书
|
||||
func (this *BaseListener) matchSSL(group *serverconfigs.ServerGroup, domain string) (*sslconfigs.SSLConfig, *tls.Certificate, error) {
|
||||
this.serversLocker.RLock()
|
||||
defer this.serversLocker.RUnlock()
|
||||
|
||||
// 如果域名为空,则取第一个
|
||||
// 通常域名为空是因为是直接通过IP访问的
|
||||
if len(domain) == 0 {
|
||||
if serverconfigs.SharedGlobalConfig().HTTPAll.MatchDomainStrictly {
|
||||
return nil, nil, errors.New("no tls server name matched")
|
||||
}
|
||||
|
||||
firstServer := group.FirstServer()
|
||||
if firstServer == nil {
|
||||
return nil, nil, errors.New("no server available")
|
||||
}
|
||||
sslConfig := firstServer.SSLConfig()
|
||||
|
||||
if sslConfig != nil {
|
||||
return sslConfig, sslConfig.FirstCert(), nil
|
||||
|
||||
}
|
||||
return nil, nil, errors.New("no tls server name found")
|
||||
}
|
||||
|
||||
// 通过代理服务域名配置匹配
|
||||
server, _ := this.findNamedServer(group, domain)
|
||||
if server == nil || server.SSLConfig() == nil || !server.SSLConfig().IsOn {
|
||||
// 搜索所有的Server,通过SSL证书内容中的DNSName匹配
|
||||
for _, server := range group.Servers {
|
||||
if server.SSLConfig() == nil || !server.SSLConfig().IsOn {
|
||||
continue
|
||||
}
|
||||
cert, ok := server.SSLConfig().MatchDomain(domain)
|
||||
if ok {
|
||||
return server.SSLConfig(), cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil, errors.New("[proxy]no server found for '" + domain + "'")
|
||||
}
|
||||
|
||||
// 证书是否匹配
|
||||
sslConfig := server.SSLConfig()
|
||||
cert, ok := sslConfig.MatchDomain(domain)
|
||||
if ok {
|
||||
return sslConfig, cert, nil
|
||||
}
|
||||
|
||||
return sslConfig, sslConfig.FirstCert(), nil
|
||||
}
|
||||
|
||||
// 根据域名来查找匹配的域名
|
||||
func (this *BaseListener) findNamedServer(group *serverconfigs.ServerGroup, name string) (serverConfig *serverconfigs.ServerConfig, serverName string) {
|
||||
// 读取缓存
|
||||
this.namedServersLocker.RLock()
|
||||
namedServer, found := this.namedServers[name]
|
||||
if found {
|
||||
this.namedServersLocker.RUnlock()
|
||||
return namedServer.Server, namedServer.Name
|
||||
}
|
||||
this.namedServersLocker.RUnlock()
|
||||
|
||||
this.serversLocker.RLock()
|
||||
defer this.serversLocker.RUnlock()
|
||||
|
||||
currentServers := group.Servers
|
||||
countServers := len(currentServers)
|
||||
if countServers == 0 {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// 只记录N个记录,防止内存耗尽
|
||||
maxNamedServers := 10240
|
||||
|
||||
// 是否严格匹配域名
|
||||
matchDomainStrictly := serverconfigs.SharedGlobalConfig().HTTPAll.MatchDomainStrictly
|
||||
|
||||
// 如果只有一个server,则默认为这个
|
||||
if countServers == 1 && !matchDomainStrictly {
|
||||
return currentServers[0], name
|
||||
}
|
||||
|
||||
// 精确查找
|
||||
for _, server := range currentServers {
|
||||
if server.MatchNameStrictly(name) {
|
||||
this.namedServersLocker.Lock()
|
||||
if len(this.namedServers) < maxNamedServers {
|
||||
this.namedServers[name] = &NamedServer{
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
}
|
||||
this.namedServersLocker.Unlock()
|
||||
return server, name
|
||||
}
|
||||
}
|
||||
|
||||
// 模糊查找
|
||||
for _, server := range currentServers {
|
||||
if matched := server.MatchName(name); matched {
|
||||
this.namedServersLocker.Lock()
|
||||
if len(this.namedServers) < maxNamedServers {
|
||||
this.namedServers[name] = &NamedServer{
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
}
|
||||
this.namedServersLocker.Unlock()
|
||||
return server, name
|
||||
}
|
||||
}
|
||||
|
||||
// 找不到而且域名严格匹配模式下不返回Server
|
||||
if matchDomainStrictly {
|
||||
return nil, name
|
||||
}
|
||||
|
||||
// 如果没有找到,则匹配到第一个
|
||||
return currentServers[0], name
|
||||
}
|
||||
68
internal/nodes/listener_http.go
Normal file
68
internal/nodes/listener_http.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"golang.org/x/net/http2"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type HTTPListener struct {
|
||||
BaseListener
|
||||
|
||||
Group *serverconfigs.ServerGroup
|
||||
Listener net.Listener
|
||||
|
||||
httpServer *http.Server
|
||||
}
|
||||
|
||||
func (this *HTTPListener) Serve() error {
|
||||
handler := http.NewServeMux()
|
||||
handler.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
this.handleHTTP(writer, request)
|
||||
})
|
||||
|
||||
this.httpServer = &http.Server{
|
||||
Addr: this.Group.Addr(),
|
||||
Handler: handler,
|
||||
IdleTimeout: 2 * time.Minute,
|
||||
}
|
||||
this.httpServer.SetKeepAlivesEnabled(true)
|
||||
|
||||
// HTTP协议
|
||||
if this.Group.IsHTTP() {
|
||||
err := this.httpServer.Serve(this.Listener)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPS协议
|
||||
if this.Group.IsHTTPS() {
|
||||
this.httpServer.TLSConfig = this.buildTLSConfig(this.Group)
|
||||
|
||||
// support http/2
|
||||
err := http2.ConfigureServer(this.httpServer, nil)
|
||||
if err != nil {
|
||||
logs.Println("[HTTP_LISTENER]configure http2 error: " + err.Error())
|
||||
}
|
||||
|
||||
err = this.httpServer.ServeTLS(this.Listener, "", "")
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *HTTPListener) Close() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *HTTPListener) handleHTTP(writer http.ResponseWriter, req *http.Request) {
|
||||
writer.Write([]byte("Hello, World"))
|
||||
}
|
||||
13
internal/nodes/listener_impl.go
Normal file
13
internal/nodes/listener_impl.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package nodes
|
||||
|
||||
// 各协议监听器的具体实现
|
||||
type ListenerImpl interface {
|
||||
// 初始化
|
||||
Init()
|
||||
|
||||
// 监听
|
||||
Serve() error
|
||||
|
||||
// 关闭
|
||||
Close() error
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -12,6 +14,7 @@ var sharedListenerManager = NewListenerManager()
|
||||
type ListenerManager struct {
|
||||
listenersMap map[string]*Listener // addr => *Listener
|
||||
locker sync.Mutex
|
||||
lastConfig *configs.NodeConfig
|
||||
}
|
||||
|
||||
func NewListenerManager() *ListenerManager {
|
||||
@@ -24,6 +27,18 @@ func (this *ListenerManager) Start(node *configs.NodeConfig) error {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
// 检查是否有变化
|
||||
if this.lastConfig != nil && this.lastConfig.Version == node.Version {
|
||||
return nil
|
||||
}
|
||||
this.lastConfig = node
|
||||
|
||||
// 初始化
|
||||
err := node.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 所有的新地址
|
||||
groupAddrs := []string{}
|
||||
for _, group := range node.AvailableGroups() {
|
||||
@@ -45,15 +60,16 @@ func (this *ListenerManager) Start(node *configs.NodeConfig) error {
|
||||
addr := group.FullAddr()
|
||||
listener, ok := this.listenersMap[addr]
|
||||
if ok {
|
||||
logs.Println("[LISTENER_MANAGER]reload '" + addr + "'")
|
||||
logs.Println("[LISTENER_MANAGER]reload '" + this.prettyAddress(addr) + "'")
|
||||
listener.Reload(group)
|
||||
} else {
|
||||
logs.Println("[LISTENER_MANAGER]listen '" + addr + "'")
|
||||
logs.Println("[LISTENER_MANAGER]listen '" + this.prettyAddress(addr) + "'")
|
||||
listener = NewListener()
|
||||
listener.Reload(group)
|
||||
err := listener.Listen()
|
||||
if err != nil {
|
||||
return err
|
||||
logs.Println("[LISTENER_MANAGER]" + err.Error())
|
||||
continue
|
||||
}
|
||||
this.listenersMap[addr] = listener
|
||||
}
|
||||
@@ -61,3 +77,14 @@ func (this *ListenerManager) Start(node *configs.NodeConfig) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ListenerManager) prettyAddress(addr string) string {
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return addr
|
||||
}
|
||||
if regexp.MustCompile(`^:\d+$`).MatchString(u.Host) {
|
||||
u.Host = "*" + u.Host
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
@@ -12,15 +12,29 @@ func TestListenerManager_Listen(t *testing.T) {
|
||||
{
|
||||
IsOn: true,
|
||||
HTTP: &configs.HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{"127.0.0.1:1234"},
|
||||
BaseProtocol: configs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*configs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: configs.ProtocolHTTP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
IsOn: true,
|
||||
HTTP: &configs.HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{"127.0.0.1:1235"},
|
||||
BaseProtocol: configs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*configs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: configs.ProtocolHTTP,
|
||||
PortRange: "1235",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -34,15 +48,29 @@ func TestListenerManager_Listen(t *testing.T) {
|
||||
{
|
||||
IsOn: true,
|
||||
HTTP: &configs.HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{"127.0.0.1:1234"},
|
||||
BaseProtocol: configs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*configs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: configs.ProtocolHTTP,
|
||||
PortRange: "1234",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
IsOn: true,
|
||||
HTTP: &configs.HTTPProtocolConfig{
|
||||
IsOn: true,
|
||||
Listen: []string{"127.0.0.1:1236"},
|
||||
BaseProtocol: configs.BaseProtocol{
|
||||
IsOn: true,
|
||||
Listen: []*configs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: configs.ProtocolHTTP,
|
||||
PortRange: "1236",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
23
internal/nodes/listener_tcp.go
Normal file
23
internal/nodes/listener_tcp.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"net"
|
||||
)
|
||||
|
||||
type TCPListener struct {
|
||||
BaseListener
|
||||
|
||||
Group *serverconfigs.ServerGroup
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
func (this *TCPListener) Serve() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *TCPListener) Close() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
23
internal/nodes/listener_udp.go
Normal file
23
internal/nodes/listener_udp.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"net"
|
||||
)
|
||||
|
||||
type UDPListener struct {
|
||||
BaseListener
|
||||
|
||||
Group *serverconfigs.ServerGroup
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
func (this *UDPListener) Serve() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *UDPListener) Close() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
23
internal/nodes/listener_unix.go
Normal file
23
internal/nodes/listener_unix.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
"net"
|
||||
)
|
||||
|
||||
type UnixListener struct {
|
||||
BaseListener
|
||||
|
||||
Group *serverconfigs.ServerGroup
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
func (this *UnixListener) Serve() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *UnixListener) Close() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
9
internal/nodes/named_server.go
Normal file
9
internal/nodes/named_server.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package nodes
|
||||
|
||||
import "github.com/TeaOSLab/EdgeNode/internal/configs/serverconfigs"
|
||||
|
||||
// 域名和服务映射
|
||||
type NamedServer struct {
|
||||
Name string // 匹配后的域名
|
||||
Server *serverconfigs.ServerConfig // 匹配后的服务配置
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sharedNodeConfig *configs.NodeConfig = nil
|
||||
var stop = make(chan bool)
|
||||
var lastVersion = -1
|
||||
|
||||
// 节点
|
||||
type Node struct {
|
||||
}
|
||||
|
||||
@@ -17,13 +23,24 @@ func NewNode() *Node {
|
||||
}
|
||||
|
||||
func (this *Node) Start() {
|
||||
// 读取API配置
|
||||
err := this.syncConfig(false)
|
||||
if err != nil {
|
||||
logs.Println(err.Error())
|
||||
}
|
||||
|
||||
// 启动同步计时器
|
||||
this.startSyncTimer()
|
||||
|
||||
// 状态变更计时器
|
||||
go NewNodeStatusExecutor().Listen()
|
||||
|
||||
// 读取配置
|
||||
nodeConfig, err := configs.SharedNodeConfig()
|
||||
if err != nil {
|
||||
logs.Println("[NODE]start failed: read node config failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
sharedNodeConfig = nodeConfig
|
||||
|
||||
// 设置rlimit
|
||||
_ = utils.SetRLimit(1024 * 1024)
|
||||
@@ -37,3 +54,59 @@ func (this *Node) Start() {
|
||||
// hold住进程
|
||||
<-stop
|
||||
}
|
||||
|
||||
// 读取API配置
|
||||
func (this *Node) syncConfig(isFirstTime bool) error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return errors.New("[NODE]create rpc client failed: " + err.Error())
|
||||
}
|
||||
configResp, err := rpcClient.NodeRPC().ComposeNodeConfig(rpcClient.Context(), &pb.ComposeNodeConfigRequest{})
|
||||
if err != nil {
|
||||
return errors.New("[NODE]read config from rpc failed: " + err.Error())
|
||||
}
|
||||
configBytes := configResp.ConfigJSON
|
||||
nodeConfig := &configs.NodeConfig{}
|
||||
err = json.Unmarshal(configBytes, nodeConfig)
|
||||
if err != nil {
|
||||
return errors.New("[NODE]decode config failed: " + err.Error())
|
||||
}
|
||||
|
||||
// 写入到文件中
|
||||
err = nodeConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果版本相同,则只是保存
|
||||
if lastVersion == nodeConfig.Version {
|
||||
return nil
|
||||
}
|
||||
lastVersion = nodeConfig.Version
|
||||
|
||||
// 刷新配置
|
||||
err = configs.ReloadNodeConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !isFirstTime {
|
||||
return sharedListenerManager.Start(nodeConfig)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 启动同步计时器
|
||||
func (this *Node) startSyncTimer() {
|
||||
ticker := time.NewTicker(60 * time.Second)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
err := this.syncConfig(false)
|
||||
if err != nil {
|
||||
logs.Println("[NODE]sync config error: " + err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
24
internal/nodes/node_status.go
Normal file
24
internal/nodes/node_status.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package nodes
|
||||
|
||||
// 节点状态
|
||||
type NodeStatus struct {
|
||||
Version string `json:"version"`
|
||||
Hostname string `json:"hostname"`
|
||||
HostIP string `json:"hostIP"`
|
||||
CPUUsage float64 `json:"cpuUsage"`
|
||||
CPULogicalCount int `json:"cpuLogicalCount"`
|
||||
CPUPhysicalCount int `json:"cpuPhysicalCount"`
|
||||
MemoryUsage float64 `json:"memoryUsage"`
|
||||
MemoryTotal uint64 `json:"memoryTotal"`
|
||||
DiskUsage float64 `json:"diskUsage"`
|
||||
DiskMaxUsage float64 `json:"diskMaxUsage"`
|
||||
DiskMaxUsagePartition string `json:"diskMaxUsagePartition"`
|
||||
DiskTotal uint64 `json:"diskTotal"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
Load1m float64 `json:"load1m"`
|
||||
Load5m float64 `json:"load5m"`
|
||||
Load15m float64 `json:"load15m"`
|
||||
|
||||
IsActive bool `json:"isActive"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
172
internal/nodes/node_status_executor.go
Normal file
172
internal/nodes/node_status_executor.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NodeStatusExecutor struct {
|
||||
isFirstTime bool
|
||||
|
||||
cpuUpdatedTime time.Time
|
||||
cpuLogicalCount int
|
||||
cpuPhysicalCount int
|
||||
}
|
||||
|
||||
func NewNodeStatusExecutor() *NodeStatusExecutor {
|
||||
return &NodeStatusExecutor{}
|
||||
}
|
||||
|
||||
func (this *NodeStatusExecutor) Listen() {
|
||||
this.isFirstTime = true
|
||||
this.cpuUpdatedTime = time.Now()
|
||||
this.update()
|
||||
|
||||
ticker := time.NewTicker(60 * time.Second)
|
||||
for range ticker.C {
|
||||
this.isFirstTime = false
|
||||
this.update()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *NodeStatusExecutor) update() {
|
||||
status := &NodeStatus{}
|
||||
status.Version = teaconst.Version
|
||||
status.IsActive = true
|
||||
|
||||
hostname, _ := os.Hostname()
|
||||
status.Hostname = hostname
|
||||
|
||||
this.updateCPU(status)
|
||||
this.updateMem(status)
|
||||
this.updateLoad(status)
|
||||
this.updateDisk(status)
|
||||
status.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 发送数据
|
||||
jsonData, err := json.Marshal(status)
|
||||
if err != nil {
|
||||
logs.Println("[NODE]serial NodeStatus fail: " + err.Error())
|
||||
return
|
||||
}
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
logs.Println("[NODE]failed to open rpc: " + err.Error())
|
||||
return
|
||||
}
|
||||
_, err = rpcClient.NodeRPC().UpdateNodeStatus(rpcClient.Context(), &pb.UpdateNodeStatusRequest{
|
||||
StatusJSON: jsonData,
|
||||
})
|
||||
if err != nil {
|
||||
logs.Println("[NODE]rpc UpdateNodeStatus() failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 更新CPU
|
||||
func (this *NodeStatusExecutor) updateCPU(status *NodeStatus) {
|
||||
duration := time.Duration(0)
|
||||
if this.isFirstTime {
|
||||
duration = 100 * time.Millisecond
|
||||
}
|
||||
percents, err := cpu.Percent(duration, false)
|
||||
if err != nil {
|
||||
status.Error = err.Error()
|
||||
return
|
||||
}
|
||||
if len(percents) == 0 {
|
||||
return
|
||||
}
|
||||
status.CPUUsage = percents[0] / 100
|
||||
|
||||
if time.Since(this.cpuUpdatedTime) > 300*time.Second { // 每隔5分钟才会更新一次
|
||||
this.cpuUpdatedTime = time.Now()
|
||||
|
||||
status.CPULogicalCount, err = cpu.Counts(true)
|
||||
if err != nil {
|
||||
status.Error = err.Error()
|
||||
return
|
||||
}
|
||||
status.CPUPhysicalCount, err = cpu.Counts(false)
|
||||
if err != nil {
|
||||
status.Error = err.Error()
|
||||
return
|
||||
}
|
||||
this.cpuLogicalCount = status.CPULogicalCount
|
||||
this.cpuPhysicalCount = status.CPUPhysicalCount
|
||||
} else {
|
||||
status.CPULogicalCount = this.cpuLogicalCount
|
||||
status.CPUPhysicalCount = this.cpuPhysicalCount
|
||||
}
|
||||
}
|
||||
|
||||
// 更新硬盘
|
||||
func (this *NodeStatusExecutor) updateDisk(status *NodeStatus) {
|
||||
partitions, err := disk.Partitions(false)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
lists.Sort(partitions, func(i int, j int) bool {
|
||||
p1 := partitions[i]
|
||||
p2 := partitions[j]
|
||||
return p1.Mountpoint > p2.Mountpoint
|
||||
})
|
||||
|
||||
// 当前TeaWeb所在的fs
|
||||
rootFS := ""
|
||||
rootTotal := uint64(0)
|
||||
if lists.ContainsString([]string{"darwin", "linux", "freebsd"}, runtime.GOOS) {
|
||||
for _, p := range partitions {
|
||||
if p.Mountpoint == "/" {
|
||||
rootFS = p.Fstype
|
||||
usage, _ := disk.Usage(p.Mountpoint)
|
||||
if usage != nil {
|
||||
rootTotal = usage.Total
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total := rootTotal
|
||||
totalUsage := uint64(0)
|
||||
maxUsage := float64(0)
|
||||
for _, partition := range partitions {
|
||||
if runtime.GOOS != "windows" && !strings.Contains(partition.Device, "/") && !strings.Contains(partition.Device, "\\") {
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过不同fs的
|
||||
if len(rootFS) > 0 && rootFS != partition.Fstype {
|
||||
continue
|
||||
}
|
||||
|
||||
usage, err := disk.Usage(partition.Mountpoint)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if partition.Mountpoint != "/" && (usage.Total != rootTotal || total == 0) {
|
||||
total += usage.Total
|
||||
}
|
||||
totalUsage += usage.Used
|
||||
if usage.UsedPercent >= maxUsage {
|
||||
maxUsage = usage.UsedPercent
|
||||
status.DiskMaxUsagePartition = partition.Mountpoint
|
||||
}
|
||||
}
|
||||
status.DiskTotal = total
|
||||
status.DiskUsage = float64(totalUsage) / float64(total)
|
||||
status.DiskMaxUsage = maxUsage / 100
|
||||
}
|
||||
40
internal/nodes/node_status_executor_unix.go
Normal file
40
internal/nodes/node_status_executor_unix.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// +build !windows
|
||||
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
// 更新内存
|
||||
func (this *NodeStatusExecutor) updateMem(status *NodeStatus) {
|
||||
stat, err := mem.VirtualMemory()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 重新计算内存
|
||||
if stat.Total > 0 {
|
||||
stat.Used = stat.Total - stat.Free - stat.Buffers - stat.Cached
|
||||
status.MemoryUsage = float64(stat.Used) / float64(stat.Total)
|
||||
}
|
||||
|
||||
status.MemoryTotal = stat.Total
|
||||
}
|
||||
|
||||
// 更新负载
|
||||
func (this *NodeStatusExecutor) updateLoad(status *NodeStatus) {
|
||||
stat, err := load.Avg()
|
||||
if err != nil {
|
||||
status.Error = err.Error()
|
||||
return
|
||||
}
|
||||
if stat == nil {
|
||||
status.Error = "load is nil"
|
||||
return
|
||||
}
|
||||
status.Load1m = stat.Load1
|
||||
status.Load5m = stat.Load5
|
||||
status.Load15m = stat.Load15
|
||||
}
|
||||
101
internal/nodes/node_status_executor_windows.go
Normal file
101
internal/nodes/node_status_executor_windows.go
Normal file
@@ -0,0 +1,101 @@
|
||||
// +build windows
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WindowsLoadValue struct {
|
||||
Timestamp int64
|
||||
Value int
|
||||
}
|
||||
|
||||
var windowsLoadValues = []*WindowsLoadValue{}
|
||||
var windowsLoadLocker = &sync.Mutex{}
|
||||
|
||||
// 更新内存
|
||||
func (this *NodeStatusExecutor) updateMem(status *NodeStatus) {
|
||||
stat, err := mem.VirtualMemory()
|
||||
if err != nil {
|
||||
status.Error = err.Error()
|
||||
return
|
||||
}
|
||||
status.MemoryUsage = stat.UsedPercent
|
||||
status.MemoryTotal = stat.Total
|
||||
}
|
||||
|
||||
// 更新负载
|
||||
func (this *NodeStatusExecutor) updateLoad(status *NodeStatus) {
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
currentLoad := 0
|
||||
info, err := cpu.ProcInfo()
|
||||
if err == nil && len(info) > 0 && info[0].ProcessorQueueLength < 1000 {
|
||||
currentLoad = int(info[0].ProcessorQueueLength)
|
||||
}
|
||||
|
||||
// 删除15分钟之前的数据
|
||||
windowsLoadLocker.Lock()
|
||||
result := []*WindowsLoadValue{}
|
||||
for _, v := range windowsLoadValues {
|
||||
if timestamp-v.Timestamp > 15*60 {
|
||||
continue
|
||||
}
|
||||
result = append(result, v)
|
||||
}
|
||||
result = append(result, &WindowsLoadValue{
|
||||
Timestamp: timestamp,
|
||||
Value: currentLoad,
|
||||
})
|
||||
windowsLoadValues = result
|
||||
|
||||
total1 := 0
|
||||
count1 := 0
|
||||
total5 := 0
|
||||
count5 := 0
|
||||
total15 := 0
|
||||
count15 := 0
|
||||
for _, v := range result {
|
||||
if timestamp-v.Timestamp <= 60 {
|
||||
total1 += v.Value
|
||||
count1++
|
||||
}
|
||||
|
||||
if timestamp-v.Timestamp <= 300 {
|
||||
total5 += v.Value
|
||||
count5++
|
||||
}
|
||||
|
||||
total15 += v.Value
|
||||
count15++
|
||||
}
|
||||
|
||||
load1 := float64(0)
|
||||
load5 := float64(0)
|
||||
load15 := float64(0)
|
||||
if count1 > 0 {
|
||||
load1 = math.Round(float64(total1*100)/float64(count1)) / 100
|
||||
}
|
||||
if count5 > 0 {
|
||||
load5 = math.Round(float64(total5*100)/float64(count5)) / 100
|
||||
}
|
||||
if count15 > 0 {
|
||||
load15 = math.Round(float64(total15*100)/float64(count15)) / 100
|
||||
}
|
||||
|
||||
windowsLoadLocker.Unlock()
|
||||
|
||||
// 在老Windows上不显示错误
|
||||
if err == context.DeadlineExceeded {
|
||||
err = nil
|
||||
}
|
||||
status.Load1m = load1
|
||||
status.Load5m = load5
|
||||
status.Load15m = load15
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/node"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type RPCClient struct {
|
||||
nodeClients []node.ServiceClient
|
||||
}
|
||||
|
||||
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
|
||||
nodeClients := []node.ServiceClient{}
|
||||
|
||||
conns := []*grpc.ClientConn{}
|
||||
for _, endpoint := range apiConfig.RPC.Endpoints {
|
||||
conn, err := grpc.Dial(endpoint, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conns = append(conns, conn)
|
||||
}
|
||||
if len(conns) == 0 {
|
||||
return nil, errors.New("[RPC]no available endpoints")
|
||||
}
|
||||
|
||||
// node clients
|
||||
for _, conn := range conns {
|
||||
nodeClients = append(nodeClients, node.NewServiceClient(conn))
|
||||
}
|
||||
|
||||
return &RPCClient{
|
||||
nodeClients: nodeClients,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *RPCClient) NodeRPC() node.ServiceClient {
|
||||
if len(this.nodeClients) > 0 {
|
||||
return this.nodeClients[rands.Int(0, len(this.nodeClients)-1)]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *RPCClient) Context() context.Context {
|
||||
return context.Background()
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/rpc/node"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRPCClient_NodeRPC(t *testing.T) {
|
||||
before := time.Now()
|
||||
defer func() {
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}()
|
||||
config, err := configs.LoadAPIConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rpc, err := NewRPCClient(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp, err := rpc.NodeRPC().Config(rpc.Context(), &node.ConfigRequest{
|
||||
NodeId: "123456",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(resp)
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: node/service.proto
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
context "context"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type 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 *ConfigRequest) Reset() {
|
||||
*x = ConfigRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_node_service_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ConfigRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConfigRequest) ProtoMessage() {}
|
||||
|
||||
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))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ConfigRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ConfigRequest) Descriptor() ([]byte, []int) {
|
||||
return file_node_service_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
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 *ConfigResponse) Reset() {
|
||||
*x = ConfigResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_node_service_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ConfigResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConfigResponse) ProtoMessage() {}
|
||||
|
||||
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))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// 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, 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 (
|
||||
file_node_service_proto_rawDescOnce sync.Once
|
||||
file_node_service_proto_rawDescData = file_node_service_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_node_service_proto_rawDescGZIP() []byte {
|
||||
file_node_service_proto_rawDescOnce.Do(func() {
|
||||
file_node_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_node_service_proto_rawDescData)
|
||||
})
|
||||
return file_node_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_node_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_node_service_proto_goTypes = []interface{}{
|
||||
(*ConfigRequest)(nil), // 0: node.ConfigRequest
|
||||
(*ConfigResponse)(nil), // 1: node.ConfigResponse
|
||||
}
|
||||
var file_node_service_proto_depIdxs = []int32{
|
||||
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
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_node_service_proto_init() }
|
||||
func file_node_service_proto_init() {
|
||||
if File_node_service_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_node_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ConfigRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_node_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ConfigResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_node_service_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_node_service_proto_goTypes,
|
||||
DependencyIndexes: file_node_service_proto_depIdxs,
|
||||
MessageInfos: file_node_service_proto_msgTypes,
|
||||
}.Build()
|
||||
File_node_service_proto = out.File
|
||||
file_node_service_proto_rawDesc = nil
|
||||
file_node_service_proto_goTypes = nil
|
||||
file_node_service_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConnInterface
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// ServiceClient is the client API for Service service.
|
||||
//
|
||||
// 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 {
|
||||
Config(ctx context.Context, in *ConfigRequest, opts ...grpc.CallOption) (*ConfigResponse, error)
|
||||
}
|
||||
|
||||
type serviceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewServiceClient(cc grpc.ClientConnInterface) ServiceClient {
|
||||
return &serviceClient{cc}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ServiceServer is the server API for Service service.
|
||||
type ServiceServer interface {
|
||||
Config(context.Context, *ConfigRequest) (*ConfigResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedServiceServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedServiceServer struct {
|
||||
}
|
||||
|
||||
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_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).Config(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/node.Service/Config",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).Config(ctx, req.(*ConfigRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Service_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "node.Service",
|
||||
HandlerType: (*ServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "config",
|
||||
Handler: _Service_Config_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "node/service.proto",
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package node;
|
||||
|
||||
option go_package = "./node";
|
||||
|
||||
service Service {
|
||||
rpc config (ConfigRequest) returns (ConfigResponse) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
message ConfigRequest {
|
||||
string nodeId = 1;
|
||||
}
|
||||
|
||||
message ConfigResponse {
|
||||
string id = 1;
|
||||
}
|
||||
260
internal/rpc/pb/model_node.pb.go
Normal file
260
internal/rpc/pb/model_node.pb.go
Normal file
@@ -0,0 +1,260 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Node struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"`
|
||||
InstallDir string `protobuf:"bytes,4,opt,name=installDir,proto3" json:"installDir,omitempty"`
|
||||
IsInstalled bool `protobuf:"varint,5,opt,name=isInstalled,proto3" json:"isInstalled,omitempty"`
|
||||
Code string `protobuf:"bytes,6,opt,name=code,proto3" json:"code,omitempty"`
|
||||
UniqueId string `protobuf:"bytes,7,opt,name=uniqueId,proto3" json:"uniqueId,omitempty"`
|
||||
Secret string `protobuf:"bytes,8,opt,name=secret,proto3" json:"secret,omitempty"`
|
||||
Cluster *NodeCluster `protobuf:"bytes,32,opt,name=cluster,proto3" json:"cluster,omitempty"`
|
||||
Login *NodeLogin `protobuf:"bytes,33,opt,name=login,proto3" json:"login,omitempty"`
|
||||
InstallStatus *NodeInstallStatus `protobuf:"bytes,34,opt,name=installStatus,proto3" json:"installStatus,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Node) Reset() {
|
||||
*x = Node{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Node) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Node) ProtoMessage() {}
|
||||
|
||||
func (x *Node) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Node.ProtoReflect.Descriptor instead.
|
||||
func (*Node) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Node) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Node) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetStatus() string {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetInstallDir() string {
|
||||
if x != nil {
|
||||
return x.InstallDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetIsInstalled() bool {
|
||||
if x != nil {
|
||||
return x.IsInstalled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Node) GetCode() string {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetUniqueId() string {
|
||||
if x != nil {
|
||||
return x.UniqueId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetSecret() string {
|
||||
if x != nil {
|
||||
return x.Secret
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Node) GetCluster() *NodeCluster {
|
||||
if x != nil {
|
||||
return x.Cluster
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Node) GetLogin() *NodeLogin {
|
||||
if x != nil {
|
||||
return x.Login
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Node) GetInstallStatus() *NodeInstallStatus {
|
||||
if x != nil {
|
||||
return x.InstallStatus
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_model_node_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x18, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f,
|
||||
0x64, 0x65, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x1a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f,
|
||||
0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x02, 0x0a, 0x04, 0x4e, 0x6f,
|
||||
0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02,
|
||||
0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x63, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x29, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4e,
|
||||
0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x21, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x3b, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_proto_rawDescOnce sync.Once
|
||||
file_model_node_proto_rawDescData = file_model_node_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_proto_rawDescGZIP() []byte {
|
||||
file_model_node_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_proto_goTypes = []interface{}{
|
||||
(*Node)(nil), // 0: pb.Node
|
||||
(*NodeCluster)(nil), // 1: pb.NodeCluster
|
||||
(*NodeLogin)(nil), // 2: pb.NodeLogin
|
||||
(*NodeInstallStatus)(nil), // 3: pb.NodeInstallStatus
|
||||
}
|
||||
var file_model_node_proto_depIdxs = []int32{
|
||||
1, // 0: pb.Node.cluster:type_name -> pb.NodeCluster
|
||||
2, // 1: pb.Node.login:type_name -> pb.NodeLogin
|
||||
3, // 2: pb.Node.installStatus:type_name -> pb.NodeInstallStatus
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_proto_init() }
|
||||
func file_model_node_proto_init() {
|
||||
if File_model_node_proto != nil {
|
||||
return
|
||||
}
|
||||
file_model_node_cluster_proto_init()
|
||||
file_model_node_login_proto_init()
|
||||
file_model_node_install_status_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Node); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_proto_depIdxs,
|
||||
MessageInfos: file_model_node_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_proto = out.File
|
||||
file_model_node_proto_rawDesc = nil
|
||||
file_model_node_proto_goTypes = nil
|
||||
file_model_node_proto_depIdxs = nil
|
||||
}
|
||||
185
internal/rpc/pb/model_node_cluster.pb.go
Normal file
185
internal/rpc/pb/model_node_cluster.pb.go
Normal file
@@ -0,0 +1,185 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_cluster.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeCluster struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
CreatedAt int64 `protobuf:"varint,3,opt,name=createdAt,proto3" json:"createdAt,omitempty"`
|
||||
GrantId int64 `protobuf:"varint,4,opt,name=grantId,proto3" json:"grantId,omitempty"`
|
||||
InstallDir string `protobuf:"bytes,5,opt,name=installDir,proto3" json:"installDir,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeCluster) Reset() {
|
||||
*x = NodeCluster{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_cluster_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeCluster) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeCluster) ProtoMessage() {}
|
||||
|
||||
func (x *NodeCluster) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_cluster_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeCluster.ProtoReflect.Descriptor instead.
|
||||
func (*NodeCluster) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_cluster_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetCreatedAt() int64 {
|
||||
if x != nil {
|
||||
return x.CreatedAt
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetGrantId() int64 {
|
||||
if x != nil {
|
||||
return x.GrantId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeCluster) GetInstallDir() string {
|
||||
if x != nil {
|
||||
return x.InstallDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_model_node_cluster_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_cluster_proto_rawDesc = []byte{
|
||||
0x0a, 0x18, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6c, 0x75,
|
||||
0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x89,
|
||||
0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_cluster_proto_rawDescOnce sync.Once
|
||||
file_model_node_cluster_proto_rawDescData = file_model_node_cluster_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_cluster_proto_rawDescGZIP() []byte {
|
||||
file_model_node_cluster_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_cluster_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_cluster_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_cluster_proto_goTypes = []interface{}{
|
||||
(*NodeCluster)(nil), // 0: pb.NodeCluster
|
||||
}
|
||||
var file_model_node_cluster_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_cluster_proto_init() }
|
||||
func file_model_node_cluster_proto_init() {
|
||||
if File_model_node_cluster_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_cluster_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeCluster); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_cluster_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_cluster_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_cluster_proto_depIdxs,
|
||||
MessageInfos: file_model_node_cluster_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_cluster_proto = out.File
|
||||
file_model_node_cluster_proto_rawDesc = nil
|
||||
file_model_node_cluster_proto_goTypes = nil
|
||||
file_model_node_cluster_proto_depIdxs = nil
|
||||
}
|
||||
223
internal/rpc/pb/model_node_grant.pb.go
Normal file
223
internal/rpc/pb/model_node_grant.pb.go
Normal file
@@ -0,0 +1,223 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_grant.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeGrant struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
|
||||
Username string `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Su bool `protobuf:"varint,6,opt,name=su,proto3" json:"su,omitempty"`
|
||||
PrivateKey string `protobuf:"bytes,7,opt,name=privateKey,proto3" json:"privateKey,omitempty"`
|
||||
Description string `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"`
|
||||
NodeId int64 `protobuf:"varint,9,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeGrant) Reset() {
|
||||
*x = NodeGrant{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_grant_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeGrant) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeGrant) ProtoMessage() {}
|
||||
|
||||
func (x *NodeGrant) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_grant_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeGrant.ProtoReflect.Descriptor instead.
|
||||
func (*NodeGrant) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_grant_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetMethod() string {
|
||||
if x != nil {
|
||||
return x.Method
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetUsername() string {
|
||||
if x != nil {
|
||||
return x.Username
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetPassword() string {
|
||||
if x != nil {
|
||||
return x.Password
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetSu() bool {
|
||||
if x != nil {
|
||||
return x.Su
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetPrivateKey() string {
|
||||
if x != nil {
|
||||
return x.PrivateKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeGrant) GetNodeId() int64 {
|
||||
if x != nil {
|
||||
return x.NodeId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_model_node_grant_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_grant_proto_rawDesc = []byte{
|
||||
0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x67, 0x72, 0x61,
|
||||
0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xe9, 0x01, 0x0a,
|
||||
0x09, 0x4e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x73, 0x75, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x73, 0x75, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_grant_proto_rawDescOnce sync.Once
|
||||
file_model_node_grant_proto_rawDescData = file_model_node_grant_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_grant_proto_rawDescGZIP() []byte {
|
||||
file_model_node_grant_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_grant_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_grant_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_grant_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_grant_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_grant_proto_goTypes = []interface{}{
|
||||
(*NodeGrant)(nil), // 0: pb.NodeGrant
|
||||
}
|
||||
var file_model_node_grant_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_grant_proto_init() }
|
||||
func file_model_node_grant_proto_init() {
|
||||
if File_model_node_grant_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_grant_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeGrant); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_grant_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_grant_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_grant_proto_depIdxs,
|
||||
MessageInfos: file_model_node_grant_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_grant_proto = out.File
|
||||
file_model_node_grant_proto_rawDesc = nil
|
||||
file_model_node_grant_proto_goTypes = nil
|
||||
file_model_node_grant_proto_depIdxs = nil
|
||||
}
|
||||
187
internal/rpc/pb/model_node_install_status.pb.go
Normal file
187
internal/rpc/pb/model_node_install_status.pb.go
Normal file
@@ -0,0 +1,187 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_install_status.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeInstallStatus struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IsRunning bool `protobuf:"varint,1,opt,name=isRunning,proto3" json:"isRunning,omitempty"`
|
||||
IsFinished bool `protobuf:"varint,2,opt,name=isFinished,proto3" json:"isFinished,omitempty"`
|
||||
IsOk bool `protobuf:"varint,3,opt,name=isOk,proto3" json:"isOk,omitempty"`
|
||||
Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
|
||||
UpdatedAt int64 `protobuf:"varint,5,opt,name=updatedAt,proto3" json:"updatedAt,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) Reset() {
|
||||
*x = NodeInstallStatus{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_install_status_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeInstallStatus) ProtoMessage() {}
|
||||
|
||||
func (x *NodeInstallStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_install_status_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeInstallStatus.ProtoReflect.Descriptor instead.
|
||||
func (*NodeInstallStatus) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_install_status_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsRunning() bool {
|
||||
if x != nil {
|
||||
return x.IsRunning
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsFinished() bool {
|
||||
if x != nil {
|
||||
return x.IsFinished
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetIsOk() bool {
|
||||
if x != nil {
|
||||
return x.IsOk
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeInstallStatus) GetUpdatedAt() int64 {
|
||||
if x != nil {
|
||||
return x.UpdatedAt
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_model_node_install_status_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_install_status_proto_rawDesc = []byte{
|
||||
0x0a, 0x1f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x73,
|
||||
0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x99, 0x01, 0x0a, 0x11, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69,
|
||||
0x73, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
|
||||
0x69, 0x73, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x46,
|
||||
0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
|
||||
0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f,
|
||||
0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f, 0x6b, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41,
|
||||
0x74, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_install_status_proto_rawDescOnce sync.Once
|
||||
file_model_node_install_status_proto_rawDescData = file_model_node_install_status_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_install_status_proto_rawDescGZIP() []byte {
|
||||
file_model_node_install_status_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_install_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_install_status_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_install_status_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_install_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_install_status_proto_goTypes = []interface{}{
|
||||
(*NodeInstallStatus)(nil), // 0: pb.NodeInstallStatus
|
||||
}
|
||||
var file_model_node_install_status_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_install_status_proto_init() }
|
||||
func file_model_node_install_status_proto_init() {
|
||||
if File_model_node_install_status_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_install_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeInstallStatus); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_install_status_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_install_status_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_install_status_proto_depIdxs,
|
||||
MessageInfos: file_model_node_install_status_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_install_status_proto = out.File
|
||||
file_model_node_install_status_proto_rawDesc = nil
|
||||
file_model_node_install_status_proto_goTypes = nil
|
||||
file_model_node_install_status_proto_depIdxs = nil
|
||||
}
|
||||
174
internal/rpc/pb/model_node_login.pb.go
Normal file
174
internal/rpc/pb/model_node_login.pb.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.12.3
|
||||
// source: model_node_login.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type NodeLogin struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Params []byte `protobuf:"bytes,4,opt,name=params,proto3" json:"params,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeLogin) Reset() {
|
||||
*x = NodeLogin{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_model_node_login_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeLogin) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeLogin) ProtoMessage() {}
|
||||
|
||||
func (x *NodeLogin) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_model_node_login_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NodeLogin.ProtoReflect.Descriptor instead.
|
||||
func (*NodeLogin) Descriptor() ([]byte, []int) {
|
||||
return file_model_node_login_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetId() int64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeLogin) GetParams() []byte {
|
||||
if x != nil {
|
||||
return x.Params
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_model_node_login_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_model_node_login_proto_rawDesc = []byte{
|
||||
0x0a, 0x16, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x5b, 0x0a, 0x09,
|
||||
0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70,
|
||||
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_model_node_login_proto_rawDescOnce sync.Once
|
||||
file_model_node_login_proto_rawDescData = file_model_node_login_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_model_node_login_proto_rawDescGZIP() []byte {
|
||||
file_model_node_login_proto_rawDescOnce.Do(func() {
|
||||
file_model_node_login_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_node_login_proto_rawDescData)
|
||||
})
|
||||
return file_model_node_login_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_model_node_login_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_model_node_login_proto_goTypes = []interface{}{
|
||||
(*NodeLogin)(nil), // 0: pb.NodeLogin
|
||||
}
|
||||
var file_model_node_login_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_model_node_login_proto_init() }
|
||||
func file_model_node_login_proto_init() {
|
||||
if File_model_node_login_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_model_node_login_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodeLogin); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_model_node_login_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_model_node_login_proto_goTypes,
|
||||
DependencyIndexes: file_model_node_login_proto_depIdxs,
|
||||
MessageInfos: file_model_node_login_proto_msgTypes,
|
||||
}.Build()
|
||||
File_model_node_login_proto = out.File
|
||||
file_model_node_login_proto_rawDesc = nil
|
||||
file_model_node_login_proto_goTypes = nil
|
||||
file_model_node_login_proto_depIdxs = nil
|
||||
}
|
||||
2426
internal/rpc/pb/service_node.pb.go
Normal file
2426
internal/rpc/pb/service_node.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user