/* map[secure: hostname:CgrDev1 callstate:ACTIVE callee_num:1002 initial_dest:1002 state:CS_EXECUTE dialplan:XML read_codec:SPEEX initial_ip_addr:127.0.0.1 write_codec:SPEEX write_bit_rate:44000 call_uuid:3427e500-10e5-4864-a589-e306b70419a2 presence_id: initial_cid_name:1001 context:default read_rate:32000 read_bit_rate:44000 callee_direction:SEND initial_context:default created:2015-06-15 18:48:13 dest:1002 callee_name:Outbound Call direction:inbound ip_addr:127.0.0.1 sent_callee_name:Outbound Call write_rate:32000 presence_data: sent_callee_num:1002 created_epoch:1434386893 cid_name:1001 application:sched_hangup application_data:+10800 alloted_timeout uuid:3427e500-10e5-4864-a589-e306b70419a2 name:sofia/cgrtest/[email protected] cid_num:1001 initial_cid_num:1001 initial_dialplan:XML] */ func (sm *FSSessionManager) SyncSessions() error { for connId, senderPool := range sm.senderPools { var aChans []map[string]string fsConn, err := senderPool.PopFSock() if err != nil { if err == fsock.ErrConnectionPoolTimeout { // Timeout waiting for connections to re-establish, cleanup calls aChans = make([]map[string]string, 0) // Emulate no call information so we can disconnect bellow } else { utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on syncing active calls, senderPool: %+v, error: %s", senderPool, err.Error())) continue } } else { activeChanStr, err := fsConn.SendApiCmd("show channels") senderPool.PushFSock(fsConn) if err != nil { utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on syncing active calls, senderPool: %+v, error: %s", senderPool, err.Error())) continue } aChans = fsock.MapChanData(activeChanStr) if len(aChans) == 0 && strings.HasPrefix(activeChanStr, "uuid,direction") { // Failed converting output from FS utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Syncing active calls, failed converting output from FS: %s", activeChanStr)) continue } } for _, session := range sm.sessions.getSessions() { if session.connId != connId { // This session belongs to another connectionId continue } var stillActive bool for _, fsAChan := range aChans { if fsAChan["call_uuid"] == session.eventStart.GetUUID() || (fsAChan["call_uuid"] == "" && fsAChan["uuid"] == session.eventStart.GetUUID()) { // Channel still active stillActive = true break } } if stillActive { // No need to do anything since the channel is still there continue } utils.Logger.Warning(fmt.Sprintf("<SM-FreeSWITCH> Sync active channels, stale session detected, uuid: %s", session.eventStart.GetUUID())) fsev := session.eventStart.(FSEvent) now := time.Now() aTime, _ := fsev.GetAnswerTime("", sm.timezone) dur := now.Sub(aTime) fsev[END_TIME] = now.String() fsev[DURATION] = strconv.FormatFloat(dur.Seconds(), 'f', -1, 64) if err := sm.sessions.removeSession(session, fsev); err != nil { // Stop loop, refund advanced charges and save the costs deducted so far to database utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on removing stale session with uuid: %s, error: %s", session.eventStart.GetUUID(), err.Error())) continue } } } return nil }
/* map[secure: hostname:CgrDev1 callstate:ACTIVE callee_num:1002 initial_dest:1002 state:CS_EXECUTE dialplan:XML read_codec:SPEEX initial_ip_addr:127.0.0.1 write_codec:SPEEX write_bit_rate:44000 call_uuid:3427e500-10e5-4864-a589-e306b70419a2 presence_id: initial_cid_name:1001 context:default read_rate:32000 read_bit_rate:44000 callee_direction:SEND initial_context:default created:2015-06-15 18:48:13 dest:1002 callee_name:Outbound Call direction:inbound ip_addr:127.0.0.1 sent_callee_name:Outbound Call write_rate:32000 presence_data: sent_callee_num:1002 created_epoch:1434386893 cid_name:1001 application:sched_hangup application_data:+10800 alloted_timeout uuid:3427e500-10e5-4864-a589-e306b70419a2 name:sofia/cgrtest/[email protected] cid_num:1001 initial_cid_num:1001 initial_dialplan:XML] */ func (sm *FSSessionManager) SyncSessions() error { for connId, senderPool := range sm.senderPools { fsConn, err := senderPool.PopFSock() if err != nil { utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on syncing active calls, senderPool: %+v, error: %s", senderPool, err.Error())) continue } activeChanStr, err := fsConn.SendApiCmd("show channels") senderPool.PushFSock(fsConn) if err != nil { utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on syncing active calls, senderPool: %+v, error: %s", senderPool, err.Error())) continue } aChans := fsock.MapChanData(activeChanStr) for _, session := range sm.sessions { if session.connId != connId { // This session belongs to another connectionId continue } var stillActive bool for _, fsAChan := range aChans { if fsAChan["call_uuid"] == session.eventStart.GetUUID() { // Channel still active stillActive = true break } } if stillActive { // No need to do anything since the channel is still there continue } utils.Logger.Warning(fmt.Sprintf("<SM-FreeSWITCH> Sync active channels, stale session detected, uuid: %s", session.eventStart.GetUUID())) sm.RemoveSession(session.eventStart.GetUUID()) // Unreference it early so we avoid concurrency fsev := session.eventStart.(FSEvent) now := time.Now() aTime, _ := fsev.GetAnswerTime("", sm.timezone) dur := now.Sub(aTime) fsev[END_TIME] = now.String() fsev[DURATION] = strconv.FormatFloat(dur.Seconds(), 'f', -1, 64) if err := session.Close(fsev); err != nil { // Stop loop, refund advanced charges and save the costs deducted so far to database utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on removing stale session with uuid: %s, error: %s", session.eventStart.GetUUID(), err.Error())) continue } } } return nil }