initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"helix-proxy/internal/models"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDuplicateProxySource = errors.New("duplicate proxy host source domain")
|
||||
ErrDuplicateRedirectionSource = errors.New("duplicate redirection host source domain")
|
||||
ErrDuplicateDeadSource = errors.New("duplicate dead host source domain")
|
||||
ErrDuplicateStreamPort = errors.New("duplicate stream incoming port")
|
||||
)
|
||||
|
||||
func IsConflictError(err error) bool {
|
||||
return errors.Is(err, ErrDuplicateProxySource) ||
|
||||
errors.Is(err, ErrDuplicateRedirectionSource) ||
|
||||
errors.Is(err, ErrDuplicateDeadSource) ||
|
||||
errors.Is(err, ErrDuplicateStreamPort)
|
||||
}
|
||||
|
||||
type domainRecord struct {
|
||||
ID int
|
||||
DomainNames []string
|
||||
}
|
||||
|
||||
func normalizeSourceDomain(d string) (normalized, display string, ok bool) {
|
||||
display = strings.TrimSpace(d)
|
||||
if display == "" {
|
||||
return "", "", false
|
||||
}
|
||||
return strings.ToLower(display), display, true
|
||||
}
|
||||
|
||||
func validateUniqueDomains(domainNames []string, selfID int, existing []domainRecord, errSentinel error) error {
|
||||
own := make(map[string]string)
|
||||
for _, d := range domainNames {
|
||||
norm, display, ok := normalizeSourceDomain(d)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if prev, dup := own[norm]; dup {
|
||||
return fmt.Errorf("%w: duplicate source domain: %s", errSentinel, prev)
|
||||
}
|
||||
own[norm] = display
|
||||
}
|
||||
|
||||
used := make(map[string]struct{})
|
||||
for _, rec := range existing {
|
||||
if rec.ID == selfID {
|
||||
continue
|
||||
}
|
||||
for _, d := range rec.DomainNames {
|
||||
norm, _, ok := normalizeSourceDomain(d)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
used[norm] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for norm, display := range own {
|
||||
if _, conflict := used[norm]; conflict {
|
||||
return fmt.Errorf("%w: source domain already in use: %s", errSentinel, display)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateProxyHostSources(hosts []models.ProxyHost, h models.ProxyHost) error {
|
||||
existing := make([]domainRecord, len(hosts))
|
||||
for i, host := range hosts {
|
||||
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
|
||||
}
|
||||
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateProxySource)
|
||||
}
|
||||
|
||||
func validateRedirectionHostSources(hosts []models.RedirectionHost, h models.RedirectionHost) error {
|
||||
existing := make([]domainRecord, len(hosts))
|
||||
for i, host := range hosts {
|
||||
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
|
||||
}
|
||||
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateRedirectionSource)
|
||||
}
|
||||
|
||||
func validateDeadHostSources(hosts []models.DeadHost, h models.DeadHost) error {
|
||||
existing := make([]domainRecord, len(hosts))
|
||||
for i, host := range hosts {
|
||||
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
|
||||
}
|
||||
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateDeadSource)
|
||||
}
|
||||
|
||||
func validateStreamIncomingPort(st models.Stream, streams []models.Stream) error {
|
||||
if st.IncomingPort <= 0 {
|
||||
return nil
|
||||
}
|
||||
for _, other := range streams {
|
||||
if other.ID == st.ID {
|
||||
continue
|
||||
}
|
||||
if other.IncomingPort == st.IncomingPort {
|
||||
return fmt.Errorf("%w: incoming port already in use: %d", ErrDuplicateStreamPort, st.IncomingPort)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user