Adding FSMinDurLowBalance, FSLowBalanceAnnFile,FSEmptyBalanceContext, FSEmptyBalanceAnnFile and logic behind to support playing annoucements and transfers before disconnecting prepaid calls within FreeSWITCH SessionManager

This commit is contained in:
DanB
2014-07-28 20:02:51 +02:00
parent 7fff0b2aad
commit fc546fe6b6
8 changed files with 73 additions and 20 deletions

View File

@@ -117,6 +117,10 @@ type CGRConfig struct {
FreeswitchServer string // freeswitch address host:port
FreeswitchPass string // FS socket password
FreeswitchReconnects int // number of times to attempt reconnect after connect fails
FSMinDurLowBalance time.Duration // Threshold which will trigger low balance warnings
FSLowBalanceAnnFile string // File to be played when low balance is reached
FSEmptyBalanceContext string // If defined, call will be transfered to this context on empty balance
FSEmptyBalanceAnnFile string // File to be played before disconnecting prepaid calls (applies only if no context defined)
OsipsListenUdp string // Address where to listen for event datagrams coming from OpenSIPS
OsipsMiAddr string // Adress where to reach OpenSIPS mi_datagram module
OsipsEvSubscInterval time.Duration // Refresh event subscription at this interval
@@ -208,6 +212,10 @@ func (self *CGRConfig) setDefaults() error {
self.FreeswitchServer = "127.0.0.1:8021"
self.FreeswitchPass = "ClueCon"
self.FreeswitchReconnects = 5
self.FSMinDurLowBalance = time.Duration(5) * time.Second
self.FSLowBalanceAnnFile = ""
self.FSEmptyBalanceContext = ""
self.FSEmptyBalanceAnnFile = ""
self.OsipsListenUdp = "127.0.0.1:2020"
self.OsipsMiAddr = "127.0.0.1:8020"
self.OsipsEvSubscInterval = time.Duration(60) * time.Second
@@ -542,6 +550,21 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
if hasOpt = c.HasOption("freeswitch", "reconnects"); hasOpt {
cfg.FreeswitchReconnects, _ = c.GetInt("freeswitch", "reconnects")
}
if hasOpt = c.HasOption("freeswitch", "min_dur_low_balance"); hasOpt {
minDurStr, _ := c.GetString("freeswitch", "min_dur_low_balance")
if cfg.FSMinDurLowBalance, err = utils.ParseDurationWithSecs(minDurStr); err != nil {
return nil, err
}
}
if hasOpt = c.HasOption("freeswitch", "low_balance_ann_file"); hasOpt {
cfg.FSLowBalanceAnnFile, _ = c.GetString("freeswitch", "low_balance_ann_file")
}
if hasOpt = c.HasOption("freeswitch", "empty_balance_context"); hasOpt {
cfg.FSEmptyBalanceContext, _ = c.GetString("freeswitch", "empty_balance_context")
}
if hasOpt = c.HasOption("freeswitch", "empty_balance_ann_file"); hasOpt {
cfg.FSEmptyBalanceAnnFile, _ = c.GetString("freeswitch", "empty_balance_ann_file")
}
if hasOpt = c.HasOption("opensips", "listen_udp"); hasOpt {
cfg.OsipsListenUdp, _ = c.GetString("opensips", "listen_udp")
}

View File

@@ -118,6 +118,10 @@ func TestDefaults(t *testing.T) {
eCfg.FreeswitchServer = "127.0.0.1:8021"
eCfg.FreeswitchPass = "ClueCon"
eCfg.FreeswitchReconnects = 5
eCfg.FSMinDurLowBalance = time.Duration(5) * time.Second
eCfg.FSLowBalanceAnnFile = ""
eCfg.FSEmptyBalanceContext = ""
eCfg.FSEmptyBalanceAnnFile = ""
eCfg.OsipsListenUdp = "127.0.0.1:2020"
eCfg.OsipsMiAddr = "127.0.0.1:8020"
eCfg.OsipsEvSubscInterval = time.Duration(60) * time.Second
@@ -258,6 +262,10 @@ func TestConfigFromFile(t *testing.T) {
eCfg.FreeswitchServer = "test"
eCfg.FreeswitchPass = "test"
eCfg.FreeswitchReconnects = 99
eCfg.FSMinDurLowBalance = time.Duration(99) * time.Second
eCfg.FSLowBalanceAnnFile = "test"
eCfg.FSEmptyBalanceContext = "test"
eCfg.FSEmptyBalanceAnnFile = "test"
eCfg.OsipsListenUdp = "test"
eCfg.OsipsMiAddr = "test"
eCfg.OsipsEvSubscInterval = time.Duration(99) * time.Second

View File

@@ -95,9 +95,13 @@ min_call_duration = 98 # Only authorize calls with allowed duration bigger than
max_call_duration = 99 # Maximum call duration a prepaid call can last
[freeswitch]
server = test # Adress where to connect to FreeSWITCH socket.
passwd = test # FreeSWITCH socket password.
reconnects = 99 # Number of attempts on connect failure.
server = test # Adress where to connect to FreeSWITCH socket.
passwd = test # FreeSWITCH socket password.
reconnects = 99 # Number of attempts on connect failure.
min_dur_low_balance = 99 # Threshold which will trigger low balance warnings
low_balance_ann_file = test # File to be played when low balance is reached
empty_balance_context = test # If defined, call will be transfered to this context on empty balance
empty_balance_ann_file = test # File to be played before disconnecting prepaid calls (applies only if no context defined)
[opensips]
listen_udp = test # Address where to listen for event datagrams coming from OpenSIPS

View File

@@ -95,14 +95,17 @@
# rater = internal # Address where to reach the Rater
# reconnects = 3 # Number of reconnects to rater/cdrs before giving up.
# debit_interval = 10 # Interval to perform debits on.
# min_call_duration = 0s Only authorize calls with allowed duration bigger than this
# min_call_duration = 0s # Only authorize calls with allowed duration bigger than this
# max_call_duration = 3h # Maximum call duration a prepaid call can last
[freeswitch]
# server = 127.0.0.1:8021 # Adress where to connect to FreeSWITCH socket.
# passwd = ClueCon # FreeSWITCH socket password.
# reconnects = 5 # Number of attempts on connect failure.
# min_dur_low_balance = 5s # Threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
# low_balance_ann_file = # File to be played when low balance is reached for prepaid calls
# empty_balance_context = # If defined, prepaid calls will be transfered to this context on empty balance
# empty_balance_ann_file = # File to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
[opensips]
# listen_udp = 127.0.0.1:2020 # Address where to listen for datagram events coming from OpenSIPS

View File

@@ -99,14 +99,24 @@ func (sm *FSSessionManager) GetSession(uuid string) *Session {
}
// Disconnects a session by sending hangup command to freeswitch
func (sm *FSSessionManager) DisconnectSession(uuid string, notify string) {
// engine.Logger.Debug(fmt.Sprintf("Session: %+v", s.uuid))
_, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_setvar %s cgr_notify %s\n\n", uuid, notify))
if err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> Could not send disconect api notification to freeswitch: %v", err))
func (sm *FSSessionManager) DisconnectSession(uuid, notify, destnr string) {
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_setvar %s cgr_notify %s\n\n", uuid, notify)); err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> Could not send disconect api notification to freeswitch: %s", err.Error()))
}
err = fsock.FS.SendMsgCmd(uuid, map[string]string{"call-command": "hangup", "hangup-cause": "MANAGER_REQUEST"}) // without + sign
if err != nil {
if notify == INSUFFICIENT_FUNDS {
if len(cfg.FSEmptyBalanceContext) != 0 {
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_transfer %s %s %s\n\n", uuid, destnr, cfg.FSEmptyBalanceContext)); err != nil {
engine.Logger.Err("<SessionManager> Could not transfer the call to empty balance context")
}
return
} else if len(cfg.FSEmptyBalanceAnnFile) != 0 {
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_broadcast %s playback!manager_request::%s aleg\n\n", uuid, cfg.FSEmptyBalanceAnnFile)); err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> Could not send uuid_broadcast to freeswitch: %s", err.Error()))
}
return
}
}
if err := fsock.FS.SendMsgCmd(uuid, map[string]string{"call-command": "hangup", "hangup-cause": "MANAGER_REQUEST"}); err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> Could not send disconect msg to freeswitch: %v", err))
}
return
@@ -139,8 +149,7 @@ func (sm *FSSessionManager) unparkCall(uuid, call_dest_nb, notify string) {
if err != nil {
engine.Logger.Err("<SessionManager> Could not send unpark api notification to freeswitch")
}
_, err = fsock.FS.SendApiCmd(fmt.Sprintf("uuid_transfer %s %s\n\n", uuid, call_dest_nb))
if err != nil {
if _, err = fsock.FS.SendApiCmd(fmt.Sprintf("uuid_transfer %s %s\n\n", uuid, call_dest_nb)); err != nil {
engine.Logger.Err("<SessionManager> Could not send unpark api call to freeswitch")
}
}
@@ -224,7 +233,7 @@ func (sm *FSSessionManager) OnChannelPark(ev Event) {
func (sm *FSSessionManager) OnChannelAnswer(ev Event) {
if ev.MissingParameter() {
sm.DisconnectSession(ev.GetUUID(), MISSING_PARAMETER)
sm.DisconnectSession(ev.GetUUID(), MISSING_PARAMETER, "")
}
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_setvar %s cgr_reqtype %s\n\n", ev.GetUUID(), ev.GetReqType(""))); err != nil {
engine.Logger.Err(fmt.Sprintf("Error on attempting to overwrite cgr_type in chan variables: %v", err))
@@ -234,7 +243,7 @@ func (sm *FSSessionManager) OnChannelAnswer(ev Event) {
var dcs utils.DerivedChargers
if err := sm.connector.GetDerivedChargers(attrsDC, &dcs); err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> OnAnswer: could not get derived charging for event %s: %s", ev.GetUUID(), err.Error()))
sm.DisconnectSession(ev.GetUUID(), SYSTEM_ERROR) // Disconnect the session since we are not able to process sessions
sm.DisconnectSession(ev.GetUUID(), SYSTEM_ERROR, "") // Disconnect the session since we are not able to process sessions
return
}
dcs, _ = dcs.AppendDefaultRun()

View File

@@ -66,7 +66,7 @@ func (osm *OsipsSessionManager) Connect() (err error) {
return errors.New("<SM-OpenSIPS> Stopped reading events")
}
func (osm *OsipsSessionManager) DisconnectSession(uuid string, notify string) {
func (osm *OsipsSessionManager) DisconnectSession(uuid, notify, destnr string) {
return
}
func (osm *OsipsSessionManager) RemoveSession(uuid string) {

View File

@@ -25,6 +25,7 @@ import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/fsock"
)
// Session type holding the call information fields, a session delegate for specific
@@ -110,13 +111,18 @@ func (s *Session) debitLoop(runIdx int) {
cc := new(engine.CallCost)
if err := s.sessionManager.MaxDebit(&nextCd, cc); err != nil {
engine.Logger.Err(fmt.Sprintf("Could not complete debit opperation: %v", err))
s.sessionManager.DisconnectSession(s.uuid, SYSTEM_ERROR)
s.sessionManager.DisconnectSession(s.uuid, SYSTEM_ERROR, "")
return
}
if cc.GetDuration() == 0 {
s.sessionManager.DisconnectSession(s.uuid, INSUFFICIENT_FUNDS)
s.sessionManager.DisconnectSession(s.uuid, INSUFFICIENT_FUNDS, nextCd.Destination)
return
}
if cc.GetDuration() <= cfg.FSMinDurLowBalance && len(cfg.FSLowBalanceAnnFile) != 0 {
if _, err := fsock.FS.SendApiCmd(fmt.Sprintf("uuid_broadcast %s %s aleg\n\n", s.uuid, cfg.FSLowBalanceAnnFile)); err != nil {
engine.Logger.Err(fmt.Sprintf("<SessionManager> Could not send uuid_broadcast to freeswitch: %s", err.Error()))
}
}
s.sessionRuns[runIdx].callCosts = append(s.sessionRuns[runIdx].callCosts, cc)
nextCd.TimeEnd = cc.GetEndTime() // set debited timeEnd
// update call duration with real debited duration

View File

@@ -26,7 +26,7 @@ import (
type SessionManager interface {
Connect() error
DisconnectSession(string, string)
DisconnectSession(string, string, string)
RemoveSession(string)
MaxDebit(*engine.CallDescriptor, *engine.CallCost) error
GetDebitPeriod() time.Duration