Simlify splitting string into non-empty entries.

This commit is contained in:
Joachim Bauch 2025-08-14 15:22:40 +02:00
commit 210aec62db
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
14 changed files with 51 additions and 89 deletions

View file

@ -83,15 +83,12 @@ func parseIPNet(s string) (*net.IPNet, error) {
func ParseAllowedIps(allowed string) (*AllowedIps, error) {
var allowedIps []*net.IPNet
for ip := range strings.SplitSeq(allowed, ",") {
ip = strings.TrimSpace(ip)
if ip != "" {
i, err := parseIPNet(ip)
if err != nil {
return nil, err
}
allowedIps = append(allowedIps, i)
for ip := range SplitEntries(allowed, ",") {
i, err := parseIPNet(ip)
if err != nil {
return nil, err
}
allowedIps = append(allowedIps, i)
}
result := &AllowedIps{

View file

@ -37,6 +37,7 @@ import (
"net/url"
"reflect"
"regexp"
"slices"
"strings"
"sync"
"sync/atomic"
@ -83,14 +84,7 @@ func NewBackendServer(config *goconf.ConfigFile, hub *Hub, version string) (*Bac
// TODO(jojo): Make the validity for TURN credentials configurable.
turnvalid := 24 * time.Hour
var turnserverslist []string
for s := range strings.SplitSeq(turnservers, ",") {
s = strings.TrimSpace(s)
if s != "" {
turnserverslist = append(turnserverslist, s)
}
}
turnserverslist := slices.Collect(SplitEntries(turnservers, ","))
if len(turnserverslist) != 0 {
if turnapikey == "" {
return nil, fmt.Errorf("need a TURN API key if TURN servers are configured")

View file

@ -88,15 +88,15 @@ func NewBackendStorageStatic(config *goconf.ConfigFile) (BackendStorage, error)
} else if allowedUrls, _ := config.GetString("backend", "allowed"); allowedUrls != "" {
// Old-style configuration, only hosts are configured and are using a common secret.
allowMap := make(map[string]bool)
for u := range strings.SplitSeq(allowedUrls, ",") {
u = strings.TrimSpace(u)
for u := range SplitEntries(allowedUrls, ",") {
if idx := strings.IndexByte(u, '/'); idx != -1 {
log.Printf("WARNING: Removing path from allowed hostname \"%s\", check your configuration!", u)
u = u[:idx]
}
if u != "" {
allowMap[strings.ToLower(u)] = true
if u = u[:idx]; u == "" {
continue
}
}
allowMap[strings.ToLower(u)] = true
}
if len(allowMap) == 0 {
@ -265,15 +265,11 @@ func (s *backendStorageStatic) UpsertHost(host string, backends []*Backend, seen
func getConfiguredBackendIDs(backendIds string) (ids []string) {
seen := make(map[string]bool)
for id := range strings.SplitSeq(backendIds, ",") {
id = strings.TrimSpace(id)
if id == "" {
continue
}
for id := range SplitEntries(backendIds, ",") {
if seen[id] {
continue
}
ids = append(ids, id)
seen[id] = true
}
@ -281,16 +277,6 @@ func getConfiguredBackendIDs(backendIds string) (ids []string) {
return ids
}
func MapIf[T any](s []T, f func(T) (T, bool)) []T {
result := make([]T, 0, len(s))
for _, v := range s {
if v, ok := f(v); ok {
result = append(result, v)
}
}
return result
}
func getConfiguredHosts(backendIds string, config *goconf.ConfigFile, commonSecret string) (hosts map[string][]*Backend) {
hosts = make(map[string][]*Backend)
seenUrls := make(map[string]string)
@ -324,12 +310,7 @@ func getConfiguredHosts(backendIds string, config *goconf.ConfigFile, commonSecr
var urls []string
if u, _ := GetStringOptionWithEnv(config, id, "urls"); u != "" {
urls = strings.Split(u, ",")
urls = MapIf(urls, func(s string) (string, bool) {
s = strings.TrimSpace(s)
return s, len(s) > 0
})
slices.Sort(urls)
urls = slices.Sorted(SplitEntries(u, ","))
urls = slices.Compact(urls)
} else if u, _ := GetStringOptionWithEnv(config, id, "url"); u != "" {
if u = strings.TrimSpace(u); u != "" {

View file

@ -35,7 +35,6 @@ import (
"os"
"os/signal"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
@ -542,7 +541,7 @@ func main() {
urls := make([]url.URL, 0)
urlstrings := make([]string, 0)
for host := range strings.SplitSeq(*addr, ",") {
for host := range signaling.SplitEntries(*addr, ",") {
u := url.URL{
Scheme: "ws",
Host: host,

View file

@ -23,8 +23,10 @@ package signaling
import (
"errors"
"iter"
"os"
"regexp"
"strings"
"github.com/dlintw/goconf"
)
@ -85,3 +87,17 @@ func GetStringOptions(config *goconf.ConfigFile, section string, ignoreErrors bo
return result, nil
}
// SplitEntries returns an iterator over all non-empty substrings of s separated
// by sep.
func SplitEntries(s string, sep string) iter.Seq[string] {
return func(yield func(entry string) bool) {
for entry := range strings.SplitSeq(s, sep) {
if entry = strings.TrimSpace(entry); entry != "" {
if !yield(entry) {
return
}
}
}
}
}

View file

@ -26,7 +26,7 @@ import (
"errors"
"fmt"
"log"
"strings"
"slices"
"sync"
"sync/atomic"
"time"
@ -103,12 +103,7 @@ func (c *EtcdClient) getConfigStringWithFallback(config *goconf.ConfigFile, opti
func (c *EtcdClient) load(config *goconf.ConfigFile, ignoreErrors bool) error {
var endpoints []string
if endpointsString := c.getConfigStringWithFallback(config, "endpoints"); endpointsString != "" {
for ep := range strings.SplitSeq(endpointsString, ",") {
ep := strings.TrimSpace(ep)
if ep != "" {
endpoints = append(endpoints, ep)
}
}
endpoints = slices.Collect(SplitEntries(endpointsString, ","))
} else if discoverySrv := c.getConfigStringWithFallback(config, "discoverysrv"); discoverySrv != "" {
discoveryService := c.getConfigStringWithFallback(config, "discoveryservice")
clients, err := srv.GetClient("etcd-client", discoverySrv, discoveryService)

View file

@ -30,7 +30,6 @@ import (
"log"
"net"
"slices"
"strings"
"sync"
"sync/atomic"
"time"
@ -612,12 +611,7 @@ func (c *GrpcClients) loadTargetsStatic(config *goconf.ConfigFile, fromReload bo
}
targets, _ := config.GetString("grpc", "targets")
for target := range strings.SplitSeq(targets, ",") {
target = strings.TrimSpace(target)
if target == "" {
continue
}
for target := range SplitEntries(targets, ",") {
if entries, found := clientsMap[target]; found {
clients = append(clients, entries.clients...)
if dnsDiscovery && entries.entry == nil {

View file

@ -802,13 +802,10 @@ func TestWebsocketFeatures(t *testing.T) {
assert.True(strings.HasPrefix(serverHeader, "nextcloud-spreed-signaling/"), "expected valid server header, got \"%s\"", serverHeader)
features := response.Header.Get("X-Spreed-Signaling-Features")
featuresList := make(map[string]bool)
for f := range strings.SplitSeq(features, ",") {
f = strings.TrimSpace(f)
if f != "" {
_, found := featuresList[f]
assert.False(found, "duplicate feature id \"%s\" in \"%s\"", f, features)
featuresList[f] = true
}
for f := range SplitEntries(features, ",") {
_, found := featuresList[f]
assert.False(found, "duplicate feature id \"%s\" in \"%s\"", f, features)
featuresList[f] = true
}
if len(featuresList) <= 1 {
assert.Fail("expected valid features header", "received \"%s\"", features)

View file

@ -250,7 +250,7 @@ func (p *mcuJanusPublisher) SendMessage(ctx context.Context, message *MessageCli
}
func getFmtpValue(fmtp string, key string) (string, bool) {
for part := range strings.SplitSeq(fmtp, ";") {
for part := range SplitEntries(fmtp, ";") {
kv := strings.SplitN(part, "=", 2)
if len(kv) != 2 {
continue

View file

@ -1565,8 +1565,8 @@ func (m *mcuProxy) loadContinentsMap(config *goconf.ConfigFile) error {
}
var values []string
for v := range strings.SplitSeq(value, ",") {
v = strings.ToUpper(strings.TrimSpace(v))
for v := range SplitEntries(value, ",") {
v = strings.ToUpper(v)
if !IsValidContinent(v) {
log.Printf("Ignore unknown continent %s for override %s", v, option)
continue

View file

@ -30,7 +30,6 @@ import (
"os"
"os/signal"
"runtime"
"strings"
"syscall"
"time"
@ -100,7 +99,7 @@ func main() {
writeTimeout = defaultWriteTimeout
}
for address := range strings.SplitSeq(addr, " ") {
for address := range signaling.SplitEntries(addr, " ") {
go func(address string) {
log.Println("Listening on", address)
listener, err := net.Listen("tcp", address)

View file

@ -316,14 +316,11 @@ func TestWebsocketFeatures(t *testing.T) {
}
features := response.Header.Get("X-Spreed-Signaling-Features")
featuresList := make(map[string]bool)
for f := range strings.SplitSeq(features, ",") {
f = strings.TrimSpace(f)
if f != "" {
if _, found := featuresList[f]; found {
assert.Fail("duplicate feature", "id \"%s\" in \"%s\"", f, features)
}
featuresList[f] = true
for f := range signaling.SplitEntries(features, ",") {
if _, found := featuresList[f]; found {
assert.Fail("duplicate feature", "id \"%s\" in \"%s\"", f, features)
}
featuresList[f] = true
}
assert.NotEmpty(featuresList, "expected valid features header, got \"%s\"", features)
if _, found := featuresList["remote-streams"]; !found {

View file

@ -27,7 +27,6 @@ import (
"maps"
"net"
"net/url"
"strings"
"sync"
"github.com/dlintw/goconf"
@ -85,12 +84,7 @@ func (p *proxyConfigStatic) configure(config *goconf.ConfigFile, fromReload bool
remove := maps.Clone(p.connectionsMap)
mcuUrl, _ := GetStringOptionWithEnv(config, "mcu", "url")
for u := range strings.SplitSeq(mcuUrl, " ") {
u = strings.TrimSpace(u)
if u == "" {
continue
}
for u := range SplitEntries(mcuUrl, " ") {
if existing, found := remove[u]; found {
// Proxy connection still exists in new configuration
delete(remove, u)

View file

@ -35,7 +35,6 @@ import (
"os/signal"
"runtime"
runtimepprof "runtime/pprof"
"strings"
"sync"
"syscall"
"time"
@ -341,7 +340,7 @@ func main() {
if writeTimeout <= 0 {
writeTimeout = defaultWriteTimeout
}
for address := range strings.SplitSeq(saddr, " ") {
for address := range signaling.SplitEntries(saddr, " ") {
go func(address string) {
log.Println("Listening on", address)
listener, err := createTLSListener(address, cert, key)
@ -374,7 +373,7 @@ func main() {
writeTimeout = defaultWriteTimeout
}
for address := range strings.SplitSeq(addr, " ") {
for address := range signaling.SplitEntries(addr, " ") {
go func(address string) {
log.Println("Listening on", address)
listener, err := createListener(address)