enhancement: add error origin information to the errorcode package

This commit is contained in:
Florian Schade
2024-06-19 15:57:35 +02:00
parent 1f012ac9b5
commit 3280b22ffe
12 changed files with 180 additions and 153 deletions
@@ -547,75 +547,6 @@ func (s *service) UpdateReceivedShare(ctx context.Context, req *collaboration.Up
}, nil
}
// GetAvailableMountpoint returns a new or existing mountpoint
func GetAvailableMountpoint(ctx context.Context, gwc gateway.GatewayAPIClient, id *provider.ResourceId, name string, userId *userpb.UserId) (string, error) {
listReceivedSharesReq := &collaboration.ListReceivedSharesRequest{}
if userId != nil {
listReceivedSharesReq.Opaque = utils.AppendJSONToOpaque(nil, "userid", userId)
}
listReceivedSharesRes, err := gwc.ListReceivedShares(ctx, listReceivedSharesReq)
if err != nil {
return "", errtypes.InternalError("grpc list received shares request failed")
}
if err := errtypes.NewErrtypeFromStatus(listReceivedSharesRes.GetStatus()); err != nil {
return "", err
}
base := filepath.Clean(name)
mount := base
existingMountpoint := ""
mountedShares := make([]string, 0, len(listReceivedSharesRes.GetShares()))
var pathExists bool
for _, s := range listReceivedSharesRes.GetShares() {
resourceIDEqual := utils.ResourceIDEqual(s.GetShare().GetResourceId(), id)
if resourceIDEqual && s.State == collaboration.ShareState_SHARE_STATE_ACCEPTED {
// a share to the resource already exists and is mounted, remembers the mount point
_, err := utils.GetResourceByID(ctx, s.GetShare().GetResourceId(), gwc)
if err == nil {
existingMountpoint = s.GetMountPoint().GetPath()
}
}
if s.State == collaboration.ShareState_SHARE_STATE_ACCEPTED {
// collect all accepted mount points
mountedShares = append(mountedShares, s.GetMountPoint().GetPath())
if s.GetMountPoint().GetPath() == mount {
// does the shared resource still exist?
_, err := utils.GetResourceByID(ctx, s.GetShare().GetResourceId(), gwc)
if err == nil {
pathExists = true
}
// TODO we could delete shares here if the stat returns code NOT FOUND ... but listening for file deletes would be better
}
}
}
if existingMountpoint != "" {
// we want to reuse the same mountpoint for all unmounted shares to the same resource
return existingMountpoint, nil
}
// If the mount point really already exists, we need to insert a number into the filename
if pathExists {
// now we have a list of shares, we want to iterate over all of them and check for name collisions agents a mount points list
for i := 1; i <= len(mountedShares)+1; i++ {
ext := filepath.Ext(base)
name := strings.TrimSuffix(base, ext)
mount = name + " (" + strconv.Itoa(i) + ")" + ext
if !slices.Contains(mountedShares, mount) {
return mount, nil
}
}
}
return mount, nil
}
func setReceivedShareMountPoint(ctx context.Context, gwc gateway.GatewayAPIClient, req *collaboration.UpdateReceivedShareRequest) (*rpc.Status, error) {
receivedShare, err := gwc.GetReceivedShare(ctx, &collaboration.GetReceivedShareRequest{
Ref: &collaboration.ShareReference{
@@ -653,7 +584,7 @@ func setReceivedShareMountPoint(ctx context.Context, gwc gateway.GatewayAPIClien
_ = utils.ReadJSONFromOpaque(req.Opaque, "userid", &userID)
// check if the requested mount point is available and if not, find a suitable one
availableMountpoint, err := GetAvailableMountpoint(ctx, gwc,
availableMountpoint, _, err := GetMountpointAndUnmountedShares(ctx, gwc,
resourceStat.GetInfo().GetId(),
resourceStat.GetInfo().GetName(),
userID,
@@ -673,3 +604,78 @@ func setReceivedShareMountPoint(ctx context.Context, gwc gateway.GatewayAPIClien
return status.NewOK(ctx), nil
}
// GetMountpointAndUnmountedShares returns a new or existing mountpoint for the given info and produces a list of unmounted received shares for the same resource
func GetMountpointAndUnmountedShares(ctx context.Context, gwc gateway.GatewayAPIClient, id *provider.ResourceId, name string, userId *userpb.UserId) (string, []*collaboration.ReceivedShare, error) {
listReceivedSharesReq := &collaboration.ListReceivedSharesRequest{}
if userId != nil {
listReceivedSharesReq.Opaque = utils.AppendJSONToOpaque(nil, "userid", userId)
}
listReceivedSharesRes, err := gwc.ListReceivedShares(ctx, listReceivedSharesReq)
if err != nil {
return "", nil, errtypes.InternalError("grpc list received shares request failed")
}
if err := errtypes.NewErrtypeFromStatus(listReceivedSharesRes.GetStatus()); err != nil {
return "", nil, err
}
unmountedShares := []*collaboration.ReceivedShare{}
base := filepath.Clean(name)
mount := base
existingMountpoint := ""
mountedShares := make([]string, 0, len(listReceivedSharesRes.GetShares()))
var pathExists bool
for _, s := range listReceivedSharesRes.GetShares() {
resourceIDEqual := utils.ResourceIDEqual(s.GetShare().GetResourceId(), id)
if resourceIDEqual && s.State == collaboration.ShareState_SHARE_STATE_ACCEPTED {
// a share to the resource already exists and is mounted, remembers the mount point
_, err := utils.GetResourceByID(ctx, s.GetShare().GetResourceId(), gwc)
if err == nil {
existingMountpoint = s.GetMountPoint().GetPath()
}
}
if resourceIDEqual && s.State != collaboration.ShareState_SHARE_STATE_ACCEPTED {
// a share to the resource already exists but is not mounted, collect the unmounted share
unmountedShares = append(unmountedShares, s)
}
if s.State == collaboration.ShareState_SHARE_STATE_ACCEPTED {
// collect all accepted mount points
mountedShares = append(mountedShares, s.GetMountPoint().GetPath())
if s.GetMountPoint().GetPath() == mount {
// does the shared resource still exist?
_, err := utils.GetResourceByID(ctx, s.GetShare().GetResourceId(), gwc)
if err == nil {
pathExists = true
}
// TODO we could delete shares here if the stat returns code NOT FOUND ... but listening for file deletes would be better
}
}
}
if existingMountpoint != "" {
// we want to reuse the same mountpoint for all unmounted shares to the same resource
return existingMountpoint, unmountedShares, nil
}
// If the mount point really already exists, we need to insert a number into the filename
if pathExists {
// now we have a list of shares, we want to iterate over all of them and check for name collisions agents a mount points list
for i := 1; i <= len(mountedShares)+1; i++ {
ext := filepath.Ext(base)
name := strings.TrimSuffix(base, ext)
mount = name + " (" + strconv.Itoa(i) + ")" + ext
if !slices.Contains(mountedShares, mount) {
return mount, unmountedShares, nil
}
}
}
return mount, unmountedShares, nil
}
@@ -34,11 +34,11 @@ import (
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/fieldmaskpb"
"github.com/cs3org/reva/v2/internal/grpc/services/usershareprovider"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/conversions"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/utils"
)
const (
@@ -73,8 +73,13 @@ func (h *Handler) AcceptReceivedShare(w http.ResponseWriter, r *http.Request) {
response.WriteOCSResponse(w, r, *ocsResponse, nil)
return
}
unmountedShares, err := getUnmountedShares(ctx, client, sharedResource.GetInfo().GetId())
mount, unmountedShares, err := usershareprovider.GetMountpointAndUnmountedShares(
ctx,
client,
sharedResource.GetInfo().GetId(),
sharedResource.GetInfo().GetName(),
nil,
)
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "could not determine mountpoint", err)
return
@@ -82,8 +87,12 @@ func (h *Handler) AcceptReceivedShare(w http.ResponseWriter, r *http.Request) {
// first update the requested share
receivedShare.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
// we need to add a path to the share
receivedShare.MountPoint = &provider.Reference{
Path: mount,
}
updateMask := &fieldmaskpb.FieldMask{Paths: []string{"state"}}
updateMask := &fieldmaskpb.FieldMask{Paths: []string{"state", "mount_point"}}
data, meta, err := h.updateReceivedShare(r.Context(), receivedShare, updateMask)
if err != nil {
// we log an error for affected shares, for the actual share we return an error
@@ -100,6 +109,10 @@ func (h *Handler) AcceptReceivedShare(w http.ResponseWriter, r *http.Request) {
}
rs.State = collaboration.ShareState_SHARE_STATE_ACCEPTED
// set the same mountpoint as for the requested received share
rs.MountPoint = &provider.Reference{
Path: mount,
}
_, _, err := h.updateReceivedShare(r.Context(), rs, updateMask)
if err != nil {
@@ -314,25 +327,6 @@ func getReceivedShareFromID(ctx context.Context, client gateway.GatewayAPIClient
return s.Share, nil
}
func getUnmountedShares(ctx context.Context, gwc gateway.GatewayAPIClient, id *provider.ResourceId) ([]*collaboration.ReceivedShare, error) {
var unmountedShares []*collaboration.ReceivedShare
receivedShares, err := listReceivedShares(ctx, gwc)
if err != nil {
return unmountedShares, err
}
for _, s := range receivedShares {
resourceIDEqual := utils.ResourceIDEqual(s.GetShare().GetResourceId(), id)
if resourceIDEqual && s.State != collaboration.ShareState_SHARE_STATE_ACCEPTED {
// a share to the resource already exists but is not mounted, collect the unmounted share
unmountedShares = append(unmountedShares, s)
}
}
return unmountedShares, err
}
// getSharedResource attempts to get a shared resource from the storage from the resource reference.
func getSharedResource(ctx context.Context, client gateway.GatewayAPIClient, resID *provider.ResourceId) (*provider.StatResponse, *response.Response) {
res, err := client.Stat(ctx, &provider.StatRequest{