newWithManagerFactory is an internal constructor seam for tests and controlled startup injection. Keep unexported; production callers should use New(...).
(cfg *config.Config, wgConfig *Config, users []*common.User, managerFactory newManagerFunc)
| 118 | // newWithManagerFactory is an internal constructor seam for tests and controlled startup injection. |
| 119 | // Keep unexported; production callers should use New(...). |
| 120 | func newWithManagerFactory(cfg *config.Config, wgConfig *Config, users []*common.User, managerFactory newManagerFunc) (*WireGuard, error) { |
| 121 | if managerFactory == nil { |
| 122 | managerFactory = NewManager |
| 123 | } |
| 124 | |
| 125 | wgCtx, wgCancel := context.WithCancel(context.Background()) |
| 126 | |
| 127 | // Get WireGuard version before starting |
| 128 | version := getWireGuardVersion() |
| 129 | |
| 130 | wg := &WireGuard{ |
| 131 | cancelFunc: wgCancel, |
| 132 | cfg: cfg, |
| 133 | statsTracker: stats.New(), |
| 134 | interfaceStats: stats.NewInterfaceCountersTracker(), |
| 135 | peerStore: NewPeerStore(), |
| 136 | logChan: make(chan string, cfg.LogBufferSize), |
| 137 | startTime: time.Now(), |
| 138 | version: version, |
| 139 | newManager: managerFactory, |
| 140 | state: lifecycleStarting, |
| 141 | } |
| 142 | |
| 143 | start := time.Now() |
| 144 | |
| 145 | if wgConfig == nil { |
| 146 | return nil, errors.New("wireguard config string must not be empty or nil") |
| 147 | } |
| 148 | |
| 149 | wg.config = wgConfig |
| 150 | |
| 151 | log.Println("config loaded in", time.Since(start).Seconds(), "second.") |
| 152 | |
| 153 | // Validate private key before creating manager. |
| 154 | // This rejects invalid configured keys during New() with no manager side effects. |
| 155 | privateKey, err := wgConfig.GetPrivateKey() |
| 156 | if err != nil { |
| 157 | return nil, fmt.Errorf("invalid wireguard private key: %w", err) |
| 158 | } |
| 159 | |
| 160 | normalizedUsers := normalizeUsers(users) |
| 161 | startupExistingByKey := wg.buildExistingPeersByKeySnapshot() |
| 162 | startupDesiredPeers, err := wg.collectDesiredPeers(normalizedUsers) |
| 163 | if err != nil { |
| 164 | return nil, fmt.Errorf("failed to collect desired peers: %w", err) |
| 165 | } |
| 166 | |
| 167 | startupDiff, err := wg.buildSyncDiff(startupExistingByKey, startupDesiredPeers) |
| 168 | if err != nil { |
| 169 | return nil, fmt.Errorf("failed to build sync diff: %w", err) |
| 170 | } |
| 171 | psk, _ := wgConfig.GetPreSharedKey() |
| 172 | startupPeerConfigs, appliedKeys := buildTargetPeerConfigs(startupDiff.TargetPeers, psk) |
| 173 | |
| 174 | manager, err := wg.newManager(wgConfig.InterfaceName) |
| 175 | if err != nil { |
| 176 | return nil, fmt.Errorf("failed to create manager: %w", err) |
| 177 | } |