This commit is contained in:
Radu Ioan Fericean
2013-05-24 10:37:40 +03:00
parent 1c943ff6a3
commit ba6fd4ae83
9 changed files with 364 additions and 151 deletions

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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 {

View File

@@ -19,34 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
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)}

114
rater/simple_marshaller.go Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>
*/
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
}

View File

@@ -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 <http://www.gnu.org/licenses/>
*/
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)
}
}

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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() {}