mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-30 22:26:38 +08:00
178 lines
5.9 KiB
Go
178 lines
5.9 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package proxy_route provides helpers for building proxy route configurations.
|
|
package proxy_route
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/model"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type proxyRouteJSONFields struct {
|
|
cacheRulesJSON string
|
|
upstreamsJSON string
|
|
customHeadersJSON string
|
|
}
|
|
|
|
func resolveProxyRouteUpstreams(ctx context.Context, upstreamType string, input Input) (string, *uint, []string, error) {
|
|
switch upstreamType {
|
|
case proxyRouteUpstreamTypeTunnel, proxyRouteUpstreamTypePages:
|
|
if upstreamType == proxyRouteUpstreamTypePages {
|
|
if err := validatePagesRouteInput(ctx, input.PagesProjectID); err != nil {
|
|
return "", nil, nil, err
|
|
}
|
|
}
|
|
originURL := "http://127.0.0.1"
|
|
return originURL, nil, []string{originURL}, nil
|
|
default:
|
|
originURL, originID, err := resolveProxyRoutePrimaryOrigin(ctx, input)
|
|
if err != nil {
|
|
return "", nil, nil, err
|
|
}
|
|
upstreams, err := normalizeUpstreams(originURL, input.Upstreams)
|
|
if err != nil {
|
|
return "", nil, nil, err
|
|
}
|
|
return originURL, originID, upstreams, nil
|
|
}
|
|
}
|
|
|
|
func marshalProxyRouteJSONFields(
|
|
upstreams []string,
|
|
cacheRules []string,
|
|
customHeaders []CustomHeaderInput,
|
|
) (*proxyRouteJSONFields, error) {
|
|
cacheRulesJSON, err := json.Marshal(cacheRules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
upstreamsJSON, err := json.Marshal(upstreams)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
customHeadersJSON, err := json.Marshal(customHeaders)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &proxyRouteJSONFields{
|
|
cacheRulesJSON: string(cacheRulesJSON),
|
|
upstreamsJSON: string(upstreamsJSON),
|
|
customHeadersJSON: string(customHeadersJSON),
|
|
}, nil
|
|
}
|
|
|
|
func normalizeProxyRouteBasicAuth(input *Input) error {
|
|
if !input.BasicAuthEnabled {
|
|
input.BasicAuthUsername = ""
|
|
input.BasicAuthPassword = ""
|
|
return nil
|
|
}
|
|
input.BasicAuthUsername = strings.TrimSpace(input.BasicAuthUsername)
|
|
input.BasicAuthPassword = strings.TrimSpace(input.BasicAuthPassword)
|
|
if input.BasicAuthUsername == "" || input.BasicAuthPassword == "" {
|
|
return errors.New(errProxyRouteBasicAuth)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func populateProxyRouteFields(
|
|
route *model.ProxyRoute,
|
|
input Input,
|
|
siteName string,
|
|
jsonFields *proxyRouteJSONFields,
|
|
originID *uint,
|
|
upstreams []string,
|
|
originHost, cachePolicy string,
|
|
limitConnPerServer, limitConnPerIP int,
|
|
limitRate, upstreamType string,
|
|
) {
|
|
route.SiteName = siteName
|
|
route.OriginID = originID
|
|
route.OriginURL = upstreams[0]
|
|
route.OriginHost = originHost
|
|
route.Upstreams = jsonFields.upstreamsJSON
|
|
route.Enabled = input.Enabled
|
|
route.EnableHTTPS = input.EnableHTTPS
|
|
route.RedirectHTTP = input.RedirectHTTP
|
|
route.LimitConnPerServer = limitConnPerServer
|
|
route.LimitConnPerIP = limitConnPerIP
|
|
route.LimitRate = limitRate
|
|
route.CacheEnabled = input.CacheEnabled
|
|
route.CachePolicy = normalizeCachePolicy(input.CacheEnabled, cachePolicy)
|
|
route.CacheRules = jsonFields.cacheRulesJSON
|
|
route.CustomHeaders = jsonFields.customHeadersJSON
|
|
route.BasicAuthEnabled = input.BasicAuthEnabled
|
|
route.BasicAuthUsername = input.BasicAuthUsername
|
|
route.BasicAuthPassword = input.BasicAuthPassword
|
|
route.UpstreamType = upstreamType
|
|
}
|
|
|
|
func applyProxyRouteUpstreamType(ctx context.Context, route *model.ProxyRoute, upstreamType string, input Input) error {
|
|
switch upstreamType {
|
|
case proxyRouteUpstreamTypeTunnel:
|
|
tunnelNodeID, err := normalizeTunnelNodeID(input.TunnelNodeID, input.TunnelID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := validateTunnelRouteInput(ctx, tunnelNodeID, input.TunnelTargetAddr, input.TunnelTargetProtocol); err != nil {
|
|
return err
|
|
}
|
|
route.TunnelNodeID = tunnelNodeID
|
|
route.TunnelTargetAddr = strings.TrimSpace(input.TunnelTargetAddr)
|
|
route.TunnelTargetProtocol = normalizeTunnelTargetProtocol(input.TunnelTargetProtocol)
|
|
route.PagesProjectID = nil
|
|
case proxyRouteUpstreamTypePages:
|
|
route.TunnelNodeID = nil
|
|
route.TunnelTargetAddr = ""
|
|
route.TunnelTargetProtocol = ""
|
|
route.PagesProjectID = input.PagesProjectID
|
|
default:
|
|
route.TunnelNodeID = nil
|
|
route.TunnelTargetAddr = ""
|
|
route.TunnelTargetProtocol = ""
|
|
route.PagesProjectID = nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func updateProxyRouteRecord(tx *gorm.DB, route *model.ProxyRoute) error {
|
|
return tx.Model(&model.ProxyRoute{}).Where("id = ?", route.ID).Updates(map[string]any{
|
|
"site_name": route.SiteName, "origin_id": route.OriginID, "origin_url": route.OriginURL,
|
|
"origin_host": route.OriginHost, "upstreams": route.Upstreams, "enabled": route.Enabled,
|
|
"enable_https": route.EnableHTTPS, "redirect_http": route.RedirectHTTP,
|
|
"limit_conn_per_server": route.LimitConnPerServer, "limit_conn_per_ip": route.LimitConnPerIP,
|
|
"limit_rate": route.LimitRate, "cache_enabled": route.CacheEnabled, "cache_policy": route.CachePolicy,
|
|
"cache_rules": route.CacheRules, "custom_headers": route.CustomHeaders,
|
|
"basic_auth_enabled": route.BasicAuthEnabled, "basic_auth_username": route.BasicAuthUsername,
|
|
"basic_auth_password": route.BasicAuthPassword,
|
|
"upstream_type": route.UpstreamType, "tunnel_node_id": route.TunnelNodeID,
|
|
"tunnel_target_addr": route.TunnelTargetAddr, "tunnel_target_protocol": route.TunnelTargetProtocol,
|
|
"pages_project_id": route.PagesProjectID,
|
|
}).Error
|
|
}
|
|
|
|
func replaceZoneDomainRouteBindings(tx *gorm.DB, routeID uint, domainIDs []uint) error {
|
|
var requested []model.ZoneDomain
|
|
if err := tx.Where("id IN ?", domainIDs).Find(&requested).Error; err != nil {
|
|
return err
|
|
}
|
|
if len(requested) != len(domainIDs) {
|
|
return errors.New(errProxyRouteZoneDomainNotFound)
|
|
}
|
|
for _, domain := range requested {
|
|
if domain.ProxyRouteID != nil && *domain.ProxyRouteID != routeID {
|
|
return errors.New(errProxyRouteZoneDomainBound)
|
|
}
|
|
}
|
|
if err := tx.Model(&model.ZoneDomain{}).Where("proxy_route_id = ? AND id NOT IN ?", routeID, domainIDs).Update("proxy_route_id", nil).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Model(&model.ZoneDomain{}).Where("id IN ?", domainIDs).Update("proxy_route_id", routeID).Error
|
|
}
|