-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
100 lines (94 loc) · 2.58 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"sync"
"time"
)
type (
Request map[string][]string
Response []string
inChannel struct {
position int
url string
}
outChannel struct {
position int
status string
}
)
func main() {
// Launching our server
http.HandleFunc("/parse", parseURL)
log.Fatal(http.ListenAndServe(":8888", nil))
}
func parseURL(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Create workers and channels
wg := new(sync.WaitGroup)
inCH := make(chan inChannel)
outCH := make(chan outChannel)
// Start workers
for i := 0; i < 250; i++ {
// Increase the WaitGroup counter
wg.Add(1)
go getHTML(inCH, outCH, wg)
}
// Decoding the json request into a variable
decoder := json.NewDecoder(r.Body)
var request Request
err := decoder.Decode(&request)
if err != nil {
log.Fatal(err)
}
// Getting the HTML statuses
statuses := getStatuses(request["urls"], inCH, outCH, wg)
// Encode the statuses variable into JSON
resp, err := json.Marshal(statuses)
if err != nil {
panic(err)
}
// Ending the function
elapsed := time.Since(start)
log.Println("\n===================================\n Completed in:", elapsed, "\n===================================\n")
fmt.Fprintln(w, string(resp))
}
func getStatuses(urls []string, inCH chan inChannel, outCH chan outChannel, wg *sync.WaitGroup) []string {
statuses := make([]string, len(urls))
// Create a goroutine that listens for the outChannel.
go func() {
// Infinite loop listening for incoming values on the outChannel. It will run until the outCH is closed
for out := range outCH {
statuses[out.position] = out.status
}
}()
// Pushing through the inChannel the URLs along with the the URL position within the POST request
for k, url := range urls {
inCH <- inChannel{position: k, url: url}
}
// Close the inChannel
close(inCH)
// Wait for all goroutines to finish
wg.Wait()
// Closing the outChannel
close(outCH)
// Return the statuses
return statuses
}
func getHTML(inCH chan inChannel, outCH chan outChannel, wg *sync.WaitGroup) {
defer wg.Done()
// Infinite loop listening for any value coming through the channel. This will run until the inChannel is closed.
for in := range inCH {
html, err := http.Get(in.url)
if err != nil {
outCH <- outChannel{position: in.position, status: err}
continue
}
// Log the url - for demonstration purposes only
log.Println(in.url)
// Push the HTML Status through the outChannel along with the URL position within the POST request
outCH <- outChannel{position: in.position, status: html.Status}
}
}