Initial commit (code only without large binaries)

This commit is contained in:
robin
2026-02-15 18:58:44 +08:00
commit 35df75498f
9442 changed files with 1495866 additions and 0 deletions

View File

@@ -0,0 +1,547 @@
package lb
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net"
"strconv"
)
type CreateAction struct {
actionutils.ParentAction
}
func (this *CreateAction) Init() {
this.Nav("", "", "create")
}
func (this *CreateAction) RunGet(params struct{}) {
var supportTCP = this.ValidateFeature(userconfigs.UserFeatureCodeServerTCP, 0)
var supportUDP = this.ValidateFeature(userconfigs.UserFeatureCodeServerUDP, 0)
if !supportTCP && !supportUDP {
return
}
this.Data["supportTCP"] = supportTCP
this.Data["supportUDP"] = supportUDP
// 服务类型
var serverTypes = []maps.Map{}
if supportTCP {
serverTypes = append(serverTypes, maps.Map{
"name": "TCP负载均衡",
"code": serverconfigs.ServerTypeTCPProxy,
})
}
if supportUDP {
serverTypes = append(serverTypes, maps.Map{
"name": "UDP负载均衡",
"code": serverconfigs.ServerTypeUDPProxy,
})
}
this.Data["serverTypes"] = serverTypes
this.Data["canSpecifyTCPPort"] = this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, 0)
this.Data["canSpecifyUDPPort"] = this.ValidateFeature(userconfigs.UserFeatureCodeServerUDPPort, 0)
this.Show()
}
func (this *CreateAction) RunPost(params struct {
Name string
ServerType string
Protocols []string
CertIdsJSON []byte
OriginsJSON []byte
TcpPorts []int
TlsPorts []int
UdpPorts []int
Must *actions.Must
CSRF *actionutils.CSRF
}) {
// 检查ServerType
var serverType = params.ServerType
if !lists.ContainsString([]string{serverconfigs.ServerTypeTCPProxy, serverconfigs.ServerTypeUDPProxy}, serverType) {
this.Fail("请选择正确的服务类型")
}
// 检查用户所在集群
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
if err != nil {
this.ErrorPage(err)
return
}
clusterId := clusterIdResp.NodeClusterId
if clusterId == 0 {
this.Fail("当前用户没有指定集群,不能使用此服务")
}
// 检查是否有TCP权限
if lists.ContainsString(params.Protocols, "tcp") && !this.ValidateFeature(userconfigs.UserFeatureCodeServerTCP, 0) {
this.Fail("你没有权限使用TCP负载均衡功能")
}
// 检查是否有UDP权限
if lists.ContainsString(params.Protocols, "udp") && !this.ValidateFeature(userconfigs.UserFeatureCodeServerUDP, 0) {
this.Fail("你没有权限使用UDP负载均衡功能")
}
params.Must.
Field("name", params.Name).
Require("请输入服务名称")
// 协议
if len(params.Protocols) == 0 {
this.Fail("请选择至少一个协议")
}
// TCP
canSpecifyTCPPort := this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, 0)
if serverType == serverconfigs.ServerTypeTCPProxy {
// 检查TCP端口
if canSpecifyTCPPort {
if lists.Contains(params.Protocols, "tcp") {
if len(params.TcpPorts) == 0 {
this.Fail("需要至少指定一个TCP监听端口")
}
for _, port := range params.TcpPorts {
if port < 1024 || port > 65534 {
this.Fail("端口 '" + strconv.Itoa(port) + "' 范围错误")
}
// 检查是否被使用
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: types.Int32(port),
NodeClusterId: clusterId,
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + strconv.Itoa(port) + "' 正在被别的服务使用,请换一个")
}
}
}
if lists.Contains(params.Protocols, "tls") {
if len(params.TlsPorts) == 0 {
this.Fail("需要至少指定一个TLS监听端口")
}
for _, port := range params.TlsPorts {
if port < 1024 || port > 65534 {
this.Fail("端口 '" + strconv.Itoa(port) + "' 范围错误")
}
if lists.ContainsInt(params.TcpPorts, port) {
this.Fail("TLS端口 '" + strconv.Itoa(port) + "' 已经被TCP端口使用不能重复使用")
}
// 检查是否被使用
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: types.Int32(port),
NodeClusterId: clusterId,
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + strconv.Itoa(port) + "' 正在被别的服务使用,请换一个")
}
}
}
}
}
// UDP
canSpecifyUDPPort := this.ValidateFeature(userconfigs.UserFeatureCodeServerUDPPort, 0)
if serverType == serverconfigs.ServerTypeUDPProxy {
// 检查UDP端口
if canSpecifyUDPPort {
if lists.Contains(params.Protocols, "udp") {
if len(params.UdpPorts) == 0 {
this.Fail("需要至少指定一个UDP监听端口")
}
for _, port := range params.UdpPorts {
if port < 1024 || port > 65534 {
this.Fail("端口 '" + strconv.Itoa(port) + "' 范围错误")
}
// 检查是否被使用
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: types.Int32(port),
NodeClusterId: clusterId,
ProtocolFamily: "udp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + strconv.Itoa(port) + "' 正在被别的服务使用,请换一个")
}
}
}
}
}
// 先加锁
lockerKey := "create_tcp_server"
lockResp, err := this.RPC().SysLockerRPC().SysLockerLock(this.UserContext(), &pb.SysLockerLockRequest{
Key: lockerKey,
TimeoutSeconds: 30,
})
if err != nil {
this.ErrorPage(err)
return
}
if !lockResp.Ok {
this.Fail("操作繁忙,请稍后再试")
}
defer func() {
_, err := this.RPC().SysLockerRPC().SysLockerUnlock(this.UserContext(), &pb.SysLockerUnlockRequest{Key: lockerKey})
if err != nil {
this.ErrorPage(err)
return
}
}()
tcpConfig := &serverconfigs.TCPProtocolConfig{}
tlsConfig := &serverconfigs.TLSProtocolConfig{}
udpConfig := &serverconfigs.UDPProtocolConfig{}
if serverType == serverconfigs.ServerTypeTCPProxy {
// TCP
ports := []int{}
if lists.ContainsString(params.Protocols, "tcp") {
tcpConfig.IsOn = true
if canSpecifyTCPPort {
for _, port := range params.TcpPorts {
tcpConfig.Listen = append(tcpConfig.Listen, &serverconfigs.NetworkAddressConfig{
Protocol: serverconfigs.ProtocolTCP,
Host: "",
PortRange: strconv.Itoa(port),
})
}
} else {
// 获取随机端口
portResp, err := this.RPC().NodeClusterRPC().FindFreePortInNodeCluster(this.UserContext(), &pb.FindFreePortInNodeClusterRequest{
NodeClusterId: clusterId,
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
port := int(portResp.Port)
ports = append(ports, port)
tcpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolTCP,
Host: "",
PortRange: strconv.Itoa(port),
},
}
}
}
// TLS
if lists.ContainsString(params.Protocols, "tls") {
tlsConfig.IsOn = true
if canSpecifyTCPPort {
for _, port := range params.TlsPorts {
tlsConfig.Listen = append(tlsConfig.Listen, &serverconfigs.NetworkAddressConfig{
Protocol: serverconfigs.ProtocolTLS,
Host: "",
PortRange: strconv.Itoa(port),
})
}
} else {
var port int
// 尝试N次
for i := 0; i < 5; i++ {
// 获取随机端口
portResp, err := this.RPC().NodeClusterRPC().FindFreePortInNodeCluster(this.UserContext(), &pb.FindFreePortInNodeClusterRequest{
NodeClusterId: clusterId,
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
p := int(portResp.Port)
if !lists.ContainsInt(ports, p) {
port = p
break
}
}
if port == 0 {
this.Fail("无法找到可用的端口,请稍后重试")
}
tlsConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolTLS,
Host: "",
PortRange: strconv.Itoa(port),
},
}
}
if len(params.CertIdsJSON) == 0 {
this.Fail("请选择或者上传TLS证书")
}
certIds := []int64{}
err := json.Unmarshal(params.CertIdsJSON, &certIds)
if err != nil {
this.ErrorPage(err)
return
}
if len(certIds) == 0 {
this.Fail("请选择或者上传TLS证书")
}
certRefs := []*sslconfigs.SSLCertRef{}
for _, certId := range certIds {
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
IsOn: true,
CertId: certId,
})
}
certRefsJSON, err := json.Marshal(certRefs)
if err != nil {
this.ErrorPage(err)
return
}
// 创建策略
sslPolicyIdResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.UserContext(), &pb.CreateSSLPolicyRequest{
Http2Enabled: false,
Http3Enabled: false,
MinVersion: "TLS 1.1",
SslCertsJSON: certRefsJSON,
HstsJSON: nil,
ClientAuthType: 0,
ClientCACertsJSON: nil,
CipherSuites: nil,
CipherSuitesIsOn: false,
})
if err != nil {
this.ErrorPage(err)
return
}
tlsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyIdResp.SslPolicyId,
}
}
}
// UDP
if serverType == serverconfigs.ServerTypeUDPProxy {
if lists.ContainsString(params.Protocols, "udp") {
udpConfig.IsOn = true
if canSpecifyUDPPort {
for _, port := range params.UdpPorts {
udpConfig.Listen = append(udpConfig.Listen, &serverconfigs.NetworkAddressConfig{
Protocol: serverconfigs.ProtocolUDP,
Host: "",
PortRange: strconv.Itoa(port),
})
}
} else {
// 获取随机端口
portResp, err := this.RPC().NodeClusterRPC().FindFreePortInNodeCluster(this.UserContext(), &pb.FindFreePortInNodeClusterRequest{
NodeClusterId: clusterId,
ProtocolFamily: "udp",
})
if err != nil {
this.ErrorPage(err)
return
}
port := int(portResp.Port)
udpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolUDP,
Host: "",
PortRange: strconv.Itoa(port),
},
}
}
}
}
// 源站信息
originMaps := []maps.Map{}
if len(params.OriginsJSON) == 0 {
this.Fail("请输入源站信息")
}
err = json.Unmarshal(params.OriginsJSON, &originMaps)
if err != nil {
this.ErrorPage(err)
return
}
if len(originMaps) == 0 {
this.Fail("请输入源站信息")
}
primaryOriginRefs := []*serverconfigs.OriginRef{}
backupOriginRefs := []*serverconfigs.OriginRef{}
for _, originMap := range originMaps {
host := originMap.GetString("host")
isPrimary := originMap.GetBool("isPrimary")
scheme := originMap.GetString("scheme")
if len(host) == 0 {
this.Fail("源站地址不能为空")
}
addrHost, addrPort, err := net.SplitHostPort(host)
if err != nil {
this.Fail("源站地址'" + host + "'格式错误")
}
if (serverType == serverconfigs.ServerTypeTCPProxy && scheme != "tcp" && scheme != "tls") ||
(serverType == serverconfigs.ServerTypeUDPProxy && scheme != "udp") {
this.Fail("错误的源站协议")
}
originIdResp, err := this.RPC().OriginRPC().CreateOrigin(this.UserContext(), &pb.CreateOriginRequest{
Name: "",
Addr: &pb.NetworkAddress{
Protocol: scheme,
Host: addrHost,
PortRange: addrPort,
},
Description: "",
Weight: 10,
IsOn: true,
})
if err != nil {
this.ErrorPage(err)
return
}
if isPrimary {
primaryOriginRefs = append(primaryOriginRefs, &serverconfigs.OriginRef{
IsOn: true,
OriginId: originIdResp.OriginId,
})
} else {
backupOriginRefs = append(backupOriginRefs, &serverconfigs.OriginRef{
IsOn: true,
OriginId: originIdResp.OriginId,
})
}
}
primaryOriginsJSON, err := json.Marshal(primaryOriginRefs)
if err != nil {
this.ErrorPage(err)
return
}
backupOriginsJSON, err := json.Marshal(backupOriginRefs)
if err != nil {
this.ErrorPage(err)
return
}
scheduling := &serverconfigs.SchedulingConfig{
Code: "random",
Options: nil,
}
schedulingJSON, err := json.Marshal(scheduling)
if err != nil {
this.ErrorPage(err)
return
}
// 反向代理
reverseProxyResp, err := this.RPC().ReverseProxyRPC().CreateReverseProxy(this.UserContext(), &pb.CreateReverseProxyRequest{
SchedulingJSON: schedulingJSON,
PrimaryOriginsJSON: primaryOriginsJSON,
BackupOriginsJSON: backupOriginsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyId := reverseProxyResp.ReverseProxyId
reverseProxyRef := &serverconfigs.ReverseProxyRef{
IsPrior: false,
IsOn: true,
ReverseProxyId: reverseProxyId,
}
reverseProxyRefJSON, err := json.Marshal(reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
// 开始保存
var tcpJSON []byte
var tlsJSON []byte
var udpJSON []byte
if tcpConfig.IsOn {
tcpJSON, err = tcpConfig.AsJSON()
if err != nil {
this.ErrorPage(err)
return
}
}
if tlsConfig.IsOn {
tlsJSON, err = tlsConfig.AsJSON()
if err != nil {
this.ErrorPage(err)
return
}
}
if udpConfig.IsOn {
udpJSON, err = udpConfig.AsJSON()
if err != nil {
this.ErrorPage(err)
return
}
}
createResp, err := this.RPC().ServerRPC().CreateServer(this.UserContext(), &pb.CreateServerRequest{
UserId: this.UserId(),
AdminId: 0,
Type: serverType,
Name: params.Name,
Description: "",
ServerNamesJSON: []byte("[]"),
HttpJSON: nil,
HttpsJSON: nil,
TcpJSON: tcpJSON,
TlsJSON: tlsJSON,
UdpJSON: udpJSON,
WebId: 0,
ReverseProxyJSON: reverseProxyRefJSON,
ServerGroupIds: nil,
NodeClusterId: clusterId,
IncludeNodesJSON: nil,
ExcludeNodesJSON: nil,
})
if err != nil {
this.ErrorPage(err)
return
}
serverId := createResp.ServerId
defer this.CreateLogInfo(codes.Server_LogCreateServer, serverId)
this.Success()
}

View File

@@ -0,0 +1,25 @@
package lb
import (
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
ServerId int64
}) {
defer this.CreateLogInfo(codes.Server_LogDeleteServer, params.ServerId)
_, err := this.RPC().ServerRPC().DeleteServer(this.UserContext(), &pb.DeleteServerRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,213 @@
package lb
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
"github.com/TeaOSLab/EdgeUser/internal/utils"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"strings"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "index")
}
func (this *IndexAction) RunGet(params struct{}) {
// 更新用户可用状态
stateResp, err := this.RPC().UserRPC().RenewUserServersState(this.UserContext(), &pb.RenewUserServersStateRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["serversIsEnabled"] = stateResp.IsEnabled
// 提醒有逾期未支付的账单
this.Data["countUnpaidBills"] = 0
priceConfig, _ := configloaders.LoadCacheableUserPriceConfig()
if priceConfig != nil && priceConfig.IsOn && priceConfig.UnpaidBillPolicy.IsOn && (priceConfig.UnpaidBillPolicy.MinDailyBillDays > 0 || priceConfig.UnpaidBillPolicy.MinMonthlyBillDays > 0) {
countResp, err := this.RPC().UserBillRPC().CountAllUserBills(this.UserContext(), &pb.CountAllUserBillsRequest{
PaidFlag: 0,
UserId: this.UserId(),
Month: "",
TrafficRelated: true,
MinDailyBillDays: priceConfig.UnpaidBillPolicy.MinDailyBillDays,
MinMonthlyBillDays: priceConfig.UnpaidBillPolicy.MinMonthlyBillDays,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["countUnpaidBills"] = countResp.Count
}
var supportTCP = this.ValidateFeature(userconfigs.UserFeatureCodeServerTCP, 0)
var supportUDP = this.ValidateFeature(userconfigs.UserFeatureCodeServerUDP, 0)
if !supportTCP && !supportUDP {
return
}
this.Data["supportTCP"] = supportTCP
this.Data["supportUDP"] = supportUDP
var protocols = []string{}
if supportTCP {
protocols = append(protocols, "tcp")
}
if supportUDP {
protocols = append(protocols, "udp")
}
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersMatch(this.UserContext(), &pb.CountAllEnabledServersMatchRequest{
ServerGroupId: 0,
Keyword: "",
UserId: this.UserId(),
ProtocolFamily: strings.Join(protocols, ","),
})
if err != nil {
this.ErrorPage(err)
return
}
var count = countResp.Count
var page = this.NewPage(count)
this.Data["page"] = page.AsHTML()
serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.UserContext(), &pb.ListEnabledServersMatchRequest{
Offset: page.Offset,
Size: page.Size,
ServerGroupId: 0,
Keyword: "",
ProtocolFamily: strings.Join(protocols, ","),
UserId: this.UserId(),
IgnoreSSLCerts: true,
})
if err != nil {
this.ErrorPage(err)
return
}
var serverMaps = []maps.Map{}
for _, server := range serversResp.Servers {
// CNAME
var cname = ""
if server.NodeCluster != nil {
clusterId := server.NodeCluster.Id
if clusterId > 0 {
dnsInfoResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.UserContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: clusterId})
if err != nil {
this.ErrorPage(err)
return
}
if dnsInfoResp.Domain != nil {
cname = server.DnsName + "." + dnsInfoResp.Domain.Name + "."
}
}
}
// TCP
var tcpPorts = []string{}
if len(server.TcpJSON) > 0 {
config, err := serverconfigs.NewTCPProtocolConfigFromJSON(server.TcpJSON)
if err != nil {
this.ErrorPage(err)
return
}
if config.IsOn {
for _, listen := range config.Listen {
tcpPorts = append(tcpPorts, listen.PortRange)
}
}
}
// TLS
var tlsPorts = []string{}
if len(server.TlsJSON) > 0 {
config, err := serverconfigs.NewTLSProtocolConfigFromJSON(server.TlsJSON)
if err != nil {
this.ErrorPage(err)
return
}
if config.IsOn {
for _, listen := range config.Listen {
tlsPorts = append(tlsPorts, listen.PortRange)
}
}
}
// UDP
var udpPorts = []string{}
if len(server.UdpJSON) > 0 {
config, err := serverconfigs.NewUDPProtocolConfigFromJSON(server.UdpJSON)
if err != nil {
this.ErrorPage(err)
return
}
if config.IsOn {
for _, listen := range config.Listen {
udpPorts = append(udpPorts, listen.PortRange)
}
}
}
// 套餐
var userPlanMap = maps.Map{"id": 0}
if server.UserPlanId > 0 {
userPlanResp, err := this.RPC().UserPlanRPC().FindEnabledUserPlan(this.UserContext(), &pb.FindEnabledUserPlanRequest{
UserPlanId: server.UserPlanId,
})
if err != nil {
if !utils.IsNotFound(err) {
this.ErrorPage(err)
return
}
} else {
var userPlan = userPlanResp.UserPlan
if userPlan != nil && userPlan.Plan != nil {
if len(userPlan.Name) == 0 {
userPlan.Name = userPlan.Plan.Name
}
userPlanMap = maps.Map{
"id": userPlan.Id,
"name": userPlan.Name,
"dayTo": userPlan.DayTo,
"isExpired": userPlan.DayTo <= timeutil.Format("Y-m-d"),
}
}
}
}
// 域名和限流状态
var trafficLimitStatus *serverconfigs.TrafficLimitStatus
if len(server.Config) > 0 {
var serverConfig = &serverconfigs.ServerConfig{}
err = json.Unmarshal(server.Config, serverConfig)
if err == nil {
if serverConfig.TrafficLimitStatus != nil && serverConfig.TrafficLimitStatus.IsValid() {
trafficLimitStatus = serverConfig.TrafficLimitStatus
}
}
}
serverMaps = append(serverMaps, maps.Map{
"id": server.Id,
"name": server.Name,
"cname": cname,
"tcpPorts": tcpPorts,
"tlsPorts": tlsPorts,
"udpPorts": udpPorts,
"isOn": server.IsOn,
"userPlan": userPlanMap,
"trafficLimitStatus": trafficLimitStatus,
})
}
this.Data["servers"] = serverMaps
this.Show()
}

View File

@@ -0,0 +1,21 @@
package lb
import (
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Data("teaMenu", "lb").
Prefix("/lb").
GetPost("", new(IndexAction)).
GetPost("/create", new(CreateAction)).
Post("/updateOn", new(UpdateOnAction)).
Post("/delete", new(DeleteAction)).
Get("/server", new(ServerAction)).
EndAll()
})
}

View File

@@ -0,0 +1,21 @@
package lb
import (
"github.com/TeaOSLab/EdgeUser/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
)
type ServerAction struct {
actionutils.ParentAction
}
func (this *ServerAction) Init() {
this.Nav("", "", "")
}
func (this *ServerAction) RunGet(params struct {
ServerId int64
}) {
// TODO 先跳转到设置页面,将来实现日志查看、统计看板等
this.RedirectURL("/lb/server/settings/basic?serverId=" + numberutils.FormatInt64(params.ServerId))
}

View File

@@ -0,0 +1,58 @@
package basic
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("basic")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
resp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.UserContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
server := resp.Server
if server == nil {
this.NotFound("server", params.ServerId)
return
}
this.Data["name"] = server.Name
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ServerId int64
Name string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("name", params.Name).
Require("请输入服务名称")
_, err := this.RPC().ServerRPC().UpdateEnabledUserServerBasic(this.UserContext(), &pb.UpdateEnabledUserServerBasicRequest{
ServerId: params.ServerId,
Name: params.Name,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,18 @@
package basic
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/basic").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,33 @@
package dns
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("dns")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
dnsInfoResp, err := this.RPC().ServerRPC().FindEnabledServerDNS(this.UserContext(), &pb.FindEnabledServerDNSRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["dnsName"] = dnsInfoResp.DnsName
if dnsInfoResp.Domain != nil {
this.Data["dnsDomain"] = dnsInfoResp.Domain.Name
} else {
this.Data["dnsDomain"] = ""
}
this.Show()
}

View File

@@ -0,0 +1,18 @@
package dns
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/dns").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,73 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package plan
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/maps"
)
// DataAction 套餐相关数据
type DataAction struct {
actionutils.ParentAction
}
func (this *DataAction) RunPost(params struct {
ServerId int64
UserPlanId int64
}) {
userPlanResp, err := this.RPC().UserPlanRPC().FindEnabledUserPlan(this.UserContext(), &pb.FindEnabledUserPlanRequest{UserPlanId: params.UserPlanId})
if err != nil {
this.ErrorPage(err)
return
}
var userPlan = userPlanResp.UserPlan
if userPlan == nil || userPlan.Plan == nil {
this.NotFound("userPlan", params.UserPlanId)
return
}
var plan = userPlan.Plan
// 网站数
countServersResp, err := this.RPC().ServerRPC().CountAllUserServers(this.UserContext(), &pb.CountAllUserServersRequest{
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["servers"] = maps.Map{
"current": countServersResp.Count,
"max": plan.TotalServers,
"isValid": plan.TotalServers <= 0 || countServersResp.Count+1 <= int64(plan.TotalServers),
}
// 当前网站域名数
countServerNamesResp, err := this.RPC().ServerRPC().CountServerNames(this.UserContext(), &pb.CountServerNamesRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["serverNames"] = maps.Map{
"current": countServerNamesResp.Count,
"max": plan.TotalServerNamesPerServer,
"isValid": plan.TotalServerNamesPerServer <= 0 || countServerNamesResp.Count <= int64(plan.TotalServerNamesPerServer),
}
// 总域名数
countAllServerNamesResp, err := this.RPC().ServerRPC().CountAllServerNamesWithUserId(this.UserContext(), &pb.CountAllServerNamesWithUserIdRequest{
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["allServerNames"] = maps.Map{
"current": countAllServerNamesResp.Count,
"max": plan.TotalServerNames,
"isValid": plan.TotalServerNames <= 0 || countAllServerNamesResp.Count+countServerNamesResp.Count <= int64(plan.TotalServerNames),
}
this.Success()
}

View File

@@ -0,0 +1,244 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package plan
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("plan")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
if !this.ValidateFeature(userconfigs.UserFeatureCodePlan, params.ServerId) {
return
}
// 所有可选套餐
userPlansResp, err := this.RPC().UserPlanRPC().FindAllEnabledUserPlansForServer(this.UserContext(), &pb.FindAllEnabledUserPlansForServerRequest{
UserId: this.UserId(),
ServerId: params.ServerId,
})
if err != nil {
this.ErrorPage(err)
return
}
var userPlanMaps = []maps.Map{}
for _, userPlan := range userPlansResp.UserPlans {
if userPlan.Plan == nil {
continue
}
var name = userPlan.Plan.Name
if len(userPlan.Name) > 0 {
name += "-" + userPlan.Name
}
userPlanMaps = append(userPlanMaps, maps.Map{
"id": userPlan.Id,
"name": name,
"dayTo": userPlan.DayTo,
"totalServers": userPlan.Plan.TotalServers,
"totalServerNames": userPlan.Plan.TotalServerNames,
"totalServerNamesPerServer": userPlan.Plan.TotalServerNamesPerServer,
})
}
this.Data["userPlans"] = userPlanMaps
// 当前使用的套餐
userPlanResp, err := this.RPC().ServerRPC().FindServerUserPlan(this.UserContext(), &pb.FindServerUserPlanRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
// 用户套餐信息
var userPlanMap = maps.Map{"id": 0}
var userPlan = userPlanResp.UserPlan
this.Data["hasTrafficLimit"] = false
if userPlan != nil {
userPlanMap = maps.Map{
"id": userPlan.Id,
"dayTo": userPlan.DayTo,
"isExpired": timeutil.Format("Y-m-d") > userPlan.DayTo,
"name": userPlan.Name,
"plan": nil,
}
var plan = userPlan.Plan
if plan != nil {
// 流量限制
var trafficLimit = &serverconfigs.TrafficLimitConfig{}
if len(plan.TrafficLimitJSON) > 0 {
err = json.Unmarshal(plan.TrafficLimitJSON, trafficLimit)
if err != nil {
this.ErrorPage(err)
return
}
}
userPlanMap["plan"] = maps.Map{
"id": plan.Id,
"name": plan.Name,
"trafficLimit": trafficLimit,
}
if !trafficLimit.IsEmpty() {
this.Data["hasTrafficLimit"] = true
}
}
}
this.Data["userPlan"] = userPlanMap
// 当前网站流量
{
trafficStatResp, err := this.RPC().ServerDailyRPC().SumServerDailyStats(this.UserContext(), &pb.SumServerDailyStatsRequest{
ServerId: params.ServerId,
Day: timeutil.Format("Ymd"),
})
if err != nil {
this.ErrorPage(err)
return
}
var trafficDailyBytes int64 = 0
if trafficStatResp.ServerDailyStat != nil {
trafficDailyBytes = trafficStatResp.ServerDailyStat.Bytes
}
this.Data["trafficDailyFormat"] = numberutils.FormatBytes(trafficDailyBytes)
}
{
trafficStatResp, err := this.RPC().ServerDailyRPC().SumServerMonthlyStats(this.UserContext(), &pb.SumServerMonthlyStatsRequest{
ServerId: params.ServerId,
Month: timeutil.Format("Ym"),
})
if err != nil {
this.ErrorPage(err)
return
}
var trafficMonthlyBytes int64 = 0
if trafficStatResp.ServerMonthlyStat != nil {
trafficMonthlyBytes = trafficStatResp.ServerMonthlyStat.Bytes
}
this.Data["trafficMonthlyFormat"] = numberutils.FormatBytes(trafficMonthlyBytes)
}
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ServerId int64
IsChanged bool
UserPlanId int64
Must *actions.Must
CSRF *actionutils.CSRF
}) {
if !params.IsChanged {
this.Success()
return
}
if params.UserPlanId <= 0 { // 取消绑定
defer this.CreateLogInfo(codes.UserPlan_LogCancelUserPlanFromServer, params.ServerId)
} else { // 变更绑定
defer this.CreateLogInfo(codes.UserPlan_LogBindUserPlanToServer, params.ServerId, params.UserPlanId)
}
// 前后套餐是否一致
oldUserPlanResp, err := this.RPC().ServerRPC().FindServerUserPlan(this.UserContext(), &pb.FindServerUserPlanRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
if oldUserPlanResp.UserPlan != nil && oldUserPlanResp.UserPlan.Id == params.UserPlanId {
this.Success()
return
}
// 检查套餐
if params.UserPlanId > 0 {
userPlanResp, err := this.RPC().UserPlanRPC().FindEnabledUserPlan(this.UserContext(), &pb.FindEnabledUserPlanRequest{UserPlanId: params.UserPlanId})
if err != nil {
this.ErrorPage(err)
return
}
var userPlan = userPlanResp.UserPlan
if userPlan == nil || userPlan.Plan == nil {
this.NotFound("userPlan", params.UserPlanId)
return
}
var plan = userPlan.Plan
// server
if plan.TotalServers > 0 {
countServersResp, err := this.RPC().ServerRPC().CountAllUserServers(this.UserContext(), &pb.CountAllUserServersRequest{
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
if countServersResp.Count+1 > int64(plan.TotalServers) {
this.Fail("已绑定网站数超出当前套餐限制")
return
}
}
countServerNamesResp, err := this.RPC().ServerRPC().CountServerNames(this.UserContext(), &pb.CountServerNamesRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
if plan.TotalServerNamesPerServer > 0 {
if countServerNamesResp.Count > int64(plan.TotalServerNamesPerServer) {
this.Fail("当前网站域名数超出当前套餐限制")
return
}
}
if plan.TotalServerNames > 0 {
countAllServerNamesResp, err := this.RPC().ServerRPC().CountAllServerNamesWithUserId(this.UserContext(), &pb.CountAllServerNamesWithUserIdRequest{
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
if countAllServerNamesResp.Count+countServerNamesResp.Count > int64(plan.TotalServerNames) {
this.Fail("已绑定域名数超出当前套餐限制")
return
}
}
}
// 提交修改
_, err = this.RPC().ServerRPC().UpdateServerUserPlan(this.UserContext(), &pb.UpdateServerUserPlanRequest{
ServerId: params.ServerId,
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,19 @@
package plan
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/plan").
GetPost("", new(IndexAction)).
Post("/data", new(DataAction)).
EndAll()
})
}

View File

@@ -0,0 +1,101 @@
package reverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/maps"
)
// IndexAction 源站列表
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.FirstMenu("index")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
serverTypeResp, err := this.RPC().ServerRPC().FindEnabledServerType(this.UserContext(), &pb.FindEnabledServerTypeRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
var serverType = serverTypeResp.Type
reverseProxyResp, err := this.RPC().ServerRPC().FindAndInitServerReverseProxyConfig(this.UserContext(), &pb.FindAndInitServerReverseProxyConfigRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyConfig"] = reverseProxy
this.Data["serverType"] = serverType
var primaryOriginMaps = []maps.Map{}
backupOriginMaps := []maps.Map{}
for _, originConfig := range reverseProxy.PrimaryOrigins {
var domains = originConfig.Domains
if len(domains) == 0 {
domains = []string{}
}
var m = maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.AddrSummary(),
"isOSS": originConfig.IsOSS(),
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
"followPort": originConfig.FollowPort,
"http2Enabled": originConfig.HTTP2Enabled,
"domains": domains,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
for _, originConfig := range reverseProxy.BackupOrigins {
var domains = originConfig.Domains
if len(domains) == 0 {
domains = []string{}
}
var m = maps.Map{
"id": originConfig.Id,
"weight": originConfig.Weight,
"addr": originConfig.AddrSummary(),
"isOSS": originConfig.IsOSS(),
"name": originConfig.Name,
"isOn": originConfig.IsOn,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
"followPort": originConfig.FollowPort,
"http2Enabled": originConfig.HTTP2Enabled,
"domains": domains,
}
backupOriginMaps = append(backupOriginMaps, m)
}
this.Data["primaryOrigins"] = primaryOriginMaps
this.Data["backupOrigins"] = backupOriginMaps
this.Show()
}

View File

@@ -0,0 +1,23 @@
package reverseProxy
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Data("mainTab", "setting").
Data("secondMenuItem", "reverseProxy").
Prefix("/lb/server/settings/reverseProxy").
Get("", new(IndexAction)).
GetPost("/scheduling", new(SchedulingAction)).
GetPost("/updateSchedulingPopup", new(UpdateSchedulingPopupAction)).
GetPost("/setting", new(SettingAction)).
EndAll()
})
}

View File

@@ -0,0 +1,45 @@
package reverseProxy
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/schedulingconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
)
type SchedulingAction struct {
actionutils.ParentAction
}
func (this *SchedulingAction) Init() {
this.FirstMenu("scheduling")
}
func (this *SchedulingAction) RunGet(params struct {
ServerId int64
}) {
reverseProxyResp, err := this.RPC().ServerRPC().FindAndInitServerReverseProxyConfig(this.UserContext(), &pb.FindAndInitServerReverseProxyConfigRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyId"] = reverseProxy.Id
schedulingCode := reverseProxy.FindSchedulingConfig().Code
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
if schedulingMap == nil {
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
return
}
this.Data["scheduling"] = schedulingMap
this.Show()
}

View File

@@ -0,0 +1,107 @@
package reverseProxy
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
type SettingAction struct {
actionutils.ParentAction
}
func (this *SettingAction) Init() {
this.FirstMenu("setting")
}
func (this *SettingAction) RunGet(params struct {
ServerId int64
}) {
reverseProxyResp, err := this.RPC().ServerRPC().FindAndInitServerReverseProxyConfig(this.UserContext(), &pb.FindAndInitServerReverseProxyConfigRequest{ServerId: params.ServerId})
if err != nil {
this.ErrorPage(err)
return
}
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
if err != nil {
this.ErrorPage(err)
return
}
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["reverseProxyRef"] = reverseProxyRef
this.Data["reverseProxyConfig"] = reverseProxy
this.Show()
}
func (this *SettingAction) RunPost(params struct {
ServerId int64
ReverseProxyRefJSON []byte
ReverseProxyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo(codes.ServerReverseProxy_LogUpdateServerReverseProxySettings, params.ServerId)
var reverseProxyConfig = &serverconfigs.ReverseProxyConfig{}
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
if err != nil {
this.ErrorPage(err)
return
}
err = reverseProxyConfig.Init(context.TODO())
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// 设置是否启用
_, err = this.RPC().ServerRPC().UpdateServerReverseProxy(this.UserContext(), &pb.UpdateServerReverseProxyRequest{
ServerId: params.ServerId,
ReverseProxyJSON: params.ReverseProxyRefJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
// PROXY Protocol
var proxyProtocolJSON = []byte{}
if reverseProxyConfig.ProxyProtocol != nil {
proxyProtocolJSON, err = json.Marshal(reverseProxyConfig.ProxyProtocol)
if err != nil {
this.ErrorPage(err)
return
}
}
// 设置反向代理相关信息
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxy(this.UserContext(), &pb.UpdateReverseProxyRequest{
ReverseProxyId: reverseProxyConfig.Id,
RequestHostType: types.Int32(reverseProxyConfig.RequestHostType),
RequestHost: reverseProxyConfig.RequestHost,
RequestURI: reverseProxyConfig.RequestURI,
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
ProxyProtocolJSON: proxyProtocolJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,163 @@
package reverseProxy
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/schedulingconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// 修改调度算法
type UpdateSchedulingPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateSchedulingPopupAction) Init() {
}
func (this *UpdateSchedulingPopupAction) RunGet(params struct {
Type string
ServerId int64
ReverseProxyId int64
}) {
serverConfig, err := dao.SharedServerDAO.FindEnabledServerConfig(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if serverConfig == nil {
this.NotFound("server", params.ServerId)
return
}
this.Data["dataType"] = params.Type
this.Data["serverId"] = params.ServerId
this.Data["reverseProxyId"] = params.ReverseProxyId
reverseProxyResp, err := this.RPC().ReverseProxyRPC().FindEnabledReverseProxyConfig(this.UserContext(), &pb.FindEnabledReverseProxyConfigRequest{
ReverseProxyId: params.ReverseProxyId,
})
if err != nil {
this.ErrorPage(err)
return
}
configData := reverseProxyResp.ReverseProxyJSON
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(configData, reverseProxyConfig)
if err != nil {
this.ErrorPage(err)
return
}
schedulingObject := &serverconfigs.SchedulingConfig{
Code: "random",
Options: nil,
}
if reverseProxyConfig.Scheduling != nil {
schedulingObject = reverseProxyConfig.Scheduling
}
this.Data["scheduling"] = schedulingObject
// 调度类型
schedulingTypes := []maps.Map{}
for _, m := range schedulingconfigs.AllSchedulingTypes() {
networks, ok := m["networks"]
if !ok {
continue
}
if !types.IsSlice(networks) {
continue
}
if (serverConfig.IsHTTPFamily() && lists.Contains(networks, "http")) ||
(serverConfig.IsTCPFamily() && lists.Contains(networks, "tcp")) ||
(serverConfig.IsUDPFamily() && lists.Contains(networks, "udp")) {
schedulingTypes = append(schedulingTypes, m)
}
}
this.Data["schedulingTypes"] = schedulingTypes
this.Show()
}
func (this *UpdateSchedulingPopupAction) RunPost(params struct {
ServerId int64
ReverseProxyId int64
Type string
HashKey string
StickyType string
StickyParam string
Must *actions.Must
}) {
defer this.CreateLogInfo(codes.ReverseProxy_LogUpdateReverseProxyScheduling, params.ReverseProxyId)
reverseProxyResp, err := this.RPC().ReverseProxyRPC().FindEnabledReverseProxyConfig(this.UserContext(), &pb.FindEnabledReverseProxyConfigRequest{ReverseProxyId: params.ReverseProxyId})
if err != nil {
this.ErrorPage(err)
return
}
configData := reverseProxyResp.ReverseProxyJSON
reverseProxy := &serverconfigs.ReverseProxyConfig{}
err = json.Unmarshal(configData, reverseProxy)
if err != nil {
this.ErrorPage(err)
return
}
if reverseProxy.Scheduling == nil {
reverseProxy.FindSchedulingConfig()
}
options := maps.Map{}
if params.Type == "hash" {
params.Must.
Field("hashKey", params.HashKey).
Require("请输入Key")
options["key"] = params.HashKey
} else if params.Type == "sticky" {
params.Must.
Field("stickyType", params.StickyType).
Require("请选择参数类型").
Field("stickyParam", params.StickyParam).
Require("请输入参数名").
Match("^[a-zA-Z0-9]+$", "参数名只能是英文字母和数字的组合").
MaxCharacters(50, "参数名长度不能超过50位")
options["type"] = params.StickyType
options["param"] = params.StickyParam
}
if schedulingconfigs.FindSchedulingType(params.Type) == nil {
this.Fail("不支持此种算法")
}
reverseProxy.Scheduling.Code = params.Type
reverseProxy.Scheduling.Options = options
schedulingData, err := json.Marshal(reverseProxy.Scheduling)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxyScheduling(this.UserContext(), &pb.UpdateReverseProxySchedulingRequest{
ReverseProxyId: params.ReverseProxyId,
SchedulingJSON: schedulingData,
})
if err != nil {
this.ErrorPage(err)
}
this.Success()
}

View File

@@ -0,0 +1,143 @@
package tcp
import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
// IndexAction TCP设置
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("tcp")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
this.Data["canSpecifyPort"] = this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
tcpConfig := &serverconfigs.TCPProtocolConfig{}
if len(server.TcpJSON) > 0 {
err := json.Unmarshal(server.TcpJSON, tcpConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
tcpConfig.IsOn = true
}
this.Data["serverType"] = server.Type
this.Data["tcpConfig"] = tcpConfig
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ServerId int64
ServerType string
Addresses string
Must *actions.Must
}) {
defer this.CreateLogInfo(codes.ServerTCP_LogUpdateTCPSettings, params.ServerId)
canSpecifyPort := this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
addresses := []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal([]byte(params.Addresses), &addresses)
if err != nil {
this.Fail("端口地址解析失败:" + err.Error())
}
// 检查端口是否被使用
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
if err != nil {
this.ErrorPage(err)
return
}
clusterId := clusterIdResp.NodeClusterId
if clusterId == 0 {
this.Fail("当前用户没有指定集群,不能使用此服务")
}
for _, address := range addresses {
port := types.Int32(address.PortRange)
if port < 1024 || port > 65534 {
this.Fail("'" + address.PortRange + "' 端口范围错误")
}
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: port,
NodeClusterId: clusterId,
ExcludeServerId: params.ServerId,
ExcludeProtocol: "tcp",
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + fmt.Sprintf("%d", port) + "' 正在被别的服务或者同服务其他网络协议使用,请换一个")
}
}
tcpConfig := &serverconfigs.TCPProtocolConfig{}
if len(server.TcpJSON) > 0 {
err := json.Unmarshal(server.TcpJSON, tcpConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
tcpConfig.IsOn = true
}
if canSpecifyPort {
tcpConfig.Listen = addresses
}
configData, err := json.Marshal(tcpConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().ServerRPC().UpdateServerTCP(this.UserContext(), &pb.UpdateServerTCPRequest{
ServerId: params.ServerId,
TcpJSON: configData,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,18 @@
package tcp
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/tcp").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,246 @@
package tls
import (
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
// IndexAction TLS设置
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("tls")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
this.Data["canSpecifyPort"] = this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
tlsConfig := &serverconfigs.TLSProtocolConfig{}
if len(server.TlsJSON) > 0 {
err := json.Unmarshal(server.TlsJSON, tlsConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
tlsConfig.IsOn = true
}
// SSL配置
var sslPolicy *sslconfigs.SSLPolicy
if tlsConfig.SSLPolicyRef != nil && tlsConfig.SSLPolicyRef.SSLPolicyId > 0 {
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.UserContext(), &pb.FindEnabledSSLPolicyConfigRequest{
SslPolicyId: tlsConfig.SSLPolicyRef.SSLPolicyId,
IgnoreData: true,
})
if err != nil {
this.ErrorPage(err)
return
}
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
if len(sslPolicyConfigJSON) > 0 {
sslPolicy = &sslconfigs.SSLPolicy{}
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
if err != nil {
this.ErrorPage(err)
return
}
}
}
this.Data["serverType"] = server.Type
this.Data["tlsConfig"] = maps.Map{
"isOn": tlsConfig.IsOn,
"listen": tlsConfig.Listen,
"sslPolicy": sslPolicy,
}
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ServerId int64
ServerType string
Addresses string
SslPolicyJSON []byte
Must *actions.Must
}) {
defer this.CreateLogInfo(codes.ServerTLS_LogUpdateTLSSettings, params.ServerId)
canSpecifyPort := this.ValidateFeature(userconfigs.UserFeatureCodeServerTCPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
addresses := []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal([]byte(params.Addresses), &addresses)
if err != nil {
this.Fail("端口地址解析失败:" + err.Error())
}
// 检查端口是否被使用
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
if err != nil {
this.ErrorPage(err)
return
}
clusterId := clusterIdResp.NodeClusterId
if clusterId == 0 {
this.Fail("当前用户没有指定集群,不能使用此服务")
}
for _, address := range addresses {
port := types.Int32(address.PortRange)
if port < 1024 || port > 65534 {
this.Fail("'" + address.PortRange + "' 端口范围错误")
}
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: port,
NodeClusterId: clusterId,
ExcludeServerId: params.ServerId,
ExcludeProtocol: "tls",
ProtocolFamily: "tcp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + fmt.Sprintf("%d", port) + "' 正在被别的服务或者同服务其他网络协议使用,请换一个")
}
}
// 校验SSL
var sslPolicyId = int64(0)
if params.SslPolicyJSON != nil {
sslPolicy := &sslconfigs.SSLPolicy{}
err = json.Unmarshal(params.SslPolicyJSON, sslPolicy)
if err != nil {
this.ErrorPage(errors.New("解析SSL配置时发生了错误" + err.Error()))
return
}
sslPolicyId = sslPolicy.Id
certsJSON, err := json.Marshal(sslPolicy.CertRefs)
if err != nil {
this.ErrorPage(err)
return
}
hstsJSON, err := json.Marshal(sslPolicy.HSTS)
if err != nil {
this.ErrorPage(err)
return
}
clientCACertsJSON, err := json.Marshal(sslPolicy.ClientCARefs)
if err != nil {
this.ErrorPage(err)
return
}
if sslPolicyId > 0 {
_, err := this.RPC().SSLPolicyRPC().UpdateSSLPolicy(this.UserContext(), &pb.UpdateSSLPolicyRequest{
SslPolicyId: sslPolicyId,
Http2Enabled: sslPolicy.HTTP2Enabled,
Http3Enabled: sslPolicy.HTTP3Enabled,
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,
CipherSuites: sslPolicy.CipherSuites,
})
if err != nil {
this.ErrorPage(err)
return
}
} else {
resp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.UserContext(), &pb.CreateSSLPolicyRequest{
Http2Enabled: sslPolicy.HTTP2Enabled,
Http3Enabled: sslPolicy.HTTP3Enabled,
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,
CipherSuites: sslPolicy.CipherSuites,
})
if err != nil {
this.ErrorPage(err)
return
}
sslPolicyId = resp.SslPolicyId
}
}
tlsConfig := &serverconfigs.TLSProtocolConfig{}
if len(server.TlsJSON) > 0 {
err := json.Unmarshal(server.TlsJSON, tlsConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
tlsConfig.IsOn = true
}
if canSpecifyPort {
tlsConfig.Listen = addresses
}
tlsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
IsOn: true,
SSLPolicyId: sslPolicyId,
}
configData, err := json.Marshal(tlsConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().ServerRPC().UpdateServerTLS(this.UserContext(), &pb.UpdateServerTLSRequest{
ServerId: params.ServerId,
TlsJSON: configData,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,18 @@
package tls
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/tls").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,144 @@
package udp
import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
)
// IndexAction UDP设置
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("udp")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
this.Data["canSpecifyPort"] = this.ValidateFeature(userconfigs.UserFeatureCodeServerUDPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
udpConfig := &serverconfigs.UDPProtocolConfig{}
if len(server.UdpJSON) > 0 {
err := json.Unmarshal(server.UdpJSON, udpConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
udpConfig.IsOn = true
}
this.Data["serverType"] = server.Type
this.Data["udpConfig"] = udpConfig
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ServerId int64
ServerType string
Addresses string
Must *actions.Must
}) {
defer this.CreateLogInfo(codes.ServerUDP_LogUpdateUDPSettings, params.ServerId)
canSpecifyPort := this.ValidateFeature(userconfigs.UserFeatureCodeServerUDPPort, params.ServerId)
server, err := dao.SharedServerDAO.FindEnabledServer(this.UserContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if server == nil {
this.NotFound("server", params.ServerId)
return
}
addresses := []*serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal([]byte(params.Addresses), &addresses)
if err != nil {
this.Fail("端口地址解析失败:" + err.Error())
}
// 检查端口是否被使用
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
if err != nil {
this.ErrorPage(err)
return
}
clusterId := clusterIdResp.NodeClusterId
if clusterId == 0 {
this.Fail("当前用户没有指定集群,不能使用此服务")
}
for _, address := range addresses {
port := types.Int32(address.PortRange)
if port < 1024 || port > 65534 {
this.Fail("'" + address.PortRange + "' 端口范围错误")
}
resp, err := this.RPC().NodeClusterRPC().CheckPortIsUsingInNodeCluster(this.UserContext(), &pb.CheckPortIsUsingInNodeClusterRequest{
Port: port,
NodeClusterId: clusterId,
ExcludeServerId: params.ServerId,
ProtocolFamily: "udp",
})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IsUsing {
this.Fail("端口 '" + fmt.Sprintf("%d", port) + "' 正在被别的服务或者同服务其他网络协议使用,请换一个")
}
}
udpConfig := &serverconfigs.UDPProtocolConfig{}
if len(server.UdpJSON) > 0 {
err := json.Unmarshal(server.UdpJSON, udpConfig)
if err != nil {
this.ErrorPage(err)
}
} else {
udpConfig.IsOn = true
}
if canSpecifyPort {
udpConfig.Listen = addresses
}
configData, err := json.Marshal(udpConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().ServerRPC().UpdateServerUDP(this.UserContext(), &pb.UpdateServerUDPRequest{
ServerId: params.ServerId,
UdpJSON: configData,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,18 @@
package udp
import (
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/lb/serverutils"
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth("")).
Helper(serverutils.NewServerHelper()).
Prefix("/lb/server/settings/udp").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -0,0 +1,297 @@
package serverutils
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/TeaOSLab/EdgeUser/internal/rpc"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/http"
"strconv"
)
type ServerHelper struct {
}
func NewServerHelper() *ServerHelper {
return &ServerHelper{}
}
func (this *ServerHelper) BeforeAction(action *actions.ActionObject) {
if action.Request.Method != http.MethodGet {
return
}
action.Data["teaMenu"] = "lb"
// 左侧菜单
this.createLeftMenu(action)
}
func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) {
// 初始化
if !action.Data.Has("leftMenuItemIsDisabled") {
action.Data["leftMenuItemIsDisabled"] = false
}
action.Data["leftMenuItems"] = []maps.Map{}
var mainTab = action.Data["mainTab"]
var secondMenuItem = action.Data["secondMenuItem"]
serverId := action.ParamInt64("serverId")
if serverId == 0 {
return
}
serverIdString := strconv.FormatInt(serverId, 10)
action.Data["serverId"] = serverId
// 读取server信息
rpcClient, err := rpc.SharedRPC()
if err != nil {
logs.Error(err)
return
}
userId := action.Context.GetInt64("userId")
ctx := rpcClient.Context(userId)
serverResp, err := rpcClient.ServerRPC().FindEnabledServer(ctx, &pb.FindEnabledServerRequest{
ServerId: serverId,
IgnoreSSLCerts: true,
})
if err != nil {
logs.Error(err)
return
}
server := serverResp.Server
if server == nil {
logs.Error(errors.New("can not find the server"))
return
}
// 服务管理
serverConfig := &serverconfigs.ServerConfig{}
err = json.Unmarshal(server.Config, serverConfig)
if err != nil {
logs.Error(err)
return
}
// 协议簇
var family = ""
if serverConfig.IsHTTPFamily() {
family = "http"
} else if serverConfig.IsTCPFamily() {
family = "tcp"
} else if serverConfig.IsUDPFamily() {
family = "udp"
}
action.Data["serverFamily"] = family
// TABBAR
var selectedTabbar = action.Data["mainTab"]
tabbar := actionutils.NewTabbar()
tabbar.Add("网站列表", "", "/lb", "", false)
//tabbar.Add("看板", "", "/servers/server/board?serverId="+serverIdString, "dashboard", selectedTabbar == "board")
//tabbar.Add("日志", "", "/servers/server/log?serverId="+serverIdString, "history", selectedTabbar == "log")
//tabbar.Add("统计", "", "/servers/server/stat?serverId="+serverIdString, "chart area", selectedTabbar == "stat")
tabbar.Add("设置", "", "/lb/server?serverId="+serverIdString, "setting", selectedTabbar == "setting")
//tabbar.Add("删除", "", "/servers/server/delete?serverId="+serverIdString, "trash", selectedTabbar == "delete")
actionutils.SetTabbar(action, tabbar)
// 左侧操作子菜单
switch types.String(mainTab) {
case "board":
action.Data["leftMenuItems"] = this.createBoardMenu(types.String(secondMenuItem), serverIdString, serverConfig)
case "log":
action.Data["leftMenuItems"] = this.createLogMenu(types.String(secondMenuItem), serverIdString, serverConfig)
case "stat":
action.Data["leftMenuItems"] = this.createStatMenu(types.String(secondMenuItem), serverIdString, serverConfig)
case "setting":
action.Data["leftMenuItems"] = this.createSettingsMenu(action, types.String(secondMenuItem), serverIdString, serverConfig)
case "delete":
action.Data["leftMenuItems"] = this.createDeleteMenu(action, types.String(secondMenuItem), serverIdString, serverConfig)
}
}
// 看板菜单
func (this *ServerHelper) createBoardMenu(secondMenuItem string, serverIdString string, serverConfig *serverconfigs.ServerConfig) []maps.Map {
menuItems := []maps.Map{}
menuItems = append(menuItems, maps.Map{
"name": "看板",
"url": "/servers/server/board?serverId=" + serverIdString,
"isActive": secondMenuItem == "index",
})
return menuItems
}
// 日志菜单
func (this *ServerHelper) createLogMenu(secondMenuItem string, serverIdString string, serverConfig *serverconfigs.ServerConfig) []maps.Map {
menuItems := []maps.Map{}
menuItems = append(menuItems, maps.Map{
"name": "实时",
"url": "/servers/server/log?serverId=" + serverIdString,
"isActive": secondMenuItem == "index",
})
menuItems = append(menuItems, maps.Map{
"name": "今天",
"url": "/servers/server/log/today?serverId=" + serverIdString,
"isActive": secondMenuItem == "today",
})
menuItems = append(menuItems, maps.Map{
"name": "历史",
"url": "/servers/server/log/history?serverId=" + serverIdString,
"isActive": secondMenuItem == "history",
})
return menuItems
}
// 统计菜单
func (this *ServerHelper) createStatMenu(secondMenuItem string, serverIdString string, serverConfig *serverconfigs.ServerConfig) []maps.Map {
menuItems := []maps.Map{}
menuItems = append(menuItems, maps.Map{
"name": "统计",
"url": "/servers/server/stat?serverId=" + serverIdString,
"isActive": secondMenuItem == "index",
})
return menuItems
}
// 设置菜单
func (this *ServerHelper) createSettingsMenu(action *actions.ActionObject, secondMenuItem string, serverIdString string, serverConfig *serverconfigs.ServerConfig) (items []maps.Map) {
menuItems := []maps.Map{
{
"name": "基本信息",
"url": "/lb/server/settings/basic?serverId=" + serverIdString,
"isActive": secondMenuItem == "basic",
"isOff": !serverConfig.IsOn,
},
{
"name": "DNS",
"url": "/lb/server/settings/dns?serverId=" + serverIdString,
"isActive": secondMenuItem == "dns",
},
}
// 是否有权限使用套餐
rpcClient, err := rpc.SharedRPC()
var supportPlan = false
if err == nil {
userId := action.Context.GetInt64("userId")
ctx := rpcClient.Context(userId)
userFeatureResp, err := rpcClient.UserRPC().FindUserFeatures(ctx, &pb.FindUserFeaturesRequest{UserId: userId})
if err == nil {
userFeatureCodes := []string{}
for _, feature := range userFeatureResp.Features {
userFeatureCodes = append(userFeatureCodes, feature.Code)
}
supportPlan = lists.ContainsString(userFeatureCodes, userconfigs.UserFeatureCodePlan)
}
}
if serverConfig.IsTCPFamily() {
menuItems = append(menuItems, maps.Map{
"name": "TCP",
"url": "/lb/server/settings/tcp?serverId=" + serverIdString,
"isActive": secondMenuItem == "tcp",
"isOn": serverConfig.TCP != nil && serverConfig.TCP.IsOn && len(serverConfig.TCP.Listen) > 0,
})
menuItems = append(menuItems, maps.Map{
"name": "TLS",
"url": "/lb/server/settings/tls?serverId=" + serverIdString,
"isActive": secondMenuItem == "tls",
"isOn": serverConfig.TLS != nil && serverConfig.TLS.IsOn && len(serverConfig.TLS.Listen) > 0,
})
if supportPlan {
var planName = ""
if serverConfig.UserPlan != nil && serverConfig.UserPlan.PlanId > 0 {
planName = this.findPlanName(serverConfig.UserPlan.PlanId)
}
menuItems = append(menuItems, maps.Map{
"name": "套餐",
"subName": planName,
"url": "/lb/server/settings/plan?serverId=" + serverIdString,
"isActive": secondMenuItem == "plan",
"isOn": serverConfig.UserPlan != nil && serverConfig.UserPlan.IsAvailable(),
})
}
menuItems = append(menuItems, maps.Map{
"name": "源站",
"url": "/lb/server/settings/reverseProxy?serverId=" + serverIdString,
"isActive": secondMenuItem == "reverseProxy",
"isOn": serverConfig.ReverseProxyRef != nil && serverConfig.ReverseProxyRef.IsOn,
})
} else if serverConfig.IsUDPFamily() {
menuItems = append(menuItems, maps.Map{
"name": "UDP",
"url": "/lb/server/settings/udp?serverId=" + serverIdString,
"isActive": secondMenuItem == "udp",
"isOn": serverConfig.UDP != nil && serverConfig.UDP.IsOn && len(serverConfig.UDP.Listen) > 0,
})
if supportPlan {
var planName = ""
if serverConfig.UserPlan != nil && serverConfig.UserPlan.PlanId > 0 {
planName = this.findPlanName(serverConfig.UserPlan.PlanId)
}
menuItems = append(menuItems, maps.Map{
"name": "套餐",
"subName": planName,
"url": "/lb/server/settings/plan?serverId=" + serverIdString,
"isActive": secondMenuItem == "plan",
"isOn": serverConfig.UserPlan != nil && serverConfig.UserPlan.IsAvailable(),
})
}
menuItems = append(menuItems, maps.Map{
"name": "源站",
"url": "/lb/server/settings/reverseProxy?serverId=" + serverIdString,
"isActive": secondMenuItem == "reverseProxy",
"isOn": serverConfig.ReverseProxyRef != nil && serverConfig.ReverseProxyRef.IsOn,
})
}
return menuItems
}
// 删除菜单
func (this *ServerHelper) createDeleteMenu(action *actions.ActionObject, secondMenuItem string, serverIdString string, serverConfig *serverconfigs.ServerConfig) []maps.Map {
var menuItems = []maps.Map{}
menuItems = append(menuItems, maps.Map{
"name": "删除",
"url": "/servers/server/delete?serverId=" + serverIdString,
"isActive": secondMenuItem == "index",
})
return menuItems
}
// 查找套餐名称
func (this *ServerHelper) findPlanName(planId int64) string {
if planId <= 0 {
return ""
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
logs.Error(err)
return ""
}
planResp, err := rpcClient.PlanRPC().FindBasicPlan(rpcClient.Context(0), &pb.FindBasicPlanRequest{PlanId: planId})
if err != nil {
logs.Error(err)
return ""
}
if planResp.Plan == nil {
return ""
}
return planResp.Plan.Name
}

View File

@@ -0,0 +1,33 @@
package lb
import (
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
)
type UpdateOnAction struct {
actionutils.ParentAction
}
func (this *UpdateOnAction) RunPost(params struct {
ServerId int64
IsOn bool
}) {
if params.IsOn {
defer this.CreateLogInfo(codes.Server_LogEnableServer, params.ServerId)
} else {
defer this.CreateLogInfo(codes.Server_LogDisableServer, params.ServerId)
}
_, err := this.RPC().ServerRPC().UpdateServerIsOn(this.UserContext(), &pb.UpdateServerIsOnRequest{
ServerId: params.ServerId,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}