/* * ============================================================================ * Projekt.....: rs2322tcp * Datei.......: internal/client/virtual_port_validation.go * Copyright (C) 2026 Dieter Lang * * SPDX-License-Identifier: GPL-3.0-or-later * * Beschreibung: * Plattformneutrale Prüfung der in client.json definierten virtuellen Ports * gegen die tatsächlich vorhandenen virtuellen Schnittstellen. * * Die Ermittlung der vorhandenen Ports erfolgt über die * plattformabhängige Funktion existingVirtualPortLinks(). * ============================================================================ */ package client import ( "fmt" "sort" "strings" "git.lang-dieter.de/rs2322tcp/internal/config" ) /////////////////////////////////////////////////////////////////////////////// // Virtual port validation /////////////////////////////////////////////////////////////////////////////// // VirtualPortValidationResult contains the differences between configured // and locally available virtual ports. type VirtualPortValidationResult struct { Missing []string Extra []string } // compareVirtualPorts compares the configured virtual ports with the // locally available virtual ports. // // Missing contains ports configured in client.json that are not available // locally. // // Extra contains locally available ports that are not configured in // client.json. // // The order of both input lists is irrelevant. func compareVirtualPorts( configured []string, available []string, ) VirtualPortValidationResult { configuredSet := make(map[string]struct{}, len(configured)) for _, port := range configured { configuredSet[port] = struct{}{} } availableSet := make(map[string]struct{}, len(available)) for _, port := range available { availableSet[port] = struct{}{} } result := VirtualPortValidationResult{ Missing: make([]string, 0), Extra: make([]string, 0), } for port := range configuredSet { if _, ok := availableSet[port]; ok { continue } result.Missing = append(result.Missing, port) } for port := range availableSet { if _, ok := configuredSet[port]; ok { continue } result.Extra = append(result.Extra, port) } sort.Strings(result.Missing) sort.Strings(result.Extra) return result } /////////////////////////////////////////////////////////////////////////////// // Local virtual-port validation /////////////////////////////////////////////////////////////////////////////// // validateLocalVirtualPorts compares the virtual ports defined in // client.json with the virtual ports currently available on the local // computer. // // The detection of available ports is performed by the platform-specific // existingVirtualPortLinks() implementation. // // A mismatch prevents the client from starting. func validateLocalVirtualPorts( cfg *config.ClientConfig, ) error { if cfg == nil { return fmt.Errorf("client configuration is nil") } configured := make( []string, 0, len(cfg.VirtualPorts), ) for _, virtualPort := range cfg.VirtualPorts { configured = append( configured, virtualPort.Port, ) } available, err := existingVirtualPortLinks( cfg.VirtualPortRange, ) if err != nil { return fmt.Errorf( "prüfen der virtuellen Ports fehlgeschlagen: %w", err, ) } result := compareVirtualPorts( configured, available, ) if len(result.Missing) == 0 && len(result.Extra) == 0 { return nil } var message strings.Builder //////////////////////////////////////////////////////////////////////////// // Missing ports //////////////////////////////////////////////////////////////////////////// if len(result.Missing) > 0 && len(result.Extra) == 0 { message.WriteString( "Virtuelle Ports nicht eingerichtet", ) message.WriteString( "\n\nFolgende Ports sind in client.json " + "eingetragen, aber auf diesem Rechner " + "nicht eingerichtet:\n\n", ) for _, port := range result.Missing { message.WriteString(" ") message.WriteString(port) message.WriteByte('\n') } message.WriteString( "\nBitte richten Sie diese virtuellen Ports " + "entsprechend der Installationsanleitung ein.", ) return fmt.Errorf( "%s", strings.TrimSpace(message.String()), ) } //////////////////////////////////////////////////////////////////////////// // Extra ports //////////////////////////////////////////////////////////////////////////// if len(result.Missing) == 0 && len(result.Extra) > 0 { message.WriteString( "Virtuelle Ports nicht konfiguriert", ) message.WriteString( "\n\nFolgende virtuelle Ports sind auf diesem " + "Rechner eingerichtet, aber nicht in " + "client.json eingetragen:\n\n", ) for _, port := range result.Extra { message.WriteString(" ") message.WriteString(port) message.WriteByte('\n') } message.WriteString( "\nBitte ergänzen Sie die entsprechenden " + "Einträge in client.json.", ) return fmt.Errorf( "%s", strings.TrimSpace(message.String()), ) } //////////////////////////////////////////////////////////////////////////// // Missing and extra ports //////////////////////////////////////////////////////////////////////////// message.WriteString( "Virtuelle Portkonfiguration stimmt nicht überein", ) message.WriteString( "\n\nIn client.json eingetragen, aber nicht " + "eingerichtet:\n\n", ) for _, port := range result.Missing { message.WriteString(" ") message.WriteString(port) message.WriteByte('\n') } message.WriteString( "\nEingerichtet, aber nicht in client.json " + "eingetragen:\n\n", ) for _, port := range result.Extra { message.WriteString(" ") message.WriteString(port) message.WriteByte('\n') } message.WriteString( "\nBitte korrigieren Sie die virtuelle " + "Portkonfiguration.", ) return fmt.Errorf( "%s", strings.TrimSpace(message.String()), ) }