]> git.ipfire.org Git - ipfire.org.git/blame - src/backend/talk.py
Drop site.js
[ipfire.org.git] / src / backend / talk.py
CommitLineData
66862195
MT
1#!/usr/bin/python
2
917434b8
MT
3import ipaddress
4import logging
77431b9c 5import re
9f05796c 6import time
77431b9c 7
5ac74b02 8from . import database
66862195 9
11347e46 10from .misc import Object
13e89ccc
MT
11from .decorators import *
12
13class Freeswitch(Object):
14 @lazy_property
15 def db(self):
16 credentials = {
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"),
21 }
22
23 return database.Connection(**credentials)
24
917434b8
MT
25 def get_sip_registrations(self, sip_uri):
26 logging.debug("Fetching SIP registrations for %s" % sip_uri)
27
28 user, delim, domain = sip_uri.partition("@")
29
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)
33
34 for row in res:
35 yield SIPRegistration(self, data=row)
36
9f05796c
MT
37 def get_sip_channels(self, account):
38 res = self.db.query("SELECT * FROM channels \
39 WHERE (direction = %s AND cid_num = %s) OR \
40 (direction = %s AND callee_num = %s) ORDER BY created_epoch",
41 "inbound", account.sip_id, "outbound", account.sip_id)
42
9c50164e
MT
43 channels = []
44
9f05796c 45 for row in res:
9c50164e
MT
46 c = Channel(self, data=row)
47 channels.append(c)
48
49 return channels
9f05796c 50
bdaf6b46 51 def get_cdr_by_account(self, account, date=None, limit=None):
525c01f7 52 res = self.db.query("SELECT * FROM cdr \
bdaf6b46
MT
53 WHERE ((caller_id_number = %s AND bleg_uuid IS NOT NULL) \
54 OR (destination_number = %s AND bleg_uuid IS NULL)) \
55 AND (%s IS NULL OR start_stamp::date = %s) \
56 ORDER BY end_stamp DESC LIMIT %s", account.sip_id,
57 account.sip_id, date, date, limit)
525c01f7
MT
58
59 for row in res:
60 yield CDR(self, data=row)
61
917434b8
MT
62
63class SIPRegistration(object):
64 def __init__(self, freeswitch, data):
65 self.freeswitch = freeswitch
66 self.data = data
67
68 @lazy_property
69 def protocol(self):
70 m = re.match(r"Registered\(([A-Z]+)(\-NAT)?\)", self.data.status)
71
72 if m:
73 return m.group(1)
74
75 @property
76 def network_ip(self):
77 return ipaddress.ip_address(self.data.network_ip)
78
79 @property
80 def network_port(self):
81 return self.data.network_port
82
83 @property
84 def user_agent(self):
85 return self.data.user_agent
86
87 def is_reachable(self):
88 return self.data.ping_status == "Reachable"
89
90 @lazy_property
91 def latency(self):
b78ec69b 92 if self.is_reachable() and self.data.ping_time:
917434b8
MT
93 return self.data.ping_time / 1000.0
94
95
9f05796c
MT
96class Channel(object):
97 def __init__(self, freeswitch, data):
98 self.freeswitch = freeswitch
99 self.data = data
66862195 100
9f05796c
MT
101 @property
102 def backend(self):
103 return self.freeswitch.backend
13e89ccc 104
9f05796c
MT
105 @property
106 def uuid(self):
107 return self.data.uuid
66862195 108
9f05796c
MT
109 @property
110 def direction(self):
111 return self.data.direction
112
113 @lazy_property
114 def caller(self):
115 return self.backend.accounts.get_by_sip_id(self.caller_number)
116
117 @property
118 def caller_name(self):
119 return self.data.cid_name
120
121 @property
122 def caller_number(self):
123 return self.data.cid_num
124
125 @lazy_property
126 def callee(self):
127 return self.backend.accounts.get_by_sip_id(self.callee_number)
66862195 128
9f05796c
MT
129 @property
130 def callee_name(self):
131 return self.data.callee_name
132
133 @property
134 def callee_number(self):
135 return self.data.callee_num
136
137 @property
138 def called_number(self):
139 return self.data.dest
140
141 @property
142 def application(self):
143 return self.data.application
66862195 144
9f05796c
MT
145 @property
146 def application_data(self):
147 return self.data.application_data
66862195 148
9f05796c
MT
149 @property
150 def duration(self):
151 return time.time() - self.data.created_epoch
66862195 152
9f05796c
MT
153 @property
154 def codec(self):
155 # We always assume a symmetric codec
156 s = [
e3dfabc1 157 self.data.write_codec,
9f05796c
MT
158 ]
159
e3dfabc1
MT
160 if self.data.write_rate:
161 s.append("%.0f kHz" % (int(self.data.write_rate) / 1000.0))
162
9f05796c
MT
163 if self.data.write_bit_rate == "0":
164 s.append("VBR")
165 else:
166 s.append("%.0f kBit/s" % (int(self.data.write_bit_rate) / 1000.0))
66862195 167
9f05796c
MT
168 return " ".join(s)
169
fe55357f
MT
170 def is_secure(self):
171 if self.data.secure:
172 return True
173
174 return False
175
9f05796c
MT
176 @property
177 def secure(self):
fe55357f
MT
178 try:
179 transport_protocol, key_negotiation, cipher_suite = self.data.secure.split(":")
180 except:
181 return
182
183 return "%s: %s" % (key_negotiation.upper(), cipher_suite.replace("_", "-"))
9f05796c
MT
184
185
525c01f7
MT
186class CDR(object):
187 def __init__(self, freeswitch, data):
188 self.freeswitch = freeswitch
189 self.data = data
190
191 @property
192 def backend(self):
193 return self.freeswitch.backend
194
195 @property
196 def direction(self):
197 if self.data.bleg_uuid:
198 return "inbound"
199
200 return "outbound"
201
202 @lazy_property
203 def caller(self):
204 return self.backend.accounts.get_by_phone_number(self.data.caller_id_number)
205
206 @property
207 def caller_number(self):
208 return self.data.caller_id_number
209
210 @lazy_property
211 def callee(self):
212 return self.backend.accounts.get_by_phone_number(self.data.destination_number)
213
214 @property
215 def callee_number(self):
216 return self.data.destination_number
217
218 @property
219 def time_start(self):
220 return self.data.start_stamp
221
222 @property
223 def time_answered(self):
224 return self.data.answer_stamp
225
226 @property
227 def duration(self):
228 return self.data.duration
229
230 @property
231 def codec(self):
232 return self.data.write_codec
233
234 @property
235 def user_agent(self):
c2c06884 236 return self.data.user_agent.replace("_", " ")
525c01f7 237
354445ed
MT
238 @property
239 def size(self):
240 return sum((self.data.rtp_audio_in_raw_bytes or 0, self.data.rtp_audio_out_raw_bytes or 0))
241
242 @property
243 def mos(self):
244 return self.data.rtp_audio_in_mos
245
525c01f7 246
9f05796c
MT
247class Talk(Object):
248 def init(self):
249 # Connect to FreeSWITCH
250 self.freeswitch = Freeswitch(self.backend)
66862195 251
66862195
MT
252 # Conferences
253
254 @property
255 def conferences(self):
256 conferences = []
257
258 for no in range(1, 10):
259 conference = Conference(self.backend, no)
260 conferences.append(conference)
261
262 return conferences
263
264 def get_conference(self, id):
265 for c in self.conferences:
266 if not c.sip_id == id:
267 continue
268
269 return c
270
271
272class Conference(Object):
273 def __init__(self, backend, no):
274 Object.__init__(self, backend)
275 self.no = no
276
277 def __cmp__(self, other):
278 return cmp(self.no, other.no)
279
280 @property
281 def name(self):
282 return "IPFire Conference Room %s" % self.no
283
284 @property
285 def sip_id(self):
286 return "%s" % (9000 + self.no)
287
288 @property
289 def sip_url(self):
290 return "%s@ipfire.org" % self.sip_id
291
292 @property
293 def participants(self):
294 if not hasattr(self, "_participants"):
295 self._participants = self.backend.talk.get_ongoing_calls(sip_id=self.sip_id)
296
297 return self._participants