diff --git a/cdrstats/metrics.go b/cdrstats/metrics.go
new file mode 100644
index 000000000..2a27268cf
--- /dev/null
+++ b/cdrstats/metrics.go
@@ -0,0 +1,60 @@
+/*
+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 cdrstats
+
+type Metric interface {
+ AddCDR(*QCDR)
+ RemoveCDR(*QCDR)
+}
+
+func CreateMetric(metric string) *Metric {
+ switch metric {
+ case "ASR":
+ return &ASRMetric{}
+ case "ACD":
+ return &ACDMetric{}
+ case "ACC":
+ return &ACCMetric{}
+ }
+ return nil
+}
+
+// ASR - Answer-Seizure Ratio
+// successfully answered Calls divided by the total number of Calls attempted and multiplied by 100
+type ASRMetric struct {
+ sum float64
+ count int64
+}
+
+func (asr *ASRMetric) AddCdr(cdr *QCDR) {
+}
+
+// ACD – Average Call Duration
+// the sum of billable seconds (billsec) of answered calls divided by the number of these answered calls.
+type ACDMetric struct {
+ sum float64
+ count int64
+}
+
+// ACC – Average Call Cost
+// the sum of cost of answered calls divided by the number of these answered calls.
+type ACCMetric struct {
+ sum float64
+ count int64
+}
diff --git a/cdrstats/stats.go b/cdrstats/stats.go
new file mode 100644
index 000000000..ac6f509d1
--- /dev/null
+++ b/cdrstats/stats.go
@@ -0,0 +1,166 @@
+/*
+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 cdrstats
+
+type StatsQueue struct {
+ cdrs []*QCDR
+ config *CdrStatsConfig
+ metrics map[string]*Metric
+}
+
+// Simplified cdr structure containing only the necessary info
+type QCDR struct {
+ SetupTime time.Time
+ AnswerTime time.Time
+ Usage time.Duration
+ Cost float64
+}
+
+func NewStatsQueue(config *CdrStatsConfig) *StatsQueue{
+ sq := &StatsQueue{
+ config:config
+ metrics:=make(map[string]*Metric, len(config.Metrics))
+ }
+ for _, m := range config.Metrics {
+ metric := CreateMetric(m)
+ if metric != nil{
+ sq.metrics[m] = metric
+ }
+ }
+}
+
+func (sq *StatsQueue) AppendCDR(cdr *utils.StoredCdr){
+ if sq.AcceptCDR(cdr){
+ qcdr := sq.SimplifyCDR(cdr)
+ sq.cdrs = append(sq.cdrs, qcdr)
+ sq.AddToMetrics(qcdr)
+ }
+}
+
+func (sq *StatsQueue) AddToMetrics(cdr *QCDR) {
+ for _, metric:= range sq.metrics {
+ metric.AddCdr(cdr)
+ }
+}
+
+func (sq *StatsQueue) RemoveFromMetrics(cdr *QCDR) {
+ for _, metric:= range sq.metrics {
+ metric.RemoveCdr(cdr)
+ }
+}
+
+func (sq *StatsQueue) SimplifyCDR(cdr *utils.StoredCdr) *QCDR{
+ return &QCDR{
+ SetupTime: cdr.SetupTime,
+ AnswerTime: cdr.AnswerTime,
+ Usage: cdr.Usage,
+ Cost: cdr.Cost
+ }
+}
+
+func (sq *StatsQueue) PurgeObsoleteCDRs {
+ currentLength := len(sq.cdrs)
+ if currentLength>sq.config.QueuedItems{
+ for _, cdr := range sq.cdrs[:currentLength-sq.config.QueuedItems] {
+ sq.RemoveFromMetrics(cdr)
+ }
+ sq.cdrs = sq.cdrs[currentLength-sq.config.QueuedItems:]
+ }
+ for i, cdr := range sq.cdrs {
+ if time.Now().Sub(cdr.SetupTime) > sq.config.TimeWindow {
+ sq.RemoveFromMetrics(cdr)
+ continue
+ } else {
+ if i > 0 {
+ sq.cdrs = sq.cdrs[i:]
+ }
+ break
+ }
+ }
+}
+
+func (sq *StatsQueue) AcceptCDR(cdr *utils.StoredCdr) bool {
+ if len(sq.config.SetupInterval) > 0 {
+ if cdr.SetupTime.Before(sq.config.SetupInterval[0]){
+ return false
+ }
+ if len(sq.config.SetupInterval) > 1 && (cdr.SetupTime.Equals(sq.config.SetupInterval[1]) || cdr.SetupTime.After(sq.config.SetupInterval[1])){
+ return false
+ }
+ }
+ if len(sq.config.TOR) >0 && !utils.IsSliceMember(sq.config.TOR, cdr.TOR){
+ return false
+ }
+ if len(sq.config.CdrHost) >0 && !utils.IsSliceMember(sq.config.CdrHost, cdr.CdrHost){
+ return false
+ }
+ if len(sq.config.CdrSource) >0 && !utils.IsSliceMember(sq.config.CdrSource, cdr.CdrSource){
+ return false
+ }
+ if len(sq.config.ReqType) >0 && !utils.IsSliceMember(sq.config.ReqType, cdr.ReqType){
+ return false
+ }
+ if len(sq.config.Direction) >0 && !utils.IsSliceMember(sq.config.Direction, cdr.Direction){
+ return false
+ }
+ if len(sq.config.Tenant) >0 && !utils.IsSliceMember(sq.config.Tenant, cdr.Tenant){
+ return false
+ }
+ if len(sq.config.Category) >0 && !utils.IsSliceMember(sq.config.Category, cdr.Category){
+ return false
+ }
+ if len(sq.config.Account) >0 && !utils.IsSliceMember(sq.config.Account, cdr.Account){
+ return false
+ }
+ if len(sq.config.Subject) >0 && !utils.IsSliceMember(sq.config.Subject, cdr.Subject){
+ return false
+ }
+ if len(sq.config.DestinationPrefix)>0 {
+ found := false
+ for _, prefix := range sq.config.DestinationPrefix {
+ if cdr.Destination.HasPrefix(prefix){
+ found=true
+ break
+ }
+ }
+ if !found{
+ return false
+ }
+ }
+ if len(sq.config.UsageInterval) > 0 {
+ if cdr.Usage < sq.config.UsageInterval[0]{
+ return false
+ }
+ if len(sq.config.UsageInterval) > 1 && cdr.Usage >= sq.config.UsageInterval[1]{
+ return false
+ }
+ }
+ if len(sq.config.MediationRunIds) >0 && !utils.IsSliceMember(sq.config.MediationRunIds, cdr.MediationRunId){
+ return false
+ }
+ if len(sq.config.CostInterval) > 0 {
+ if cdr.Cost < sq.config.CostInterval[0]{
+ return false
+ }
+ if len(sq.config.CostInterval) > 1 && cdr.Cost >= sq.config.CostInterval[1]{
+ return false
+ }
+ }
+ return true
+}
diff --git a/cdrstats/stats_test.go b/cdrstats/stats_test.go
new file mode 100644
index 000000000..e5f85cd13
--- /dev/null
+++ b/cdrstats/stats_test.go
@@ -0,0 +1,19 @@
+/*
+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 cdrstats
diff --git a/config/cdrstatsconfig.go b/config/cdrstatsconfig.go
index c234340be..0c9800857 100644
--- a/config/cdrstatsconfig.go
+++ b/config/cdrstatsconfig.go
@@ -24,7 +24,6 @@ import (
type CdrStatsConfig struct {
Id string // Config id, unique per config instance
- RatedCdrs bool // Build the stats for rated cdrs instead of raw ones
QueuedItems int64 // Number of items in the stats buffer
TimeWindow time.Duration // Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
Metrics []string // ASR, ACD, ACC
diff --git a/utils/storedcdr.go b/utils/storedcdr.go
index aedd8c057..97d4b3042 100644
--- a/utils/storedcdr.go
+++ b/utils/storedcdr.go
@@ -1,4 +1,4 @@
-/*
+ *utilssssss/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) 2012-2014 ITsysCOM GmbH