]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/talk.py
10 from .misc
import Object
11 from .decorators
import *
13 class Freeswitch(Object
):
17 "host" : self
.settings
.get("freeswitch_database_host"),
18 "database" : self
.settings
.get("freeswitch_database_name", "freeswitch"),
19 "user" : self
.settings
.get("freeswitch_database_user"),
20 "password" : self
.settings
.get("freeswitch_database_password"),
23 return database
.Connection(**credentials
)
25 def get_sip_registrations(self
, sip_uri
):
26 logging
.debug("Fetching SIP registrations for %s" % sip_uri
)
28 user
, delim
, domain
= sip_uri
.partition("@")
30 res
= self
.db
.query("SELECT * FROM sip_registrations \
31 WHERE sip_user = %s AND sip_host = %s AND expires >= EXTRACT(epoch FROM CURRENT_TIMESTAMP) \
32 ORDER BY contact", user
, domain
)
35 yield SIPRegistration(self
, data
=row
)
37 def _get_channels(self
, query
, *args
):
38 res
= self
.db
.query(query
, *args
)
42 c
= Channel(self
, data
=row
)
47 def get_sip_channels(self
, account
):
48 return self
._get
_channels
("SELECT * FROM channels \
49 WHERE (direction = %s AND cid_num = %s) OR \
50 (direction = %s AND (callee_num = %s OR callee_num = ANY(%s))) \
51 AND callstate != %s ORDER BY created_epoch",
52 "inbound", account
.sip_id
, "outbound", account
.sip_id
,
53 account
._all
_telephone
_numbers
, "DOWN")
55 def get_cdr_by_account(self
, account
, date
=None, limit
=None):
56 res
= self
.db
.query("SELECT * FROM cdr \
57 WHERE ((caller_id_number = ANY(%s) AND bleg_uuid IS NOT NULL) \
58 OR (destination_number = ANY(%s) AND bleg_uuid IS NULL)) \
59 AND (%s IS NULL OR start_stamp::date = %s) \
60 ORDER BY end_stamp DESC LIMIT %s", account
._all
_telephone
_numbers
,
61 account
._all
_telephone
_numbers
, date
, date
, limit
)
64 yield CDR(self
, data
=row
)
66 def get_call_by_uuid(self
, uuid
):
67 res
= self
.db
.get("SELECT * FROM cdr \
68 WHERE uuid = %s", uuid
)
71 return CDR(self
, data
=res
)
73 def get_conferences(self
):
74 res
= self
.db
.query("SELECT DISTINCT application_data AS handle FROM channels \
75 WHERE application = %s AND application_data LIKE %s \
76 ORDER BY application_data", "conference", "%%@ipfire.org")
80 c
= Conference(self
, row
.handle
)
85 def get_agent_status(self
, account
):
86 res
= self
.db
.get("SELECT status FROM agents \
87 WHERE name = %s", account
.sip_url
)
92 class SIPRegistration(object):
93 def __init__(self
, freeswitch
, data
):
94 self
.freeswitch
= freeswitch
99 m
= re
.match(r
"Registered\(([A-Z]+)(\-NAT)?\)", self
.data
.status
)
105 def network_ip(self
):
106 return ipaddress
.ip_address(self
.data
.network_ip
)
109 def network_port(self
):
110 return self
.data
.network_port
113 def user_agent(self
):
114 return self
.data
.user_agent
116 def is_reachable(self
):
117 return self
.data
.ping_status
== "Reachable"
121 if self
.is_reachable() and self
.data
.ping_time
:
122 return self
.data
.ping_time
/ 1000.0
125 class Channel(object):
126 def __init__(self
, freeswitch
, data
):
127 self
.freeswitch
= freeswitch
132 return self
.freeswitch
.backend
136 return self
.data
.uuid
140 return self
.data
.direction
144 return self
.backend
.accounts
.get_by_sip_id(self
.caller_number
)
147 def caller_name(self
):
148 return self
.data
.cid_name
151 def caller_number(self
):
152 return self
.data
.cid_num
156 return self
.backend
.accounts
.get_by_sip_id(self
.callee_number
)
159 def callee_name(self
):
160 return self
.data
.callee_name
163 def callee_number(self
):
164 return self
.data
.callee_num
167 def called_number(self
):
168 return self
.data
.dest
172 return self
.data
.callstate
175 def application(self
):
176 return self
.data
.application
179 def application_data(self
):
180 return self
.data
.application_data
183 def conference(self
):
184 if self
.application
== "conference":
185 return Conference(self
.freeswitch
, self
.application_data
)
189 return time
.time() - self
.data
.created_epoch
193 # We always assume a symmetric codec
194 return format_codec(self
.data
.write_codec
, int(self
.data
.write_rate
or 0), int(self
.data
.write_bit_rate
or 0))
205 transport_protocol
, key_negotiation
, cipher_suite
= self
.data
.secure
.split(":")
209 return "%s: %s" % (key_negotiation
.upper(), cipher_suite
.replace("_", "-"))
213 def __init__(self
, freeswitch
, data
):
214 self
.freeswitch
= freeswitch
219 return self
.freeswitch
.backend
223 return self
.freeswitch
.db
227 return self
.data
.uuid
231 if self
.data
.bleg_uuid
:
232 return self
.freeswitch
.get_call_by_uuid(self
.data
.bleg_uuid
)
234 # If we are the bleg, we need to search for one where UUID is the bleg
235 res
= self
.db
.get("SELECT * FROM cdr WHERE bleg_uuid = %s", self
.uuid
)
238 return CDR(self
.freeswitch
, data
=res
)
242 if self
.data
.bleg_uuid
:
249 return self
.backend
.accounts
.get_by_phone_number(self
.data
.caller_id_number
)
252 def caller_number(self
):
253 return self
.data
.caller_id_number
257 return self
.backend
.accounts
.get_by_phone_number(self
.data
.destination_number
)
260 def callee_number(self
):
261 return self
.data
.destination_number
264 def time_start(self
):
265 return self
.data
.start_stamp
268 def time_answered(self
):
269 return self
.data
.answer_stamp
273 return self
.data
.duration
277 return format_codec(self
.data
.write_codec
, int(self
.data
.write_rate
or 0), int(self
.data
.write_bit_rate
or 0))
280 def user_agent(self
):
281 if self
.data
.user_agent
:
282 return self
.data
.user_agent
.replace("_", " ")
286 return sum((self
.data
.rtp_audio_in_raw_bytes
or 0, self
.data
.rtp_audio_out_raw_bytes
or 0))
290 return self
.data
.rtp_audio_in_mos
293 class Conference(object):
294 def __init__(self
, freeswitch
, handle
):
295 self
.freeswitch
= freeswitch
299 return "<%s %s>" % (self
.__class
__.__name
__, self
.handle
)
302 return len(self
.channels
)
304 def __eq__(self
, other
):
305 if isinstance(other
, self
.__class
__):
306 return self
.handle
== other
.handle
309 return iter(self
.channels
)
313 m
= re
.match(r
"conf(\d+)@", self
.handle
)
321 return 900 + self
.number
325 return self
.freeswitch
._get
_channels
("SELECT * FROM channels \
326 WHERE application = %s AND application_data = %s \
327 ORDER BY created_epoch", "conference", self
.handle
)
332 # Connect to FreeSWITCH
333 self
.freeswitch
= Freeswitch(self
.backend
)
336 def conferences(self
):
337 return self
.freeswitch
.get_conferences()
340 def format_codec(name
, bit_rate
, bandwidth
):
349 s
.append("%.0f kHz" % (bit_rate
/ 1000.0))
352 s
.append("%.0f kBit/s" % (bandwidth
/ 1000.0))