from application.python.weakref import defaultweakobjectmap
from application.system import makedirs
from eventlib import coros, proc
from eventlib.twistedutil import block_on
from sipsimple.configuration.settings import SIPSimpleSettings
from sipsimple.core import SIPURI
from sipsimple.lookup import DNSLookup, DNSLookupError
from sipsimple.threading.green import call_in_green_thread, run_in_green_thread
from twisted.internet import reactor
from sylk.applications.webrtcgateway.configuration import GeneralConfig, get_room_config
from sylk.applications.webrtcgateway.logger import ConnectionLogger, VideoroomLogger
from sylk.applications.webrtcgateway.models import sylkrtc
from sylk.applications.webrtcgateway.storage import TokenStorage
from sylk.applications.webrtcgateway.util import GreenEvent
SIP_PREFIX_RE = re.compile('^sips?:')
sylkrtc_models = {model.sylkrtc.default_value: model for model in vars(sylkrtc).values() if hasattr(model, 'sylkrtc') and issubclass(model, sylkrtc.SylkRTCRequestBase)}
self.account_handles_map = {} # Janus handle ID -> account
self.sip_sessions = SessionContainer() # keeps references to all the SIP sessions created or received by this device
self.videoroom_sessions = SessionContainer() # keeps references to all the videoroom sessions created by this participant (as publisher and subscriber)
self.ready_event = GreenEvent()
self.resolver = DNSLookup()
self.proc = proc.spawn(self._operations_handler)
self.operations_queue = coros.queue()
self.log = ConnectionLogger(self)
def start(self):
self._create_janus_session()
def stop(self):
if self.proc is not None: # Kill the operation's handler proc first, in order to not have any operations active while we cleanup.
self.proc.kill() # Also proc.kill() will switch to another green thread, which is another reason to do it first so that
self.proc = None # we do not switch to another green thread in the middle of the cleanup with a partially deleted handler
if cfg.deny.match(from_uri) or not cfg.allow.match(from_uri):
raise ACLValidationError
else:
if cfg.deny.match(from_uri) and not cfg.allow.match(from_uri):
raise ACLValidationError
# internal methods (not overriding / implementing the protocol API)
def _send_response(self, response):
response.validate()
self._send_data(json.dumps(response.to_struct()))
def _send_data(self, data):
self.protocol.sendMessage(data)
def _cleanup_session(self, session):
# should only be called from a green thread.
if self.janus_session_id is None: # The connection was closed, there is noting to do
return
if session.direction == 'outgoing' and session in self.sip_sessions:
# Destroy plugin handle for outgoing sessions. For incoming ones it's the same as the account handle, so don't
block_on(self.protocol.backend.janus_detach(self.janus_session_id, session.janus_handle_id)) # todo: do we care to wait for this or not? (we ignore the detached event anyway)
# should only be called for publisher sessions and only from a green thread.
if self.janus_session_id is None: # The connection was closed, there is noting to do
return
if session in self.videoroom_sessions:
self.videoroom_sessions.remove(session)
session.room.remove(session)
session.feeds.clear()
block_on(self.protocol.backend.janus_detach(self.janus_session_id, session.janus_handle_id)) # todo: do we care to wait for this or not? (we ignore the detached event anyway)