Skip to content
Snippets Groups Projects
Select Git revision
  • 8190f92a5f6eb416f138574dc3c42f15dcc54d4c
  • main default protected
  • v1.298.0
  • v1.297.0
  • v1.296.0
  • v1.295.0
  • v1.294.0
  • v1.293.0
  • v1.292.0
  • v1.291.0
  • v1.290.0
  • v1.289.0
  • v1.288.0
  • v1.287.0
  • v1.286.0
  • v1.285.0
  • v1.284.0
  • v1.283.0
  • v1.282.0
  • v1.281.0
  • v1.280.0
  • v1.279.0
22 results

service.go

Blame
  • service.go 2.86 KiB
    package service
    
    import (
    	"context"
    	"os"
    
    	"gitlab.com/uafrica/go-utils/audit"
    	"gitlab.com/uafrica/go-utils/errors"
    	"gitlab.com/uafrica/go-utils/logger"
    	"gitlab.com/uafrica/go-utils/string_utils"
    )
    
    type Service interface {
    	logger.Logger
    	IErrorReporter
    	audit.Auditor
    	WithStarter(name string, starter IStarter) Service
    	WithProducer(producer Producer) Service
    	WithAuditor(auditor audit.Auditor) Service
    	WithErrorReporter(reporter IErrorReporter) Service
    	NewContext(base context.Context, requestID string, values map[string]interface{}) (Context, error)
    }
    
    func New() Service {
    	env := os.Getenv("ENVIRONMENT") //todo: support config loading for local dev and env for lambda in prod
    	if env == "" {
    		env = "dev"
    	}
    	return service{
    		Logger:         logger.New().WithFields(map[string]interface{}{"env": env}),
    		IErrorReporter: DoNotReportErrors{},
    		Auditor:        audit.None(),
    		env:            env,
    		starters:       map[string]IStarter{},
    	}
    }
    
    type service struct {
    	logger.Logger //for logging outside of context
    	Producer      //for sending async events
    	IErrorReporter
    	audit.Auditor
    	env      string
    	starters map[string]IStarter
    }
    
    func (s service) Env() string {
    	return s.env
    }
    
    //adds a starter function to call in each new context
    //they will be called in the sequence they were added (before api/cron/queue checks)
    //and they do not have details about the event
    //if starter returns error, processing fails
    //if starter succeeds, and return !=nil data, it is stored against the name
    //		so your handler can retieve it with:
    //			checkData := ctx.Value(name).(expectedType)
    //		or
    //			checkData,ok := ctx.Value(name).(expectedType)
    //			if !ok { ... }
    //you can implement one starter that does everything and return a struct or
    //implement one for your db, one for rate limit, one for ...
    //the name must be snake-case, e.g. "this_is_my_starter_name"
    func (s service) WithStarter(name string, starter IStarter) Service {
    	if !string_utils.IsSnakeCase(name) {
    		panic(errors.Errorf("invalid starter name=\"%s\", expecting snake_case names only", name))
    	}
    	if starter == nil {
    		panic(errors.Errorf("starter(%s)==nil", name))
    	}
    	if _, ok := s.starters[name]; ok {
    		panic(errors.Errorf("starter(%s) already defined", name))
    	}
    	s.starters[name] = starter
    	return s
    }
    
    func (s service) WithProducer(producer Producer) Service {
    	if producer != nil {
    		s.Producer = producer
    	}
    	return s
    }
    
    func (s service) WithErrorReporter(reporter IErrorReporter) Service {
    	if reporter == nil {
    		panic(errors.Errorf("ErrorReporter==nil"))
    	}
    	s.IErrorReporter = reporter
    	return s
    }
    
    func (s service) WithAuditor(auditor audit.Auditor) Service {
    	if auditor != nil {
    		s.Auditor = auditor
    	}
    	return s
    }
    
    type IErrorReporter interface {
    	ReportError(fields map[string]interface{}, err error)
    }
    
    type DoNotReportErrors struct{}
    
    func (DoNotReportErrors) ReportError(fields map[string]interface{}, err error) {}