1.4.5.2
This commit is contained in:
589
EdgeUser/internal/web/actions/default/servers/create.go
Normal file
589
EdgeUser/internal/web/actions/default/servers/create.go
Normal file
@@ -0,0 +1,589 @@
|
||||
package servers
|
||||
|
||||
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/ossconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateAction) Init() {
|
||||
this.Nav("", "", "create")
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunGet(params struct{}) {
|
||||
// 检查用户状态
|
||||
this.CheckUserStatus()
|
||||
|
||||
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["clusterId"] = clusterIdResp.NodeClusterId
|
||||
|
||||
// 套餐
|
||||
userPlansResp, err := this.RPC().UserPlanRPC().FindAllEnabledUserPlansForServer(this.UserContext(), &pb.FindAllEnabledUserPlansForServerRequest{
|
||||
UserId: this.UserId(),
|
||||
ServerId: 0,
|
||||
})
|
||||
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,
|
||||
})
|
||||
}
|
||||
this.Data["userPlans"] = userPlanMaps
|
||||
|
||||
// 是否必须使用套餐
|
||||
this.Data["requirePlan"] = false
|
||||
userServerConfig, err := configloaders.LoadServerConfig()
|
||||
if err == nil && userServerConfig.RequirePlan {
|
||||
this.Data["requirePlan"] = true
|
||||
}
|
||||
|
||||
// OSS
|
||||
this.Data["ossTypes"] = ossconfigs.FindAllOSSTypes()
|
||||
this.Data["ossBucketParams"] = ossconfigs.FindAllOSSBucketParamDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
ServerNames []byte
|
||||
Protocols []string
|
||||
CertIdsJSON []byte
|
||||
OriginsJSON []byte
|
||||
RequestHostType int32
|
||||
RequestHost string
|
||||
CacheCondsJSON []byte
|
||||
|
||||
GroupIds []int64
|
||||
UserPlanId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 检查用户所在集群
|
||||
clusterIdResp, err := this.RPC().UserRPC().FindUserNodeClusterId(this.UserContext(), &pb.FindUserNodeClusterIdRequest{UserId: this.UserId()})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var clusterId = clusterIdResp.NodeClusterId
|
||||
|
||||
if len(params.ServerNames) == 0 {
|
||||
this.Data["requireServerNames"] = true
|
||||
this.Fail("请添加要加速的域名")
|
||||
}
|
||||
|
||||
var serverNames = []*serverconfigs.ServerNameConfig{}
|
||||
err = json.Unmarshal(params.ServerNames, &serverNames)
|
||||
if err != nil {
|
||||
this.Fail("域名参数解析错误:" + err.Error())
|
||||
}
|
||||
serverconfigs.NormalizeServerNames(serverNames)
|
||||
|
||||
var allDomainNames = serverconfigs.PlainServerNames(serverNames)
|
||||
if len(allDomainNames) == 0 {
|
||||
this.Data["requireServerNames"] = true
|
||||
this.Fail("请添加要加速的域名")
|
||||
}
|
||||
|
||||
for _, domainName := range allDomainNames {
|
||||
if !domainutils.ValidateDomainFormat(strings.ReplaceAll(domainName, "*.", "") /** 支持泛域名 **/) {
|
||||
this.Fail("域名'" + domainName + "'输入错误")
|
||||
}
|
||||
}
|
||||
|
||||
// 检查域名是否已经存在
|
||||
dupResp, err := this.RPC().ServerRPC().CheckServerNameDuplicationInNodeCluster(this.UserContext(), &pb.CheckServerNameDuplicationInNodeClusterRequest{
|
||||
ServerNames: allDomainNames,
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(dupResp.DuplicatedServerNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(dupResp.DuplicatedServerNames, ", ") + " 已经被其他网站所占用,不能重复使用")
|
||||
}
|
||||
|
||||
serverNamesJSON, err := json.Marshal(serverNames)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 协议
|
||||
if len(params.Protocols) == 0 {
|
||||
this.Fail("请选择至少一个域名协议")
|
||||
}
|
||||
|
||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
|
||||
// HTTP
|
||||
if lists.ContainsString(params.Protocols, "http") {
|
||||
httpConfig.IsOn = true
|
||||
httpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTP,
|
||||
Host: "",
|
||||
PortRange: "80",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPS
|
||||
if lists.ContainsString(params.Protocols, "https") {
|
||||
httpsConfig.IsOn = true
|
||||
httpsConfig.Listen = []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTPS,
|
||||
Host: "",
|
||||
PortRange: "443",
|
||||
},
|
||||
}
|
||||
|
||||
if len(params.CertIdsJSON) == 0 {
|
||||
this.Fail("请选择或者上传HTTPS证书")
|
||||
}
|
||||
certIds := []int64{}
|
||||
err := json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(certIds) == 0 {
|
||||
this.Fail("请选择或者上传HTTPS证书")
|
||||
}
|
||||
|
||||
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,
|
||||
OcspIsOn: false,
|
||||
ClientAuthType: 0,
|
||||
ClientCACertsJSON: nil,
|
||||
CipherSuites: nil,
|
||||
CipherSuitesIsOn: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
|
||||
IsOn: true,
|
||||
SSLPolicyId: sslPolicyIdResp.SslPolicyId,
|
||||
}
|
||||
}
|
||||
|
||||
// 源站信息
|
||||
var 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("请输入源站信息")
|
||||
}
|
||||
var primaryOriginRefs = []*serverconfigs.OriginRef{}
|
||||
var backupOriginRefs = []*serverconfigs.OriginRef{}
|
||||
|
||||
var hasOSS = false
|
||||
|
||||
for _, originMap := range originMaps {
|
||||
var host = originMap.GetString("host")
|
||||
var isPrimary = originMap.GetBool("isPrimary")
|
||||
var scheme = originMap.GetString("scheme")
|
||||
|
||||
if ossconfigs.IsOSSProtocol(scheme) {
|
||||
hasOSS = true
|
||||
continue
|
||||
}
|
||||
|
||||
if len(host) == 0 {
|
||||
this.Fail("源站地址不能为空")
|
||||
}
|
||||
if strings.Index(host, ":") > 0 {
|
||||
_, _, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
this.Fail("源站地址'" + host + "'格式错误")
|
||||
}
|
||||
} else if !domainutils.ValidateDomainFormat(host) {
|
||||
this.Fail("源站地址'" + host + "'格式错误")
|
||||
}
|
||||
|
||||
if scheme != "http" && scheme != "https" {
|
||||
this.Fail("错误的源站协议")
|
||||
}
|
||||
|
||||
addrHost, addrPort, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
addrHost = host
|
||||
if scheme == "http" {
|
||||
addrPort = "80"
|
||||
} else if scheme == "https" {
|
||||
addrPort = "443"
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
var 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
|
||||
}
|
||||
var reverseProxyId = reverseProxyResp.ReverseProxyId
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{
|
||||
IsPrior: false,
|
||||
IsOn: true,
|
||||
ReverseProxyId: reverseProxyId,
|
||||
}
|
||||
reverseProxyRefJSON, err := json.Marshal(reverseProxyRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if params.RequestHostType > 0 {
|
||||
_, err = this.RPC().ReverseProxyRPC().UpdateReverseProxy(this.UserContext(), &pb.UpdateReverseProxyRequest{
|
||||
ReverseProxyId: reverseProxyId,
|
||||
RequestHostType: params.RequestHostType,
|
||||
RequestHost: params.RequestHost,
|
||||
RequestURI: "",
|
||||
StripPrefix: "",
|
||||
AutoFlush: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存设置
|
||||
var cacheCondMaps = []maps.Map{}
|
||||
if len(params.CacheCondsJSON) > 0 {
|
||||
err = json.Unmarshal(params.CacheCondsJSON, &cacheCondMaps)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var cacheRefs = []*serverconfigs.HTTPCacheRef{}
|
||||
if len(cacheCondMaps) > 0 {
|
||||
for _, condMap := range cacheCondMaps {
|
||||
var durationMap = condMap.GetMap("duration")
|
||||
if durationMap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var duration = &shared.TimeDuration{
|
||||
Count: durationMap.GetInt64("count"),
|
||||
Unit: durationMap.GetString("unit"),
|
||||
}
|
||||
|
||||
var value string
|
||||
var param string
|
||||
var operator string
|
||||
var condType = condMap.GetString("type")
|
||||
switch condType {
|
||||
case "url-extension":
|
||||
param = "${requestPathExtension}"
|
||||
operator = shared.RequestCondOperatorIn
|
||||
result := []string{}
|
||||
v := condMap.GetString("value")
|
||||
if len(v) > 0 {
|
||||
err = json.Unmarshal([]byte(v), &result)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
value = v
|
||||
}
|
||||
case "url-prefix":
|
||||
param = "${requestPath}"
|
||||
operator = shared.RequestCondOperatorHasPrefix
|
||||
value = condMap.GetString("value")
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
var conds = &shared.HTTPRequestCondsConfig{
|
||||
IsOn: true,
|
||||
Connector: "or",
|
||||
Groups: []*shared.HTTPRequestCondGroup{
|
||||
{
|
||||
IsOn: true,
|
||||
Connector: "or",
|
||||
Conds: []*shared.HTTPRequestCond{
|
||||
{
|
||||
IsRequest: true,
|
||||
Type: condType,
|
||||
Param: param,
|
||||
Operator: operator,
|
||||
Value: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var cacheRef = &serverconfigs.HTTPCacheRef{
|
||||
IsOn: true,
|
||||
CachePolicyId: 0,
|
||||
Key: "${scheme}://${host}${requestURI}",
|
||||
Life: duration,
|
||||
Status: []int{200},
|
||||
MaxSize: &shared.SizeCapacity{
|
||||
Count: 128,
|
||||
Unit: shared.SizeCapacityUnitMB,
|
||||
},
|
||||
SkipResponseCacheControlValues: nil,
|
||||
SkipResponseSetCookie: true,
|
||||
EnableRequestCachePragma: false,
|
||||
Conds: conds,
|
||||
CachePolicy: nil,
|
||||
AllowChunkedEncoding: true,
|
||||
AllowPartialContent: false,
|
||||
}
|
||||
cacheRefs = append(cacheRefs, cacheRef)
|
||||
}
|
||||
}
|
||||
|
||||
var cacheConfig = &serverconfigs.HTTPCacheConfig{
|
||||
IsPrior: false,
|
||||
IsOn: true,
|
||||
CacheRefs: cacheRefs,
|
||||
AddStatusHeader: true,
|
||||
}
|
||||
cacheConfigJSON, err := cacheConfig.AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否必须使用套餐
|
||||
userServerConfig, err := configloaders.LoadServerConfig()
|
||||
if err == nil {
|
||||
if params.UserPlanId <= 0 && userServerConfig.RequirePlan {
|
||||
this.Fail("请选择套餐")
|
||||
}
|
||||
}
|
||||
|
||||
// 检查套餐
|
||||
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.UserId != this.UserId() {
|
||||
this.Fail("找不到要使用的套餐")
|
||||
}
|
||||
}
|
||||
|
||||
// 开始保存
|
||||
httpJSON, err := httpConfig.AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
httpsJSON, err := httpsConfig.AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ServerRPC().CreateServer(this.UserContext(), &pb.CreateServerRequest{
|
||||
UserId: this.UserId(),
|
||||
AdminId: 0,
|
||||
Type: serverconfigs.ServerTypeHTTPProxy,
|
||||
Name: serverNames[0].Name,
|
||||
Description: "",
|
||||
ServerNamesJSON: serverNamesJSON,
|
||||
HttpJSON: httpJSON,
|
||||
HttpsJSON: httpsJSON,
|
||||
TcpJSON: nil,
|
||||
TlsJSON: nil,
|
||||
UdpJSON: nil,
|
||||
WebId: 0,
|
||||
ReverseProxyJSON: reverseProxyRefJSON,
|
||||
ServerGroupIds: params.GroupIds,
|
||||
NodeClusterId: clusterId,
|
||||
IncludeNodesJSON: nil,
|
||||
ExcludeNodesJSON: nil,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var serverId = createResp.ServerId
|
||||
|
||||
defer this.CreateLogInfo(codes.Server_LogCreateServer, serverId)
|
||||
|
||||
// 保存缓存设置
|
||||
webIdResp, err := this.RPC().HTTPWebRPC().CreateHTTPWeb(this.UserContext(), &pb.CreateHTTPWebRequest{RootJSON: nil})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var webId = webIdResp.HttpWebId
|
||||
_, err = this.RPC().ServerRPC().UpdateServerWeb(this.UserContext(), &pb.UpdateServerWebRequest{
|
||||
ServerId: serverId,
|
||||
WebId: webId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebCache(this.UserContext(), &pb.UpdateHTTPWebCacheRequest{
|
||||
HttpWebId: webId,
|
||||
CacheJSON: cacheConfigJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 统计
|
||||
if userServerConfig != nil && userServerConfig.EnableStat {
|
||||
var statConfig = &serverconfigs.HTTPStatRef{
|
||||
IsPrior: false,
|
||||
IsOn: true,
|
||||
}
|
||||
statJSON, err := json.Marshal(statConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebStat(this.UserContext(), &pb.UpdateHTTPWebStatRequest{
|
||||
HttpWebId: webId,
|
||||
StatJSON: statJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定套餐
|
||||
_, err = this.RPC().ServerRPC().UpdateServerUserPlan(this.UserContext(), &pb.UpdateServerUserPlanRequest{
|
||||
ServerId: serverId,
|
||||
UserPlanId: params.UserPlanId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["serverId"] = serverId
|
||||
this.Data["hasOSS"] = hasOSS
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Reference in New Issue
Block a user