-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathmain.go
130 lines (112 loc) · 3.24 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package main
import (
"fmt"
"html/template"
"log"
"math/rand"
"os"
"time"
)
var config *Config
var version = "debug"
var outputTemplate *template.Template
type logWriter struct {
}
func (writer logWriter) Write(bytes []byte) (int, error) {
return fmt.Print(time.Now().UTC().Format("2006-01-02 15:04:05 ") + string(bytes))
}
func init() {
// setup log time format
// https://stackoverflow.com/a/36140590/6091246
log.SetFlags(0)
log.SetOutput(new(logWriter))
config = &Config{}
if err := config.Parse("config.toml"); err != nil {
log.Fatal(err)
}
outputPath := "output"
if _, err := os.Stat(outputPath); os.IsNotExist(err) {
err = os.Mkdir(outputPath, 0755)
if err != nil {
log.Fatalf("Error creating output folder: %v", err)
}
}
fmt.Fprintf(os.Stderr, "templateName: %s", config.TemplateName)
rand.Seed(41)
// outputTemplate is used to render output
outputTemplate = template.Must(template.New(config.TemplateName).Funcs(
template.FuncMap{"convertTime": func(ts int64) string {
// convertTime converts unix timestamp to the following format
// How do I format an unix timestamp to RFC3339 - golang?
// https://stackoverflow.com/a/21814954/6091246
// Convert UTC to “local” time - Go
// https://stackoverflow.com/a/45137855/6091246
// Using Functions Inside Go Templates
// https://www.calhoun.io/using-functions-inside-go-templates/
// Go template function
// https://stackoverflow.com/a/20872724/6091246
return time.Unix(ts, 0).In(time.Local).Format("2006-01-02 15:04")
},
}).ParseFiles("template/" + config.TemplateName))
}
func main() {
println("tiebaSpider")
println("version:", version)
println("project url: https://github.com/hjhee/tiebaSpider")
// closing done to force all goroutines to quit
// Go Concurrency Patterns: Pipelines and cancellation
// https://blog.golang.org/pipelines
done := make(chan struct{})
defer close(done)
err, errcConfig := config.Watch()
if err != nil {
panic(err)
}
pc, errcFetch := fetchHTMLList(done, "url.txt")
tempc, errcParse := parseHTML(done, pc)
outputc, errcRender := renderHTML(done, pc, tempc, outputTemplate)
for {
// programme exits when all error channels are closed:
// breaking out of a select statement when all channels are closed
// https://stackoverflow.com/a/13666733/6091246
if errcFetch == nil && errcParse == nil && errcRender == nil {
log.Printf("Job done!\n")
break
}
parseSelect:
select {
case <-done:
break parseSelect
case err, ok := <-errcConfig:
if !ok {
log.Fatalf("[Cofnig] Config watcher encountered error")
}
fmt.Fprintf(os.Stderr, "[Config] Config watcher encountered error: %v\n", err)
case err, ok := <-errcFetch:
if !ok {
errcFetch = nil
log.Printf("[Fetch] job done")
continue
}
fmt.Fprintf(os.Stderr, "[Fetch] error: %v\n", err)
case err, ok := <-errcParse:
if !ok {
errcParse = nil
log.Printf("[Parse] job done")
continue
}
fmt.Fprintf(os.Stderr, "[Parse] error: %v\n", err)
case err, ok := <-errcRender:
if !ok {
errcRender = nil
log.Printf("[Template] job done")
continue
}
fmt.Fprintf(os.Stderr, "[Template] error: %v\n", err)
case file, ok := <-outputc:
if ok {
log.Printf("[Template] %s done\n", file)
}
}
}
}