You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
3.7 KiB

package cdr
import (
"fmt"
"time"
)
type (
// LineKind defines several types of records
LineKind int
// ReasonKind is metadata about a certain Line
ReasonKind int
// CallKind defines if the call came through a user's PBX
CallKind int
)
const (
// UnknownLine aka "never seen this LineKind before"
UnknownLine LineKind = iota
// VoiceLine aka "this line belongs to (a part of) a voice call"
VoiceLine
// TextLine aka "this line belongs to a text message"
TextLine
// DataLine aka "this line belongs to a data session"
DataLine
)
// LineKindMap translates string from CSV to our typed LineKind
var LineKindMap = map[string]LineKind{
"Voice": VoiceLine,
"Data": DataLine,
"SMS": TextLine,
}
const (
// UnknownReason aka "never seen this reason before"
UnknownReason ReasonKind = iota
// ORIG aka "originated"
ORIG
// CFIM aka "call forward immediately"
CFIM
// CFNA aka "call forward not available"
CFNA
// CFBS aka "call forward busy"
CFBS
// CFOR aka "call forward out of reach"
CFOR
// ROAM aka "roaming"
ROAM
// PBXOR aka "PBX out of reach"
PBXOR
)
func (r ReasonKind) String() string {
switch r {
case ORIG:
return "ORIG"
case CFIM:
return "CFIM"
case CFNA:
return "CFNA"
case CFBS:
return "CFBS"
case CFOR:
return "CFOR"
case ROAM:
return "ROAM"
case PBXOR:
return "PBXOR"
default:
return "UNKN"
}
}
// ReasonKindMap translates string from CSV to our typed ReasonKind
var ReasonKindMap = map[string]ReasonKind{
"ORIG": ORIG,
"CFIM": CFIM,
"CFNA": CFNA,
"CFBS": CFBS,
"CFOR": CFOR,
"ROAM": ROAM,
"PBXOR": PBXOR,
}
const (
UnknownCall CallKind = iota
Regular
PBX
)
var CallKindMap = map[string]CallKind{
"Regular": Regular,
"PBX": PBX,
}
// Line contains the original metadata of a (call) detail record
type Line struct {
Id string
Time time.Time
CLI string
From string
To string
Account string
Source string
Destination string
RawCount int
RawCosts int
Leg int
Reason ReasonKind
Kind LineKind
// non-public properties
pkg string
package_cost int
network_cost int
service_cost int
}
// PricedLine connects a cost (buy) and price (sell) to a particular Line
type PricedLine struct {
Line
Cost int
Price int
OurRef string
}
// Call is a record of one or more PricedLines that ultimately form "a call".
type Call struct {
From string
To string
Time time.Time
Duration time.Duration
RawCost int
Cost int
Price int
Kind CallKind
Account string
Description string
Legs []PricedLine
}
func (c *Call) String() string {
diff := float64(c.RawCost-c.Cost) / 10000.0
return fmt.Sprintf("%s (%d) (%12s->%12s) cost: %.4f (%.4f=>%+.4f), price: %.4f (dur: %v): %v",
c.Time.Format(DateTimeFormat), len(c.Legs), c.From, c.To,
float64(c.Cost)/10000.0, float64(c.RawCost)/10000.0, diff, float64(c.Price)/10000.0, c.Duration, c.Description)
}
// Text is a specific PricedLine for a text message.
type Text struct {
PricedLine
Account string
}
func (t *Text) String() string {
return fmt.Sprintf("%s (%12s->%12s) textCost: %.4f, textPrice: %.4f", t.PricedLine.Line.Time.Format(DateTimeFormat), t.PricedLine.Line.From, t.PricedLine.Line.To, float64(t.PricedLine.Cost)/10000.0, float64(t.PricedLine.Price)/10000.0)
}
// Data is a specific PricedLine that annotates the number of bytes consumed in that session.
type Data struct {
PricedLine
Account string
Kilobytes int
}
func (d *Data) String() string {
return fmt.Sprintf("%s (%s) %v kilobytes, cost: %.4f, price: %.4f", d.PricedLine.Line.Time.Format(DateTimeFormat), d.Account, d.Kilobytes, float64(d.PricedLine.Cost)/10000.0, float64(d.PricedLine.Price)/10000.0)
}