-
Notifications
You must be signed in to change notification settings - Fork 75
/
pac_updater.go
110 lines (99 loc) · 2.17 KB
/
pac_updater.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
package main
import (
"bufio"
"io"
"net/http"
"os"
"sync"
"time"
"github.com/eahydra/socks"
)
type PACUpdater struct {
pac PAC
lock sync.RWMutex
data []byte
modtime time.Time
timer *time.Timer
}
func NewPACUpdater(pac PAC) (*PACUpdater, error) {
p := &PACUpdater{
pac: pac,
}
go p.backgroundUpdate()
return p, nil
}
func parseRule(reader io.Reader) ([]string, error) {
var err error
var line []byte
var rules []string
r := bufio.NewReader(reader)
for line, _, err = r.ReadLine(); err == nil; line, _, err = r.ReadLine() {
s := string(line)
if s != "" {
rules = append(rules, s)
}
}
if err == io.EOF {
err = nil
}
return rules, err
}
func loadLocalRule(filepath string) ([]string, error) {
f, err := os.OpenFile(filepath, os.O_RDONLY, os.ModePerm)
if err != nil {
return nil, err
}
defer f.Close()
return parseRule(f)
}
func loadRemoteRule(ruleURL string, upstream Upstream) ([]string, error) {
forward, err := BuildUpstream(upstream, socks.Direct)
if err != nil {
return nil, err
}
client := &http.Client{
Transport: &http.Transport{
Dial: forward.Dial,
},
}
resp, err := client.Get(ruleURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return parseRule(resp.Body)
}
func (p *PACUpdater) get() ([]byte, time.Time) {
p.lock.RLock()
defer p.lock.RUnlock()
d := make([]byte, len(p.data))
copy(d, p.data)
return d, p.modtime
}
func (p *PACUpdater) set(data []byte) {
p.lock.Lock()
defer p.lock.Unlock()
p.data = make([]byte, len(data))
copy(p.data, data)
p.modtime = time.Now()
}
func (p *PACUpdater) backgroundUpdate() {
pg := NewPACGenerator(p.pac.Proxy, p.pac.SOCKS5)
for {
duration := 1 * time.Minute
if rules, err := loadLocalRule(p.pac.LocalRules); err == nil {
if data, err := pg.Generate(rules); err == nil {
p.set(data)
InfoLog.Println("update rules from", p.pac.LocalRules, "succeeded")
}
}
if rules, err := loadRemoteRule(p.pac.RemoteRules, p.pac.Upstream); err == nil {
if data, err := pg.Generate(rules); err == nil {
p.set(data)
duration = 1 * time.Hour
InfoLog.Println("update rules from", p.pac.RemoteRules, "succeeded")
}
}
time.Sleep(duration)
}
}