package services import ( "context" "errors" "fmt" "log/slog" "sync" "code.tczkiot.com/wlw/ai-agent/identity" "code.tczkiot.com/wlw/ai-agent/internal/pkg/enums" "code.tczkiot.com/wlw/ai-agent/internal/pkg/openidentity" ) var SubjectService = &subjectService{} type subjectService struct { mu sync.RWMutex query identity.QuerySubjectsFunc authorize identity.AuthorizeFunc } func SetQuerySubjects(query identity.QuerySubjectsFunc) { SubjectService.mu.Lock() defer SubjectService.mu.Unlock() SubjectService.query = query } func SetAuthorize(authorize identity.AuthorizeFunc) { SubjectService.mu.Lock() defer SubjectService.mu.Unlock() SubjectService.authorize = authorize } func (s *subjectService) Authorize(ctx context.Context, operation string) error { s.mu.RLock() fn := s.authorize s.mu.RUnlock() if fn == nil { return errors.New("ai-agent: Authorize is not initialized") } return fn(ctx, operation) } func (s *subjectService) Query(ctx context.Context, query identity.Query) ([]identity.Subject, error) { s.mu.RLock() fn := s.query s.mu.RUnlock() if fn == nil { return nil, errors.New("ai-agent: QuerySubjects is not initialized") } return fn(ctx, query) } func (s *subjectService) Current(ctx context.Context) (*identity.Subject, error) { items, err := s.Query(ctx, identity.Query{Current: true, EnabledOnly: true}) if err != nil { return nil, err } if len(items) == 0 { return nil, errors.New("ai-agent: current subject not found") } return &items[0], nil } func (s *subjectService) CurrentExternal(ctx context.Context) (*openidentity.ExternalUser, error) { subject, err := s.Current(ctx) if err != nil { return nil, err } if subject.Category != identity.CategoryUser || !subject.Enabled { return nil, errors.New("ai-agent: current subject is not a customer identity") } return &openidentity.ExternalUser{ ExternalSource: enums.ExternalSourceUser, ExternalID: fmt.Sprintf("%s:%d", subject.Type, subject.ID), ExternalName: subject.Name, }, nil } func (s *subjectService) Get(id int64) *identity.Subject { items, err := s.Query(context.Background(), identity.Query{ Types: []identity.SubjectType{identity.SubjectAgent}, IDs: []int64{id}, EnabledOnly: true, }) if err != nil { slog.Warn("query external subject failed", "id", id, "error", err) return nil } if len(items) == 0 { return nil } return &items[0] } func (s *subjectService) FindByIDs(ids []int64) []identity.Subject { if len(ids) == 0 { return nil } items, err := s.Query(context.Background(), identity.Query{ Types: []identity.SubjectType{identity.SubjectAgent}, IDs: ids, EnabledOnly: true, }) if err != nil { slog.Warn("query external subjects failed", "error", err) return nil } return items }