Skip to content

Commit

Permalink
wtf
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
  • Loading branch information
butonic committed Dec 15, 2021
1 parent a92acf9 commit 743e7a3
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 96 deletions.
141 changes: 112 additions & 29 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,14 +725,11 @@ func (s *svc) Stat(ctx context.Context, req *provider.StatRequest) (*provider.St
continue
}

spaceID := ""
mountPath := providerInfos[i].ProviderPath

spacePaths := decodeSpacePaths(providerInfos[i].Opaque)
if len(spacePaths) == 0 {
spacePaths[""] = mountPath
spacePaths[""] = providerInfos[i].ProviderPath
}
for spaceID, mountPath = range spacePaths {
for spaceID, mountPath := range spacePaths {
var root *provider.ResourceId
rootSpace, rootNode := utils.SplitStorageSpaceID(spaceID)
if rootSpace != "" && rootNode != "" {
Expand Down Expand Up @@ -776,29 +773,88 @@ func (s *svc) Stat(ctx context.Context, req *provider.StatRequest) (*provider.St
continue
}

if requestPath != "" && strings.HasPrefix(mountPath, requestPath) { // when path is used and requested path is above mount point
if requestPath != "" {
if strings.HasPrefix(mountPath, requestPath) { // when path is used and requested path is above mount point
// mount path might be the reuqest path for file based shares
if mountPath != requestPath {
// mountpoint is deeper than the statted path
// -> make child a folder
statResp.Info.Type = provider.ResourceType_RESOURCE_TYPE_CONTAINER
statResp.Info.MimeType = "httpd/unix-directory"
// -> unset checksums for a folder
statResp.Info.Checksum = nil
if statResp.Info.Opaque != nil {
delete(statResp.Info.Opaque.Map, "md5")
delete(statResp.Info.Opaque.Map, "adler32")
}
}

// mount path might be the reuqest path for file based shares
if mountPath != requestPath {
// mountpoint is deeper than the statted path
// -> make child a folder
statResp.Info.Type = provider.ResourceType_RESOURCE_TYPE_CONTAINER
statResp.Info.MimeType = "httpd/unix-directory"
// -> unset checksums for a folder
statResp.Info.Checksum = nil
if statResp.Info.Opaque != nil {
delete(statResp.Info.Opaque.Map, "md5")
delete(statResp.Info.Opaque.Map, "adler32")
// -> update metadata for /foo/bar -> set path to './bar'?
statResp.Info.Path = strings.TrimPrefix(mountPath, requestPath)
statResp.Info.Path, _ = router.ShiftPath(statResp.Info.Path)
statResp.Info.Path = utils.MakeRelativePath(statResp.Info.Path)
// TODO invent resourceid?
if utils.IsAbsoluteReference(req.Ref) {
statResp.Info.Path = path.Join(requestPath, statResp.Info.Path)
}
}
} else {
// we need to check if the response info carries a root opaque to determine the correct mount point
if statResp.Info.Opaque != nil && statResp.Info.Opaque.Map != nil && statResp.Info.Opaque.Map["root"] != nil {
// we had an id based stat
// the info should carry the same id as the resource id
// the path should be relative to a root:
// if no "root" is in the opaque the path is relative to the mount point of the storage space?
// but that might be the personal space of another user where the current user has no access
// so we need to take the "root" in the opaque and find its mount point for the current user
spaceRoot := string(statResp.Info.Opaque.Map["root"].Value)
// what is the root to which the path of the statResp is relative?
/*spaceRootId := &provider.ResourceId{
StorageId: statResp.Info.Id.StorageId,
OpaqueId: spaceRoot,
}*/
// is there a share for the spaceRootId that we can use to build an absolute path
//-> try to find a mount point of a space with that id
// -> try to find a share for that file?
// the spaces registry should know the path or base name for that file

if spaceRoot == statResp.Info.Id.OpaqueId && rootNode == spaceRoot {
// all good
} else {
// we need to look up a space whose root is a cs3 reference to the root of the statResp
// now what? we are stating a shared resource from another space
// find space root with FindStorageProvider? but now we need a reference
shareProviderInfos, err := s.findProviders(ctx, &provider.Reference{ResourceId: &provider.ResourceId{
//StorageId: statResp.Info.Id.StorageId,
StorageId: "a0ca6a90-a365-4782-871e-d44447bbc668",
OpaqueId: spaceRoot,
}})
switch {
case err != nil:
appctx.GetLogger(ctx).Error().Err(err).Msg("gateway: error finding provider for root, skipping")
continue
case len(shareProviderInfos) < 1:
appctx.GetLogger(ctx).Error().Msg("gateway: no provider found for root, skipping")
continue
case len(shareProviderInfos) > 1:
appctx.GetLogger(ctx).Warn().Msg("gateway: more than one provider found for root, picking first")
// what if there is more than one provider? pick random one?
}
spaceID := ""
mp := shareProviderInfos[0].ProviderPath

// -> update metadata for /foo/bar -> set path to './bar'?
statResp.Info.Path = strings.TrimPrefix(mountPath, requestPath)
statResp.Info.Path, _ = router.ShiftPath(statResp.Info.Path)
statResp.Info.Path = utils.MakeRelativePath(statResp.Info.Path)
// TODO invent resourceid?
if utils.IsAbsoluteReference(req.Ref) {
statResp.Info.Path = path.Join(requestPath, statResp.Info.Path)
spacePaths := decodeSpacePaths(shareProviderInfos[0].Opaque)
if len(spacePaths) == 0 {
spacePaths[""] = mountPath
}
for spaceID, mp = range spacePaths {
shareRootSpace, shareRootNode := utils.SplitStorageSpaceID(spaceID)
if shareRootSpace == statResp.Info.Id.StorageId && shareRootNode == spaceRoot {
mountPath = mp
break // we have a matching space, use the current mount point
}
}
}
}
}
if statResp.Info.Id.StorageId == "" {
Expand All @@ -810,9 +866,20 @@ func (s *svc) Stat(ctx context.Context, req *provider.StatRequest) (*provider.St
switch {
case utils.IsAbsolutePathReference(req.Ref):
currentInfo.Path = requestPath
case utils.IsAbsoluteReference(req.Ref):
case utils.IsAbsoluteReference(req.Ref) /*|| req.Ref.Path == "."*/ :
// an id based reference needs to adjust the path in the response with the provider path
currentInfo.Path = path.Join(mountPath, currentInfo.Path)
if strings.HasSuffix(mountPath, currentInfo.Path) {
currentInfo.Path = mountPath
} else {
currentInfo.Path = path.Join(mountPath, currentInfo.Path)
}
/*
if rootNode == currentInfo.Id.OpaqueId {
currentInfo.Path = mountPath
} else {
currentInfo.Path = path.Join(mountPath, currentInfo.Path)
}
*/
}
info = currentInfo
} else {
Expand Down Expand Up @@ -1004,6 +1071,21 @@ func (s *svc) ListContainer(ctx context.Context, req *provider.ListContainerRequ
// TODO invent resourceid? or unset resourceid? derive from path?

if utils.IsAbsoluteReference(req.Ref) {
if statResp.Info.Path == "." {
// this feels too hacky:
// it triggers for pending share spaces: they should not be listed in the /Shares folder,
// pending shares have no mountpoint so the path tamplate which uses
// /users/{{.CurrentUser.Id.OpaqueId}}/Shares/{{.Share.Name}} currently will produce
// no child segment.
// - We could make the sharesstorageprovider list all references as spaces in its root and
// just use /users/{{.CurrentUser.Id.OpaqueId}}/Shares as the path template. A ListContainer
// for the root would list only CS3 references for accepted shares and the gateway could resolve them.
// -> we would be listing mount points / references as spaces, not shares
// But shares can be statted by id as well. Do we really want to return the same path as for the reference?
// The share manager keeps track of the shares and the mount points ... hmm
appctx.GetLogger(ctx).Debug().Msg("gateway: space path template produced no child segment, skipping")
continue
}
statResp.Info.Path = path.Join(requestPath, statResp.Info.Path)
}

Expand Down Expand Up @@ -1414,7 +1496,8 @@ func (s *svc) getStorageProviderClient(_ context.Context, p *registry.ProviderIn
return nil, err
}

return Cached(c, s.statCache), nil
//return Cached(c, s.statCache), nil
return c, nil
}

/*
Expand Down Expand Up @@ -1518,11 +1601,11 @@ func (s *svc) findProviders(ctx context.Context, ref *provider.Reference) ([]*re
return nil, errtypes.NotFound("gateway: provider is nil")
}

if ref.ResourceId != nil {
/*if ref.ResourceId != nil {
if err = s.providerCache.Set(ref.ResourceId.StorageId, res.Providers); err != nil {
appctx.GetLogger(ctx).Warn().Err(err).Interface("reference", ref).Msg("gateway: could not cache providers")
}
} /* else {
}*/ /* else {
// every user has a cache for mount points?
// the path map must be cached in the registry, not in the gateway?
// - in the registry we cannot determine if other spaces have been mounted or removed. if a new project space was mounted that happens in the registry
Expand Down
102 changes: 71 additions & 31 deletions internal/grpc/services/sharesstorageprovider/sharesstorageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,22 +304,18 @@ func (s *service) CreateStorageSpace(ctx context.Context, req *provider.CreateSt

func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSpacesRequest) (*provider.ListStorageSpacesResponse, error) {

var nodeid string
for _, f := range req.Filters {
switch f.Type {
case provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE:
if f.GetSpaceType() != "share" {
if f.GetSpaceType() != "reference" {
return &provider.ListStorageSpacesResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
}, nil
}
case provider.ListStorageSpacesRequest_Filter_TYPE_ID:
spaceid, _ := utils.SplitStorageSpaceID(f.GetId().OpaqueId)
if spaceid != utils.ShareStorageProviderID {
return &provider.ListStorageSpacesResponse{
// a specific id was requested, return not found instead of empty list
Status: &rpc.Status{Code: rpc.Code_CODE_NOT_FOUND},
}, nil
}
//var spaceid string
_, nodeid = utils.SplitStorageSpaceID(f.GetId().OpaqueId)
}
}

Expand All @@ -334,40 +330,51 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
res := &provider.ListStorageSpacesResponse{}
for i := range lsRes.Shares {

if lsRes.Shares[i].MountPoint == nil {
// the gateway needs a name to use as the path segment in the dir listing
//if lsRes.Shares[i].MountPoint == nil {
// TODO return all as type "share", only mounted ones below also as "reference"?
// the gateway needs a name to use as the path segment in the dir listing
// continue
//}
if nodeid != "" && nodeid != lsRes.Shares[i].Share.ResourceId.OpaqueId {
// only a specific share was requested
continue
}
space := &provider.StorageSpace{
Id: &provider.StorageSpaceId{
// Do we need a unique spaceid for every share?
// we are going to use the opaque id of the resource as the spaceid
// FIXME The storage space id should always equal the root id,
// however, the root is just the mount point. A resource the recipient can rename to his liking.
// It should be a reference pointig to the actual resource.
// The storagespaceprovider needs to be federated by teaching storage providers to keep track of all mount points
// -> maybe as liststoragespaces with space type = 'reference'?
OpaqueId: "a0ca6a90-a365-4782-871e-d44447bbc668!" + lsRes.Shares[i].Share.ResourceId.OpaqueId,
},
SpaceType: "share",
SpaceType: "reference", // TODO actually these are references/mount points: the receiving side of an accepted share
Owner: &userv1beta1.User{Id: lsRes.Shares[i].Share.Owner},
// return the actual resource id
//Root: lsRes.Shares[i].Share.ResourceId,
// the sharesstorageprovider keeps track of share references
Root: &provider.ResourceId{
StorageId: utils.ShareStorageProviderID,
OpaqueId: lsRes.Shares[i].Share.ResourceId.OpaqueId,
},
// TODO in the future the spaces registry will handle the alias for share spaces.
// for now use the name
Name: lsRes.Shares[i].MountPoint.Path,
}

// TODO the gateway needs to stat if it needs the mtime
/*
info, st, err := s.statResource(ctx, lsRes.Shares[i].Share.ResourceId, "")
if err != nil {
return nil, err
}
if st.Code != rpc.Code_CODE_OK {
continue
}
space.Mtime = info.Mtime
*/
sRes, err := s.gateway.Stat(ctx, &provider.StatRequest{
Opaque: req.Opaque,
Ref: &provider.Reference{
ResourceId: lsRes.Shares[i].Share.ResourceId,
},
})

if err == nil && sRes.Status.Code == rpc.Code_CODE_OK {
space.Name = filepath.Base(sRes.Info.Path)
space.Mtime = sRes.Info.Mtime
// TODO more metadata?
}

// TODO in the future the spaces registry will handle the alias for share spaces.
// for now use the name from the share to override the name determined by stat
if lsRes.Shares[i].MountPoint != nil {
space.Name = lsRes.Shares[i].MountPoint.Path
}

// what if we don't have a name?
res.StorageSpaces = append(res.StorageSpaces, space)
Expand Down Expand Up @@ -477,7 +484,14 @@ func (s *service) Move(ctx context.Context, req *provider.MoveRequest) (*provide
len(strings.SplitN(req.Destination.Path, "/", 3)) == 2 {

// Change the MountPoint of the share, it has no relative prefix
srcReceivedShare.MountPoint = &provider.Reference{Path: filepath.Base(req.Destination.Path)}
srcReceivedShare.MountPoint = &provider.Reference{
// FIXME actually it does have a resource id: the one of the sharesstorageprovider
//ResourceId: &provider.ResourceId{
// StorageId: "a0ca6a90-a365-4782-871e-d44447bbc668",
// OpaqueId: "a0ca6a90-a365-4782-871e-d44447bbc668", // FIXME or use the node id of the resource?
//},
Path: filepath.Base(req.Destination.Path),
}

_, err = s.sharesProviderClient.UpdateReceivedShare(ctx, &collaboration.UpdateReceivedShareRequest{
Share: srcReceivedShare,
Expand Down Expand Up @@ -535,15 +549,41 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
Status: rpcStatus,
}, nil
}
if receivedShare.State == collaboration.ShareState_SHARE_STATE_PENDING {
return &provider.StatResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_NOT_FOUND},
// not mounted yet
}, nil
}

return s.gateway.Stat(ctx, &provider.StatRequest{
/*
return &provider.StatResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
Info: &provider.ResourceInfo{
Type: provider.ResourceType_RESOURCE_TYPE_REFERENCE,
Id: &provider.ResourceId{
StorageId: "a0ca6a90-a365-4782-871e-d44447bbc668",
OpaqueId: receivedShare.Share.ResourceId.OpaqueId,
},
Target: utils.ResourceToTarget(receivedShare.Share.ResourceId),
},
}, nil
*/
sRes, err := s.gateway.Stat(ctx, &provider.StatRequest{
Opaque: req.Opaque,
Ref: &provider.Reference{
ResourceId: receivedShare.Share.ResourceId,
Path: req.Ref.Path,
},
ArbitraryMetadataKeys: req.ArbitraryMetadataKeys,
})

if err == nil && sRes.Status.Code == rpc.Code_CODE_OK {
sRes.Info.Id.StorageId = "a0ca6a90-a365-4782-871e-d44447bbc668"
//sRes.Info.Path = "" // the path of a share is determined by the mount point
}

return sRes, err
}

func (s *service) ListContainerStream(req *provider.ListContainerStreamRequest, ss provider.ProviderAPI_ListContainerStreamServer) error {
Expand Down
2 changes: 2 additions & 0 deletions internal/http/services/archiver/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ func (s *svc) getFiles(ctx context.Context, files, ids []string) ([]string, erro
},
},
})
// FIXME an id based stat on a shared file currently returns the owners path ... not the shared path ... hmm?
// has nothing to do with caching

switch {
case err != nil:
Expand Down
Loading

0 comments on commit 743e7a3

Please sign in to comment.