2019-07-06 18:53:20 +03:00
|
|
|
package services
|
|
|
|
|
|
|
|
import (
|
2021-01-21 02:26:52 +03:00
|
|
|
"errors"
|
2021-12-26 19:02:14 +03:00
|
|
|
"fmt"
|
2021-01-30 13:17:37 +03:00
|
|
|
"github.com/emvi/logbuch"
|
2020-09-29 19:55:07 +03:00
|
|
|
"github.com/muety/wakapi/config"
|
2021-01-21 02:26:52 +03:00
|
|
|
"github.com/muety/wakapi/models"
|
2020-11-01 18:56:36 +03:00
|
|
|
"github.com/muety/wakapi/repositories"
|
2019-10-10 17:47:19 +03:00
|
|
|
"sync"
|
2019-07-06 18:53:20 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type AliasService struct {
|
2020-11-01 18:56:36 +03:00
|
|
|
config *config.Config
|
2020-11-08 12:12:49 +03:00
|
|
|
repository repositories.IAliasRepository
|
2019-07-06 18:53:20 +03:00
|
|
|
}
|
|
|
|
|
2020-11-08 12:12:49 +03:00
|
|
|
func NewAliasService(aliasRepo repositories.IAliasRepository) *AliasService {
|
2020-05-24 18:32:26 +03:00
|
|
|
return &AliasService{
|
2020-11-01 18:56:36 +03:00
|
|
|
config: config.Get(),
|
|
|
|
repository: aliasRepo,
|
2020-05-24 18:32:26 +03:00
|
|
|
}
|
|
|
|
}
|
2019-07-06 18:53:20 +03:00
|
|
|
|
2020-05-24 18:32:26 +03:00
|
|
|
var userAliases sync.Map
|
2020-02-20 16:28:55 +03:00
|
|
|
|
2021-01-21 02:26:52 +03:00
|
|
|
func (srv *AliasService) IsInitialized(userId string) bool {
|
|
|
|
if _, ok := userAliases.Load(userId); ok {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *AliasService) InitializeUser(userId string) error {
|
2020-11-01 18:56:36 +03:00
|
|
|
aliases, err := srv.repository.GetByUser(userId)
|
|
|
|
if err == nil {
|
|
|
|
userAliases.Store(userId, aliases)
|
2019-07-06 18:53:20 +03:00
|
|
|
}
|
2020-11-01 18:56:36 +03:00
|
|
|
return err
|
2019-07-06 18:53:20 +03:00
|
|
|
}
|
|
|
|
|
2021-12-26 19:02:14 +03:00
|
|
|
func (srv *AliasService) MayInitializeUser(userId string) {
|
|
|
|
if err := srv.InitializeUser(userId); err != nil {
|
|
|
|
logbuch.Error("failed to initialize user alias map for user %s", userId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-21 02:26:52 +03:00
|
|
|
func (srv *AliasService) GetByUser(userId string) ([]*models.Alias, error) {
|
2021-12-26 19:02:14 +03:00
|
|
|
if !srv.IsInitialized(userId) {
|
|
|
|
srv.MayInitializeUser(userId)
|
|
|
|
}
|
|
|
|
if aliases, ok := userAliases.Load(userId); ok {
|
|
|
|
return aliases.([]*models.Alias), nil
|
|
|
|
} else {
|
|
|
|
return nil, errors.New(fmt.Sprintf("no user aliases loaded for user %s", userId))
|
2021-01-21 02:26:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 19:10:24 +03:00
|
|
|
func (srv *AliasService) GetByUserAndType(userId string, summaryType uint8) ([]*models.Alias, error) {
|
|
|
|
check := func(a *models.Alias) bool {
|
|
|
|
return a.Type == summaryType
|
2021-12-26 19:02:14 +03:00
|
|
|
}
|
2022-01-13 19:10:24 +03:00
|
|
|
return srv.getFiltered(userId, check)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *AliasService) GetByUserAndKeyAndType(userId, key string, summaryType uint8) ([]*models.Alias, error) {
|
|
|
|
check := func(a *models.Alias) bool {
|
|
|
|
return a.Key == key && a.Type == summaryType
|
2021-01-21 02:26:52 +03:00
|
|
|
}
|
2022-01-13 19:10:24 +03:00
|
|
|
return srv.getFiltered(userId, check)
|
2021-01-21 02:26:52 +03:00
|
|
|
}
|
|
|
|
|
2019-07-06 18:53:20 +03:00
|
|
|
func (srv *AliasService) GetAliasOrDefault(userId string, summaryType uint8, value string) (string, error) {
|
2020-11-01 18:03:30 +03:00
|
|
|
if !srv.IsInitialized(userId) {
|
2021-12-26 19:02:14 +03:00
|
|
|
srv.MayInitializeUser(userId)
|
2019-07-06 18:53:20 +03:00
|
|
|
}
|
2020-11-01 18:03:30 +03:00
|
|
|
|
2021-12-26 19:02:14 +03:00
|
|
|
if aliases, ok := userAliases.Load(userId); ok {
|
|
|
|
for _, a := range aliases.([]*models.Alias) {
|
|
|
|
if a.Type == summaryType && a.Value == value {
|
|
|
|
return a.Key, nil
|
|
|
|
}
|
2020-11-01 18:03:30 +03:00
|
|
|
}
|
|
|
|
}
|
2021-12-26 19:02:14 +03:00
|
|
|
|
2020-11-01 18:03:30 +03:00
|
|
|
return value, nil
|
2019-07-06 18:53:20 +03:00
|
|
|
}
|
|
|
|
|
2021-01-21 02:26:52 +03:00
|
|
|
func (srv *AliasService) Create(alias *models.Alias) (*models.Alias, error) {
|
|
|
|
result, err := srv.repository.Insert(alias)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-13 19:10:24 +03:00
|
|
|
// manually update cache
|
|
|
|
srv.updateCache(alias, false)
|
|
|
|
// reload entire cache (async, though)
|
2021-12-26 19:02:14 +03:00
|
|
|
go srv.MayInitializeUser(alias.UserID)
|
2022-01-13 19:10:24 +03:00
|
|
|
|
2021-01-21 02:26:52 +03:00
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *AliasService) Delete(alias *models.Alias) error {
|
|
|
|
if alias.UserID == "" {
|
|
|
|
return errors.New("no user id specified")
|
|
|
|
}
|
|
|
|
err := srv.repository.Delete(alias.ID)
|
2022-01-13 19:10:24 +03:00
|
|
|
|
|
|
|
// manually update cache
|
|
|
|
if err == nil {
|
|
|
|
srv.updateCache(alias, false)
|
|
|
|
}
|
|
|
|
// reload entire cache (async, though)
|
2021-12-26 19:02:14 +03:00
|
|
|
go srv.MayInitializeUser(alias.UserID)
|
2022-01-13 19:10:24 +03:00
|
|
|
|
2021-01-21 02:26:52 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *AliasService) DeleteMulti(aliases []*models.Alias) error {
|
|
|
|
ids := make([]uint, len(aliases))
|
|
|
|
affectedUsers := make(map[string]bool)
|
|
|
|
for i, a := range aliases {
|
|
|
|
if a.UserID == "" {
|
|
|
|
return errors.New("no user id specified")
|
|
|
|
}
|
|
|
|
affectedUsers[a.UserID] = true
|
|
|
|
ids[i] = a.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
err := srv.repository.DeleteBatch(ids)
|
|
|
|
|
2022-01-13 19:10:24 +03:00
|
|
|
// manually update cache
|
|
|
|
if err == nil {
|
|
|
|
for _, a := range aliases {
|
|
|
|
srv.updateCache(a, true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// reload entire cache (async, though)
|
2021-01-21 02:26:52 +03:00
|
|
|
for k := range affectedUsers {
|
2021-12-26 19:02:14 +03:00
|
|
|
go srv.MayInitializeUser(k)
|
2021-01-21 02:26:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
2022-01-13 19:10:24 +03:00
|
|
|
|
|
|
|
func (srv *AliasService) updateCache(reason *models.Alias, removal bool) {
|
|
|
|
if !removal {
|
|
|
|
if aliases, ok := userAliases.Load(reason.UserID); ok {
|
|
|
|
updatedAliases := aliases.([]*models.Alias)
|
|
|
|
updatedAliases = append(updatedAliases, reason)
|
|
|
|
userAliases.Store(reason.UserID, updatedAliases)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if aliases, ok := userAliases.Load(reason.UserID); ok {
|
|
|
|
updatedAliases := make([]*models.Alias, 0, len(aliases.([]*models.Alias))) // if we only had generics...
|
|
|
|
for _, a := range aliases.([]*models.Alias) {
|
|
|
|
if a.ID != reason.ID {
|
|
|
|
updatedAliases = append(updatedAliases, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
userAliases.Store(reason.UserID, updatedAliases)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *AliasService) getFiltered(userId string, check func(alias *models.Alias) bool) ([]*models.Alias, error) {
|
|
|
|
if !srv.IsInitialized(userId) {
|
|
|
|
srv.MayInitializeUser(userId)
|
|
|
|
}
|
|
|
|
if aliases, ok := userAliases.Load(userId); ok {
|
|
|
|
filteredAliases := make([]*models.Alias, 0, len(aliases.([]*models.Alias)))
|
|
|
|
for _, a := range aliases.([]*models.Alias) {
|
|
|
|
if check(a) {
|
|
|
|
filteredAliases = append(filteredAliases, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filteredAliases, nil
|
|
|
|
} else {
|
|
|
|
return nil, errors.New(fmt.Sprintf("no user aliases loaded for user %s", userId))
|
|
|
|
}
|
|
|
|
}
|