Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
@@ -0,0 +1,136 @@
package eventSVC
import (
"context"
"sync/atomic"
"github.com/qsfera/server/pkg/log"
"github.com/qsfera/server/services/policies/pkg/engine"
"github.com/opencloud-eu/reva/v2/pkg/events"
"go.opentelemetry.io/otel/trace"
)
// Service defines the service handlers.
type Service struct {
ctx context.Context
query string
log log.Logger
stream events.Stream
engine engine.Engine
tp trace.TracerProvider
stopCh chan struct{}
stopped *atomic.Bool
}
// New returns a service implementation for Service.
func New(ctx context.Context, stream events.Stream, logger log.Logger, tp trace.TracerProvider, engine engine.Engine, query string) (Service, error) {
svc := Service{
ctx: ctx,
log: logger,
query: query,
tp: tp,
engine: engine,
stream: stream,
stopCh: make(chan struct{}, 1),
stopped: new(atomic.Bool),
}
return svc, nil
}
// Run to fulfil Runner interface
func (s Service) Run() error {
ch, err := events.Consume(s.stream, "policies", events.StartPostprocessingStep{})
if err != nil {
return err
}
EventLoop:
for {
select {
case <-s.stopCh:
break EventLoop
case e, ok := <-ch:
if !ok {
break EventLoop
}
err := s.processEvent(e)
if err != nil {
return err
}
if s.stopped.Load() {
break EventLoop
}
}
}
return nil
}
// Close will make the policies service to stop processing, so the `Run`
// method can finish.
// TODO: Underlying services can't be stopped. This means that some goroutines
// will get stuck trying to push events through a channel nobody is reading
// from, so resources won't be freed and there will be memory leaks. For now,
// if the service is stopped, you should close the app soon after.
func (s Service) Close() {
if s.stopped.CompareAndSwap(false, true) {
close(s.stopCh)
}
}
func (s Service) processEvent(e events.Event) error {
ctx := e.GetTraceContext(s.ctx)
ctx, span := s.tp.Tracer("policies").Start(ctx, "processEvent")
defer span.End()
switch ev := e.Event.(type) {
case events.StartPostprocessingStep:
if ev.StepToStart != events.PPStepPolicies {
return nil
}
outcome := events.PPOutcomeContinue
if s.query != "" {
env := engine.Environment{
Stage: engine.StagePP,
Resource: engine.Resource{
Name: ev.Filename,
URL: ev.URL,
Size: ev.Filesize,
},
}
if ev.ExecutingUser != nil {
env.User = *ev.ExecutingUser
}
if ev.ResourceID != nil {
env.Resource.ID = *ev.ResourceID
}
result, err := s.engine.Evaluate(context.TODO(), s.query, env)
if err != nil {
s.log.Error().Err(err).Msg("unable evaluate policy")
}
if !result {
outcome = events.PPOutcomeDelete
}
}
if err := events.Publish(ctx, s.stream, events.PostprocessingStepFinished{
Outcome: outcome,
UploadID: ev.UploadID,
ExecutingUser: ev.ExecutingUser,
Filename: ev.Filename,
FinishedStep: ev.StepToStart,
}); err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,35 @@
package grpcSVC
import (
"context"
v0 "github.com/qsfera/server/protogen/gen/qsfera/services/policies/v0"
"github.com/qsfera/server/services/policies/pkg/engine"
)
// Service defines the service handlers.
type Service struct {
engine engine.Engine
}
// New returns a service implementation for Service.
func New(engine engine.Engine) (Service, error) {
svc := Service{
engine: engine,
}
return svc, nil
}
// Evaluate exposes the engine policy evaluation.
func (s Service) Evaluate(ctx context.Context, request *v0.EvaluateRequest, response *v0.EvaluateResponse) error {
env, err := engine.NewEnvironmentFromPB(request.Environment)
if err != nil {
return err
}
result, err := s.engine.Evaluate(ctx, request.Query, env)
response.Result = result
return err
}