add support for github users

This commit is contained in:
Massaki Archambault 2024-08-04 21:00:34 -04:00
parent a0aaa4491b
commit 937e5c341d
3 changed files with 122 additions and 0 deletions

View File

@ -22,6 +22,9 @@ type githubClient struct {
organizationCacheMux sync.RWMutex organizationCacheMux sync.RWMutex
organizationNameToIDMap map[string]int64 organizationNameToIDMap map[string]int64
organizationCache map[int64]*Organization organizationCache map[int64]*Organization
userCacheMux sync.RWMutex
userNameToIDMap map[string]int64
userCache map[int64]*User
} }
func NewClient(logger *slog.Logger, config config.GithubClientConfig) (*githubClient, error) { func NewClient(logger *slog.Logger, config config.GithubClientConfig) (*githubClient, error) {
@ -40,6 +43,8 @@ func NewClient(logger *slog.Logger, config config.GithubClientConfig) (*githubCl
organizationNameToIDMap: map[string]int64{}, organizationNameToIDMap: map[string]int64{},
organizationCache: map[int64]*Organization{}, organizationCache: map[int64]*Organization{},
userNameToIDMap: map[string]int64{},
userCache: map[int64]*User{},
} }
return gitHubClient, nil return gitHubClient, nil
@ -57,6 +62,15 @@ func (c *githubClient) FetchRootGroupContent() (map[string]fstree.GroupSource, e
rootContent[org.Name] = org rootContent[org.Name] = org
} }
} }
for _, user_name := range c.GithubClientConfig.UserNames {
user, err := c.fetchUser(user_name)
if err != nil {
c.logger.Warn(err.Error())
} else {
rootContent[user.Name] = user
}
}
// TODO: user + current user // TODO: user + current user
c.rootContent = rootContent c.rootContent = rootContent
@ -68,5 +82,8 @@ func (c *githubClient) FetchGroupContent(gid uint64) (map[string]fstree.GroupSou
if org, found := c.organizationCache[int64(gid)]; found { if org, found := c.organizationCache[int64(gid)]; found {
return c.fetchOrganizationContent(org) return c.fetchOrganizationContent(org)
} }
if user, found := c.userCache[int64(gid)]; found {
return c.fetchUserContent(user)
}
return nil, nil, fmt.Errorf("invalid gid: %v", gid) return nil, nil, fmt.Errorf("invalid gid: %v", gid)
} }

View File

@ -62,6 +62,7 @@ func (c *githubClient) fetchOrganization(org_name string) (*Organization, error)
// save in cache // save in cache
c.organizationCacheMux.Lock() c.organizationCacheMux.Lock()
c.organizationCache[newOrg.ID] = &newOrg c.organizationCache[newOrg.ID] = &newOrg
c.organizationNameToIDMap[newOrg.Name] = newOrg.ID
c.organizationCacheMux.Unlock() c.organizationCacheMux.Unlock()
return &newOrg, nil return &newOrg, nil

View File

@ -1 +1,105 @@
package github package github
import (
"context"
"fmt"
"sync"
"github.com/badjware/gitlabfs/fstree"
"github.com/google/go-github/v63/github"
)
type User struct {
ID int64
Name string
mux sync.Mutex
// hold user content
childRepositories map[string]fstree.RepositorySource
}
func (u *User) GetGroupID() uint64 {
return uint64(u.ID)
}
func (u *User) InvalidateContentCache() {
u.mux.Lock()
defer u.mux.Unlock()
// clear child repositories from cache
u.childRepositories = nil
}
func (c *githubClient) fetchUser(user_name string) (*User, error) {
c.userCacheMux.RLock()
cachedId, found := c.userNameToIDMap[user_name]
if found {
cachedUser := c.userCache[cachedId]
c.userCacheMux.RUnlock()
// if found in cache, return the cached reference
c.logger.Debug("User cache hit", "user_name", user_name)
return cachedUser, nil
} else {
c.userCacheMux.RUnlock()
c.logger.Debug("User cache miss", "user_name", user_name)
}
// If not found in cache, fetch user infos from API
githubUser, _, err := c.client.Users.Get(context.Background(), user_name)
if err != nil {
return nil, fmt.Errorf("failed to fetch user with name %v: %v", user_name, err)
}
newUser := User{
ID: *githubUser.ID,
Name: *githubUser.Login,
childRepositories: nil,
}
// save in cache
c.userCacheMux.Lock()
c.userCache[newUser.ID] = &newUser
c.userNameToIDMap[newUser.Name] = newUser.ID
c.userCacheMux.Unlock()
return &newUser, nil
}
func (c *githubClient) fetchUserContent(user *User) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
user.mux.Lock()
defer user.mux.Unlock()
// Get cached data if available
// TODO: cache cache invalidation?
if user.childRepositories == nil {
childRepositories := make(map[string]fstree.RepositorySource)
// Fetch the user repositories
repositoryListOpt := &github.RepositoryListByUserOptions{
ListOptions: github.ListOptions{PerPage: 100},
}
for {
githubRepositories, response, err := c.client.Repositories.ListByUser(context.Background(), user.Name, repositoryListOpt)
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch repository in github: %v", err)
}
for _, githubRepository := range githubRepositories {
repository := c.newRepositoryFromGithubRepository(githubRepository)
if repository != nil {
childRepositories[repository.Path] = repository
}
}
if response.NextPage == 0 {
break
}
// Get the next page
repositoryListOpt.Page = response.NextPage
}
user.childRepositories = childRepositories
}
return make(map[string]fstree.GroupSource), user.childRepositories, nil
}