""" Port conflict detection for PIC. Maps each service section to the port field names it exposes, and provides detect_conflicts() to find cases where two distinct (section, field) slots resolve to the same integer port value. """ # Maps section → list of port field names within that section's config dict. # Must stay in sync with the _port_fields dict in app.py's update_config(). PORT_FIELDS = { 'network': ['dns_port'], 'wireguard': ['port'], 'email': ['smtp_port', 'submission_port', 'imap_port', 'webmail_port'], 'calendar': ['port'], 'files': ['port', 'manager_port'], } def detect_conflicts(effective_config, incoming_patch): """ Detect port conflicts across all tracked service sections. Parameters ---------- effective_config : dict The current full config as stored (e.g. config_manager.configs). Each key is a section name; the value is a dict of that section's config fields. incoming_patch : dict The partial update the user is trying to save. Values here override whatever is in effective_config for the purpose of conflict checking. Returns ------- list of dict Each element is {'port': , 'conflicts': [(section, field), ...]}. Only entries where 2+ (section, field) pairs share the same port are included. Returns an empty list when there are no conflicts. """ # Build merged view: start from stored config, overlay the patch merged = {} for section in PORT_FIELDS: stored = effective_config.get(section, {}) or {} patch = incoming_patch.get(section, {}) or {} merged[section] = {**stored, **patch} # Collect port → [(section, field)] mapping port_map = {} for section, fields in PORT_FIELDS.items(): for field in fields: raw = merged[section].get(field) if raw is None or raw == '': continue try: port_val = int(raw) except (ValueError, TypeError): continue port_map.setdefault(port_val, []).append((section, field)) # Return only entries that have more than one (section, field) slot conflicts = [] for port_val, slots in port_map.items(): if len(slots) >= 2: conflicts.append({'port': port_val, 'conflicts': slots}) return conflicts