Йосиф обнови решението на 05.12.2014 01:06 (преди над 3 години)
+package main
+
+import "time"
+
+type CallError struct {
+ message string
+}
+
+func (ce *CallError) Error() string {
+ return ce.message
+}
+
+func SeekAndDestroy(callback func(string) bool, chunkedUrlsToCheck <-chan []string, workersCount int) (str string, err error) {
+ if workersCount < 1 {
+ return "", &CallError{message: "Invalid value for \"workersCount\" !!!"}
+ } else if chunkedUrlsToCheck == nil {
+ return "", &CallError{message: "Uninitialised channel !!!"}
+ }
+
+ result := make(chan string)
+ kill := make(chan struct{})
+
+ go startRoutines(result, kill, chunkedUrlsToCheck, workersCount, callback)
+
+ select {
+ case res := <-result:
+ kill <- struct{}{}
+ return res, nil
+ case _ = <-time.After(15 * time.Second):
+ kill <- struct{}{}
+ return "", &CallError{message: "Nothing found !!!"}
+ }
+}
+
+func startRoutines(result chan string, ownDeath chan struct{}, chunkedUrlsToCheck <-chan []string, workersCount int, callback func(string) bool) {
+ pool := make(chan struct{}, workersCount)
+ for i := 0; i < workersCount; i++ {
+ pool <- struct{}{}
+ }
+
+ i := 0
+ killSliceRoutine := make(map[int]chan struct{})
+
+ for {
+ select {
+ case _ = <-ownDeath:
+ for _, killMachine := range killSliceRoutine {
+ killMachine <- struct{}{}
+ }
+ return
+ case urlSlice := <-chunkedUrlsToCheck:
+ killSliceRoutine[i] = make(chan struct{})
+ go func(death chan struct{}, urlSlice []string) {
+ chans := make([]chan string, len(urlSlice))
+ for _, url := range urlSlice {
+ select {
+ case _ = <-pool:
+ newChan := make(chan string)
+ chans = append(chans, newChan)
+
+ //worker-routine
+ go func(url string, newChan chan string) {
+ if callback(url) {
+ newChan <- url
+ }
+ }(url, newChan)
+
+ go func(newChan chan string) {
+ select {
+ case _ = <-time.After(3 * time.Second):
+ pool <- struct{}{}
+ case match := <-newChan:
+ result <- match
+ }
+ }(newChan)
+
+ case _ = <-death:
+ return
+ }
+ }
+ }(killSliceRoutine[i], urlSlice)
+ i++
+ }
+ }
+}