From ba6fd4ae832e323ca57c4836c14ebb78dc2eb3fb Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Fri, 24 May 2013 10:37:40 +0300 Subject: [PATCH] started --- rater/activationperiod.go | 32 ------ rater/activationperiod_test.go | 187 +++++++++++++++++++++++++------- rater/ratingprofile.go | 34 ------ rater/ratingprofile_test.go | 24 ---- rater/simple_marshaller.go | 114 +++++++++++++++++++ rater/simple_marshaller_test.go | 80 ++++++++++++++ rater/storage_gosexy.go | 3 +- rater/storage_interface.go | 39 +++---- rater/storage_map.go | 2 +- 9 files changed, 364 insertions(+), 151 deletions(-) create mode 100644 rater/simple_marshaller.go create mode 100644 rater/simple_marshaller_test.go diff --git a/rater/activationperiod.go b/rater/activationperiod.go index c9bd0a714..a06d037be 100644 --- a/rater/activationperiod.go +++ b/rater/activationperiod.go @@ -20,8 +20,6 @@ package rater import ( "github.com/cgrates/cgrates/cache2go" - "strconv" - "strings" "time" ) @@ -67,33 +65,3 @@ func (ap *ActivationPeriod) AddIntervalIfNotPresent(is ...*Interval) { func (ap *ActivationPeriod) Equal(o *ActivationPeriod) bool { return ap.ActivationTime == o.ActivationTime } - -/* -Serializes the activation periods for the storage. Used for key-value storages. -*/ -func (ap *ActivationPeriod) store() (result string) { - result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + "|" - for _, i := range ap.Intervals { - result += i.store() + "|" - } - result = strings.TrimRight(result, "|") - return -} - -/* -De-serializes the activation periods for the storage. Used for key-value storages. -*/ -func (ap *ActivationPeriod) restore(input string) { - elements := strings.Split(input, "|") - unixNano, _ := strconv.ParseInt(elements[0], 10, 64) - ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC) - els := elements[1:] - if len(els) > 1 { - els = elements[1 : len(elements)-1] - } - for _, is := range els { - i := &Interval{} - i.restore(is) - ap.Intervals = append(ap.Intervals, i) - } -} diff --git a/rater/activationperiod_test.go b/rater/activationperiod_test.go index 66c82586a..8e1c216e2 100644 --- a/rater/activationperiod_test.go +++ b/rater/activationperiod_test.go @@ -20,43 +20,12 @@ package rater import ( "encoding/json" + //"log" "reflect" "testing" "time" - //"log" ) -func TestApStoreRestore(t *testing.T) { - d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, - WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, - StartTime: "14:30:00", - EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) - result := ap.store() - expected := "1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0" - if result != expected { - t.Errorf("Expected %q was %q", expected, result) - } - ap1 := ActivationPeriod{} - ap1.restore(result) - if reflect.DeepEqual(ap, ap1) { - t.Errorf("Expected %v was %v", ap, ap1) - } -} - -func TestApRestoreFromString(t *testing.T) { - s := "1325376000000000000|;1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5,6,0;00:00:00;;10;0;0.2;60;1\n" - ap := ActivationPeriod{} - ap.restore(s) - if len(ap.Intervals) != 1 { - t.Error("Error restoring activation period from string", ap) - } -} - func TestApRestoreFromStorage(t *testing.T) { cd := &CallDescriptor{ Direction: "OUT", @@ -84,9 +53,9 @@ func TestApStoreRestoreJson(t *testing.T) { if string(result) != expected { t.Errorf("Expected %q was %q", expected, result) } - ap1 := ActivationPeriod{} - json.Unmarshal(result, &ap1) - if reflect.DeepEqual(ap, ap1) { + ap1 := &ActivationPeriod{} + json.Unmarshal(result, ap1) + if !reflect.DeepEqual(ap, ap1) { t.Errorf("Expected %v was %v", ap, ap1) } } @@ -190,9 +159,9 @@ func BenchmarkActivationPeriodStoreRestoreJson(b *testing.B) { } func BenchmarkActivationPeriodRestore(b *testing.B) { - ap := ActivationPeriod{} + ap := &ActivationPeriod{} for i := 0; i < b.N; i++ { - ap.restore("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0") + activationPeriodRestore("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0", ap) } } @@ -210,7 +179,147 @@ func BenchmarkActivationPeriodStoreRestore(b *testing.B) { ap1 := ActivationPeriod{} b.StartTimer() for i := 0; i < b.N; i++ { - result := ap.store() - ap1.restore(result) + result, _ := Marshal(ap) + Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerMyStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(MyMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerJSONStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(JSONMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerBSONStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(BSONMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerJSONBufStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(JSONBufMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerGOBStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(GOBMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerMsgpackStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(MsgpackMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) + } +} + +func BenchmarkActivationPeriodMarshallerGoMsgpStoreRestore(b *testing.B) { + b.StopTimer() + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{Months: []time.Month{time.February}, + MonthDays: []int{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + + ap1 := ActivationPeriod{} + b.StartTimer() + ms := new(GoMsgpackMarshaler) + for i := 0; i < b.N; i++ { + result, _ := ms.Marshal(ap) + ms.Unmarshal(result, ap1) } } diff --git a/rater/ratingprofile.go b/rater/ratingprofile.go index ef401457d..6002b581a 100644 --- a/rater/ratingprofile.go +++ b/rater/ratingprofile.go @@ -21,7 +21,6 @@ package rater import ( "errors" "fmt" - "strings" ) const ( @@ -35,39 +34,6 @@ type RatingProfile struct { DestinationMap map[string][]*ActivationPeriod } -func (rp *RatingProfile) store() (result string) { - result += rp.FallbackKey + ">" - for k, aps := range rp.DestinationMap { - result += k + "=" - for _, ap := range aps { - result += ap.store() + "<" - } - result = strings.TrimRight(result, "<") - result += ">" - } - result = strings.TrimRight(result, ">") - return -} - -func (rp *RatingProfile) restore(input string) { - if rp.DestinationMap == nil { - rp.DestinationMap = make(map[string][]*ActivationPeriod, 1) - } - elements := strings.Split(input, ">") - rp.FallbackKey = elements[0] - for _, kv := range elements[1:] { - pair := strings.SplitN(kv, "=", 2) - apList := strings.Split(pair[1], "<") - var newAps []*ActivationPeriod - for _, aps := range apList { - ap := new(ActivationPeriod) - ap.restore(aps) - newAps = append(newAps, ap) - } - rp.DestinationMap[pair[0]] = newAps - } -} - // Adds an activation period that applyes to current rating profile if not already present. func (rp *RatingProfile) AddActivationPeriodIfNotPresent(destInfo string, aps ...*ActivationPeriod) { if rp.DestinationMap == nil { diff --git a/rater/ratingprofile_test.go b/rater/ratingprofile_test.go index 5a329a23e..8daacf6ec 100644 --- a/rater/ratingprofile_test.go +++ b/rater/ratingprofile_test.go @@ -19,34 +19,10 @@ along with this program. If not, see package rater import ( - "reflect" "testing" "time" ) -func TestRpStoreRestore(t *testing.T) { - d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{ - Months: Months{time.February}, - MonthDays: MonthDays{1}, - WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, - StartTime: "14:30:00", - EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) - rp := &RatingProfile{FallbackKey: "test"} - rp.AddActivationPeriodIfNotPresent("0723", ap) - result := rp.store() - expected := "test>0723=1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0" - if result != expected { - t.Errorf("Expected %q was %q", expected, result) - } - ap1 := ActivationPeriod{} - ap1.restore(result) - if reflect.DeepEqual(ap, ap1) { - t.Errorf("Expected %v was %v", ap, ap1) - } -} func TestRpAddAPIfNotPresent(t *testing.T) { ap1 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} ap2 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)} diff --git a/rater/simple_marshaller.go b/rater/simple_marshaller.go new file mode 100644 index 000000000..604d88e99 --- /dev/null +++ b/rater/simple_marshaller.go @@ -0,0 +1,114 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package rater + +import ( + "errors" + "strconv" + "strings" + "time" +) + +func Marshal(v interface{}) ([]byte, error) { + switch i := v.(type) { + case *ActivationPeriod: + result, err := activationPeriodStore(i) + return []byte(result), err + case *RatingProfile: + result, err := ratingProfileStore(i) + return []byte(result), err + } + return nil, errors.New("Not supported type") +} + +func Unmarshal(data []byte, v interface{}) error { + switch i := v.(type) { + case *ActivationPeriod: + return activationPeriodRestore(string(data), i) + case *RatingProfile: + return ratingProfileRestore(string(data), i) + } + return errors.New("Not supported type") +} + +func activationPeriodStore(ap *ActivationPeriod) (result string, err error) { + result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + "|" + for _, i := range ap.Intervals { + result += i.store() + "|" + } + result = strings.TrimRight(result, "|") + return +} + +func activationPeriodRestore(input string, ap *ActivationPeriod) error { + elements := strings.Split(input, "|") + unixNano, _ := strconv.ParseInt(elements[0], 10, 64) + ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC) + els := elements[1:] + if len(els) > 1 { + els = elements[1 : len(elements)-1] + } + for _, is := range els { + i := &Interval{} + i.restore(is) + ap.Intervals = append(ap.Intervals, i) + } + return nil +} + +func ratingProfileStore(rp *RatingProfile) (result string, err error) { + result += rp.FallbackKey + ">" + for k, aps := range rp.DestinationMap { + result += k + "=" + for _, ap := range aps { + aps, err := activationPeriodStore(ap) + if err != nil { + return result, err + } + result += aps + "<" + } + result = strings.TrimRight(result, "<") + result += ">" + } + result = strings.TrimRight(result, ">") + return +} + +func ratingProfileRestore(input string, rp *RatingProfile) error { + if rp.DestinationMap == nil { + rp.DestinationMap = make(map[string][]*ActivationPeriod, 1) + } + elements := strings.Split(input, ">") + rp.FallbackKey = elements[0] + for _, kv := range elements[1:] { + pair := strings.SplitN(kv, "=", 2) + apList := strings.Split(pair[1], "<") + var newAps []*ActivationPeriod + for _, aps := range apList { + ap := new(ActivationPeriod) + err := activationPeriodRestore(aps, ap) + if err != nil { + return err + } + newAps = append(newAps, ap) + } + rp.DestinationMap[pair[0]] = newAps + } + return nil +} diff --git a/rater/simple_marshaller_test.go b/rater/simple_marshaller_test.go new file mode 100644 index 000000000..129528afe --- /dev/null +++ b/rater/simple_marshaller_test.go @@ -0,0 +1,80 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package rater + +import ( + "reflect" + "testing" + "time" +) + +func TestSimpleMarshallerApStoreRestore(t *testing.T) { + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{ + Months: Months{time.February}, + MonthDays: MonthDays{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + result, err := Marshal(ap) + expected := []byte("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0") + if err != nil || !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %q was %q", expected, result) + } + ap1 := &ActivationPeriod{} + err = Unmarshal(result, ap1) + if err != nil || !reflect.DeepEqual(ap, ap1) { + t.Errorf("Expected %v was %v: %v", ap, ap1, err) + } +} + +func TestSimpleMarshallerApRestoreFromString(t *testing.T) { + s := []byte("1325376000000000000|;1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5,6,0;00:00:00;;10;0;0.2;60;1\n") + ap := &ActivationPeriod{} + err := Unmarshal(s, ap) + if err != nil || len(ap.Intervals) != 1 { + t.Error("Error restoring activation period from string", ap) + } +} + +func TestRpStoreRestore(t *testing.T) { + d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) + i := &Interval{ + Months: Months{time.February}, + MonthDays: MonthDays{1}, + WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, + StartTime: "14:30:00", + EndTime: "15:00:00"} + ap := &ActivationPeriod{ActivationTime: d} + ap.AddInterval(i) + rp := &RatingProfile{FallbackKey: "test"} + rp.AddActivationPeriodIfNotPresent("0723", ap) + result, err := Marshal(rp) + expected := []byte("test>0723=1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0") + if err != nil || !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %q was %q", expected, result) + } + rp1 := &RatingProfile{} + err = Unmarshal(result, rp1) + if err != nil || !reflect.DeepEqual(rp, rp1) { + t.Errorf("Expected %v was %v", rp, rp1) + } +} diff --git a/rater/storage_gosexy.go b/rater/storage_gosexy.go index 7787ae754..6840131de 100644 --- a/rater/storage_gosexy.go +++ b/rater/storage_gosexy.go @@ -55,8 +55,7 @@ func NewGosexyStorage(address string, db int, pass string) (DataStorage, error) return nil, err } } - ms := new(MyMarshaler) - return &GosexyStorage{db: ndb, dbNb: db, ms: ms}, nil + return &GosexyStorage{db: ndb, dbNb: db, ms: new(MsgpackMarshaler)}, nil } func (rs *GosexyStorage) Close() { diff --git a/rater/storage_interface.go b/rater/storage_interface.go index d13d2c66b..359d99832 100644 --- a/rater/storage_interface.go +++ b/rater/storage_interface.go @@ -24,6 +24,7 @@ import ( "encoding/json" gmsgpack "github.com/ugorji/go-msgpack" "github.com/vmihailenco/msgpack" + "labix.org/v2/mgo/bson" "strings" ) @@ -86,22 +87,27 @@ func (jm *JSONMarshaler) Unmarshal(data []byte, v interface{}) error { return json.Unmarshal(data, v) } -type JSONBufMarshaler struct { - buf bytes.Buffer +type BSONMarshaler struct{} + +func (jm *BSONMarshaler) Marshal(v interface{}) ([]byte, error) { + return bson.Marshal(v) } +func (jm *BSONMarshaler) Unmarshal(data []byte, v interface{}) error { + return bson.Unmarshal(data, v) +} + +type JSONBufMarshaler struct{} + func (jbm *JSONBufMarshaler) Marshal(v interface{}) (data []byte, err error) { - jbm.buf.Reset() - if err = json.NewEncoder(&jbm.buf).Encode(v); err == nil { - data = jbm.buf.Bytes() - } + buf := new(bytes.Buffer) + err = json.NewEncoder(buf).Encode(v) + data = buf.Bytes() return } func (jbm *JSONBufMarshaler) Unmarshal(data []byte, v interface{}) error { - jbm.buf.Reset() - jbm.buf.Write(data) - return json.NewDecoder(&jbm.buf).Decode(v) + return json.NewDecoder(bytes.NewBuffer(data)).Decode(v) } type MsgpackMarshaler struct{} @@ -124,22 +130,17 @@ func (jm *GoMsgpackMarshaler) Unmarshal(data []byte, v interface{}) error { return gmsgpack.Unmarshal(data, v, nil) } -type GOBMarshaler struct { - buf bytes.Buffer -} +type GOBMarshaler struct{} func (gm *GOBMarshaler) Marshal(v interface{}) (data []byte, err error) { - gm.buf.Reset() - if err = gob.NewEncoder(&gm.buf).Encode(v); err == nil { - data = gm.buf.Bytes() - } + buf := new(bytes.Buffer) + err = gob.NewEncoder(buf).Encode(v) + data = buf.Bytes() return } func (gm *GOBMarshaler) Unmarshal(data []byte, v interface{}) error { - gm.buf.Reset() - gm.buf.Write(data) - return gob.NewDecoder(&gm.buf).Decode(v) + return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v) } type storer interface { diff --git a/rater/storage_map.go b/rater/storage_map.go index 5203b9253..4336279c3 100644 --- a/rater/storage_map.go +++ b/rater/storage_map.go @@ -31,7 +31,7 @@ type MapStorage struct { } func NewMapStorage() (DataStorage, error) { - return &MapStorage{dict: make(map[string][]byte), ms: new(MyMarshaler)}, nil + return &MapStorage{dict: make(map[string][]byte), ms: new(JSONMarshaler)}, nil } func (ms *MapStorage) Close() {}