github.com/ali-iotechsys/cli@v20.10.0+incompatible/cli/context/store/metadatastore.go (about)

     1  package store
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"sort"
    11  
    12  	"github.com/fvbommel/sortorder"
    13  )
    14  
    15  const (
    16  	metadataDir = "meta"
    17  	metaFile    = "meta.json"
    18  )
    19  
    20  type metadataStore struct {
    21  	root   string
    22  	config Config
    23  }
    24  
    25  func (s *metadataStore) contextDir(id contextdir) string {
    26  	return filepath.Join(s.root, string(id))
    27  }
    28  
    29  func (s *metadataStore) createOrUpdate(meta Metadata) error {
    30  	contextDir := s.contextDir(contextdirOf(meta.Name))
    31  	if err := os.MkdirAll(contextDir, 0755); err != nil {
    32  		return err
    33  	}
    34  	bytes, err := json.Marshal(&meta)
    35  	if err != nil {
    36  		return err
    37  	}
    38  	return ioutil.WriteFile(filepath.Join(contextDir, metaFile), bytes, 0644)
    39  }
    40  
    41  func parseTypedOrMap(payload []byte, getter TypeGetter) (interface{}, error) {
    42  	if len(payload) == 0 || string(payload) == "null" {
    43  		return nil, nil
    44  	}
    45  	if getter == nil {
    46  		var res map[string]interface{}
    47  		if err := json.Unmarshal(payload, &res); err != nil {
    48  			return nil, err
    49  		}
    50  		return res, nil
    51  	}
    52  	typed := getter()
    53  	if err := json.Unmarshal(payload, typed); err != nil {
    54  		return nil, err
    55  	}
    56  	return reflect.ValueOf(typed).Elem().Interface(), nil
    57  }
    58  
    59  func (s *metadataStore) get(id contextdir) (Metadata, error) {
    60  	contextDir := s.contextDir(id)
    61  	bytes, err := ioutil.ReadFile(filepath.Join(contextDir, metaFile))
    62  	if err != nil {
    63  		return Metadata{}, convertContextDoesNotExist(err)
    64  	}
    65  	var untyped untypedContextMetadata
    66  	r := Metadata{
    67  		Endpoints: make(map[string]interface{}),
    68  	}
    69  	if err := json.Unmarshal(bytes, &untyped); err != nil {
    70  		return Metadata{}, err
    71  	}
    72  	r.Name = untyped.Name
    73  	if r.Metadata, err = parseTypedOrMap(untyped.Metadata, s.config.contextType); err != nil {
    74  		return Metadata{}, err
    75  	}
    76  	for k, v := range untyped.Endpoints {
    77  		if r.Endpoints[k], err = parseTypedOrMap(v, s.config.endpointTypes[k]); err != nil {
    78  			return Metadata{}, err
    79  		}
    80  	}
    81  	return r, err
    82  }
    83  
    84  func (s *metadataStore) remove(id contextdir) error {
    85  	contextDir := s.contextDir(id)
    86  	return os.RemoveAll(contextDir)
    87  }
    88  
    89  func (s *metadataStore) list() ([]Metadata, error) {
    90  	ctxDirs, err := listRecursivelyMetadataDirs(s.root)
    91  	if err != nil {
    92  		if os.IsNotExist(err) {
    93  			return nil, nil
    94  		}
    95  		return nil, err
    96  	}
    97  	var res []Metadata
    98  	for _, dir := range ctxDirs {
    99  		c, err := s.get(contextdir(dir))
   100  		if err != nil {
   101  			return nil, err
   102  		}
   103  		res = append(res, c)
   104  	}
   105  	sort.Slice(res, func(i, j int) bool {
   106  		return sortorder.NaturalLess(res[i].Name, res[j].Name)
   107  	})
   108  	return res, nil
   109  }
   110  
   111  func isContextDir(path string) bool {
   112  	s, err := os.Stat(filepath.Join(path, metaFile))
   113  	if err != nil {
   114  		return false
   115  	}
   116  	return !s.IsDir()
   117  }
   118  
   119  func listRecursivelyMetadataDirs(root string) ([]string, error) {
   120  	fis, err := ioutil.ReadDir(root)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	var result []string
   125  	for _, fi := range fis {
   126  		if fi.IsDir() {
   127  			if isContextDir(filepath.Join(root, fi.Name())) {
   128  				result = append(result, fi.Name())
   129  			}
   130  			subs, err := listRecursivelyMetadataDirs(filepath.Join(root, fi.Name()))
   131  			if err != nil {
   132  				return nil, err
   133  			}
   134  			for _, s := range subs {
   135  				result = append(result, fmt.Sprintf("%s/%s", fi.Name(), s))
   136  			}
   137  		}
   138  	}
   139  	return result, nil
   140  }
   141  
   142  func convertContextDoesNotExist(err error) error {
   143  	if os.IsNotExist(err) {
   144  		return &contextDoesNotExistError{}
   145  	}
   146  	return err
   147  }
   148  
   149  type untypedContextMetadata struct {
   150  	Metadata  json.RawMessage            `json:"metadata,omitempty"`
   151  	Endpoints map[string]json.RawMessage `json:"endpoints,omitempty"`
   152  	Name      string                     `json:"name,omitempty"`
   153  }