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  }