mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-16 13:49:53 +05:00
working on tariff plans
This commit is contained in:
@@ -16,11 +16,15 @@ var (
|
||||
mongoserver = flag.String("mongoserver", "127.0.0.1:27017", "mongo server address (127.0.0.1:27017)")
|
||||
mongodb = flag.String("mdb", "test", "mongo database name (test)")
|
||||
redispass = flag.String("pass", "", "redis database password")
|
||||
apfile = flag.String("apfile", "ap.json", "Activation Periods containing intervals file")
|
||||
destfile = flag.String("destfile", "dest.json", "Destinations file")
|
||||
apfile = flag.String("apfile", "ap.json", "Activation Periods containing intervals file")
|
||||
destfile = flag.String("destfile", "dest.json", "Destinations file")
|
||||
tpfile = flag.String("tpfile", "tp.json", "Tariff plans file")
|
||||
)
|
||||
|
||||
func writeToStorage(storage timespans.StorageGetter,callDescriptors []*timespans.CallDescriptor,destinations []*timespans.Destination){
|
||||
func writeToStorage(storage timespans.StorageGetter,
|
||||
callDescriptors []*timespans.CallDescriptor,
|
||||
destinations []*timespans.Destination,
|
||||
tariffPlans []*timespans.TariffPlan) {
|
||||
for _, cd := range callDescriptors {
|
||||
storage.SetActivationPeriods(cd.GetKey(), cd.ActivationPeriods)
|
||||
log.Printf("Storing %q", cd.GetKey())
|
||||
@@ -29,18 +33,23 @@ func writeToStorage(storage timespans.StorageGetter,callDescriptors []*timespans
|
||||
storage.SetDestination(d)
|
||||
log.Printf("Storing %q", d.Id)
|
||||
}
|
||||
for _, tp := range tariffPlans {
|
||||
storage.SetTariffPlan(tp)
|
||||
log.Printf("Storing %q", tp.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
|
||||
log.Print("Reading from ", *apfile, *destfile)
|
||||
|
||||
// reading activation periods
|
||||
fin, err := os.Open(*apfile)
|
||||
|
||||
if err != nil {log.Print("Cannot open activation periods input file", err)}
|
||||
if err != nil {
|
||||
log.Print("Cannot open activation periods input file", err)
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(fin)
|
||||
|
||||
@@ -54,7 +63,9 @@ func main() {
|
||||
// reading destinations
|
||||
fin, err = os.Open(*destfile)
|
||||
|
||||
if err != nil {log.Print("Cannot open destinations input file", err)}
|
||||
if err != nil {
|
||||
log.Print("Cannot open destinations input file", err)
|
||||
}
|
||||
|
||||
dec = json.NewDecoder(fin)
|
||||
|
||||
@@ -65,19 +76,35 @@ func main() {
|
||||
}
|
||||
fin.Close()
|
||||
|
||||
// reading triff plans
|
||||
fin, err = os.Open(*tpfile)
|
||||
|
||||
if err != nil {
|
||||
log.Print("Cannot open tariff plans input file", err)
|
||||
}
|
||||
|
||||
dec = json.NewDecoder(fin)
|
||||
|
||||
var tariffPlans []*timespans.TariffPlan
|
||||
if err := dec.Decode(&tariffPlans); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
fin.Close()
|
||||
|
||||
switch *storage {
|
||||
case "kyoto":
|
||||
storage, _ := timespans.NewKyotoStorage(*kyotofile)
|
||||
defer storage.Close()
|
||||
writeToStorage(storage, callDescriptors, destinations)
|
||||
writeToStorage(storage, callDescriptors, destinations, tariffPlans)
|
||||
case "mongo":
|
||||
storage, _ := timespans.NewMongoStorage("127.0.0.1", "test")
|
||||
defer storage.Close()
|
||||
writeToStorage(storage, callDescriptors, destinations)
|
||||
writeToStorage(storage, callDescriptors, destinations, tariffPlans)
|
||||
|
||||
default:
|
||||
storage, _ := timespans.NewRedisStorage(*redisserver, *redisdb)
|
||||
defer storage.Close()
|
||||
writeToStorage(storage, callDescriptors, destinations)
|
||||
writeToStorage(storage, callDescriptors, destinations, tariffPlans)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) {
|
||||
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) + ";"
|
||||
var is string
|
||||
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
|
||||
for _, i := range ap.Intervals {
|
||||
var is string
|
||||
is = strconv.Itoa(int(i.Month)) + "|"
|
||||
is += strconv.Itoa(i.MonthDay) + "|"
|
||||
for _, wd := range i.WeekDays {
|
||||
|
||||
@@ -24,3 +24,15 @@ func (d *Destination) store() (result string) {
|
||||
func (d *Destination) restore(input string) {
|
||||
d.Prefixes = strings.Split(input, ",")
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if the bucket contains specified prefix.
|
||||
*/
|
||||
func (d *Destination) containsPrefix(prefix string) bool {
|
||||
for _, p := range d.Prefixes {
|
||||
if prefix == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import (
|
||||
func TestDestinationStoreRestore(t *testing.T) {
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
s := nationale.store()
|
||||
d1 := &Destination{Id: "nationale"}
|
||||
d1 := &Destination{Id: "nat"}
|
||||
d1.restore(s)
|
||||
if d1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, d1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestKyotoStore(t *testing.T) {
|
||||
func TestDestinationKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
@@ -25,7 +25,7 @@ func TestKyotoStore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedisStore(t *testing.T) {
|
||||
func TestDestinationRedisStore(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
@@ -36,7 +36,7 @@ func TestRedisStore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMongoStore(t *testing.T) {
|
||||
func TestDestinationMongoStore(t *testing.T) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
@@ -47,6 +47,16 @@ func TestMongoStore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationContainsPrefix(t *testing.T) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
if !nationale.containsPrefix("0256") {
|
||||
t.Error("Should contain prefix: ", nationale)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************* Benchmarks **********************************/
|
||||
|
||||
func BenchmarkDestinationKyotoStoreRestore(b *testing.B) {
|
||||
|
||||
@@ -51,3 +51,14 @@ func (ks *KyotoStorage) GetDestination(key string) (dest *Destination, err error
|
||||
func (ks *KyotoStorage) SetDestination(dest *Destination) {
|
||||
ks.db.Set(dest.Id, dest.store())
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
values, err := ks.db.Get(key)
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(values)
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetTariffPlan(tp *TariffPlan) {
|
||||
ks.db.Set(tp.Id, tp.store())
|
||||
}
|
||||
|
||||
@@ -4,17 +4,13 @@ type MinuteBucket struct {
|
||||
seconds int
|
||||
priority int
|
||||
price float64
|
||||
destinationId string
|
||||
destination *Destination
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if the bucket contains specified prefix.
|
||||
*/
|
||||
func (mb *MinuteBucket) containsPrefix(prefix string) bool {
|
||||
for _, p := range mb.destination.Prefixes {
|
||||
if prefix == p {
|
||||
return true
|
||||
}
|
||||
func (mb *MinuteBucket) getDestination(storage StorageGetter) (dest *Destination) {
|
||||
if mb.destination == nil {
|
||||
mb.destination,_ = storage.GetDestination(mb.destinationId)
|
||||
}
|
||||
return false
|
||||
return mb.destination
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDestination(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
mb := &MinuteBucket{destinationId: "nationale"}
|
||||
d := mb.getDestination(getter)
|
||||
if d.Id != "nationale" || len(d.Prefixes) != 4 {
|
||||
t.Error("Got wrong destination: ", d)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,3 +57,15 @@ func (ms *MongoStorage) SetDestination(dest *Destination) {
|
||||
ndb := ms.db.C("dest")
|
||||
ndb.Insert(&dest)
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetTariffPlan(key string) (result *TariffPlan, err error) {
|
||||
ndb := ms.db.C("tp")
|
||||
result = &TariffPlan{}
|
||||
err = ndb.Find(bson.M{"id": key}).One(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetTariffPlan(tp *TariffPlan) {
|
||||
ndb := ms.db.C("tp")
|
||||
ndb.Insert(&tp)
|
||||
}
|
||||
|
||||
@@ -56,3 +56,16 @@ func (rs *RedisStorage) SetDestination(dest *Destination) {
|
||||
rs.db.Select(rs.dbNb + 1)
|
||||
rs.db.Set(dest.Id, dest.store())
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
rs.db.Select(rs.dbNb + 2)
|
||||
values, err := rs.db.Get(key)
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(values.String())
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetTariffPlan(tp *TariffPlan) {
|
||||
rs.db.Select(rs.dbNb + 2)
|
||||
rs.db.Set(tp.Id, tp.store())
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ Interface for storage providers.
|
||||
*/
|
||||
type StorageGetter interface {
|
||||
Close()
|
||||
GetActivationPeriods(key string) ([]*ActivationPeriod, error)
|
||||
SetActivationPeriods(key string, aps []*ActivationPeriod)
|
||||
GetDestination(key string) (*Destination, error)
|
||||
SetDestination(dest *Destination)
|
||||
GetActivationPeriods(string) ([]*ActivationPeriod, error)
|
||||
SetActivationPeriods(string, []*ActivationPeriod)
|
||||
GetDestination(string) (*Destination, error)
|
||||
SetDestination(*Destination)
|
||||
GetTariffPlan(string) (*TariffPlan, error)
|
||||
SetTariffPlan(*TariffPlan)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,50 @@
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure describing a tariff plan's number of bonus items. It is uset to restore
|
||||
these numbers to the user budget every month.
|
||||
*/
|
||||
type TariffPlan struct {
|
||||
Id string
|
||||
SmsCredit int
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the activation periods for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) store() (result string) {
|
||||
result += strconv.Itoa(tp.SmsCredit) + ";"
|
||||
for _, mb := range tp.MinuteBuckets {
|
||||
var mbs string
|
||||
mbs += strconv.Itoa(int(mb.seconds)) + "|"
|
||||
mbs += strconv.Itoa(int(mb.priority)) + "|"
|
||||
mbs += strconv.FormatFloat(mb.price, 'f', -1, 64) + "|"
|
||||
mbs += mb.destinationId
|
||||
result += mbs + ";"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the activation periods for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
tp.SmsCredit,_ = strconv.Atoi(elements[0])
|
||||
for _, mbs := range elements[1 : len(elements)-1] {
|
||||
mb := &MinuteBucket{}
|
||||
mbse := strings.Split(mbs, "|")
|
||||
mb.seconds,_ = strconv.Atoi(mbse[0])
|
||||
mb.priority,_ = strconv.Atoi(mbse[1])
|
||||
mb.price,_ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.destinationId = mbse[3]
|
||||
|
||||
tp.MinuteBuckets = append(tp.MinuteBuckets, mb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTariffPlanStoreRestore(t *testing.T) {
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
s := seara.store()
|
||||
tp1 := &TariffPlan{Id: "seara"}
|
||||
tp1.restore(s)
|
||||
if tp1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, tp1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
t.Errorf("Expected %q was %q", seara, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanRedisStore(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
t.Errorf("Expected %q was %q", seara, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanMongoStore(t *testing.T) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if result.SmsCredit != seara.SmsCredit || len(result.MinuteBuckets) != len(seara.MinuteBuckets) {
|
||||
t.Errorf("Expected %q was %q", seara, result)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************* Benchmarks **********************************/
|
||||
|
||||
func BenchmarkTariffPlanKyotoStoreRestore(b *testing.B) {
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTariffPlanRedisStoreRestore(b *testing.B) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTariffPlanMongoStoreRestore(b *testing.B) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{seconds: 10, priority: 10, price: 0.01, destinationId: "nationale"}
|
||||
b2 := &MinuteBucket{seconds: 100, priority: 20, price: 0.0, destinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -20,7 +20,7 @@ type UserBudget struct {
|
||||
/*
|
||||
Returns user's avaliable minutes for the specified destination
|
||||
*/
|
||||
func (ub *UserBudget) GetSecondsForPrefix(prefix string) (seconds int) {
|
||||
func (ub *UserBudget) GetSecondsForPrefix(storage StorageGetter, prefix string) (seconds int) {
|
||||
if len(ub.minuteBuckets) == 0 {
|
||||
log.Print("There are no minute buckets to check for user", ub.id)
|
||||
return
|
||||
@@ -28,7 +28,8 @@ func (ub *UserBudget) GetSecondsForPrefix(prefix string) (seconds int) {
|
||||
bestBucket := ub.minuteBuckets[0]
|
||||
|
||||
for _, mb := range ub.minuteBuckets {
|
||||
if mb.containsPrefix(prefix) && mb.priority > bestBucket.priority {
|
||||
d := mb.getDestination(storage)
|
||||
if d.containsPrefix(prefix) && mb.priority > bestBucket.priority {
|
||||
bestBucket = mb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func TestGetSeconds(t *testing.T) {
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 200, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
seconds := ub1.GetSecondsForPrefix("0723")
|
||||
seconds := ub1.GetSecondsForPrefix(nil, "0723")
|
||||
expected := 100
|
||||
if seconds != expected {
|
||||
t.Errorf("Expected %v was %v", expected, seconds)
|
||||
@@ -28,7 +28,7 @@ func TestGetPricedSeconds(t *testing.T) {
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 21, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
seconds := ub1.GetSecondsForPrefix("0723")
|
||||
seconds := ub1.GetSecondsForPrefix(nil, "0723")
|
||||
expected := 21
|
||||
if seconds != expected {
|
||||
t.Errorf("Expected %v was %v", expected, seconds)
|
||||
@@ -46,6 +46,6 @@ func BenchmarkGetSecondForPrefix(b *testing.B) {
|
||||
ub1 := &UserBudget{id: "rif", minuteBuckets: []*MinuteBucket{b1, b2}, credit: 21, tariffPlan: tf1, resetDayOfTheMonth: 10}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ub1.GetSecondsForPrefix("0723")
|
||||
ub1.GetSecondsForPrefix(nil,"0723")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user