You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
settings/settings.go

308 lines
6.3 KiB
Go

package settings
import (
"context"
"fmt"
"strings"
"sync"
"go-micro.dev/v4/errors"
"github.com/google/uuid"
"github.com/urfave/cli/v2"
"jochum.dev/jo-micro/components"
"jochum.dev/jo-micro/settings/cmd/microsettingsd/config"
"jochum.dev/jo-micro/settings/proto/settingspb"
"jochum.dev/jo-micro/settings/utils"
)
const Name = "settingsClient"
func serviceToClient(in *settingspb.Setting) (*Setting, error) {
id, err := uuid.Parse(in.Id)
if err != nil {
return nil, errors.FromError(err)
}
ownerID, _ := uuid.Parse(in.OwnerId)
return &Setting{
Id: id,
Service: in.Service,
OwnerID: ownerID,
Name: in.Name,
Content: in.Content,
CreatedAt: in.CreatedAt.AsTime(),
UpdatedAt: in.UpdatedAt.AsTime(),
}, nil
}
type Handler struct {
initialized bool
cReg *components.Registry
cacheGetLock *sync.RWMutex
cacheGet map[string]*Setting
cacheListLock *sync.RWMutex
cacheList map[string][]*Setting
}
func MustReg(cReg *components.Registry) *Handler {
return cReg.Must(Name).(*Handler)
}
func (h *Handler) sClient() (settingspb.SettingsService, error) {
// Wait until the service is here
_, err := utils.ServiceRetryGet(h.cReg.Service(), config.Name, 10)
if err != nil {
return nil, err
}
service := settingspb.NewSettingsService(config.Name, h.cReg.Service().Client())
return service, nil
}
// NewLog creates a new component
func New() *Handler {
return &Handler{
initialized: false,
cacheGetLock: &sync.RWMutex{},
cacheGet: make(map[string]*Setting),
cacheListLock: &sync.RWMutex{},
cacheList: make(map[string][]*Setting),
}
}
func (c *Handler) Priority() int {
return 30
}
func (c *Handler) Name() string {
return Name
}
func (c *Handler) Flags(cReg *components.Registry) []cli.Flag {
return []cli.Flag{
&cli.IntFlag{
Name: fmt.Sprintf("%s_settings_cachetime", strings.ToLower(cReg.FlagPrefix())),
Usage: "Time in seconds where settings caches your request",
Value: 3600,
},
}
}
func (c *Handler) Initialized() bool {
return c.initialized
}
func (h *Handler) Init(cReg *components.Registry, cli *cli.Context) error {
if h.initialized {
return nil
}
h.cReg = cReg
h.initialized = true
return nil
}
func (h *Handler) Stop() error {
h.initialized = false
return nil
}
func (c *Handler) Health(context context.Context) error {
if !c.Initialized() {
return errors.InternalServerError("NOT_INITIALIZED", "Not initialized")
}
return nil
}
func (c *Handler) Get(ctx context.Context, id, ownerId, service, name string) (*Setting, error) {
// Build the request
req := &settingspb.GetRequest{}
cacheKey := ""
if len(id) > 0 {
req.Id = id
cacheKey = id
} else if len(ownerId) > 0 {
req.OwnerId = ownerId
if len(name) > 0 {
req.Name = name
cacheKey = fmt.Sprintf("%s-%s", req.OwnerId, req.Name)
} else {
cacheKey = req.OwnerId
}
} else if len(service) > 0 {
req.Service = service
if len(name) > 0 {
req.Name = name
cacheKey = fmt.Sprintf("%s-%s", req.Service, req.Name)
} else {
cacheKey = req.Service
}
} else {
return nil, errors.BadRequest("INVALID_ARGUMENTS", "invalid arguments")
}
// Check cache and return from cache
c.cacheGetLock.RLock()
if result, ok := c.cacheGet[cacheKey]; ok {
c.cacheGetLock.RUnlock()
return result, nil
}
c.cacheGetLock.RUnlock()
client, err := c.sClient()
if err != nil {
return nil, err
}
result, err := client.Get(ctx, req)
if err != nil {
return nil, fmt.Errorf("%s: %s", cacheKey, err)
}
cResult, err := serviceToClient(result)
if err != nil {
return nil, err
}
// Store the result in cache
c.cacheGetLock.Lock()
c.cacheGet[cacheKey] = cResult
c.cacheGetLock.Unlock()
return cResult, nil
}
func (c *Handler) List(ctx context.Context, id, ownerId, service, name string) ([]*Setting, error) {
// Build the request
req := &settingspb.ListRequest{}
cacheKey := ""
if len(id) > 0 {
req.Id = id
cacheKey = id
} else if len(service) > 0 {
req.Service = service
if len(name) > 0 {
req.Name = name
cacheKey = fmt.Sprintf("%s-%s", req.Service, req.Name)
} else {
cacheKey = req.Service
}
} else if len(ownerId) > 0 {
req.OwnerId = ownerId
if len(name) > 0 {
req.Name = name
cacheKey = fmt.Sprintf("%s-%s", req.OwnerId, req.Name)
} else {
cacheKey = req.OwnerId
}
} else {
return nil, errors.BadRequest("INVALID_ARGUMENTS", "invalid arguments")
}
// Check cache and return from cache
c.cacheListLock.RLock()
if result, ok := c.cacheList[cacheKey]; ok {
c.cacheListLock.RUnlock()
return result, nil
}
c.cacheListLock.RUnlock()
// Fetch
client, err := c.sClient()
if err != nil {
return nil, err
}
result, err := client.List(ctx, req)
if err != nil {
return nil, err
}
cResult := make([]*Setting, len(result.Data))
for idx, s := range result.Data {
cS, err := serviceToClient(s)
if err != nil {
return nil, err
}
cResult[idx] = cS
}
// Store the result in cache
c.cacheListLock.Lock()
c.cacheList[cacheKey] = cResult
c.cacheListLock.Unlock()
return cResult, nil
}
func (c *Handler) Create(ctx context.Context, req CreateRequest) (*Setting, error) {
// Create
client, err := c.sClient()
if err != nil {
return nil, err
}
sReq := &settingspb.CreateRequest{
Service: req.Service,
OwnerId: req.OwnerId,
Name: req.Name,
Content: req.Content,
RolesRead: req.RolesRead,
RolesUpdate: req.RolesUpdate,
}
result, err := client.Create(ctx, sReq)
if err != nil {
return nil, err
}
return serviceToClient(result)
}
func (c *Handler) Update(ctx context.Context, req UpdateRequest) (*Setting, error) {
// Update
client, err := c.sClient()
if err != nil {
return nil, err
}
sReq := &settingspb.UpdateRequest{
Id: req.Id.String(),
Content: req.Content,
}
result, err := client.Update(ctx, sReq)
if err != nil {
return nil, err
}
return serviceToClient(result)
}
func (c *Handler) Upsert(ctx context.Context, req *UpsertRequest) (*Setting, error) {
// Upsert
client, err := c.sClient()
if err != nil {
return nil, err
}
sReq := &settingspb.UpsertRequest{
Id: req.Id.String(),
OwnerId: req.OwnerId.String(),
Service: req.Service,
Name: req.Name,
Content: req.Content,
RolesRead: req.RolesRead,
RolesUpdate: req.RolesUpdate,
}
result, err := client.Upsert(ctx, sReq)
if err != nil {
return nil, err
}
return serviceToClient(result)
}