alexandre-normand/slackscot

View on GitHub
user.go

Summary

Maintainability
A
0 mins
Test Coverage
A
91%
package slackscot

import (
    "fmt"
    "github.com/alexandre-normand/slackscot/config"
    "github.com/hashicorp/golang-lru"
    "github.com/slack-go/slack"
    "github.com/spf13/viper"
)

const (
    userInfoCacheSizeDisabledValue = 0
)

// UserInfoFinder defines the interface for finding a slack user's info
type UserInfoFinder interface {
    GetUserInfo(userID string) (user *slack.User, err error)
}

// selfInfoFinder defines the interface for finding our (the slackscot instance) user info
type selfInfoFinder interface {
    GetInfo() (user *slack.Info)
}

// cachingUserInfoFinder holds a cache and a loading UserInfoFinder to implement the UserInfoFinder loading entries from cache
type cachingUserInfoFinder struct {
    loader           UserInfoFinder
    logger           SLogger
    userProfileCache *lru.ARCCache
}

// NewCachingUserInfoFinder creates a new user info service with caching if enabled via userProfileCacheSizeKey. It requires an implementation
// of the interface that will do the actual loading when not in cache
func NewCachingUserInfoFinder(v *viper.Viper, loader UserInfoFinder, logger SLogger) (uf UserInfoFinder, err error) {
    cuf := new(cachingUserInfoFinder)

    cs := v.GetInt(config.UserInfoCacheSizeKey)

    if cs > userInfoCacheSizeDisabledValue {
        cuf.userProfileCache, err = lru.NewARC(cs)
        if err != nil {
            return nil, err
        }
    }

    cuf.loader = loader
    cuf.logger = logger

    return cuf, nil
}

// GetUserInfo gets the user info or returns an error and a nil user is not found or
// an error occurred during retrieval
func (c cachingUserInfoFinder) GetUserInfo(userID string) (u *slack.User, err error) {
    if c.userProfileCache == nil {
        c.logger.Debugf("Cache disabled, loading user info for [%s] from slack instead\n", userID)
        return c.loader.GetUserInfo(userID)
    }

    if userProfile, exists := c.userProfileCache.Get(userID); exists {
        c.logger.Debugf("User info in cache [%s] so using that\n", userID)

        userProfile, ok := userProfile.(slack.User)
        if !ok {
            return nil, fmt.Errorf("Error converting cached value for user id [%s]: %v", userID, err)
        }

        return &userProfile, nil
    }

    c.logger.Debugf("User info for [%s] not found in cache, retrieving from slack and saving\n", userID)
    u, err = c.loader.GetUserInfo(userID)

    // Add the user to cache if it was loaded without error
    if u != nil {
        c.userProfileCache.Add(userID, *u)
    }

    return u, err
}