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

298 lines
6.3 KiB
Go

package settings
import (
"context"
"fmt"
"strings"
"sync"
"go-micro.dev/v4/errors"
"github.com/urfave/cli/v2"
"jochum.dev/jo-micro/auth2"
"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"
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) client(ctx context.Context) (settingspb.SettingsService, context.Context, error) {
// Wait until the service is here
_, err := utils.ServiceRetryGet(h.cReg.Service(), config.Name, 10)
if err != nil {
return nil, ctx, err
}
service := settingspb.NewSettingsService(config.Name, h.cReg.Service().Client())
// Optional Service Account
if err := auth2.RegHasClientAuth(h.cReg); err == nil {
ctx, err = auth2.ClientAuthMustReg(h.cReg).Plugin().ServiceContext(ctx)
if err != nil {
return nil, ctx, err
}
}
return service, ctx, 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 errors.InternalServerError("ALREADY_INITIALIZED", "already initialized")
}
h.cReg = cReg
h.initialized = true
return nil
}
func (h *Handler) Stop() error {
h.initialized = false
return nil
}
func (h *Handler) Health(context context.Context) error {
if !h.Initialized() {
return errors.InternalServerError("NOT_INITIALIZED", "not initialized")
}
return nil
}
func (h *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
h.cacheGetLock.RLock()
if result, ok := h.cacheGet[cacheKey]; ok {
h.cacheGetLock.RUnlock()
return result, nil
}
h.cacheGetLock.RUnlock()
client, ctx, err := h.client(ctx)
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
h.cacheGetLock.Lock()
h.cacheGet[cacheKey] = cResult
h.cacheGetLock.Unlock()
return cResult, nil
}
func (h *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
h.cacheListLock.RLock()
if result, ok := h.cacheList[cacheKey]; ok {
h.cacheListLock.RUnlock()
return result, nil
}
h.cacheListLock.RUnlock()
// Fetch
client, ctx, err := h.client(ctx)
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
h.cacheListLock.Lock()
h.cacheList[cacheKey] = cResult
h.cacheListLock.Unlock()
return cResult, nil
}
func (h *Handler) Create(ctx context.Context, req CreateRequest) (*Setting, error) {
// Create
client, ctx, err := h.client(ctx)
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 (h *Handler) Update(ctx context.Context, req UpdateRequest) (*Setting, error) {
// Update
client, ctx, err := h.client(ctx)
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 (h *Handler) Upsert(ctx context.Context, req UpsertRequest) (*Setting, error) {
// Upsert
client, ctx, err := h.client(ctx)
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)
}