diff --git a/cache2go/cache_store.go b/cache2go/cache_store.go
index 355d1e784..4bcb25fb2 100644
--- a/cache2go/cache_store.go
+++ b/cache2go/cache_store.go
@@ -18,7 +18,6 @@ along with this program. If not, see
package cache2go
import (
- "fmt"
"strings"
"sync"
@@ -184,7 +183,6 @@ func (cs lrustore) Put(key string, value interface{}) {
var err error
mp, err = lru.New(10000)
if err != nil {
- utils.Logger.Debug(fmt.Sprintf(": error at init: %v", err))
return
}
cs[prefix] = mp
diff --git a/cache2go/lruttl.go b/cache2go/lruttl.go
index d583663b5..facb56939 100644
--- a/cache2go/lruttl.go
+++ b/cache2go/lruttl.go
@@ -19,11 +19,8 @@ package cache2go
import (
"container/list"
- "fmt"
"sync"
"time"
-
- "github.com/cgrates/cgrates/utils"
)
// Cache is an LRU cache.
@@ -172,8 +169,6 @@ func (c *Cache) removeElement(e *list.Element) {
if e.Value != nil {
kv := e.Value.(*entry)
delete(c.cache, kv.key)
- } else {
- utils.Logger.Debug(fmt.Sprintf(": nil element: %+v", e))
}
}
diff --git a/data/tutorials/asterisk_events/asterisk/etc/asterisk/extensions.conf b/data/tutorials/asterisk_events/asterisk/etc/asterisk/extensions.conf
index 5e7c39442..01de11c58 100755
--- a/data/tutorials/asterisk_events/asterisk/etc/asterisk/extensions.conf
+++ b/data/tutorials/asterisk_events/asterisk/etc/asterisk/extensions.conf
@@ -1,6 +1,8 @@
[internal]
exten => _1XXX,1,NoOp()
+ same => n,Set(CGRMaxSessionTime=0); use it to disconnect automatically the call if bridge is not active
+ same => n,DumpChan()
same => n,Stasis(cgrates_auth,cgr_reqtype=*prepaid,cgr_destination=${EXTEN})
- same => n,Dial(PJSIP/${EXTEN},30)
+ same => n,Dial(PJSIP/${EXTEN},30,L(${CGRMaxSessionTime}))
same => n,Hangup()
diff --git a/data/tutorials/asterisk_events/asterisk/etc/asterisk/modules.conf b/data/tutorials/asterisk_events/asterisk/etc/asterisk/modules.conf
index 280614a06..38df4bcac 100755
--- a/data/tutorials/asterisk_events/asterisk/etc/asterisk/modules.conf
+++ b/data/tutorials/asterisk_events/asterisk/etc/asterisk/modules.conf
@@ -15,6 +15,7 @@ load = app_voicemail.so
load = app_directory.so
load = app_confbridge.so
load = app_queue.so
+load = app_dumpchan.so
; Bridging
diff --git a/engine/calldesc.go b/engine/calldesc.go
index 1ad994785..aaa839e67 100644
--- a/engine/calldesc.go
+++ b/engine/calldesc.go
@@ -201,7 +201,6 @@ func (cd *CallDescriptor) LoadRatingPlans() (err error) {
if err == utils.ErrNotFound && rec == 1 {
//if err != nil || !cd.continousRatingInfos() {
// use the default subject only if the initial one was not found
- //utils.Logger.Debug(fmt.Sprintf("Try the default subject for %s and account: %s, subject: %s", cd.Destination, cd.GetAccountKey(), cd.GetKey(cd.Subject)))
err, _ = cd.getRatingPlansForPrefix(cd.GetKey(FALLBACK_SUBJECT), 1)
}
//load the rating plans
@@ -390,7 +389,6 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
//log.Printf("==============%v==================", i)
//log.Printf("TS: %+v", timespans[i])
rp := timespans[i].ratingInfo
- // utils.Logger.Debug(fmt.Sprintf("rp: %+v", rp))
//timespans[i].RatingPlan = nil
rateIntervals := rp.SelectRatingIntevalsForTimespan(timespans[i])
//log.Print("RIs: ", utils.ToJSON(rateIntervals))
@@ -423,10 +421,8 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
//log.Print(timespans[i].RateInterval.Timing)
}
- //utils.Logger.Debug(fmt.Sprintf("After SplitByRateInterval: %+v", timespans))
//log.Printf("After SplitByRateInterval: %+v", timespans[0].RateInterval.Timing)
timespans = cd.roundTimeSpansToIncrement(timespans)
- // utils.Logger.Debug(fmt.Sprintf("After round: %+v", timespans))
//log.Printf("After round: %+v", timespans[0].RateInterval.Timing)
return
}
@@ -578,27 +574,18 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura
if origCD.TOR == "" {
origCD.TOR = utils.VOICE
}
- //utils.Logger.Debug("ORIG: " + utils.ToJSON(origCD))
cd := origCD.Clone()
initialDuration := cd.TimeEnd.Sub(cd.TimeStart)
- //utils.Logger.Debug(fmt.Sprintf("INITIAL_DURATION: %v", initialDuration))
defaultBalance := account.GetDefaultMoneyBalance()
//use this to check what increment was payed with debt
initialDefaultBalanceValue := defaultBalance.GetValue()
- //utils.Logger.Debug("ACCOUNT: " + utils.ToJSON(account))
- //utils.Logger.Debug("DEFAULT_BALANCE: " + utils.ToJSON(defaultBalance))
-
cc, err := cd.debit(account, true, false)
- //utils.Logger.Debug("CC: " + utils.ToJSON(cc))
- //log.Print("CC: ", utils.ToIJSON(cc))
- //utils.Logger.Debug(fmt.Sprintf("ERR: %v", err))
if err != nil {
return 0, err
}
- //log.Printf("CC: %+v", cc)
// not enough credit for connect fee
if cc.negativeConnectFee == true {
return 0, nil
@@ -607,16 +594,10 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura
var totalCost float64
var totalDuration time.Duration
cc.Timespans.Decompress()
- //log.Printf("ACC: %+v", account)
for _, ts := range cc.Timespans {
- //if ts.RateInterval != nil {
- //log.Printf("TS: %+v", ts)
- //utils.Logger.Debug("TS: " + utils.ToJSON(ts))
- //}
if cd.MaxRate > 0 && cd.MaxRateUnit > 0 {
rate, _, rateUnit := ts.RateInterval.GetRateParameters(ts.GetGroupStart())
if rate/rateUnit.Seconds() > cd.MaxRate/cd.MaxRateUnit.Seconds() {
- //utils.Logger.Debug(fmt.Sprintf("0_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration))
return utils.MinDuration(initialDuration, totalDuration), nil
}
}
@@ -624,14 +605,12 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura
ts.createIncrementsSlice()
}
for _, incr := range ts.Increments {
- //utils.Logger.Debug("INCR: " + utils.ToJSON(incr))
totalCost += incr.Cost
if incr.BalanceInfo.Monetary != nil && incr.BalanceInfo.Monetary.UUID == defaultBalance.Uuid {
initialDefaultBalanceValue -= incr.Cost
if initialDefaultBalanceValue < 0 {
// this increment was payed with debt
// TODO: improve this check
- //utils.Logger.Debug(fmt.Sprintf("1_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration))
return utils.MinDuration(initialDuration, totalDuration), nil
}
@@ -640,13 +619,10 @@ func (origCD *CallDescriptor) getMaxSessionDuration(origAcc *Account) (time.Dura
//log.Print("INC: ", utils.ToJSON(incr))
if totalDuration >= initialDuration {
// we have enough, return
- //utils.Logger.Debug(fmt.Sprintf("2_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration))
return initialDuration, nil
}
}
}
- //utils.Logger.Debug(fmt.Sprintf("3_INIT DUR %v, TOTAL DUR: %v", initialDuration, totalDuration))
-
return utils.MinDuration(initialDuration, totalDuration), nil
}
diff --git a/engine/responder.go b/engine/responder.go
index 8a6f6ff87..0a195d045 100644
--- a/engine/responder.go
+++ b/engine/responder.go
@@ -476,9 +476,12 @@ func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error {
continue // We only consider prepaid sessions
}
startTime, err := ev.GetAnswerTime(dc.AnswerTimeField, rs.Timezone)
- if err != nil {
- rs.getCache().Cache(cacheKey, &cache2go.CacheItem{Err: err})
- return errors.New("Error parsing answer event start time")
+ if err != nil || startTime.IsZero() { // AnswerTime not parsable, try SetupTime
+ startTime, err = ev.GetSetupTime(dc.SetupTimeField, rs.Timezone)
+ if err != nil {
+ rs.getCache().Cache(cacheKey, &cache2go.CacheItem{Err: err})
+ return errors.New("Error parsing answer event start time")
+ }
}
endTime, err := ev.GetEndTime("", rs.Timezone)
if err != nil {
diff --git a/sessionmanager/smasterisk.go b/sessionmanager/smasterisk.go
index fd2597de9..e39cf14c9 100644
--- a/sessionmanager/smasterisk.go
+++ b/sessionmanager/smasterisk.go
@@ -20,6 +20,7 @@ package sessionmanager
import (
"fmt"
"net/url"
+ "strconv"
"strings"
"github.com/cgrates/aringo"
@@ -29,7 +30,8 @@ import (
)
const (
- CGRAuthAPP = "cgrates_auth"
+ CGRAuthAPP = "cgrates_auth"
+ CGRMaxSessionTime = "CGRMaxSessionTime"
)
func NewSMAsterisk(cgrCfg *config.CGRConfig, astConnIdx int, smg rpcclient.RpcClientConnection) (*SMAsterisk, error) {
@@ -92,12 +94,52 @@ func (sma *SMAsterisk) handleStasisStart(ev *SMAsteriskEvent) {
// Since we got error, disconnect channel
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
- return
}
+ return
}
+
+ var maxUsage float64
+ smgEv, err := ev.AsSMGenericSessionStart()
+ if err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when generating SMG for channelID: %s", err.Error(), ev.ChannelID()))
+ // Since we got error, disconnect channel
+ if err := sma.hangupChannel(ev.ChannelID()); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
+ }
+ return
+ }
+
+ if err = sma.smg.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to initiate session for channelID: %s", err.Error(), ev.ChannelID()))
+ if err := sma.hangupChannel(ev.ChannelID()); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
+ }
+ return
+ }
+
+ if maxUsage == -1 {
+ maxUsage = 0 // So we can set it later as unlimited
+ } else if maxUsage == 0 || maxUsage < sma.cgrCfg.SMAsteriskCfg().MinCallDuration.Seconds() {
+ if err := sma.hangupChannel(ev.ChannelID()); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
+ }
+ return
+ }
+ // Call allowed, set absolute timeout
+ if _, err := sma.astConn.Call(aringo.HTTP_POST, fmt.Sprintf("http://%s/ari/channels/%s/variable",
+ sma.cgrCfg.SMAsteriskCfg().AsteriskConns[sma.astConnIdx].Address, ev.ChannelID()),
+ url.Values{"variable": {CGRMaxSessionTime}, "value": {strconv.FormatFloat(maxUsage*1000, 'f', -1, 64)}}); err != nil { // Asterisk expects value in ms
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when setting %s for channelID: %s", err.Error(), CGRMaxSessionTime, ev.ChannelID()))
+ // Since we got error, disconnect channel
+ if err := sma.hangupChannel(ev.ChannelID()); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
+ }
+ return
+ }
+
// Exit channel from stasis
if _, err := sma.astConn.Call(aringo.HTTP_POST, fmt.Sprintf("http://%s/ari/channels/%s/continue",
- sma.cgrCfg.SMAsteriskCfg().AsteriskConns[sma.astConnIdx].Address, ev.ChannelID()), url.Values{"channelId": {ev.ChannelID()}}); err != nil {
+ sma.cgrCfg.SMAsteriskCfg().AsteriskConns[sma.astConnIdx].Address, ev.ChannelID()), nil); err != nil {
}
}
diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go
index 595a6cfbb..5f1e798b7 100644
--- a/sessionmanager/smgeneric.go
+++ b/sessionmanager/smgeneric.go
@@ -293,14 +293,13 @@ func (self *SMGeneric) sessionEnd(sessionId string, usage time.Duration) error {
}
for idx, s := range ss {
s.totalUsage = usage // save final usage as totalUsage
- //utils.Logger.Info(fmt.Sprintf(" Ending session: %s, runId: %s", sessionId, s.runId))
if idx == 0 && s.stopDebit != nil {
close(s.stopDebit) // Stop automatic debits
}
aTime, err := s.eventStart.GetAnswerTime(utils.META_DEFAULT, self.cgrCfg.DefaultTimezone)
if err != nil || aTime.IsZero() {
- utils.Logger.Err(fmt.Sprintf(" Could not retrieve answer time for session: %s, runId: %s, aTime: %+v, error: %s",
- sessionId, s.runId, aTime, err.Error()))
+ utils.Logger.Err(fmt.Sprintf(" Could not retrieve answer time for session: %s, runId: %s, aTime: %+v, error: %v",
+ sessionId, s.runId, aTime, err))
}
if err := s.close(aTime.Add(usage)); err != nil {
utils.Logger.Err(fmt.Sprintf(" Could not close session: %s, runId: %s, error: %s", sessionId, s.runId, err.Error()))
diff --git a/utils/coreutils.go b/utils/coreutils.go
index 8e19d3938..b611a5738 100644
--- a/utils/coreutils.go
+++ b/utils/coreutils.go
@@ -139,12 +139,15 @@ func ParseTimeDetectLayout(tmStr string, timezone string) (time.Time, error) {
sqlRule := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$`)
gotimeRule := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.?\d*\s[+,-]\d+\s\w+$`)
fsTimestamp := regexp.MustCompile(`^\d{16}$`)
+ astTimestamp := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d*[+,-]\d+$`)
unixTimestampRule := regexp.MustCompile(`^\d{10}$`)
oneLineTimestampRule := regexp.MustCompile(`^\d{14}$`)
oneSpaceTimestampRule := regexp.MustCompile(`^\d{2}\.\d{2}.\d{4}\s{1}\d{2}:\d{2}:\d{2}$`)
eamonTimestampRule := regexp.MustCompile(`^\d{2}/\d{2}/\d{4}\s{1}\d{2}:\d{2}:\d{2}$`)
broadsoftTimestampRule := regexp.MustCompile(`^\d{14}\.\d{3}`)
switch {
+ case astTimestamp.MatchString(tmStr):
+ return time.Parse("2006-01-02T15:04:05.999999999-0700", tmStr)
case rfc3339Rule.MatchString(tmStr):
return time.Parse(time.RFC3339, tmStr)
case gotimeRule.MatchString(tmStr):
diff --git a/utils/utils_test.go b/utils/utils_test.go
index d0bb684b1..349b76e7a 100644
--- a/utils/utils_test.go
+++ b/utils/utils_test.go
@@ -266,6 +266,14 @@ func TestParseTimeDetectLayout(t *testing.T) {
} else if !broadTmS.Equal(expectedTime) {
t.Errorf("Expecting: %v, received: %v", expectedTime, broadTmS)
}
+ astTimestamp := "2016-09-14T19:37:43.665+0000"
+ expectedTime = time.Date(2016, 9, 14, 19, 37, 43, 665000000, time.UTC)
+ astTMS, err := ParseTimeDetectLayout(astTimestamp, "")
+ if err != nil {
+ t.Error(err)
+ } else if !astTMS.Equal(expectedTime) {
+ t.Errorf("Expecting: %v, received: %v", expectedTime, astTMS)
+ }
}
func TestParseDateUnix(t *testing.T) {