Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions pkg/scd/actions/constraint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package actions

import (
"context"

"github.com/golang/geo/s2"
restapi "github.com/interuss/dss/pkg/api/scdv1"
dsserr "github.com/interuss/dss/pkg/errors"
dssmodels "github.com/interuss/dss/pkg/models"
scdmodels "github.com/interuss/dss/pkg/scd/models"
"github.com/interuss/dss/pkg/scd/repos"
dssstore "github.com/interuss/dss/pkg/store"
"github.com/interuss/stacktrace"
"github.com/jackc/pgx/v5"
)

func init() {
Registry[restapi.DeleteConstraintReferenceOperationID] = dssstore.OperationHandler[repos.Repository]{
Encode: dssstore.EncodeJSON,
Decode: dssstore.DecodeJSON[*restapi.DeleteConstraintReferenceRequest],
Execute: ExecuteDeleteConstraint,
}
}

func ExecuteDeleteConstraint(ctx context.Context, repo repos.Repository, request dssstore.OperationRequest) (any, error) {
req, ok := request.(*restapi.DeleteConstraintReferenceRequest)
if !ok {
return nil, stacktrace.NewError("unexpected request type %T for operation %q", request, restapi.DeleteConstraintReferenceOperationID)
}

// Retrieve Constraint ID
id, err := dssmodels.IDFromString(string(req.Entityid))
if err != nil {
return nil, stacktrace.NewErrorWithCode(dsserr.BadRequest, "Invalid ID format: `%s`", req.Entityid)
}

// Make sure deletion request is valid
old, err := repo.GetConstraint(ctx, id)
switch {
case err == pgx.ErrNoRows:
return nil, stacktrace.NewErrorWithCode(dsserr.NotFound, "Constraint %s not found", id.String())
case err != nil:
return nil, stacktrace.Propagate(err, "Unable to get Constraint from repo")
case old.Manager != dssmodels.Manager(*req.Auth.ClientID):
return nil, stacktrace.NewErrorWithCode(dsserr.PermissionDenied,
"Constraint owned by %s, but %s attempted to delete", old.Manager, *req.Auth.ClientID)
case old.OVN != scdmodels.OVN(req.Ovn):
return nil, stacktrace.NewErrorWithCode(dsserr.VersionMismatch,
"Current version is %s but client specified version %s", old.OVN, scdmodels.OVN(req.Ovn))
}

// Delete Constraint in repo
err = repo.DeleteConstraint(ctx, id)
if err != nil {
return nil, stacktrace.Propagate(err, "Unable to delete Constraint from repo")
}

// Find the Subscriptions interested in Constraints and increment their
// notification indices.
subs, err := repo.IncrementNotificationIndicesForConstraints(ctx, &dssmodels.Volume4D{
StartTime: old.StartTime,
EndTime: old.EndTime,
SpatialVolume: &dssmodels.Volume3D{
AltitudeHi: old.AltitudeUpper,
AltitudeLo: old.AltitudeLower,
Footprint: dssmodels.GeometryFunc(func() (s2.CellUnion, error) {
return old.Cells, nil
}),
}})
if err != nil {
return nil, stacktrace.Propagate(err, "Unable to increment notification indices")
}

// Return response to client
return &restapi.ChangeConstraintReferenceResponse{
ConstraintReference: *old.ToRest(),
Subscribers: makeSubscribersToNotify(subs),
}, nil
}
23 changes: 23 additions & 0 deletions pkg/scd/actions/registry.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
package actions

import (
restapi "github.com/interuss/dss/pkg/api/scdv1"
scdmodels "github.com/interuss/dss/pkg/scd/models"
"github.com/interuss/dss/pkg/scd/repos"
dssstore "github.com/interuss/dss/pkg/store"
)

// Registry maps operation IDs to their handlers
var Registry = map[string]dssstore.OperationHandler[repos.Repository]{}

func makeSubscribersToNotify(subscriptions []*scdmodels.Subscription) []restapi.SubscriberToNotify {
result := []restapi.SubscriberToNotify{}

subscriptionsByURL := map[string][]restapi.SubscriptionState{}
for _, sub := range subscriptions {
subState := restapi.SubscriptionState{
SubscriptionId: restapi.SubscriptionID(sub.ID.String()),
NotificationIndex: restapi.SubscriptionNotificationIndex(sub.NotificationIndex),
}
subscriptionsByURL[sub.USSBaseURL] = append(subscriptionsByURL[sub.USSBaseURL], subState)
}
for url, states := range subscriptionsByURL {
result = append(result, restapi.SubscriberToNotify{
UssBaseUrl: restapi.SubscriptionUssBaseURL(url),
Subscriptions: states,
})
}

return result
}
55 changes: 3 additions & 52 deletions pkg/scd/constraints_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (a *Server) DeleteConstraintReference(ctx context.Context, req *restapi.Del
) restapi.DeleteConstraintReferenceResponseSet {

// Retrieve Constraint ID
id, err := dssmodels.IDFromString(string(req.Entityid))
_, err := dssmodels.IDFromString(string(req.Entityid))
if err != nil {
return restapi.DeleteConstraintReferenceResponseSet{Response400: &restapi.ErrorResponse{
Message: dsserr.Handle(ctx, stacktrace.NewErrorWithCode(dsserr.BadRequest, "Invalid ID format: `%s`", req.Entityid))}}
Expand All @@ -35,61 +35,12 @@ func (a *Server) DeleteConstraintReference(ctx context.Context, req *restapi.Del
}

// Retrieve OVN
ovn := scdmodels.OVN(req.Ovn)
if ovn == "" {
if req.Ovn == "" {
return restapi.DeleteConstraintReferenceResponseSet{Response400: &restapi.ErrorResponse{
Message: dsserr.Handle(ctx, stacktrace.NewErrorWithCode(dsserr.BadRequest, "Missing OVN for constraint to modify"))}}
}

var response *restapi.ChangeConstraintReferenceResponse
action := func(ctx context.Context, r repos.Repository) (err error) {
// Make sure deletion request is valid
old, err := r.GetConstraint(ctx, id)
switch {
case err == pgx.ErrNoRows:
return stacktrace.NewErrorWithCode(dsserr.NotFound, "Constraint %s not found", id.String())
case err != nil:
return stacktrace.Propagate(err, "Unable to get Constraint from repo")
case old.Manager != dssmodels.Manager(*req.Auth.ClientID):
return stacktrace.NewErrorWithCode(dsserr.PermissionDenied,
"Constraint owned by %s, but %s attempted to delete", old.Manager, *req.Auth.ClientID)
case old.OVN != ovn:
return stacktrace.NewErrorWithCode(dsserr.VersionMismatch,
"Current version is %s but client specified version %s", old.OVN, ovn)
}

// Delete Constraint in repo
err = r.DeleteConstraint(ctx, id)
if err != nil {
return stacktrace.Propagate(err, "Unable to delete Constraint from repo")
}

// Find the Subscriptions interested in Constraints and increment their
// notification indices.
subs, err := r.IncrementNotificationIndicesForConstraints(ctx, &dssmodels.Volume4D{
StartTime: old.StartTime,
EndTime: old.EndTime,
SpatialVolume: &dssmodels.Volume3D{
AltitudeHi: old.AltitudeUpper,
AltitudeLo: old.AltitudeLower,
Footprint: dssmodels.GeometryFunc(func() (s2.CellUnion, error) {
return old.Cells, nil
}),
}})
if err != nil {
return stacktrace.Propagate(err, "Unable to increment notification indices")
}

// Return response to client
response = &restapi.ChangeConstraintReferenceResponse{
ConstraintReference: *old.ToRest(),
Subscribers: makeSubscribersToNotify(subs),
}

return nil
}

_, err = a.Store.Transact(ctx, dssstore.NewFuncOperation(action))
response, err := dssstore.TransactWithResult[repos.Repository, *restapi.ChangeConstraintReferenceResponse](ctx, a.Store, req)
if err != nil {
err = stacktrace.Propagate(err, "Could not delete constraint")
errResp := &restapi.ErrorResponse{Message: dsserr.Handle(ctx, err)}
Expand Down
Loading