This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,217 @@
package nodes
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/configs"
teaconst "github.com/TeaOSLab/EdgeUser/internal/const"
"github.com/TeaOSLab/EdgeUser/internal/events"
"github.com/TeaOSLab/EdgeUser/internal/monitor"
"github.com/TeaOSLab/EdgeUser/internal/remotelogs"
"github.com/TeaOSLab/EdgeUser/internal/rpc"
"github.com/TeaOSLab/EdgeUser/internal/utils"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/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()
// TODO 这个时间间隔可以配置
ticker := time.NewTicker(30 * time.Second)
events.On(events.EventQuit, func() {
remotelogs.Println("NODE_STATUS", "quit executor")
ticker.Stop()
})
for range ticker.C {
this.isFirstTime = false
this.update()
}
}
func (this *NodeStatusExecutor) update() {
status := &nodeconfigs.NodeStatus{}
status.BuildVersion = teaconst.Version
status.BuildVersionCode = utils.VersionToLong(teaconst.Version)
status.OS = runtime.GOOS
status.Arch = runtime.GOARCH
status.ConfigVersion = 0
status.IsActive = true
status.ConnectionCount = 0 // TODO 将来显示连接数
hostname, _ := os.Hostname()
status.Hostname = hostname
this.updateCPU(status)
this.updateMem(status)
this.updateLoad(status)
this.updateDisk(status)
status.UpdatedAt = time.Now().Unix()
status.Timestamp = status.UpdatedAt
// 发送数据
jsonData, err := json.Marshal(status)
if err != nil {
remotelogs.Error("NODE_STATUS", "serial NodeStatus fail: "+err.Error())
return
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("NODE_STATUS", "failed to open rpc: "+err.Error())
} else {
remotelogs.Error("NODE_STATUS", "failed to open rpc: "+err.Error())
}
return
}
nodeId := int64(0)
if configs.SharedAPIConfig != nil {
nodeId = configs.SharedAPIConfig.NumberId
}
_, err = rpcClient.UserNodeRPC().UpdateUserNodeStatus(rpcClient.Context(0), &pb.UpdateUserNodeStatusRequest{
UserNodeId: nodeId,
StatusJSON: jsonData,
})
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("NODE_STATUS", "rpc UpdateUserNodeStatus() failed: "+err.Error())
} else {
remotelogs.Error("NODE_STATUS", "rpc UpdateUserNodeStatus() failed: "+err.Error())
}
return
}
}
// 更新CPU
func (this *NodeStatusExecutor) updateCPU(status *nodeconfigs.NodeStatus) {
duration := time.Duration(0)
if this.isFirstTime {
duration = 100 * time.Millisecond
}
percents, err := cpu.Percent(duration, false)
if err != nil {
status.Error = "cpu.Percent(): " + 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 = "cpu.Counts(): " + err.Error()
return
}
status.CPUPhysicalCount, err = cpu.Counts(false)
if err != nil {
status.Error = "cpu.Counts(): " + err.Error()
return
}
this.cpuLogicalCount = status.CPULogicalCount
this.cpuPhysicalCount = status.CPUPhysicalCount
} else {
status.CPULogicalCount = this.cpuLogicalCount
status.CPUPhysicalCount = this.cpuPhysicalCount
}
// 记录监控数据
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemCPU, maps.Map{
"usage": status.CPUUsage,
"cores": runtime.NumCPU(),
})
}
// 更新硬盘
func (this *NodeStatusExecutor) updateDisk(status *nodeconfigs.NodeStatus) {
partitions, err := disk.Partitions(false)
if err != nil {
if rpc.IsConnError(err) {
remotelogs.Debug("NODE_STATUS", err.Error())
} else {
remotelogs.Error("NODE_STATUS", err.Error())
}
return
}
lists.Sort(partitions, func(i int, j int) bool {
p1 := partitions[i]
p2 := partitions[j]
return p1.Mountpoint > p2.Mountpoint
})
// 当前TeaWeb所在的fs
var rootFS = ""
var 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
}
}
}
var total = rootTotal
var 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
if total > 0 {
status.DiskUsage = float64(totalUsage) / float64(total)
}
status.DiskMaxUsage = maxUsage / 100
}

View File

@@ -0,0 +1,27 @@
package nodes
import (
"github.com/shirou/gopsutil/v3/cpu"
"testing"
"time"
)
func TestNodeStatusExecutor_CPU(t *testing.T) {
countLogicCPU, err := cpu.Counts(true)
if err != nil {
t.Fatal(err)
}
t.Log("logic count:", countLogicCPU)
countPhysicalCPU, err := cpu.Counts(false)
if err != nil {
t.Fatal(err)
}
t.Log("physical count:", countPhysicalCPU)
percents, err := cpu.Percent(100*time.Millisecond, false)
if err != nil {
t.Fatal(err)
}
t.Log(percents)
}

View File

@@ -0,0 +1,58 @@
//go:build !windows
// +build !windows
package nodes
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeUser/internal/monitor"
"github.com/iwind/TeaGo/maps"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
)
// 更新内存
func (this *NodeStatusExecutor) updateMem(status *nodeconfigs.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
// 记录监控数据
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemMemory, maps.Map{
"usage": status.MemoryUsage,
"total": status.MemoryTotal,
"used": stat.Used,
})
}
// 更新负载
func (this *NodeStatusExecutor) updateLoad(status *nodeconfigs.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
// 记录监控数据
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemLoad, maps.Map{
"load1m": status.Load1m,
"load5m": status.Load5m,
"load15m": status.Load15m,
})
}

View File

@@ -0,0 +1,102 @@
//go:build windows
// +build windows
package nodes
import (
"context"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/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
}

View File

@@ -0,0 +1,70 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package serverutils
import (
"errors"
"github.com/iwind/TeaGo"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/types"
"gopkg.in/yaml.v3"
"net"
"os"
"time"
)
const configFilename = "server.yaml"
// LoadServerConfig 读取当前服务配置
func LoadServerConfig() (*TeaGo.ServerConfig, error) {
var configFile = Tea.ConfigFile(configFilename)
data, err := os.ReadFile(configFile)
if err != nil {
return nil, err
}
var serverConfig = &TeaGo.ServerConfig{}
err = yaml.Unmarshal(data, serverConfig)
if err != nil {
return nil, err
}
return serverConfig, nil
}
// ReadServerHTTPS 检查HTTPS地址
func ReadServerHTTPS() (port int, err error) {
config, err := LoadServerConfig()
if err != nil {
return 0, err
}
if config == nil {
return 0, errors.New("could not load server config")
}
if config.Https.On && len(config.Https.Listen) > 0 {
for _, listen := range config.Https.Listen {
_, portString, splitErr := net.SplitHostPort(listen)
if splitErr == nil {
var portInt = types.Int(portString)
if portInt > 0 {
// 是否已经启动
checkErr := func() error {
conn, connErr := net.DialTimeout("tcp", ":"+portString, 1*time.Second)
if connErr != nil {
return connErr
}
_ = conn.Close()
return nil
}()
if checkErr != nil {
continue
}
port = portInt
err = nil
break
}
}
}
}
return
}

View File

@@ -0,0 +1,118 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodes
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/rpc"
"github.com/TeaOSLab/EdgeUser/internal/ttlcache"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/logs"
"strings"
"time"
)
// SessionManager SESSION管理
type SessionManager struct {
life uint
}
func NewSessionManager() (*SessionManager, error) {
return &SessionManager{}, nil
}
func (this *SessionManager) Init(config *actions.SessionConfig) {
this.life = config.Life
}
func (this *SessionManager) Read(sid string) map[string]string {
// 忽略OTP
if strings.HasSuffix(sid, "_otp") {
return map[string]string{}
}
var result = map[string]string{}
var cacheKey = "SESSION@" + sid
var item = ttlcache.DefaultCache.Read(cacheKey)
if item != nil && item.Value != nil {
itemMap, ok := item.Value.(map[string]string)
if ok {
return itemMap
}
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
return map[string]string{}
}
resp, err := rpcClient.LoginSessionRPC().FindLoginSession(rpcClient.Context(0), &pb.FindLoginSessionRequest{Sid: sid})
if err != nil {
logs.Println("SESSION", "read '"+sid+"' failed: "+err.Error())
result["@error"] = err.Error()
return result
}
var session = resp.LoginSession
if session == nil || len(session.ValuesJSON) == 0 {
return result
}
err = json.Unmarshal(session.ValuesJSON, &result)
if err != nil {
logs.Println("SESSION", "decode '"+sid+"' values failed: "+err.Error())
}
// Write to cache
ttlcache.DefaultCache.Write(cacheKey, result, time.Now().Unix()+300 /** must not be too long **/)
return result
}
func (this *SessionManager) WriteItem(sid string, key string, value string) bool {
// 删除缓存
defer ttlcache.DefaultCache.Delete("SESSION@" + sid)
// 忽略OTP
if strings.HasSuffix(sid, "_otp") {
return false
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
return false
}
_, err = rpcClient.LoginSessionRPC().WriteLoginSessionValue(rpcClient.Context(0), &pb.WriteLoginSessionValueRequest{
Sid: sid,
Key: key,
Value: value,
})
if err != nil {
logs.Println("SESSION", "write sid:'"+sid+"' key:'"+key+"' failed: "+err.Error())
}
return true
}
func (this *SessionManager) Delete(sid string) bool {
// 删除缓存
defer ttlcache.DefaultCache.Delete("SESSION@" + sid)
// 忽略OTP
if strings.HasSuffix(sid, "_otp") {
return false
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
return false
}
_, err = rpcClient.LoginSessionRPC().DeleteLoginSession(rpcClient.Context(0), &pb.DeleteLoginSessionRequest{Sid: sid})
if err != nil {
logs.Println("SESSION", "delete '"+sid+"' failed: "+err.Error())
}
return true
}

View File

@@ -0,0 +1,486 @@
package nodes
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
"github.com/TeaOSLab/EdgeUser/internal/configs"
teaconst "github.com/TeaOSLab/EdgeUser/internal/const"
"github.com/TeaOSLab/EdgeUser/internal/events"
"github.com/TeaOSLab/EdgeUser/internal/rpc"
_ "github.com/TeaOSLab/EdgeUser/internal/tasks"
"github.com/TeaOSLab/EdgeUser/internal/utils"
_ "github.com/TeaOSLab/EdgeUser/internal/web"
"github.com/iwind/TeaGo"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock"
"gopkg.in/yaml.v3"
"log"
"net"
"os"
"os/exec"
"time"
)
type UserNode struct {
sock *gosock.Sock
}
func NewUserNode() *UserNode {
return &UserNode{
sock: gosock.NewTmpSock(teaconst.ProcessName),
}
}
func (this *UserNode) Run() {
// 启动用户界面
var secret = this.genSecret()
configs.Secret = secret
// 本地Sock
err := this.listenSock()
if err != nil {
logs.Println("[USER_NODE]" + err.Error())
return
}
// 检查server配置
err = this.checkServer()
if err != nil {
logs.Println("[USER_NODE]" + err.Error())
return
}
// 触发事件
events.Notify(events.EventStart)
// 拉取配置
err = this.pullConfig()
if err != nil {
logs.Println("[USER_NODE]pull config failed: " + err.Error())
return
}
// 设置DNS
this.setupDNS()
// 监控状态
go NewNodeStatusExecutor().Listen()
logs.Println("[USER_NODE]initializing ip library ...")
err = iplibrary.InitPlus()
if err != nil {
logs.Println("[USER_NODE]initialize ip library failed: " + err.Error())
}
// 启动Web服务
sessionManager, err := NewSessionManager()
if err != nil {
log.Fatal("start session failed: " + err.Error())
return
}
TeaGo.NewServer(false).
AccessLog(false).
EndAll().
Session(sessionManager, teaconst.CookieSID).
ReadHeaderTimeout(3*time.Second).
ReadTimeout(600*time.Second).
Static("/www", Tea.Root+"/www").
Start()
}
// Daemon 实现守护进程
func (this *UserNode) Daemon() {
var isDebug = lists.ContainsString(os.Args, "debug")
for {
conn, err := this.sock.Dial()
if err != nil {
if isDebug {
log.Println("[DAEMON]starting ...")
}
// 尝试启动
err = func() error {
exe, err := os.Executable()
if err != nil {
return err
}
cmd := exec.Command(exe)
err = cmd.Start()
if err != nil {
return err
}
err = cmd.Wait()
if err != nil {
return err
}
return nil
}()
if err != nil {
if isDebug {
log.Println("[DAEMON]", err)
}
time.Sleep(1 * time.Second)
} else {
time.Sleep(5 * time.Second)
}
} else {
_ = conn.Close()
time.Sleep(5 * time.Second)
}
}
}
// InstallSystemService 安装系统服务
func (this *UserNode) InstallSystemService() error {
var shortName = teaconst.SystemdServiceName
exe, err := os.Executable()
if err != nil {
return err
}
manager := utils.NewServiceManager(shortName, teaconst.ProductName)
err = manager.Install(exe, []string{})
if err != nil {
return err
}
return nil
}
// 检查Server配置
func (this *UserNode) checkServer() error {
var configFile = Tea.ConfigFile("server.yaml")
_, err := os.Stat(configFile)
if err == nil {
return nil
}
if os.IsNotExist(err) {
// 创建文件
var templateFile = Tea.ConfigFile("server.template.yaml")
data, err := os.ReadFile(templateFile)
if err == nil {
err = os.WriteFile(configFile, data, 0666)
if err != nil {
return fmt.Errorf("create config file failed: %w", err)
}
} else {
templateYAML := `# environment code
env: prod
# http
http:
"on": true
listen: [ "0.0.0.0:7789" ]
# https
https:
"on": false
listen: [ "0.0.0.0:443"]
cert: ""
key: ""
`
err = os.WriteFile(configFile, []byte(templateYAML), 0666)
if err != nil {
return fmt.Errorf("create config file failed: %w", err)
}
}
} else {
return fmt.Errorf("can not read config from 'configs/server.yaml': %w", err)
}
return nil
}
// 生成Secret
func (this *UserNode) genSecret() string {
var tmpFile = os.TempDir() + "/edge-user-secret.tmp"
data, err := os.ReadFile(tmpFile)
if err == nil && len(data) == 32 {
return string(data)
}
secret := rands.String(32)
_ = os.WriteFile(tmpFile, []byte(secret), 0666)
return secret
}
// 拉取配置
func (this *UserNode) pullConfig() error {
rpcClient, err := rpc.SharedRPC()
if err != nil {
return err
}
var nodeResp *pb.FindCurrentUserNodeResponse
for i := 0; i < 10; i++ { // may retry many times
nodeResp, err = rpcClient.UserNodeRPC().FindCurrentUserNode(rpcClient.Context(0), &pb.FindCurrentUserNodeRequest{})
if err != nil {
time.Sleep(1 * time.Second)
continue
}
break
}
if err != nil {
return err
}
var node = nodeResp.UserNode
if node == nil {
return errors.New("invalid 'nodeId' or 'secret'")
}
if configs.SharedAPIConfig != nil {
configs.SharedAPIConfig.NumberId = node.Id
}
// 读取Web服务配置
var serverConfig = &TeaGo.ServerConfig{
Env: Tea.EnvProd,
}
if Tea.IsTesting() {
serverConfig.Env = Tea.EnvDev
}
// HTTP
httpConfig, err := this.decodeHTTP(node)
if err != nil {
return fmt.Errorf("decode http config failed: %w", err)
}
if httpConfig != nil && httpConfig.IsOn && len(httpConfig.Listen) > 0 {
serverConfig.Http.On = true
var listens = []string{}
for _, listen := range httpConfig.Listen {
listens = append(listens, listen.Addresses()...)
}
serverConfig.Http.Listen = listens
}
// HTTPS
httpsConfig, err := this.DecodeHTTPS(node)
if err != nil {
return fmt.Errorf("decode https config failed: %w", err)
}
if httpsConfig != nil && httpsConfig.IsOn && len(httpsConfig.Listen) > 0 {
serverConfig.Https.On = true
serverConfig.Https.Cert = "configs/https.cert.pem"
serverConfig.Https.Key = "configs/https.key.pem"
var listens = []string{}
for _, listen := range httpsConfig.Listen {
listens = append(listens, listen.Addresses()...)
}
serverConfig.Https.Listen = listens
}
// 保存到文件
serverYAML, err := yaml.Marshal(serverConfig)
if err != nil {
return err
}
err = os.WriteFile(Tea.ConfigFile("server.yaml"), serverYAML, 0666)
if err != nil {
return err
}
// add to local firewall
var ports = []int{}
for _, listens := range [][]string{serverConfig.Http.Listen, serverConfig.Https.Listen} {
for _, listen := range listens {
_, portString, err := net.SplitHostPort(listen)
if err == nil {
var port = types.Int(portString)
if port > 0 && !lists.ContainsInt(ports, port) {
ports = append(ports, port)
}
}
}
}
if len(ports) > 0 {
go utils.AddPortsToFirewall(ports)
}
return nil
}
// 解析HTTP配置
func (this *UserNode) decodeHTTP(node *pb.UserNode) (*serverconfigs.HTTPProtocolConfig, error) {
if len(node.HttpJSON) == 0 {
return nil, nil
}
config := &serverconfigs.HTTPProtocolConfig{}
err := json.Unmarshal(node.HttpJSON, config)
if err != nil {
return nil, err
}
err = config.Init()
if err != nil {
return nil, err
}
return config, nil
}
// DecodeHTTPS 解析HTTPS配置
func (this *UserNode) DecodeHTTPS(node *pb.UserNode) (*serverconfigs.HTTPSProtocolConfig, error) {
if len(node.HttpsJSON) == 0 {
return nil, nil
}
var config = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(node.HttpsJSON, config)
if err != nil {
return nil, err
}
err = config.Init(context.TODO())
if err != nil {
return nil, err
}
if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
rpcClient, err := rpc.SharedRPC()
if err != nil {
return nil, err
}
policyConfigResp, err := rpcClient.SSLPolicyRPC().FindEnabledSSLPolicyConfig(rpcClient.Context(0), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: policyId})
if err != nil {
return nil, err
}
if len(policyConfigResp.SslPolicyJSON) > 0 {
policyConfig := &sslconfigs.SSLPolicy{}
err = json.Unmarshal(policyConfigResp.SslPolicyJSON, policyConfig)
if err != nil {
return nil, err
}
if len(policyConfig.Certs) > 0 {
err = os.WriteFile(Tea.ConfigFile("https.cert.pem"), policyConfig.Certs[0].CertData, 0666)
if err != nil {
return nil, err
}
err = os.WriteFile(Tea.ConfigFile("https.key.pem"), policyConfig.Certs[0].KeyData, 0666)
if err != nil {
return nil, err
}
}
}
}
}
err = config.Init(context.TODO())
if err != nil {
return nil, err
}
return config, nil
}
// 监听本地sock
func (this *UserNode) listenSock() error {
// 检查是否在运行
if this.sock.IsListening() {
reply, err := this.sock.Send(&gosock.Command{Code: "pid"})
if err == nil {
return errors.New("error: the process is already running, pid: " + maps.NewMap(reply.Params).GetString("pid"))
} else {
return errors.New("error: the process is already running")
}
}
// 启动监听
go func() {
this.sock.OnCommand(func(cmd *gosock.Command) {
switch cmd.Code {
case "pid":
_ = cmd.Reply(&gosock.Command{
Code: "pid",
Params: map[string]interface{}{
"pid": os.Getpid(),
},
})
case "info":
exePath, _ := os.Executable()
_ = cmd.Reply(&gosock.Command{
Code: "info",
Params: map[string]interface{}{
"pid": os.Getpid(),
"version": teaconst.Version,
"path": exePath,
},
})
case "stop":
_ = cmd.ReplyOk()
// 退出主进程
events.Notify(events.EventQuit)
os.Exit(0)
case "dev": // 切换到dev
Tea.Env = Tea.EnvDev
_ = cmd.ReplyOk()
case "prod": // 切换到prod
Tea.Env = Tea.EnvProd
_ = cmd.ReplyOk()
case "demo":
teaconst.IsDemoMode = !teaconst.IsDemoMode
_ = cmd.Reply(&gosock.Command{
Params: map[string]interface{}{"isDemo": teaconst.IsDemoMode},
})
}
})
err := this.sock.Listen()
if err != nil {
logs.Println("NODE", err.Error())
}
}()
events.On(events.EventQuit, func() {
logs.Println("NODE", "quit unix sock")
_ = this.sock.Close()
})
return nil
}
// 设置DNS相关
func (this *UserNode) setupDNS() {
config, loadErr := configloaders.LoadUIConfig()
if loadErr != nil {
// 默认使用go原生
err := os.Setenv("GODEBUG", "netdns=go")
if err != nil {
logs.Println("[DNS_RESOLVER]set env failed: " + err.Error())
}
return
}
var err error
switch config.DNSResolver.Type {
case nodeconfigs.DNSResolverTypeGoNative:
err = os.Setenv("GODEBUG", "netdns=go")
case nodeconfigs.DNSResolverTypeCGO:
err = os.Setenv("GODEBUG", "netdns=cgo")
default:
// 默认使用go原生
err = os.Setenv("GODEBUG", "netdns=go")
}
if err != nil {
logs.Println("[DNS_RESOLVER]set env failed: " + err.Error())
}
}