mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-24 16:48:45 +05:00
gob is creating extra problems
This commit is contained in:
@@ -47,7 +47,7 @@ func TestApRestoreRedis(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestApStoreRestore(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
|
||||
i := &Interval{Month: time.February,
|
||||
@@ -68,3 +68,23 @@ func TestApStoreRestore(t *testing.T) {
|
||||
}
|
||||
|
||||
/**************************** Benchmarks *************************************/
|
||||
|
||||
func BenchmarkActivationPeriodStoreRestore(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
|
||||
i := &Interval{Month: time.February,
|
||||
MonthDay: 1,
|
||||
WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
|
||||
StartTime: "14:30:00",
|
||||
EndTime: "15:00:00"}
|
||||
ap := &ActivationPeriod{ActivationTime: d}
|
||||
ap.AddInterval(i)
|
||||
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetActivationPeriods("storerestore", []*ActivationPeriod{ap})
|
||||
getter.GetActivationPeriods("storerestore")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) {
|
||||
|
||||
cost := 0.0
|
||||
for i, ts := range timespans {
|
||||
if ts.MinuteInfo == nil && i == 0 {
|
||||
if i == 0 && ts.MinuteInfo == nil && ts.Interval != nil {
|
||||
cost += ts.Interval.ConnectFee
|
||||
}
|
||||
cost += ts.GetCost(cd)
|
||||
|
||||
@@ -209,7 +209,7 @@ func TestMaxSessionTimeNoUserBudget(t *testing.T) {
|
||||
defer getter.Close()
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", storageGetter: getter, Amount: 1000}
|
||||
result, err := cd.GetMaxSessionTime()
|
||||
if result != 1000 || err != nil {
|
||||
if result != 1000 || err == nil {
|
||||
t.Errorf("Expected %v was %v", 1000, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package timespans
|
||||
|
||||
import (
|
||||
//"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure that gathers multiple destination prefixes under a common id.
|
||||
*/
|
||||
@@ -30,21 +25,6 @@ type Destination struct {
|
||||
Prefixes []string
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (d *Destination) store() (result string) {
|
||||
for _, p := range d.Prefixes {
|
||||
result += p + ","
|
||||
}
|
||||
result = strings.TrimRight(result, ",")
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Destination) restore(input string) {
|
||||
d.Prefixes = strings.Split(input, ",")
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
|
||||
@@ -21,16 +21,6 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDestinationStoreRestore(t *testing.T) {
|
||||
nationale = &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
s := nationale.store()
|
||||
d1 := &Destination{Id: "nat"}
|
||||
d1.restore(s)
|
||||
if d1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, d1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Rating system designed to be used in VoIP Carrieks World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
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.
|
||||
the Free Software Foundation, either veksion 3 of the License, or
|
||||
(at your option) any later veksion.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -21,25 +21,38 @@ import (
|
||||
"bitbucket.org/ww/cabinet"
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
//"github.com/fsouza/gokabinet/kc"
|
||||
// "log"
|
||||
//"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type KyotoStorage struct {
|
||||
//db *kc.DB
|
||||
db *cabinet.KCDB
|
||||
buf bytes.Buffer
|
||||
dec *gob.Decoder
|
||||
mux sync.Mutex // we need norma lock because we reset the buf variable
|
||||
db *cabinet.KCDB
|
||||
buf bytes.Buffer
|
||||
decAP *gob.Decoder
|
||||
encAP *gob.Encoder
|
||||
decDest *gob.Decoder
|
||||
encDest *gob.Encoder
|
||||
decTP *gob.Decoder
|
||||
encTP *gob.Encoder
|
||||
decUB *gob.Decoder
|
||||
encUB *gob.Encoder
|
||||
mux sync.Mutex // we need norma lock because we reset the buf variable
|
||||
}
|
||||
|
||||
func NewKyotoStorage(filaName string) (*KyotoStorage, error) {
|
||||
//ndb, err := kc.Open(filaName, kc.WRITE)
|
||||
ndb := cabinet.New()
|
||||
err := ndb.Open(filaName, cabinet.KCOWRITER|cabinet.KCOCREATE)
|
||||
ks := &KyotoStorage{db: ndb}
|
||||
ks.dec = gob.NewDecoder(&ks.buf)
|
||||
|
||||
ks.decAP = gob.NewDecoder(&ks.buf)
|
||||
ks.encAP = gob.NewEncoder(&ks.buf)
|
||||
ks.decDest = gob.NewDecoder(&ks.buf)
|
||||
ks.encDest = gob.NewEncoder(&ks.buf)
|
||||
ks.decTP = gob.NewDecoder(&ks.buf)
|
||||
ks.encTP = gob.NewEncoder(&ks.buf)
|
||||
ks.decUB = gob.NewDecoder(&ks.buf)
|
||||
ks.encUB = gob.NewEncoder(&ks.buf)
|
||||
return ks, err
|
||||
}
|
||||
|
||||
@@ -51,10 +64,9 @@ func (ks *KyotoStorage) SetActivationPeriods(key string, aps []*ActivationPeriod
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
var writeBuf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&writeBuf)
|
||||
encoder.Encode(aps)
|
||||
return ks.db.Set([]byte(key), writeBuf.Bytes())
|
||||
ks.buf.Reset()
|
||||
ks.encAP.Encode(aps)
|
||||
return ks.db.Set([]byte(key), ks.buf.Bytes())
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) {
|
||||
@@ -65,42 +77,69 @@ func (ks *KyotoStorage) GetActivationPeriods(key string) (aps []*ActivationPerio
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.buf.Write(values)
|
||||
ks.dec.Decode(&aps)
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetDestination(key string) (dest *Destination, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
dest = &Destination{Id: key}
|
||||
dest.restore(string(values))
|
||||
}
|
||||
ks.decAP.Decode(&aps)
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetDestination(dest *Destination) error {
|
||||
return ks.db.Set([]byte(dest.Id), []byte(dest.store()))
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.encDest.Encode(dest)
|
||||
return ks.db.Set([]byte(dest.Id), ks.buf.Bytes())
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(string(values))
|
||||
}
|
||||
func (ks *KyotoStorage) GetDestination(key string) (dest *Destination, err error) {
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
values, err := ks.db.Get([]byte(key))
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.buf.Write(values)
|
||||
ks.decDest.Decode(&dest)
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetTariffPlan(tp *TariffPlan) error {
|
||||
return ks.db.Set([]byte(tp.Id), []byte(tp.store()))
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.encTP.Encode(tp)
|
||||
return ks.db.Set([]byte(tp.Id), ks.buf.Bytes())
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetUserBudget(key string) (ub *UserBudget, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
ub = &UserBudget{Id: key}
|
||||
ub.restore(string(values))
|
||||
}
|
||||
func (ks *KyotoStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
values, err := ks.db.Get([]byte(key))
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.buf.Write(values)
|
||||
ks.decTP.Decode(&tp)
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetUserBudget(ub *UserBudget) error {
|
||||
return ks.db.Set([]byte(ub.Id), []byte(ub.store()))
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.encUB.Encode(ub)
|
||||
return ks.db.Set([]byte(ub.Id), ks.buf.Bytes())
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetUserBudget(key string) (ub *UserBudget, err error) {
|
||||
ks.mux.Lock()
|
||||
defer ks.mux.Unlock()
|
||||
|
||||
values, err := ks.db.Get([]byte(key))
|
||||
|
||||
ks.buf.Reset()
|
||||
ks.buf.Write(values)
|
||||
ks.decUB.Decode(&ub)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ package timespans
|
||||
import (
|
||||
// "log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MinuteBucket struct {
|
||||
@@ -33,28 +31,6 @@ type MinuteBucket struct {
|
||||
precision int
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the minute bucket for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (mb *MinuteBucket) store() (result string) {
|
||||
result += strconv.Itoa(int(mb.Seconds)) + "|"
|
||||
result += strconv.Itoa(int(mb.Priority)) + "|"
|
||||
result += strconv.FormatFloat(mb.Price, 'f', -1, 64) + "|"
|
||||
result += mb.DestinationId
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the minute bucket for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (mb *MinuteBucket) restore(input string) {
|
||||
elements := strings.Split(input, "|")
|
||||
mb.Seconds, _ = strconv.ParseFloat(elements[0], 64)
|
||||
mb.Priority, _ = strconv.Atoi(elements[1])
|
||||
mb.Price, _ = strconv.ParseFloat(elements[2], 64)
|
||||
mb.DestinationId = elements[3]
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the destination loading it from the storage if necessary.
|
||||
*/
|
||||
|
||||
@@ -30,3 +30,29 @@ func TestGetDestination(t *testing.T) {
|
||||
t.Error("Got wrong destination: ", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleGetDestination(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
mb := &MinuteBucket{DestinationId: "nationale"}
|
||||
d := mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
if d.Id != "nationale" || len(d.Prefixes) != 4 {
|
||||
t.Error("Got wrong destination: ", d)
|
||||
}
|
||||
/*mb = &MinuteBucket{DestinationId: "retea"}
|
||||
d = mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
if d.Id != "retea" || len(d.Prefixes) != 2 {
|
||||
t.Error("Got wrong destination: ", d)
|
||||
}
|
||||
mb = &MinuteBucket{DestinationId: "mobil"}
|
||||
d = mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
d = mb.getDestination(getter)
|
||||
if d.Id != "mobil" || len(d.Prefixes) != 2 {
|
||||
t.Error("Got wrong destination: ", d)
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -21,23 +21,29 @@ import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"github.com/simonz05/godis"
|
||||
// "log"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RedisStorage struct {
|
||||
dbNb int
|
||||
db *godis.Client
|
||||
buf bytes.Buffer
|
||||
dec *gob.Decoder
|
||||
mux sync.Mutex
|
||||
dbNb int
|
||||
db *godis.Client
|
||||
buf bytes.Buffer
|
||||
decAP *gob.Decoder
|
||||
decDest *gob.Decoder
|
||||
decTP *gob.Decoder
|
||||
decUB *gob.Decoder
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
func NewRedisStorage(address string, db int) (*RedisStorage, error) {
|
||||
ndb := godis.New(address, db, "")
|
||||
rs := &RedisStorage{db: ndb, dbNb: db}
|
||||
|
||||
rs.dec = gob.NewDecoder(&rs.buf)
|
||||
rs.decAP = gob.NewDecoder(&rs.buf)
|
||||
rs.decDest = gob.NewDecoder(&rs.buf)
|
||||
rs.decTP = gob.NewDecoder(&rs.buf)
|
||||
rs.decUB = gob.NewDecoder(&rs.buf)
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
@@ -49,6 +55,7 @@ func (rs *RedisStorage) SetActivationPeriods(key string, aps []*ActivationPeriod
|
||||
//.db.Select(rs.dbNb)
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
var writeBuf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&writeBuf)
|
||||
encoder.Encode(aps)
|
||||
@@ -64,48 +71,76 @@ func (rs *RedisStorage) GetActivationPeriods(key string) (aps []*ActivationPerio
|
||||
rs.buf.Reset()
|
||||
rs.buf.Write(elem.Bytes())
|
||||
|
||||
rs.dec.Decode(&aps)
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetDestination(key string) (dest *Destination, err error) {
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
dest = &Destination{Id: key}
|
||||
dest.restore(values.String())
|
||||
}
|
||||
rs.decAP.Decode(&aps)
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetDestination(dest *Destination) error {
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
return rs.db.Set(dest.Id, dest.store())
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
var writeBuf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&writeBuf)
|
||||
encoder.Encode(dest)
|
||||
return rs.db.Set(dest.Id, writeBuf.Bytes())
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
//rs.db.Select(rs.dbNb + 2)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(values.String())
|
||||
}
|
||||
func (rs *RedisStorage) GetDestination(key string) (dest *Destination, err error) {
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
elem, err := rs.db.Get(key)
|
||||
rs.buf.Reset()
|
||||
rs.buf.Write(elem.Bytes())
|
||||
err = rs.decDest.Decode(&dest)
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetTariffPlan(tp *TariffPlan) error {
|
||||
//rs.db.Select(rs.dbNb + 2)
|
||||
return rs.db.Set(tp.Id, tp.store())
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
var writeBuf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&writeBuf)
|
||||
encoder.Encode(tp)
|
||||
return rs.db.Set(tp.Id, writeBuf.Bytes())
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetUserBudget(key string) (ub *UserBudget, err error) {
|
||||
//rs.db.Select(rs.dbNb + 3)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
ub = &UserBudget{Id: key}
|
||||
ub.restore(values.String())
|
||||
}
|
||||
func (rs *RedisStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
//rs.db.Select(rs.dbNb + 2)
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
elem, err := rs.db.Get(key)
|
||||
rs.buf.Reset()
|
||||
rs.buf.Write(elem.Bytes())
|
||||
rs.decTP.Decode(&tp)
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetUserBudget(ub *UserBudget) error {
|
||||
//rs.db.Select(rs.dbNb + 3)
|
||||
return rs.db.Set(ub.Id, ub.store())
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
var writeBuf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&writeBuf)
|
||||
encoder.Encode(ub)
|
||||
return rs.db.Set(ub.Id, writeBuf.Bytes())
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetUserBudget(key string) (ub *UserBudget, err error) {
|
||||
//rs.db.Select(rs.dbNb + 3)
|
||||
rs.mux.Lock()
|
||||
defer rs.mux.Unlock()
|
||||
|
||||
elem, err := rs.db.Get(key)
|
||||
rs.buf.Reset()
|
||||
rs.buf.Write(elem.Bytes())
|
||||
rs.decUB.Decode(&ub)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ package timespans
|
||||
|
||||
import (
|
||||
// "log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -45,62 +43,6 @@ type VolumeDiscount struct {
|
||||
Discount float64 // procentage
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) store() (result string) {
|
||||
result += strconv.FormatFloat(tp.SmsCredit, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(tp.Traffic, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(tp.ReceivedCallSecondsLimit, 'f', -1, 64) + ";"
|
||||
if tp.RecivedCallBonus == nil {
|
||||
tp.RecivedCallBonus = &RecivedCallBonus{}
|
||||
}
|
||||
result += tp.RecivedCallBonus.store() + ";"
|
||||
for i, mb := range tp.MinuteBuckets {
|
||||
if i > 0 {
|
||||
result += ","
|
||||
}
|
||||
result += mb.store()
|
||||
}
|
||||
if tp.VolumeDiscountThresholds != nil {
|
||||
result += ";"
|
||||
}
|
||||
for i, vd := range tp.VolumeDiscountThresholds {
|
||||
if i > 0 {
|
||||
result += ","
|
||||
}
|
||||
result += strconv.FormatFloat(vd.Volume, 'f', -1, 64) + "|" + strconv.FormatFloat(vd.Discount, 'f', -1, 64)
|
||||
}
|
||||
result = strings.TrimRight(result, ";")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
tp.SmsCredit, _ = strconv.ParseFloat(elements[0], 64)
|
||||
tp.Traffic, _ = strconv.ParseFloat(elements[1], 64)
|
||||
tp.ReceivedCallSecondsLimit, _ = strconv.ParseFloat(elements[2], 64)
|
||||
tp.RecivedCallBonus = &RecivedCallBonus{}
|
||||
tp.RecivedCallBonus.restore(elements[3])
|
||||
for _, mbs := range strings.Split(elements[4], ",") {
|
||||
mb := &MinuteBucket{}
|
||||
mb.restore(mbs)
|
||||
tp.MinuteBuckets = append(tp.MinuteBuckets, mb)
|
||||
}
|
||||
if len(elements) > 5 {
|
||||
for _, vdss := range strings.Split(elements[5], ",") {
|
||||
vd := &VolumeDiscount{}
|
||||
vds := strings.Split(vdss, "|")
|
||||
vd.Volume, _ = strconv.ParseFloat(vds[0], 64)
|
||||
vd.Discount, _ = strconv.ParseFloat(vds[1], 64)
|
||||
tp.VolumeDiscountThresholds = append(tp.VolumeDiscountThresholds, vd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Structure to be filled for each tariff plan with the bonus value for received calls minutes.
|
||||
*/
|
||||
@@ -110,31 +52,3 @@ type RecivedCallBonus struct {
|
||||
Traffic float64
|
||||
MinuteBucket *MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (rcb *RecivedCallBonus) store() (result string) {
|
||||
result += strconv.FormatFloat(rcb.Credit, 'f', -1, 64) + ","
|
||||
result += strconv.FormatFloat(rcb.SmsCredit, 'f', -1, 64) + ","
|
||||
result += strconv.FormatFloat(rcb.Traffic, 'f', -1, 64)
|
||||
if rcb.MinuteBucket != nil {
|
||||
result += ","
|
||||
result += rcb.MinuteBucket.store()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (rcb *RecivedCallBonus) restore(input string) {
|
||||
elements := strings.Split(input, ",")
|
||||
rcb.Credit, _ = strconv.ParseFloat(elements[0], 64)
|
||||
rcb.SmsCredit, _ = strconv.ParseFloat(elements[1], 64)
|
||||
rcb.Traffic, _ = strconv.ParseFloat(elements[2], 64)
|
||||
if len(elements) > 3 {
|
||||
rcb.MinuteBucket = &MinuteBucket{}
|
||||
rcb.MinuteBucket.restore(elements[3])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,25 +21,6 @@ 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"}
|
||||
rcb := &RecivedCallBonus{Credit: 100}
|
||||
vd := &VolumeDiscount{100, 10}
|
||||
seara := &TariffPlan{Id: "seara_voo",
|
||||
SmsCredit: 100,
|
||||
ReceivedCallSecondsLimit: 0,
|
||||
RecivedCallBonus: rcb,
|
||||
MinuteBuckets: []*MinuteBucket{b1, b2},
|
||||
VolumeDiscountThresholds: []*VolumeDiscount{vd}}
|
||||
s := seara.store()
|
||||
tp1 := &TariffPlan{Id: "seara_voo"}
|
||||
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()
|
||||
|
||||
Binary file not shown.
@@ -20,8 +20,6 @@ package timespans
|
||||
import (
|
||||
// "log"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -70,55 +68,11 @@ func (bs bucketsorter) Less(j, i int) bool {
|
||||
bs[i].Price > bs[j].Price
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the user budget for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ub *UserBudget) store() (result string) {
|
||||
result += strconv.FormatFloat(ub.Credit, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(ub.SmsCredit, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(ub.Traffic, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(ub.VolumeDiscountSeconds, 'f', -1, 64) + ";"
|
||||
result += strconv.FormatFloat(ub.ReceivedCallSeconds, 'f', -1, 64) + ";"
|
||||
result += strconv.Itoa(ub.ResetDayOfTheMonth) + ";"
|
||||
result += ub.TariffPlanId
|
||||
if ub.MinuteBuckets != nil {
|
||||
result += ";"
|
||||
}
|
||||
for i, mb := range ub.MinuteBuckets {
|
||||
if i > 0 {
|
||||
result += ","
|
||||
}
|
||||
result += mb.store()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the user budget for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ub *UserBudget) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
ub.Credit, _ = strconv.ParseFloat(elements[0], 64)
|
||||
ub.SmsCredit, _ = strconv.ParseFloat(elements[1], 64)
|
||||
ub.Traffic, _ = strconv.ParseFloat(elements[2], 64)
|
||||
ub.VolumeDiscountSeconds, _ = strconv.ParseFloat(elements[3], 64)
|
||||
ub.ReceivedCallSeconds, _ = strconv.ParseFloat(elements[4], 64)
|
||||
ub.ResetDayOfTheMonth, _ = strconv.Atoi(elements[5])
|
||||
ub.TariffPlanId = elements[6]
|
||||
if len(elements) > 7 {
|
||||
for _, mbs := range strings.Split(elements[7], ",") {
|
||||
mb := &MinuteBucket{}
|
||||
mb.restore(mbs)
|
||||
ub.MinuteBuckets = append(ub.MinuteBuckets, mb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the tariff plan loading it from the storage if necessary.
|
||||
*/
|
||||
func (ub *UserBudget) getTariffPlan(storage StorageGetter) (tp *TariffPlan, err error) {
|
||||
if ub.tariffPlan == nil {
|
||||
if ub.tariffPlan == nil && ub.TariffPlanId != "" {
|
||||
ub.tariffPlan, err = storage.GetTariffPlan(ub.TariffPlanId)
|
||||
}
|
||||
return ub.tariffPlan, err
|
||||
@@ -150,7 +104,6 @@ func (ub *UserBudget) getSecondsForPrefix(sg StorageGetter, prefix string) (seco
|
||||
// log.Print("There are no minute buckets to check for user: ", ub.Id)
|
||||
return
|
||||
}
|
||||
|
||||
for _, mb := range ub.MinuteBuckets {
|
||||
d := mb.getDestination(sg)
|
||||
if d == nil {
|
||||
|
||||
@@ -53,19 +53,6 @@ func TestGetPricedSeconds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserBudgetStoreRestore(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}}
|
||||
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, tariffPlan: seara, ResetDayOfTheMonth: 10}
|
||||
s := rifsBudget.store()
|
||||
ub1 := &UserBudget{Id: "other"}
|
||||
ub1.restore(s)
|
||||
if ub1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, ub1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserBudgetKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
Reference in New Issue
Block a user