blob: a0d5fc47652d47693b1261b1042c5167ecde923c [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040017package model
18
19import (
20 "bytes"
21 "crypto/md5"
22 "encoding/json"
23 "fmt"
npujar9a30c702019-11-14 17:06:39 +053024 "reflect"
25
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040026 "github.com/golang/protobuf/proto"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080027 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040028)
29
Stephane Barbariedc5022d2018-11-19 15:21:44 -050030// DataRevision stores the data associated to a revision along with its calculated checksum hash value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040031type DataRevision struct {
32 Data interface{}
33 Hash string
34}
35
Stephane Barbariedc5022d2018-11-19 15:21:44 -050036// NewDataRevision creates a new instance of a DataRevision structure
37func NewDataRevision(root *root, data interface{}) *DataRevision {
38 dr := DataRevision{}
39 dr.Data = data
40 dr.Hash = dr.hashData(root, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040041
Stephane Barbariedc5022d2018-11-19 15:21:44 -050042 return &dr
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040043}
44
Stephane Barbariedc5022d2018-11-19 15:21:44 -050045func (dr *DataRevision) hashData(root *root, data interface{}) string {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040046 var buffer bytes.Buffer
47
48 if IsProtoMessage(data) {
49 if pbdata, err := proto.Marshal(data.(proto.Message)); err != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050050 log.Debugf("problem to marshal protobuf data --> err: %s", err.Error())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040051 } else {
52 buffer.Write(pbdata)
Stephane Barbariedc5022d2018-11-19 15:21:44 -050053 // To ensure uniqueness in case data is nil, also include data type
54 buffer.Write([]byte(reflect.TypeOf(data).String()))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040055 }
56
57 } else if reflect.ValueOf(data).IsValid() {
58 dataObj := reflect.New(reflect.TypeOf(data).Elem())
59 if json, err := json.Marshal(dataObj.Interface()); err != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050060 log.Debugf("problem to marshal data --> err: %s", err.Error())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040061 } else {
62 buffer.Write(json)
63 }
64 } else {
65 dataObj := reflect.New(reflect.TypeOf(data).Elem())
66 buffer.Write(dataObj.Bytes())
67 }
68
Stephane Barbariedc5022d2018-11-19 15:21:44 -050069 // Add the root pointer that owns the current data for extra uniqueness
70 rootPtr := fmt.Sprintf("%p", root)
71 buffer.Write([]byte(rootPtr))
72
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040073 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
74}