identity.go (3491B)
1 package identity
2
3 import (
4 "path/filepath"
5 "strings"
6 "sync"
7 "sync/atomic"
8 )
9
10 // NewIdentityManager creates a new Manager starting at id.
11 func NewManager(id Provider) Manager {
12 return &identityManager{
13 Provider: id,
14 ids: Identities{id.GetIdentity(): id},
15 }
16 }
17
18 // NewPathIdentity creates a new Identity with the two identifiers
19 // type and path.
20 func NewPathIdentity(typ, pat string) PathIdentity {
21 pat = strings.ToLower(strings.TrimPrefix(filepath.ToSlash(pat), "/"))
22 return PathIdentity{Type: typ, Path: pat}
23 }
24
25 // Identities stores identity providers.
26 type Identities map[Identity]Provider
27
28 func (ids Identities) search(depth int, id Identity) Provider {
29 if v, found := ids[id.GetIdentity()]; found {
30 return v
31 }
32
33 depth++
34
35 // There may be infinite recursion in templates.
36 if depth > 100 {
37 // Bail out.
38 return nil
39 }
40
41 for _, v := range ids {
42 switch t := v.(type) {
43 case IdentitiesProvider:
44 if nested := t.GetIdentities().search(depth, id); nested != nil {
45 return nested
46 }
47 }
48 }
49 return nil
50 }
51
52 // IdentitiesProvider provides all Identities.
53 type IdentitiesProvider interface {
54 GetIdentities() Identities
55 }
56
57 // Identity represents an thing that can provide an identify. This can be
58 // any Go type, but the Identity returned by GetIdentify must be hashable.
59 type Identity interface {
60 Provider
61 Name() string
62 }
63
64 // Manager manages identities, and is itself a Provider of Identity.
65 type Manager interface {
66 SearchProvider
67 Add(ids ...Provider)
68 Reset()
69 }
70
71 // SearchProvider provides access to the chained set of identities.
72 type SearchProvider interface {
73 Provider
74 IdentitiesProvider
75 Search(id Identity) Provider
76 }
77
78 // A PathIdentity is a common identity identified by a type and a path, e.g. "layouts" and "_default/single.html".
79 type PathIdentity struct {
80 Type string
81 Path string
82 }
83
84 // GetIdentity returns itself.
85 func (id PathIdentity) GetIdentity() Identity {
86 return id
87 }
88
89 // Name returns the Path.
90 func (id PathIdentity) Name() string {
91 return id.Path
92 }
93
94 // A KeyValueIdentity a general purpose identity.
95 type KeyValueIdentity struct {
96 Key string
97 Value string
98 }
99
100 // GetIdentity returns itself.
101 func (id KeyValueIdentity) GetIdentity() Identity {
102 return id
103 }
104
105 // Name returns the Key.
106 func (id KeyValueIdentity) Name() string {
107 return id.Key
108 }
109
110 // Provider provides the hashable Identity.
111 type Provider interface {
112 // GetIdentity is for internal use.
113 GetIdentity() Identity
114 }
115
116 type identityManager struct {
117 sync.Mutex
118 Provider
119 ids Identities
120 }
121
122 func (im *identityManager) Add(ids ...Provider) {
123 im.Lock()
124 for _, id := range ids {
125 im.ids[id.GetIdentity()] = id
126 }
127 im.Unlock()
128 }
129
130 func (im *identityManager) Reset() {
131 im.Lock()
132 id := im.GetIdentity()
133 im.ids = Identities{id.GetIdentity(): id}
134 im.Unlock()
135 }
136
137 // TODO(bep) these identities are currently only read on server reloads
138 // so there should be no concurrency issues, but that may change.
139 func (im *identityManager) GetIdentities() Identities {
140 im.Lock()
141 defer im.Unlock()
142 return im.ids
143 }
144
145 func (im *identityManager) Search(id Identity) Provider {
146 im.Lock()
147 defer im.Unlock()
148 return im.ids.search(0, id.GetIdentity())
149 }
150
151 // Incrementer increments and returns the value.
152 // Typically used for IDs.
153 type Incrementer interface {
154 Incr() int
155 }
156
157 // IncrementByOne implements Incrementer adding 1 every time Incr is called.
158 type IncrementByOne struct {
159 counter uint64
160 }
161
162 func (c *IncrementByOne) Incr() int {
163 return int(atomic.AddUint64(&c.counter, uint64(1)))
164 }