blob: c2155d09bd9d919c5b414bb2571f23cf5430a813 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package storage
import (
"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/normalpath"
)
// Mapper is a path mapper.
//
// This will cause a Bucket to operate as if the Mapper has all paths mapped.
type Mapper interface {
// Map maps the path to the full path.
//
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
// If the path cannot be mapped, this returns false.
MapPath(path string) (string, bool)
// Map maps the prefix to the full prefix.
//
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
// If the path cannot be mapped, this returns false.
MapPrefix(prefix string) (string, bool)
// UnmapFullPath maps the full path to the path.
//
// Returns false if the full path does not apply.
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
UnmapFullPath(fullPath string) (string, bool, error)
isMapper()
}
// MapOnPrefix returns a Mapper that will map the Bucket as if it was created on the given prefix.
//
// The prefix is expected to be normalized and validated.
func MapOnPrefix(prefix string) Mapper {
return prefixMapper{prefix}
}
// MapChain chains the mappers.
//
// If any mapper does not match, this stops checking Mappers and returns
// an empty path and false. This is as opposed to MatchAnd, that runs
// every Matcher and returns the path regardless.
//
// If the Mappers are empty, a no-op Mapper is returned.
// If there is more than one Mapper, the Mappers are called in order
// for UnmapFullPath, with the order reversed for MapPath and MapPrefix.
//
// That is, order these assuming you are starting with a full path and
// working to a path.
func MapChain(mappers ...Mapper) Mapper {
switch len(mappers) {
case 0:
return nopMapper{}
case 1:
return mappers[0]
default:
return chainMapper{mappers}
}
}
// ***** private *****
type prefixMapper struct {
prefix string
}
func (p prefixMapper) MapPath(path string) (string, bool) {
return normalpath.Join(p.prefix, path), true
}
func (p prefixMapper) MapPrefix(prefix string) (string, bool) {
return normalpath.Join(p.prefix, prefix), true
}
func (p prefixMapper) UnmapFullPath(fullPath string) (string, bool, error) {
if !normalpath.EqualsOrContainsPath(p.prefix, fullPath, normalpath.Relative) {
return "", false, nil
}
path, err := normalpath.Rel(p.prefix, fullPath)
if err != nil {
return "", false, err
}
return path, true, nil
}
func (prefixMapper) isMapper() {}
type chainMapper struct {
mappers []Mapper
}
func (c chainMapper) MapPath(path string) (string, bool) {
return c.mapFunc(path, Mapper.MapPath)
}
func (c chainMapper) MapPrefix(prefix string) (string, bool) {
return c.mapFunc(prefix, Mapper.MapPrefix)
}
func (c chainMapper) UnmapFullPath(fullPath string) (string, bool, error) {
path := fullPath
var matches bool
var err error
for _, mapper := range c.mappers {
path, matches, err = mapper.UnmapFullPath(path)
if err != nil {
return "", false, err
}
if !matches {
return "", false, nil
}
}
return path, true, nil
}
func (c chainMapper) mapFunc(
pathOrPrefix string,
f func(Mapper, string) (string, bool),
) (string, bool) {
fullPathOrPrefix := pathOrPrefix
var matches bool
for i := len(c.mappers) - 1; i >= 0; i-- {
mapper := c.mappers[i]
fullPathOrPrefix, matches = f(mapper, fullPathOrPrefix)
if !matches {
return "", false
}
}
return fullPathOrPrefix, true
}
func (chainMapper) isMapper() {}
type nopMapper struct{}
func (n nopMapper) MapPath(path string) (string, bool) {
return path, true
}
func (n nopMapper) MapPrefix(prefix string) (string, bool) {
return prefix, true
}
func (nopMapper) UnmapFullPath(fullPath string) (string, bool, error) {
return fullPath, true, nil
}
func (nopMapper) isMapper() {}