]>
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
)
86 class SIPRegistration(object):
87 def __init__(self
, freeswitch
, data
):
88 self
.freeswitch
= freeswitch
93 m
= re
.match(r
"Registered\(([A-Z]+)(\-NAT)?\)", self
.data
.status
)
100 return ipaddress
.ip_address(self
.data
.network_ip
)
103 def network_port(self
):
104 return self
.data
.network_port
107 def user_agent(self
):
108 return self
.data
.user_agent
110 def is_reachable(self
):
111 return self
.data
.ping_status
== "Reachable"
115 if self
.is_reachable() and self
.data
.ping_time
:
116 return self
.data
.ping_time
/ 1000.0
119 class Channel(object):
120 def __init__(self
, freeswitch
, data
):
121 self
.freeswitch
= freeswitch
126 return self
.freeswitch
.backend
130 return self
.data
.uuid
134 return self
.data
.direction
138 return self
.backend
.accounts
.get_by_sip_id(self
.caller_number
)
141 def caller_name(self
):
142 return self
.data
.cid_name
145 def caller_number(self
):
146 return self
.data
.cid_num
150 return self
.backend
.accounts
.get_by_sip_id(self
.callee_number
)
153 def callee_name(self
):
154 return self
.data
.callee_name
157 def callee_number(self
):
158 return self
.data
.callee_num
161 def called_number(self
):
162 return self
.data
.dest
166 return self
.data
.callstate
169 def application(self
):
170 return self
.data
.application
173 def application_data(self
):
174 return self
.data
.application_data
177 def conference(self
):
178 if self
.application
== "conference":
179 return Conference(self
.freeswitch
, self
.application_data
)
183 return time
.time() - self
.data
.created_epoch
187 # We always assume a symmetric codec
188 return format_codec(self
.data
.write_codec
, int(self
.data
.write_rate
or 0), int(self
.data
.write_bit_rate
or 0))
199 transport_protocol
, key_negotiation
, cipher_suite
= self
.data
.secure
.split(":")
203 return "%s: %s" % (key_negotiation
.upper(), cipher_suite
.replace("_", "-"))
207 def __init__(self
, freeswitch
, data
):
208 self
.freeswitch
= freeswitch
213 return self
.freeswitch
.backend
217 return self
.freeswitch
.db
221 return self
.data
.uuid
225 if self
.data
.bleg_uuid
:
226 return self
.freeswitch
.get_call_by_uuid(self
.data
.bleg_uuid
)
228 # If we are the bleg, we need to search for one where UUID is the bleg
229 res
= self
.db
.get("SELECT * FROM cdr WHERE bleg_uuid = %s", self
.uuid
)
232 return CDR(self
.freeswitch
, data
=res
)
236 if self
.data
.bleg_uuid
:
243 return self
.backend
.accounts
.get_by_phone_number(self
.data
.caller_id_number
)
246 def caller_number(self
):
247 return self
.data
.caller_id_number
251 return self
.backend
.accounts
.get_by_phone_number(self
.data
.destination_number
)
254 def callee_number(self
):
255 return self
.data
.destination_number
258 def time_start(self
):
259 return self
.data
.start_stamp
262 def time_answered(self
):
263 return self
.data
.answer_stamp
267 return self
.data
.duration
271 return format_codec(self
.data
.write_codec
, int(self
.data
.write_rate
or 0), int(self
.data
.write_bit_rate
or 0))
274 def user_agent(self
):
275 if self
.data
.user_agent
:
276 return self
.data
.user_agent
.replace("_", " ")
280 return sum((self
.data
.rtp_audio_in_raw_bytes
or 0, self
.data
.rtp_audio_out_raw_bytes
or 0))
284 return self
.data
.rtp_audio_in_mos
287 class Conference(object):
288 def __init__(self
, freeswitch
, handle
):
289 self
.freeswitch
= freeswitch
293 return "<%s %s>" % (self
.__class
__.__name
__, self
.handle
)
296 return len(self
.channels
)
298 def __eq__(self
, other
):
299 if isinstance(other
, self
.__class
__):
300 return self
.handle
== other
.handle
303 return iter(self
.channels
)
307 m
= re
.match(r
"conf(\d+)@", self
.handle
)
315 return 900 + self
.number
319 return self
.freeswitch
._get
_channels
("SELECT * FROM channels \
320 WHERE application = %s AND application_data = %s \
321 ORDER BY created_epoch", "conference", self
.handle
)
326 # Connect to FreeSWITCH
327 self
.freeswitch
= Freeswitch(self
.backend
)
330 def conferences(self
):
331 return self
.freeswitch
.get_conferences()
334 def format_codec(name
, bit_rate
, bandwidth
):
343 s
.append("%.0f kHz" % (bit_rate
/ 1000.0))
346 s
.append("%.0f kBit/s" % (bandwidth
/ 1000.0))