processQueue runs the queue in its own goroutine.
()
| 262 | |
| 263 | // processQueue runs the queue in its own goroutine. |
| 264 | func (f *Fetcher) processQueue() { |
| 265 | loop: |
| 266 | for v := range f.q.ch { |
| 267 | if v == nil { |
| 268 | // Special case, when the Queue is closed, a nil command is sent, use this |
| 269 | // indicator to check for the closed signal, instead of looking on every loop. |
| 270 | select { |
| 271 | case <-f.q.closed: |
| 272 | // Close signal, exit loop |
| 273 | break loop |
| 274 | default: |
| 275 | // Keep going |
| 276 | } |
| 277 | } |
| 278 | select { |
| 279 | case <-f.q.cancelled: |
| 280 | // queue got cancelled, drain |
| 281 | continue |
| 282 | default: |
| 283 | // go on |
| 284 | } |
| 285 | |
| 286 | // Get the URL to enqueue |
| 287 | u := v.URL() |
| 288 | |
| 289 | // Check if a channel is already started for this host |
| 290 | f.mu.Lock() |
| 291 | in, ok := f.hosts[u.Host] |
| 292 | if !ok { |
| 293 | // Start a new channel and goroutine for this host. |
| 294 | |
| 295 | var rob *url.URL |
| 296 | if !f.DisablePoliteness { |
| 297 | // Must send the robots.txt request. |
| 298 | rob = u.ResolveReference(robotsTxtParsedPath) |
| 299 | } |
| 300 | |
| 301 | // Create the infinite queue: the in channel to send on, and the out channel |
| 302 | // to read from in the host's goroutine, and add to the hosts map |
| 303 | var out chan Command |
| 304 | in, out = make(chan Command, 1), make(chan Command, 1) |
| 305 | f.hosts[u.Host] = in |
| 306 | f.mu.Unlock() |
| 307 | f.q.wg.Add(1) |
| 308 | // Start the infinite queue goroutine for this host |
| 309 | go sliceIQ(in, out) |
| 310 | // Start the working goroutine for this host |
| 311 | go f.processChan(out, u.Host) |
| 312 | |
| 313 | if !f.DisablePoliteness { |
| 314 | // Enqueue the robots.txt request first. |
| 315 | in <- robotCommand{&Cmd{U: rob, M: "GET"}} |
| 316 | } |
| 317 | } else { |
| 318 | f.mu.Unlock() |
| 319 | } |
| 320 | // Send the request |
| 321 | in <- v |
no test coverage detected