-
Notifications
You must be signed in to change notification settings - Fork 0
/
example.go
executable file
·154 lines (138 loc) · 5.71 KB
/
example.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"flag"
"fmt"
"github.com/opesun/goquery"
"strings"
"time"
//Пакеты, которые пригодятся для работы с файлами и сигналами:
"io"
"os"
"os/signal"
//А вот эти - для высчитывания хешей:
"crypto/md5"
"encoding/hex"
)
var (
WORKERS int = 2 //кол-во "потоков"
REPORT_PERIOD int = 10 //частота отчетов (сек)
DUP_TO_STOP int = 500 //максимум повторов до останова
HASH_FILE string = "hash.bin" //файл с хешами
QUOTES_FILE string = "quotes.txt" //файл с цитатами
used map[string]bool = make(map[string]bool) //map в котором в качестве ключей будем использовать строки, а для значений - булев тип.
)
func init() {
//Задаем правила разбора:
flag.IntVar(&WORKERS, "w", WORKERS, "количество потоков")
flag.IntVar(&REPORT_PERIOD, "r", REPORT_PERIOD, "частота отчетов (сек)")
flag.IntVar(&DUP_TO_STOP, "d", DUP_TO_STOP, "кол-во дубликатов для остановки")
flag.StringVar(&HASH_FILE, "hf", HASH_FILE, "файл хешей")
flag.StringVar("ES_FILE, "qf", QUOTES_FILE, "файл записей")
//И запускаем разбор аргументов
flag.Parse()
}
func grab() <-chan string { //функция вернет канал, из которого мы будем читать данные типа string
c := make(chan string)
for i := 0; i < WORKERS; i++ { //в цикле создадим нужное нам количество гоурутин - worker'oв
go func() {
for { //в вечном цикле собираем данные
x, err := goquery.ParseUrl("http://vpustotu.ru/moderation/")
if err == nil {
if s := strings.TrimSpace(x.Find(".fi_text").Text()); s != "" {
c <- s //и отправляем их в канал
}
}
time.Sleep(100 * time.Millisecond)
}
}()
}
fmt.Println("Запущено потоков: ", WORKERS)
return c
}
func check(e error) {
if e != nil {
panic(e)
}
}
func readHashes() {
//проверим файл на наличие
if _, err := os.Stat(HASH_FILE); err != nil {
if os.IsNotExist(err) {
fmt.Println("Файл хешей не найден, будет создан новый.")
return
}
}
fmt.Println("Чтение хешей...")
hash_file, err := os.OpenFile(HASH_FILE, os.O_RDONLY, 0666)
check(err)
defer hash_file.Close()
//читать будем блоками по 16 байт - как раз один хеш:
data := make([]byte, 16)
for {
n, err := hash_file.Read(data) //n вернет количество прочитанных байт, а err - ошибку, в случае таковой.
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
if n == 16 {
used[hex.EncodeToString(data)] = true
}
}
fmt.Println("Завершено. Прочитано хешей: ", len(used))
}
func main() {
readHashes()
//Открываем файл с цитатами...
quotes_file, err := os.OpenFile(QUOTES_FILE, os.O_APPEND|os.O_CREATE, 0666)
check(err)
defer quotes_file.Close()
//...и файл с хешами
hash_file, err := os.OpenFile(HASH_FILE, os.O_APPEND|os.O_CREATE, 0666)
check(err)
defer hash_file.Close()
//Создаем Ticker который будет оповещать нас когда пора отчитываться о работе
ticker := time.NewTicker(time.Duration(REPORT_PERIOD) * time.Second)
defer ticker.Stop()
//Создаем канал, который будет ловить сигнал завершения, и привязываем к нему нотификатор...
key_chan := make(chan os.Signal, 1)
signal.Notify(key_chan, os.Interrupt)
//...и все что нужно для подсчета хешей
hasher := md5.New()
//Счетчики цитат и дубликатов
quotes_count, dup_count := 0, 0
//Все готово, поехали!
quotes_chan := grab()
for {
select {
case quote := <-quotes_chan: //если "пришла" новая цитата:
quotes_count++
//считаем хеш, и конвертируем его в строку:
hasher.Reset()
io.WriteString(hasher, quote)
hash := hasher.Sum(nil)
hash_string := hex.EncodeToString(hash)
//проверяем уникальность хеша цитаты
if !used[hash_string] {
//все в порядке - заносим хеш в хранилище, и записываем его и цитату в файлы
used[hash_string] = true
hash_file.Write(hash)
quotes_file.WriteString(quote + "\n\n\n")
dup_count = 0
} else {
//получен повтор - пришло время проверить, не пора ли закругляться?
if dup_count++; dup_count == DUP_TO_STOP {
fmt.Println("Достигнут предел повторов, завершаю работу. Всего записей: ", len(used))
return
}
}
case <-key_chan: //если пришла информация от нотификатора сигналов:
fmt.Println("CTRL-C: Завершаю работу. Всего записей: ", len(used))
return
case <-ticker.C: //и, наконец, проверяем не пора ли вывести очередной отчет
fmt.Printf("Всего %d / Повторов %d (%d записей/сек) \n", len(used), dup_count, quotes_count/REPORT_PERIOD)
quotes_count = 0
}
}
}