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 }