saveToProfile updates the active profile's sni_pool with the top-ranked SNIs and the connect.host + fallback_ips with the best IPs.
()
| 322 | // saveToProfile updates the active profile's sni_pool with the top-ranked |
| 323 | // SNIs and the connect.host + fallback_ips with the best IPs. |
| 324 | func (m *scanModel) saveToProfile() tea.Cmd { |
| 325 | cfg := m.app.cfg |
| 326 | if cfg == nil { |
| 327 | return setStatus("no config loaded") |
| 328 | } |
| 329 | p, ok := cfg.Lookup(cfg.Active) |
| 330 | if !ok { |
| 331 | return setStatus("active profile %q not found", cfg.Active) |
| 332 | } |
| 333 | top := scanner.RankSNIs(m.snis) |
| 334 | if len(top) == 0 { |
| 335 | return setStatus("no successful SNI probes to save") |
| 336 | } |
| 337 | if len(top) > 10 { |
| 338 | top = top[:10] |
| 339 | } |
| 340 | pool := make([]string, 0, len(top)) |
| 341 | for _, r := range top { |
| 342 | pool = append(pool, r.SNI) |
| 343 | } |
| 344 | p.Spoof.SNIPool = pool |
| 345 | p.Spoof.SNI = "" |
| 346 | |
| 347 | // If we also have IP results, refresh connect.host + fallback_ips. |
| 348 | if ips := scanner.RankIPs(m.ips); len(ips) > 0 { |
| 349 | p.Connect.Host = ips[0].IP.String() |
| 350 | fb := make([]string, 0, len(ips)) |
| 351 | for _, r := range ips[1:] { |
| 352 | fb = append(fb, r.IP.String()) |
| 353 | } |
| 354 | if len(fb) > 5 { |
| 355 | fb = fb[:5] |
| 356 | } |
| 357 | p.Connect.FallbackIPs = fb |
| 358 | } |
| 359 | |
| 360 | return func() tea.Msg { |
| 361 | if err := writeYAML(m.app.opts.ConfigPath, cfg); err != nil { |
| 362 | return statusMsg(fmt.Sprintf("write failed: %v", err)) |
| 363 | } |
| 364 | return tea.Sequence( |
| 365 | setStatus("saved top %d SNIs to profile %q", len(pool), cfg.Active), |
| 366 | func() tea.Msg { return configReloadMsg{} }, |
| 367 | )() |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | // Messages ------------------------------------------------------------- |
| 372 |