github.com/cs3org/reva/v2@v2.27.7/pkg/cbox/group/rest/cache.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package rest 20 21 import ( 22 "encoding/json" 23 "errors" 24 "fmt" 25 "strconv" 26 "strings" 27 "time" 28 29 grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" 30 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 31 "github.com/gomodule/redigo/redis" 32 ) 33 34 const ( 35 groupPrefix = "group:" 36 idPrefix = "id:" 37 namePrefix = "name:" 38 gidPrefix = "gid:" 39 groupMembersPrefix = "members:" 40 groupInternalIDPrefix = "internal:" 41 ) 42 43 func initRedisPool(address, username, password string) *redis.Pool { 44 return &redis.Pool{ 45 46 MaxIdle: 50, 47 MaxActive: 1000, 48 IdleTimeout: 240 * time.Second, 49 50 Dial: func() (redis.Conn, error) { 51 var c redis.Conn 52 var err error 53 switch { 54 case username != "": 55 c, err = redis.Dial("tcp", address, 56 redis.DialUsername(username), 57 redis.DialPassword(password), 58 ) 59 case password != "": 60 c, err = redis.Dial("tcp", address, 61 redis.DialPassword(password), 62 ) 63 default: 64 c, err = redis.Dial("tcp", address) 65 } 66 67 if err != nil { 68 return nil, err 69 } 70 return c, err 71 }, 72 73 TestOnBorrow: func(c redis.Conn, t time.Time) error { 74 _, err := c.Do("PING") 75 return err 76 }, 77 } 78 } 79 80 func (m *manager) setVal(key, val string, expiration int) error { 81 conn := m.redisPool.Get() 82 defer conn.Close() 83 if conn != nil { 84 args := []interface{}{key, val} 85 if expiration != -1 { 86 args = append(args, "EX", expiration) 87 } 88 if _, err := conn.Do("SET", args...); err != nil { 89 return err 90 } 91 return nil 92 } 93 return errors.New("rest: unable to get connection from redis pool") 94 } 95 96 func (m *manager) getVal(key string) (string, error) { 97 conn := m.redisPool.Get() 98 defer conn.Close() 99 if conn != nil { 100 val, err := redis.String(conn.Do("GET", key)) 101 if err != nil { 102 return "", err 103 } 104 return val, nil 105 } 106 return "", errors.New("rest: unable to get connection from redis pool") 107 } 108 109 func (m *manager) fetchCachedInternalID(gid *grouppb.GroupId) (string, error) { 110 return m.getVal(groupPrefix + groupInternalIDPrefix + gid.OpaqueId) 111 } 112 113 func (m *manager) cacheInternalID(gid *grouppb.GroupId, internalID string) error { 114 return m.setVal(groupPrefix+groupInternalIDPrefix+gid.OpaqueId, internalID, -1) 115 } 116 117 func (m *manager) findCachedGroups(query string) ([]*grouppb.Group, error) { 118 conn := m.redisPool.Get() 119 defer conn.Close() 120 if conn != nil { 121 query = fmt.Sprintf("%s*%s*", groupPrefix, strings.ReplaceAll(strings.ToLower(query), " ", "_")) 122 keys, err := redis.Strings(conn.Do("KEYS", query)) 123 if err != nil { 124 return nil, err 125 } 126 var args []interface{} 127 for _, k := range keys { 128 args = append(args, k) 129 } 130 131 // Fetch the groups for all these keys 132 groupStrings, err := redis.Strings(conn.Do("MGET", args...)) 133 if err != nil { 134 return nil, err 135 } 136 groupMap := make(map[string]*grouppb.Group) 137 for _, group := range groupStrings { 138 g := grouppb.Group{} 139 if err = json.Unmarshal([]byte(group), &g); err == nil { 140 groupMap[g.Id.OpaqueId] = &g 141 } 142 } 143 144 var groups []*grouppb.Group 145 for _, g := range groupMap { 146 groups = append(groups, g) 147 } 148 149 return groups, nil 150 } 151 152 return nil, errors.New("rest: unable to get connection from redis pool") 153 } 154 155 func (m *manager) fetchCachedGroupDetails(gid *grouppb.GroupId) (*grouppb.Group, error) { 156 group, err := m.getVal(groupPrefix + idPrefix + gid.OpaqueId) 157 if err != nil { 158 return nil, err 159 } 160 161 g := grouppb.Group{} 162 if err = json.Unmarshal([]byte(group), &g); err != nil { 163 return nil, err 164 } 165 return &g, nil 166 } 167 168 func (m *manager) cacheGroupDetails(g *grouppb.Group) error { 169 encodedGroup, err := json.Marshal(&g) 170 if err != nil { 171 return err 172 } 173 if err = m.setVal(groupPrefix+idPrefix+strings.ToLower(g.Id.OpaqueId), string(encodedGroup), -1); err != nil { 174 return err 175 } 176 177 if g.GidNumber != 0 { 178 if err = m.setVal(groupPrefix+gidPrefix+strconv.FormatInt(g.GidNumber, 10), g.Id.OpaqueId, -1); err != nil { 179 return err 180 } 181 } 182 if g.DisplayName != "" { 183 if err = m.setVal(groupPrefix+namePrefix+g.Id.OpaqueId+"_"+strings.ToLower(g.DisplayName), g.Id.OpaqueId, -1); err != nil { 184 return err 185 } 186 } 187 return nil 188 } 189 190 func (m *manager) fetchCachedGroupByParam(field, claim string) (*grouppb.Group, error) { 191 group, err := m.getVal(groupPrefix + field + ":" + strings.ToLower(claim)) 192 if err != nil { 193 return nil, err 194 } 195 196 g := grouppb.Group{} 197 if err = json.Unmarshal([]byte(group), &g); err != nil { 198 return nil, err 199 } 200 return &g, nil 201 } 202 203 func (m *manager) fetchCachedGroupMembers(gid *grouppb.GroupId) ([]*userpb.UserId, error) { 204 members, err := m.getVal(groupPrefix + groupMembersPrefix + strings.ToLower(gid.OpaqueId)) 205 if err != nil { 206 return nil, err 207 } 208 u := []*userpb.UserId{} 209 if err = json.Unmarshal([]byte(members), &u); err != nil { 210 return nil, err 211 } 212 return u, nil 213 } 214 215 func (m *manager) cacheGroupMembers(gid *grouppb.GroupId, members []*userpb.UserId) error { 216 u, err := json.Marshal(&members) 217 if err != nil { 218 return err 219 } 220 return m.setVal(groupPrefix+groupMembersPrefix+strings.ToLower(gid.OpaqueId), string(u), m.conf.GroupMembersCacheExpiration*60) 221 }