github.com/cs3org/reva/v2@v2.27.7/pkg/mentix/meshdata/meshdata.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package meshdata
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/gob"
    24  	"encoding/json"
    25  	"fmt"
    26  	"reflect"
    27  	"strings"
    28  )
    29  
    30  const (
    31  	// StatusDefault signals that this is just regular data.
    32  	StatusDefault = iota
    33  
    34  	// StatusObsolete flags the mesh data for removal.
    35  	StatusObsolete
    36  )
    37  
    38  // MeshData holds the entire mesh data managed by Mentix.
    39  type MeshData struct {
    40  	Sites        []*Site
    41  	ServiceTypes []*ServiceType
    42  
    43  	Status int `json:"-"`
    44  }
    45  
    46  // Clear removes all saved data, leaving an empty mesh.
    47  func (meshData *MeshData) Clear() {
    48  	meshData.Sites = nil
    49  	meshData.ServiceTypes = nil
    50  
    51  	meshData.Status = StatusDefault
    52  }
    53  
    54  // AddSite adds a new site; if a site with the same ID already exists, the existing one is overwritten.
    55  func (meshData *MeshData) AddSite(site *Site) {
    56  	if siteExisting := meshData.FindSite(site.ID); siteExisting != nil {
    57  		*siteExisting = *site
    58  	} else {
    59  		meshData.Sites = append(meshData.Sites, site)
    60  	}
    61  }
    62  
    63  // RemoveSite removes the provided site.
    64  func (meshData *MeshData) RemoveSite(site *Site) {
    65  	for idx, siteExisting := range meshData.Sites {
    66  		if strings.EqualFold(siteExisting.ID, site.ID) { // Remove the site by its ID
    67  			lastIdx := len(meshData.Sites) - 1
    68  			meshData.Sites[idx] = meshData.Sites[lastIdx]
    69  			meshData.Sites[lastIdx] = nil
    70  			meshData.Sites = meshData.Sites[:lastIdx]
    71  			break
    72  		}
    73  	}
    74  }
    75  
    76  // FindSite searches for a site with the given ID.
    77  func (meshData *MeshData) FindSite(id string) *Site {
    78  	for _, site := range meshData.Sites {
    79  		if strings.EqualFold(site.ID, id) {
    80  			return site
    81  		}
    82  	}
    83  	return nil
    84  }
    85  
    86  // AddServiceType adds a new service type; if a type with the same name already exists, the existing one is overwritten.
    87  func (meshData *MeshData) AddServiceType(serviceType *ServiceType) {
    88  	if svcTypeExisting := meshData.FindServiceType(serviceType.Name); svcTypeExisting != nil {
    89  		*svcTypeExisting = *serviceType
    90  	} else {
    91  		meshData.ServiceTypes = append(meshData.ServiceTypes, serviceType)
    92  	}
    93  }
    94  
    95  // RemoveServiceType removes the provided service type.
    96  func (meshData *MeshData) RemoveServiceType(serviceType *ServiceType) {
    97  	for idx, svcTypeExisting := range meshData.ServiceTypes {
    98  		if strings.EqualFold(svcTypeExisting.Name, serviceType.Name) { // Remove the service type by its name
    99  			lastIdx := len(meshData.ServiceTypes) - 1
   100  			meshData.ServiceTypes[idx] = meshData.ServiceTypes[lastIdx]
   101  			meshData.ServiceTypes[lastIdx] = nil
   102  			meshData.ServiceTypes = meshData.ServiceTypes[:lastIdx]
   103  			break
   104  		}
   105  	}
   106  }
   107  
   108  // FindServiceType searches for a service type with the given name.
   109  func (meshData *MeshData) FindServiceType(name string) *ServiceType {
   110  	for _, serviceType := range meshData.ServiceTypes {
   111  		if strings.EqualFold(serviceType.Name, name) {
   112  			return serviceType
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  // Merge merges data from another MeshData instance into this one.
   119  func (meshData *MeshData) Merge(inData *MeshData) {
   120  	for _, site := range inData.Sites {
   121  		meshData.AddSite(site)
   122  	}
   123  
   124  	for _, serviceType := range inData.ServiceTypes {
   125  		meshData.AddServiceType(serviceType)
   126  	}
   127  }
   128  
   129  // Unmerge removes data from another MeshData instance from this one.
   130  func (meshData *MeshData) Unmerge(inData *MeshData) {
   131  	for _, site := range inData.Sites {
   132  		meshData.RemoveSite(site)
   133  	}
   134  
   135  	for _, serviceType := range inData.ServiceTypes {
   136  		meshData.RemoveServiceType(serviceType)
   137  	}
   138  }
   139  
   140  // Verify checks if the mesh data is valid.
   141  func (meshData *MeshData) Verify() error {
   142  	// Verify all sites
   143  	for _, site := range meshData.Sites {
   144  		if err := site.Verify(); err != nil {
   145  			return err
   146  		}
   147  	}
   148  
   149  	// Verify all service types
   150  	for _, serviceType := range meshData.ServiceTypes {
   151  		if err := serviceType.Verify(); err != nil {
   152  			return err
   153  		}
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  // InferMissingData infers missing data from other data where possible.
   160  func (meshData *MeshData) InferMissingData() {
   161  	// Infer missing site data
   162  	for _, site := range meshData.Sites {
   163  		site.InferMissingData()
   164  	}
   165  
   166  	// Infer missing service type data
   167  	for _, serviceType := range meshData.ServiceTypes {
   168  		serviceType.InferMissingData()
   169  	}
   170  }
   171  
   172  // ToJSON converts the data to JSON.
   173  func (meshData *MeshData) ToJSON() (string, error) {
   174  	data, err := json.MarshalIndent(meshData, "", "\t")
   175  	if err != nil {
   176  		return "", fmt.Errorf("unable to marshal the mesh data: %v", err)
   177  	}
   178  	return string(data), nil
   179  }
   180  
   181  // FromJSON converts JSON data to mesh data.
   182  func (meshData *MeshData) FromJSON(data string) error {
   183  	meshData.Clear()
   184  	if err := json.Unmarshal([]byte(data), meshData); err != nil {
   185  		return fmt.Errorf("unable to unmarshal the mesh data: %v", err)
   186  	}
   187  	return nil
   188  }
   189  
   190  // Clone creates an exact copy of the mesh data.
   191  func (meshData *MeshData) Clone() *MeshData {
   192  	clone := &MeshData{}
   193  
   194  	// To avoid any "deep copy" packages, use gob en- and decoding instead
   195  	var buf bytes.Buffer
   196  	enc := gob.NewEncoder(&buf)
   197  	dec := gob.NewDecoder(&buf)
   198  
   199  	if err := enc.Encode(meshData); err == nil {
   200  		if err := dec.Decode(clone); err != nil {
   201  			// In case of an error, clear the data
   202  			clone.Clear()
   203  		}
   204  	}
   205  
   206  	return clone
   207  }
   208  
   209  // Compare checks whether the stored data equals the data of another MeshData object.
   210  func (meshData *MeshData) Compare(other *MeshData) bool {
   211  	return reflect.DeepEqual(meshData, other)
   212  }
   213  
   214  // New returns a new (empty) MeshData object.
   215  func New() *MeshData {
   216  	meshData := &MeshData{}
   217  	meshData.Clear()
   218  	return meshData
   219  }