blob: 0861d76f8b058674d5070a724781b7a7f965f7eb [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"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027)
28
Stephane Barbariedc5022d2018-11-19 15:21:44 -050029// DataRevision stores the data associated to a revision along with its calculated checksum hash value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040030type DataRevision struct {
31 Data interface{}
32 Hash string
33}
34
Stephane Barbariedc5022d2018-11-19 15:21:44 -050035// NewDataRevision creates a new instance of a DataRevision structure
36func NewDataRevision(root *root, data interface{}) *DataRevision {
37 dr := DataRevision{}
38 dr.Data = data
39 dr.Hash = dr.hashData(root, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040040
Stephane Barbariedc5022d2018-11-19 15:21:44 -050041 return &dr
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040042}
43
Stephane Barbariedc5022d2018-11-19 15:21:44 -050044func (dr *DataRevision) hashData(root *root, data interface{}) string {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040045 var buffer bytes.Buffer
46
47 if IsProtoMessage(data) {
48 if pbdata, err := proto.Marshal(data.(proto.Message)); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000049 logger.Debugf("problem to marshal protobuf data --> err: %s", err.Error())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040050 } else {
51 buffer.Write(pbdata)
Stephane Barbariedc5022d2018-11-19 15:21:44 -050052 // To ensure uniqueness in case data is nil, also include data type
53 buffer.Write([]byte(reflect.TypeOf(data).String()))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040054 }
55
56 } else if reflect.ValueOf(data).IsValid() {
57 dataObj := reflect.New(reflect.TypeOf(data).Elem())
58 if json, err := json.Marshal(dataObj.Interface()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000059 logger.Debugf("problem to marshal data --> err: %s", err.Error())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040060 } else {
61 buffer.Write(json)
62 }
63 } else {
64 dataObj := reflect.New(reflect.TypeOf(data).Elem())
65 buffer.Write(dataObj.Bytes())
66 }
67
Stephane Barbariedc5022d2018-11-19 15:21:44 -050068 // Add the root pointer that owns the current data for extra uniqueness
69 rootPtr := fmt.Sprintf("%p", root)
70 buffer.Write([]byte(rootPtr))
71
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040072 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
73}