mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-23 16:18:44 +05:00
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:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user