Attack reads its Targets from the passed Targeter and attacks them at the rate specified by the Pacer. When the duration is zero the attack runs until Stop is called. Results are sent to the returned channel as soon as they arrive and will have their Attack field set to the given name.
(tr Targeter, p Pacer, du time.Duration, name string)
| 444 | // runs until Stop is called. Results are sent to the returned channel as soon |
| 445 | // as they arrive and will have their Attack field set to the given name. |
| 446 | func (a *Attacker) Attack(tr Targeter, p Pacer, du time.Duration, name string) <-chan *Result { |
| 447 | var wg sync.WaitGroup |
| 448 | |
| 449 | workers := a.workers |
| 450 | if workers > a.maxWorkers { |
| 451 | workers = a.maxWorkers |
| 452 | } |
| 453 | |
| 454 | atk := &attack{ |
| 455 | name: name, |
| 456 | began: time.Now(), |
| 457 | } |
| 458 | |
| 459 | results := make(chan *Result) |
| 460 | ticks := make(chan struct{}) |
| 461 | for i := uint64(0); i < workers; i++ { |
| 462 | wg.Add(1) |
| 463 | go a.attack(tr, atk, &wg, ticks, results) |
| 464 | } |
| 465 | |
| 466 | go func() { |
| 467 | defer func() { |
| 468 | close(ticks) |
| 469 | wg.Wait() |
| 470 | close(results) |
| 471 | a.Stop() |
| 472 | }() |
| 473 | |
| 474 | count := uint64(0) |
| 475 | for { |
| 476 | elapsed := time.Since(atk.began) |
| 477 | if du > 0 && elapsed > du { |
| 478 | return |
| 479 | } |
| 480 | |
| 481 | wait, stop := p.Pace(elapsed, count) |
| 482 | if stop { |
| 483 | return |
| 484 | } |
| 485 | |
| 486 | time.Sleep(wait) |
| 487 | |
| 488 | if workers < a.maxWorkers { |
| 489 | select { |
| 490 | case ticks <- struct{}{}: |
| 491 | count++ |
| 492 | continue |
| 493 | case <-a.stopch: |
| 494 | return |
| 495 | default: |
| 496 | // all workers are blocked. start one more and try again |
| 497 | workers++ |
| 498 | wg.Add(1) |
| 499 | go a.attack(tr, atk, &wg, ticks, results) |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | select { |