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 }