-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcontext.go
116 lines (101 loc) · 2.04 KB
/
context.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
package crawler
import (
"net/url"
"sync"
"time"
"golang.org/x/net/context"
)
type ctxKey int
const (
ckDepth ctxKey = 1 + iota
ckLoaded
ckNumVisit
ckNumError
ckLastTime
ckError
)
type Context struct {
cw *Crawler
url *url.URL
depth int
err error
C context.Context
}
var (
ctxFreeList = &sync.Pool{
New: func() interface{} {
return &Context{}
},
}
emptyContext = Context{}
)
func (cw *Crawler) newContext(u *url.URL, ctx context.Context) (*Context, error) {
depth, err := cw.store.GetDepth(u)
if err != nil {
return nil, err
}
c := ctxFreeList.Get().(*Context)
c.cw = cw
c.url = u
c.depth = depth
c.C = ctx
return c, nil
}
func (c *Context) free() {
*c = emptyContext
ctxFreeList.Put(c)
}
func (c *Context) URL() *url.URL { return c.url }
func (c *Context) Depth() int { return c.depth }
func (c *Context) With(ctx context.Context) { c.C = ctx }
func (c *Context) WithValue(k, v interface{}) {
c.C = context.WithValue(c.C, k, v)
}
func (c *Context) Value(k interface{}) interface{} {
return c.C.Value(k)
}
func (c *Context) Retry(err error) {
c.err = RetryableError{err}
}
func (c *Context) Error(err error) {
c.err = err
}
func (c *Context) Fatal(err error) {
c.err = FatalError{err}
}
func (c *Context) NumVisit() (cnt int, err error) {
if err = c.fromStore(); err == nil {
cnt = c.Value(ckNumVisit).(int)
}
return
}
func (c *Context) NumError() (cnt int, err error) {
if err = c.fromStore(); err == nil {
cnt = c.Value(ckNumError).(int)
}
return
}
func (c *Context) LastTime() (t time.Time, err error) {
if err = c.fromStore(); err == nil {
t = c.Value(ckLastTime).(time.Time)
}
return
}
func (c *Context) fromStore() error {
if loaded, ok := c.Value(ckLoaded).(bool); ok && loaded {
return nil
}
u, err := c.cw.store.Get(c.url)
if err != nil {
return err
}
c.fromURL(u)
return nil
}
func (c *Context) fromURL(u *URL) {
c.WithValue(ckDepth, u.Depth)
c.WithValue(ckNumVisit, u.NumVisit)
c.WithValue(ckNumError, u.NumRetry)
c.WithValue(ckLastTime, u.Last)
c.WithValue(ckLoaded, true)
}