Daniel Brötzmann pushed to branch master at gajim / gajim
Commits: aede87a1 by wurstsalat at 2022-05-28T01:33:20+02:00 imprv: Smaller Jingle file transfer widget
- - - - - d4435639 by wurstsalat at 2022-05-28T01:33:45+02:00 chore: JingleTransport: Add type annotations
- - - - - 3644ba0c by wurstsalat at 2022-05-28T01:34:10+02:00 chore: JingleContent: Add type annotations
- - - - - 8ee6677a by wurstsalat at 2022-05-28T01:34:25+02:00 chore: JingleSession: Add type annotations
- - - - - 48db9a10 by wurstsalat at 2022-05-28T01:34:46+02:00 chore: JingleRTP: Add type annotations
- - - - - c63f6f80 by wurstsalat at 2022-05-28T01:35:11+02:00 chore: JingleFileTransfer: Add type annotations
- - - - - f79f7c7f by wurstsalat at 2022-05-28T01:35:45+02:00 chore: JingleFileTransferStates: Add type annotations
- - - - -
7 changed files:
- gajim/common/jingle_content.py - gajim/common/jingle_ft.py - gajim/common/jingle_ftstates.py - gajim/common/jingle_rtp.py - gajim/common/jingle_session.py - gajim/common/jingle_transport.py - gajim/data/gui/file_transfer_jingle.ui
Changes:
===================================== gajim/common/jingle_content.py ===================================== @@ -18,19 +18,20 @@
from __future__ import annotations
-import typing -from typing import Any +from typing import Any, Callable from typing import Optional +from typing import TYPE_CHECKING
import nbxmpp from nbxmpp.namespaces import Namespace
from gajim.common import app from gajim.common import configpaths +from gajim.common.file_props import FileProp from gajim.common.jingle_xtls import SELF_SIGNED_CERTIFICATE from gajim.common.jingle_xtls import load_cert_file
-if typing.TYPE_CHECKING: +if TYPE_CHECKING: from gajim.common.jingle_transport import JingleTransport from gajim.common.jingle_session import JingleSession
@@ -38,7 +39,7 @@ contents: dict[str, Any] = {}
-def get_jingle_content(node): +def get_jingle_content(node: nbxmpp.Node): namespace = node.getNamespace() if namespace in contents: return contents[namespace](node) @@ -58,32 +59,36 @@ class JingleContent: def __init__(self, session: JingleSession, transport: Optional[JingleTransport], - senders: Optional[str]) -> None: + senders: Optional[str] + ) -> None:
self.session = session self.transport = transport # will be filled by JingleSession.add_content() # don't uncomment these lines, we will catch more buggy code then # (a JingleContent not added to session shouldn't send anything) - self.creator = None - self.name = None + self.creator: Optional[str] = None + self.name: Optional[str] = None self.accepted = False self.sent = False self.negotiated = False
- self.media = None + self.media: Optional[str] = None
self.senders = senders if self.senders is None: self.senders = 'both'
- self.allow_sending = True # Used for stream direction, attribute 'senders' + # Used for stream direction, attribute 'senders' + self.allow_sending = True
# These were found by the Politie - self.file_props = None + self.file_props: Optional[FileProp] = None self.use_security: Optional[bool] = None
- self.callbacks = { + self.callbacks: dict[str, list[Callable[ + [nbxmpp.Node, nbxmpp.Node, Optional[nbxmpp.Node], str], + None]]] = { # these are called when *we* get stanzas 'content-accept': [self.__on_transport_info, self.__on_content_accept], @@ -114,13 +119,18 @@ def __init__(self, 'session-terminate-sent': [], }
- def is_ready(self): + def is_ready(self) -> bool: return self.accepted and not self.sent
- def __on_content_accept(self, stanza, content, error, action): + def __on_content_accept(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: self.on_negotiated()
- def on_negotiated(self): + def on_negotiated(self) -> None: if self.accepted: self.negotiated = True self.session.content_negotiated(self.media) @@ -131,7 +141,12 @@ def add_remote_candidates(self, candidates): """ self.transport.remote_candidates = candidates
- def on_stanza(self, stanza, content, error, action): + def on_stanza(self, + stanza: nbxmpp.Node, + content: Optional[nbxmpp.Node], + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Called when something related to our content was sent by peer """ @@ -139,10 +154,20 @@ def on_stanza(self, stanza, content, error, action): for callback in self.callbacks[action]: callback(stanza, content, error, action)
- def __on_transport_replace(self, stanza, content, error, action): + def __on_transport_replace(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: content.addChild(node=self.transport.make_transport())
- def __on_transport_info(self, stanza, content, error, action): + def __on_transport_info(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Got a new transport candidate """ @@ -151,7 +176,9 @@ def __on_transport_info(self, stanza, content, error, action): if candidates: self.add_remote_candidates(candidates)
- def __content(self, payload=None): + def __content(self, + payload: Optional[list[nbxmpp.Node]] = None + ) -> nbxmpp.Node: """ Build a XML content-wrapper for our data """ @@ -163,7 +190,7 @@ def __content(self, payload=None): 'senders': self.senders}, payload=payload)
- def send_candidate(self, candidate): + def send_candidate(self, candidate: dict[str, Any]) -> None: """ Send a transport candidate for a previously defined transport. """ @@ -171,7 +198,7 @@ def send_candidate(self, candidate): content.addChild(node=self.transport.make_transport([candidate])) self.session.send_transport_info(content)
- def send_error_candidate(self): + def send_error_candidate(self) -> None: """ Sends a candidate-error when we can't connect to a candidate. """ @@ -182,12 +209,17 @@ def send_error_candidate(self): self.session.send_transport_info(content)
- def send_description_info(self): + def send_description_info(self) -> None: content = self.__content() self._fill_content(content) self.session.send_description_info(content)
- def __fill_jingle_stanza(self, stanza, content, error, action): + def __fill_jingle_stanza(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Add our things to session-initiate stanza """ @@ -195,7 +227,7 @@ def __fill_jingle_stanza(self, stanza, content, error, action): self.sent = True content.addChild(node=self.transport.make_transport())
- def _fill_content(self, content): + def _fill_content(self, content: nbxmpp.Node) -> None: description_node = nbxmpp.simplexml.Node( tag=Namespace.JINGLE_FILE_TRANSFER_5 + ' description') file_tag = description_node.setTag('file') @@ -253,6 +285,6 @@ def _fill_content(self, content): content.addChild(node=security) content.addChild(node=description_node)
- def destroy(self): + def destroy(self) -> None: self.callbacks = None del self.session.contents[(self.creator, self.name)]
===================================== gajim/common/jingle_ft.py ===================================== @@ -18,13 +18,15 @@
from __future__ import annotations
-import typing +from typing import Any from typing import Optional +from typing import TYPE_CHECKING
import logging import threading import time -from enum import IntEnum, unique +from enum import IntEnum +from enum import unique
import nbxmpp from nbxmpp import JID @@ -50,7 +52,7 @@ from gajim.common.jingle_ftstates import StateCandSentAndRecv from gajim.common.jingle_ftstates import StateTransportReplace
-if typing.TYPE_CHECKING: +if TYPE_CHECKING: from gajim.common.jingle_session import JingleSession from gajim.common.jingle_transport import JingleTransport
@@ -101,7 +103,7 @@ def __init__(self, self.callbacks['iq-result'] += [self.__on_iq_result]
self.use_security = use_security - self.x509_fingerprint = None + self.x509_fingerprint: Optional[str] = None self.file_props = file_props self.weinitiate = self.session.weinitiate self.werequest = self.session.werequest @@ -143,7 +145,10 @@ def __init__(self, and cert_name.with_suffix('.pkey').exists()): jingle_xtls.make_certs(cert_name, 'gajim')
- def __state_changed(self, nextstate, args=None): + def __state_changed(self, + nextstate: State, + args: Optional[dict[str, Any]] =None + ) -> None: # Executes the next state action and sets the next state current_state = self.state st = self.states[nextstate] @@ -152,7 +157,12 @@ def __state_changed(self, nextstate, args=None): if self.state == current_state: self.state = nextstate
- def __on_session_initiate(self, stanza, content, error, action): + def __on_session_initiate(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.debug("Jingle FT request received") self._raise_event(stanza, content)
@@ -177,7 +187,10 @@ def __on_session_initiate(self, stanza, content, error, action): self.session.approve_content(self.media, self.name) self.session.accept_session()
- def _raise_event(self, stanza, content): + def _raise_event(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node + ) -> None: con = self.session.connection id_ = stanza.getID() fjid = con.get_module('Bytestream')._ft_get_from(stanza) @@ -260,10 +273,15 @@ def _raise_event(self, stanza, content): jid=jid, file_props=file_props))
- def __on_session_initiate_sent(self, stanza, content, error, action): + def __on_session_initiate_sent(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: pass
- def __send_hash(self): + def __send_hash(self) -> None: # Send hash in a session info checksum = nbxmpp.Node(tag='checksum', payload=[nbxmpp.Node(tag='file', @@ -280,7 +298,7 @@ def __send_hash(self): } self.session.connection.get_module('Jingle').set_file_info(file_info)
- def _compute_hash(self): + def _compute_hash(self) -> Optional[nbxmpp.Hashes2]: # Calculates the hash and returns a xep-300 hash stanza if self.file_props.algo is None: return @@ -301,11 +319,16 @@ def _compute_hash(self): h.addHash(hash_, self.file_props.algo) return h
- def on_cert_received(self): + def on_cert_received(self) -> None: self.session.approve_session() self.session.approve_content('file', name=self.name)
- def __on_session_accept(self, stanza, content, error, action): + def __on_session_accept(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_session_accept") con = self.session.connection security = content.getTag('security') @@ -326,7 +349,7 @@ def __on_session_accept(self, stanza, content, error, action): raise nbxmpp.NodeProcessed self.continue_session_accept(stanza)
- def continue_session_accept(self, stanza): + def continue_session_accept(self, stanza: nbxmpp.Node) -> None: if self.state == State.TRANSPORT_REPLACE: # If we are requesting we don't have the file if self.session.werequest: @@ -351,31 +374,61 @@ def continue_session_accept(self, stanza): if self.transport.type_ == TransportType.SOCKS5: sid = self.file_props.transport_sid app.socks5queue.connect_to_hosts(self.session.connection.name, - sid, - self.on_connect, - self._on_connect_error, - fingerprint=fingerprint, - receiving=False) + sid, + self.on_connect, + self._on_connect_error, + fingerprint=fingerprint, + receiving=False) raise nbxmpp.NodeProcessed self.__state_changed(State.TRANSFERRING) raise nbxmpp.NodeProcessed
- def __on_session_terminate(self, stanza, content, error, action): + def __on_session_terminate(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_session_terminate")
- def __on_session_info(self, stanza, content, error, action): + def __on_session_info(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: pass
- def __on_transport_accept(self, stanza, content, error, action): + def __on_transport_accept(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_transport_accept")
- def __on_transport_replace(self, stanza, content, error, action): + def __on_transport_replace(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_transport_replace")
- def __on_transport_reject(self, stanza, content, error, action): + def __on_transport_reject(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_transport_reject")
- def __on_transport_info(self, stanza, content, error, action): + def __on_transport_info(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_transport_info") cand_error = content.getTag('transport').getTag('candidate-error') cand_used = content.getTag('transport').getTag('candidate-used') @@ -426,7 +479,12 @@ def __on_transport_info(self, stanza, content, error, action): raise nbxmpp.NodeProcessed self.__state_changed(State.CAND_RECEIVED, args)
- def __on_iq_result(self, stanza, content, error, action): + def __on_iq_result(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: log.info("__on_iq_result")
if self.state in (State.NOT_STARTED, State.CAND_RECEIVED): @@ -441,8 +499,12 @@ def __on_iq_result(self, stanza, content, error, action): # initiate transfer self.__state_changed(State.TRANSFERRING)
- def __transport_setup(self, stanza=None, content=None, error=None, - action=None): + def __transport_setup(self, + stanza: nbxmpp.Node, + content: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: # Sets up a few transport specific things for the file transfer if self.transport.type_ == TransportType.IBB: # No action required, just set the state to transferring @@ -462,23 +524,23 @@ def on_connect(self, streamhost): self.nominated_cand['our-cand'] = streamhost self.__send_candidate(args)
- def _on_connect_error(self, sid): + def _on_connect_error(self, sid: str) -> None: log.info('connect error, sid=%s', sid) args = {'candError' : True, 'sendCand' : True} self.__send_candidate(args)
- def __send_candidate(self, args): + def __send_candidate(self, args: dict[str, Any]) -> None: if self.state == State.CAND_RECEIVED: self.__state_changed(State.CAND_SENT_AND_RECEIVED, args) else: self.__state_changed(State.CAND_SENT, args)
- def _store_socks5_sid(self, sid, hash_id): + def _store_socks5_sid(self, sid: str, hash_id: str) -> None: # callback from socsk5queue.start_listener self.file_props.hash_ = hash_id
- def _listen_host(self): + def _listen_host(self) -> None: receiver = self.file_props.receiver sender = self.file_props.sender sha_str = helpers.get_auth_sha(self.file_props.sid, sender, @@ -497,7 +559,7 @@ def _listen_host(self): # send error message, notify the user return
- def is_our_candidate_used(self): + def is_our_candidate_used(self) -> bool: ''' If this method returns true then the candidate we nominated will be used, if false, the candidate nominated by peer will be used @@ -513,12 +575,12 @@ def is_our_candidate_used(self): return our_pr > peer_pr return self.weinitiate
- def start_ibb_transfer(self): + def start_ibb_transfer(self) -> None: if self.file_props.type_ == 's': self.__state_changed(State.TRANSFERRING)
-def get_content(desc): +def get_content(desc) -> JingleFileTransfer: return JingleFileTransfer
contents[Namespace.JINGLE_FILE_TRANSFER_5] = get_content
===================================== gajim/common/jingle_ftstates.py ===================================== @@ -12,16 +12,26 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+from __future__ import annotations + +from typing import Any +from typing import Optional +from typing import TYPE_CHECKING + import logging
import nbxmpp from nbxmpp.namespaces import Namespace
from gajim.common import app +from gajim.common import types from gajim.common.jingle_transport import TransportType from gajim.common.socks5 import Socks5ReceiverClient from gajim.common.socks5 import Socks5SenderClient
+if TYPE_CHECKING: + from gajim.common.jingle_ft import JingleFileTransfer + log = logging.getLogger('gajim.c.jingle_ftstates')
@@ -30,10 +40,10 @@ class JingleFileTransferStates: This class implements the state machine design pattern '''
- def __init__(self, jingleft): + def __init__(self, jingleft: JingleFileTransfer) -> None: self.jft = jingleft
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: ''' This method MUST be overridden by a subclass ''' @@ -45,7 +55,7 @@ class StateInitialized(JingleFileTransferStates): This state initializes the file transfer '''
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: if self.jft.weinitiate: # update connection's fileprops self.jft._listen_host() @@ -65,7 +75,7 @@ class StateCandSent(JingleFileTransferStates): This state sends our nominated candidate '''
- def _send_candidate(self, args): + def _send_candidate(self, args: dict[str, Any]) -> None: if 'candError' in args: self.jft.nominated_cand['our-cand'] = False self.jft.send_error_candidate() @@ -85,7 +95,7 @@ def _send_candidate(self, args): content.addChild(node=transport) self.jft.session.send_transport_info(content)
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: self._send_candidate(args)
@@ -95,7 +105,7 @@ class StateCandReceived(JingleFileTransferStates): It takes the arguments: canError if we receive a candidate-error '''
- def _recv_candidate(self, args): + def _recv_candidate(self, args: dict[str, Any]) -> None: if 'candError' in args: return content = args['content'] @@ -112,7 +122,7 @@ def _recv_candidate(self, args): # We save the candidate nominated by peer self.jft.nominated_cand['peer-cand'] = streamhost_used
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: self._recv_candidate(args)
@@ -123,7 +133,7 @@ class StateCandSentAndRecv(StateCandSent, StateCandReceived): we should execute the action of when we receive or send a candidate. '''
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: if args['sendCand']: self._send_candidate(args) else: @@ -135,7 +145,7 @@ class StateTransportReplace(JingleFileTransferStates): This state initiates transport replace '''
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: self.jft.session.transport_replace()
@@ -145,14 +155,14 @@ class StateTransfering(JingleFileTransferStates): we have. '''
- def _start_ibb_transfer(self, con): + def _start_ibb_transfer(self, con: types.Client) -> None: self.jft.file_props.transport_sid = self.jft.transport.sid fp = open(self.jft.file_props.file_name, 'rb') con.get_module('IBB').send_open(self.jft.session.peerjid, self.jft.file_props.sid, fp)
- def _start_sock5_transfer(self): + def _start_sock5_transfer(self) -> None: # It tells whether we start the transfer as client or server mode = None if self.jft.is_our_candidate_used(): @@ -221,7 +231,7 @@ def _start_sock5_transfer(self): app.socks5queue.send_file(self.jft.file_props, self.jft.session.connection.name, mode)
- def action(self, args=None): + def action(self, args: Optional[dict[str, Any]] = None) -> None: if self.jft.transport.type_ == TransportType.IBB: self._start_ibb_transfer(self.jft.session.connection) elif self.jft.transport.type_ == TransportType.SOCKS5:
===================================== gajim/common/jingle_rtp.py ===================================== @@ -16,6 +16,13 @@ Handles Jingle RTP sessions (XEP 0167) """
+from __future__ import annotations + +from typing import Any +from typing import Callable +from typing import Iterator +from typing import Optional + import os import logging import socket @@ -40,13 +47,18 @@ from gajim.common.jingle_content import JingleContent from gajim.common.jingle_content import JingleContentSetupException from gajim.common.jingle_session import FailedApplication - +from gajim.common.jingle_session import JingleSession +from gajim.common.jingle_transport import JingleTransport
log = logging.getLogger('gajim.c.jingle_rtp')
class JingleRTPContent(JingleContent): - def __init__(self, session, media, transport=None): + def __init__(self, + session: JingleSession, + media: str, + transport: Optional[JingleTransport] = None + ) -> None: if transport is None: transport = JingleTransportICEUDP(None) JingleContent.__init__(self, session, transport, None) @@ -56,17 +68,17 @@ def __init__(self, session, media, transport=None): 'audio': Farstream.MediaType.AUDIO, 'video': Farstream.MediaType.VIDEO}[media]
- self.pipeline = None - self.src_bin = None + self.pipeline: Optional[Gst.Pipeline] = None + self.src_bin: Optional[Gst.Bin] = None self.stream_failed_once = False
- self.candidates_ready = False # True when local candidates are prepared + self.candidates_ready = False # True when local candidates are prepared
# TODO - self.conference = None - self.funnel = None - self.p2psession = None - self.p2pstream = None + self.conference: Optional[Farstream.Conference] = None + self.funnel: Optional[Gst.Element] = None + self.p2psession: Optional[Farstream.Session] = None + self.p2pstream: Optional[Farstream.Stream] = None
self.callbacks['session-initiate'] += [self.__on_remote_codecs] self.callbacks['content-add'] += [self.__on_remote_codecs] @@ -76,7 +88,10 @@ def __init__(self, session, media, transport=None): self.callbacks['session-terminate'] += [self.__stop] self.callbacks['session-terminate-sent'] += [self.__stop]
- def setup_stream(self, on_src_pad_added): + def setup_stream(self, + on_src_pad_added: Callable[ + [Farstream.Stream, Gst.Pad, Farstream.Codec], None] + ) -> None: # pipeline and bus self.pipeline = Gst.Pipeline() bus = self.pipeline.get_bus() @@ -114,10 +129,14 @@ def setup_stream(self, on_src_pad_added): self.p2pstream.connect('src-pad-added', on_src_pad_added) self.p2pstream.set_transmitter_ht('nice', params)
- def is_ready(self): + def is_ready(self) -> bool: return JingleContent.is_ready(self) and self.candidates_ready
- def make_bin_from_config(self, config_key, pipeline, text): + def make_bin_from_config(self, + config_key: str, + pipeline: str, + text: str + ) -> Optional[Gst.Bin]: pipeline = pipeline % app.settings.get(config_key) log.debug('Pipeline: %s', str(pipeline)) try: @@ -136,18 +155,18 @@ def add_remote_candidates(self, candidates): if self.sent: self.p2pstream.add_remote_candidates(candidates)
- def batch_dtmf(self, events): + def batch_dtmf(self, events: list[str]) -> None: """ Send several DTMF tones """ if self._dtmf_running: raise Exception("There is a DTMF batch already running") - events = deque(events) + d_events = deque(events) self._dtmf_running = True - self.start_dtmf(events.popleft()) - GLib.timeout_add(500, self._next_dtmf, events) + self.start_dtmf(d_events.popleft()) + GLib.timeout_add(500, self._next_dtmf, d_events)
- def _next_dtmf(self, events): + def _next_dtmf(self, events: deque[str]): self.stop_dtmf() if events: self.start_dtmf(events.popleft()) @@ -164,28 +183,32 @@ def start_dtmf(self, key: str) -> None: event = int(key) self.p2psession.start_telephony_event(event, 2)
- def stop_dtmf(self): + def stop_dtmf(self) -> None: self.p2psession.stop_telephony_event()
- def _fill_content(self, content): + def _fill_content(self, content: nbxmpp.Node) -> None: content.addChild(Namespace.JINGLE_RTP + ' description', attrs={'media': self.media}, payload=list(self.iter_codecs()))
- def _setup_funnel(self): + def _setup_funnel(self) -> None: self.funnel = Gst.ElementFactory.make('funnel', None) self.pipeline.add(self.funnel) self.funnel.link(self.sink) self.sink.set_state(Gst.State.PLAYING) self.funnel.set_state(Gst.State.PLAYING)
- def _on_src_pad_added(self, _stream, pad, codec): + def _on_src_pad_added(self, + _stream: Farstream.Stream, + pad: Gst.Pad, + codec: Farstream.Codec + ) -> None: log.info('Used codec: %s', codec.to_string()) if not self.funnel: self._setup_funnel() pad.link(self.funnel.get_request_pad('sink_%u'))
- def _on_gst_message(self, _bus, message): + def _on_gst_message(self, _bus: Gst.Bus, message: Gst.Message) -> None: if message.type == Gst.MessageType.ELEMENT: name = message.get_structure().get_name() message_string = message.get_structure().to_string() @@ -257,10 +280,10 @@ def _on_gst_message(self, _bus, message): self.pipeline.set_state(Gst.State.PLAYING)
@staticmethod - def get_fallback_src(): + def get_fallback_src() -> Optional[Gst.Element]: return Gst.ElementFactory.make('fakesrc', None)
- def on_negotiated(self): + def on_negotiated(self) -> None: if self.accepted: if self.p2psession.get_property('codecs'): # those lines MUST be done after we get info on our codecs @@ -273,11 +296,16 @@ def on_negotiated(self): # Farstream.StreamDirection.BOTH) JingleContent.on_negotiated(self)
- def __on_remote_codecs(self, _stanza, content, _error, _action): + def __on_remote_codecs(self, + _stanza: nbxmpp.Node, + content: nbxmpp.Node, + _error: Optional[nbxmpp.Node], + _action: str + ) -> None: """ Get peer codecs from what we get from peer """ - codecs = [] + codecs: list[Farstream.Codec] = [] for codec in content.getTag('description').iterTags('payload-type'): if not codec['id'] or not codec['name'] or not codec['clockrate']: # ignore invalid payload-types @@ -303,7 +331,7 @@ def __on_remote_codecs(self, _stanza, content, _error, _action): except GLib.Error: raise FailedApplication
- def iter_codecs(self): + def iter_codecs(self) -> Iterator[nbxmpp.Node]: codecs = self.p2psession.props.codecs_without_config for codec in codecs: attrs = { @@ -322,13 +350,13 @@ def iter_codecs(self): payload = [] yield nbxmpp.Node('payload-type', attrs, payload)
- def __stop(self, *things): + def __stop(self, *args: Any) -> None: self.pipeline.set_state(Gst.State.NULL)
- def __del__(self): + def __del__(self) -> None: self.__stop()
- def destroy(self): + def destroy(self) -> None: JingleContent.destroy(self) self.p2pstream.disconnect_by_func(self._on_src_pad_added) self.pipeline.get_bus().disconnect_by_func(self._on_gst_message) @@ -340,7 +368,10 @@ class JingleAudio(JingleRTPContent): protocol """
- def __init__(self, session, transport=None): + def __init__(self, + session: JingleSession, + transport: Optional[JingleTransport] = None + ) -> None: JingleRTPContent.__init__(self, session, 'audio', transport) self.setup_stream()
@@ -356,11 +387,11 @@ def set_out_volume(self, vol: float) -> None: """ self.out_volume.set_property('volume', vol)
- def setup_stream(self): + def setup_stream(self) -> None: JingleRTPContent.setup_stream(self, self._on_src_pad_added)
# list of codecs that are explicitly allowed - allow_codecs = [ + allow_codecs: list[Farstream.Codec] = [ Farstream.Codec.new(Farstream.CODEC_ID_ANY, 'OPUS', Farstream.MediaType.AUDIO, 48000), Farstream.Codec.new(Farstream.CODEC_ID_ANY, 'SPEEX', @@ -380,7 +411,7 @@ def setup_stream(self): ]
# disable all other codecs - disable_codecs = [] + disable_codecs: list[Farstream.Codec] = [] codecs_without_config = self.p2psession.props.codecs_without_config allowed_encoding_names = [c.encoding_name for c in allow_codecs] allowed_encoding_names.append('telephone-event') @@ -428,12 +459,15 @@ def setup_stream(self):
class JingleVideo(JingleRTPContent): - def __init__(self, session, transport=None): + def __init__(self, + session: JingleSession, + transport: Optional[JingleTransport] = None + ) -> None: JingleRTPContent.__init__(self, session, 'video', transport) self.sink = None self.setup_stream()
- def setup_stream(self): + def setup_stream(self) -> None: # TODO: Everything is not working properly: # sometimes, one window won't show up, # sometimes it'll freeze... @@ -443,7 +477,7 @@ def setup_stream(self):
# list of codecs that are explicitly allowed # for now only VP8/H264 (available in gst-plugins-good) - allow_codecs = [ + allow_codecs: list[Farstream.Codec] = [ #Farstream.Codec.new(Farstream.CODEC_ID_ANY, 'VP9', # Farstream.MediaType.VIDEO, 90000), Farstream.Codec.new(Farstream.CODEC_ID_ANY, 'VP8', @@ -453,7 +487,7 @@ def setup_stream(self): ]
# disable all other codecs - disable_codecs = [] + disable_codecs: list[Farstream.Codec] = [] codecs_without_config = self.p2psession.props.codecs_without_config allowed_encoding_names = [c.encoding_name for c in allow_codecs] for codec in codecs_without_config: @@ -466,7 +500,10 @@ def setup_stream(self):
self.p2psession.set_codec_preferences(allow_codecs + disable_codecs)
- def do_setup(self, self_display_sink, other_sink): + def do_setup(self, + self_display_sink: Gst.Element, + other_sink: Gst.Element + ) -> None: if app.settings.get('video_see_self'): tee = ('! tee name=split ! queue name=self-display-queue split. ! ' 'queue name=network-queue') @@ -510,7 +547,8 @@ def do_setup(self, self_display_sink, other_sink): log.debug('Could not save pipeline graph. Make sure ' 'graphviz is installed.')
- def get_fallback_src(self): + @staticmethod + def get_fallback_src() -> Optional[Gst.Bin]: # TODO: Use avatar? pipeline = ('videotestsrc is-live=true ! video/x-raw,framerate=10/1 ! ' 'videoconvert')
===================================== gajim/common/jingle_session.py ===================================== @@ -29,7 +29,10 @@
from __future__ import annotations
+from typing import Any +from typing import Callable from typing import Optional +from typing import TYPE_CHECKING
import time import logging @@ -38,6 +41,7 @@ import nbxmpp from nbxmpp import JID from nbxmpp.namespaces import Namespace +from nbxmpp.protocol import Iq from nbxmpp.util import generate_id
from gajim.common import app @@ -52,6 +56,8 @@ from gajim.common.jingle_content import JingleContentSetupException from gajim.common.jingle_ft import State from gajim.common.file_props import FilesProp +if TYPE_CHECKING: + from gajim.common.jingle_transport import JingleTransport
log = logging.getLogger("app.c.jingle_session") @@ -144,7 +150,9 @@ def __init__(self, # callbacks to call on proper contents # use .prepend() to add new callbacks, especially when you're going # to send error instead of ack - self.callbacks = { + self.callbacks: dict[str, list[Callable[ + [nbxmpp.Node, nbxmpp.Node, Optional[nbxmpp.Node], str], + None]]] = { 'content-accept': [self.__ack, self.__on_content_accept, self.__broadcast], 'content-add': [self.__ack, @@ -175,17 +183,17 @@ def __init__(self, 'iq-error': [self.__on_error], }
- def collect_iq_id(self, iq_id): + def collect_iq_id(self, iq_id: str) -> None: if iq_id is not None: self.iq_ids.append(iq_id)
- def approve_session(self): + def approve_session(self) -> None: """ Called when user accepts session in UI (when we aren't the initiator) """ self.accept_session()
- def decline_session(self): + def decline_session(self) -> None: """ Called when user declines session in UI (when we aren't the initiator) """ @@ -193,7 +201,7 @@ def decline_session(self): reason.addChild('decline') self._session_terminate(reason)
- def cancel_session(self): + def cancel_session(self) -> None: """ Called when user declines session in UI (when we aren't the initiator) """ @@ -215,7 +223,7 @@ def reject_content(self, media: str, name: Optional[str] = None) -> None: content.destroy() self.on_session_state_changed()
- def end_session(self): + def end_session(self) -> None: """ Called when user stops or cancel session in UI """ @@ -263,7 +271,11 @@ def add_content(self, # The content is from us, accept it content.accepted = True
- def remove_content(self, creator, name, reason=None): + def remove_content(self, + creator: str, + name: str, + reason: Optional[nbxmpp.Node] = None + ) -> None: """ Remove the content `name` created by `creator` by sending content-remove, or by sending session-terminate if @@ -276,7 +288,11 @@ def remove_content(self, creator, name, reason=None): if not self.contents: self.end_session()
- def modify_content(self, creator, name, transport=None): + def modify_content(self, + creator: str, + name: str, + transport: Optional[JingleTransport] = None + ) -> None: ''' Currently used for transport replacement ''' @@ -320,50 +336,50 @@ def on_session_state_changed(self, # The other side created this content, we accept it. self.__content_accept(content)
- def is_ready(self): + def is_ready(self) -> bool: """ Return True when all codecs and candidates are ready (for all contents) """ return (all((content.is_ready() for content in self.contents.values())) and self.accepted)
- def accept_session(self): + def accept_session(self) -> None: """ Mark the session as accepted """ self.accepted = True self.on_session_state_changed()
- def start_session(self): + def start_session(self) -> None: """ Mark the session as ready to be started """ self.accepted = True self.on_session_state_changed()
- def send_session_info(self): + def send_session_info(self) -> Any: pass
- def send_content_accept(self, content): + def send_content_accept(self, content: nbxmpp.Node) -> None: assert self.state != JingleStates.ENDED stanza, jingle = self.__make_jingle('content-accept') jingle.addChild(node=content) self.connection.connection.send(stanza)
- def send_transport_info(self, content): + def send_transport_info(self, content: nbxmpp.Node) -> None: assert self.state != JingleStates.ENDED stanza, jingle = self.__make_jingle('transport-info') jingle.addChild(node=content) self.connection.connection.send(stanza) self.collect_iq_id(stanza.getID())
- def send_description_info(self, content): + def send_description_info(self, content: nbxmpp.Node) -> None: assert self.state != JingleStates.ENDED stanza, jingle = self.__make_jingle('description-info') jingle.addChild(node=content) self.connection.connection.send(stanza)
- def on_stanza(self, stanza): + def on_stanza(self, stanza: nbxmpp.Node) -> None: """ A callback for ConnectionJingle. It gets stanza, then tries to send it to all internally registered callbacks. First one to raise @@ -404,7 +420,12 @@ def on_stanza(self, stanza): reason.addChild('failed-application') self._session_terminate(reason)
- def __ack(self, stanza, jingle, error, action): + def __ack(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Default callback for action stanzas -- simple ack and stop processing """ @@ -412,7 +433,12 @@ def __ack(self, stanza, jingle, error, action): response.delChild(response.getQuery()) self.connection.connection.send(response)
- def __on_error(self, stanza, jingle, error, action): + def __on_error(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: nbxmpp.Node, + action: str + ) -> None: # FIXME text = error.getTagData('text') error_name = None @@ -424,7 +450,7 @@ def __on_error(self, stanza, jingle, error, action): error_name = child.getName() self.__dispatch_error(error_name, text, error.getAttr('type'))
- def transport_replace(self): + def transport_replace(self) -> None: transport = JingleTransportIBB() # For debug only, delete this and replace for a function # that will identify contents by its sid @@ -438,7 +464,12 @@ def transport_replace(self): self.connection.connection.send(stanza) self.state = JingleStates.PENDING
- def __on_transport_replace(self, stanza, jingle, error, action): + def __on_transport_replace(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: for content in jingle.iterTags('content'): creator = content['creator'] name = content['name'] @@ -474,7 +505,12 @@ def __on_transport_replace(self, stanza, jingle, error, action): self.connection.connection.send(stanza) raise nbxmpp.NodeProcessed
- def __on_session_info(self, stanza, jingle, error, action): + def __on_session_info(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: # TODO: active, (un)hold, (un)mute ringing = jingle.getTag('ringing') if ringing is not None: @@ -499,7 +535,12 @@ def __on_session_info(self, stanza, jingle, error, action): type_='modify') raise nbxmpp.NodeProcessed
- def __on_content_remove(self, stanza, jingle, error, action): + def __on_content_remove(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: for content in jingle.iterTags('content'): creator = content['creator'] name = content['name'] @@ -515,14 +556,23 @@ def __on_content_remove(self, stanza, jingle, error, action): reason.setTag('success') self._session_terminate(reason)
- def __on_session_accept(self, stanza, jingle, error, action): + def __on_session_accept(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: # FIXME if self.state != JingleStates.PENDING: raise OutOfOrder self.state = JingleStates.ACTIVE
@staticmethod - def __on_content_accept(stanza, jingle, error, action): + def __on_content_accept(stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Called when we get content-accept stanza or equivalent one (like session-accept) @@ -533,7 +583,12 @@ def __on_content_accept(stanza, jingle, error, action): # name = content['name'] return
- def __on_content_add(self, stanza, jingle, error, action): + def __on_content_add(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: if self.state == JingleStates.ENDED: raise OutOfOrder parse_result = self.__parse_contents(jingle) @@ -546,7 +601,12 @@ def __on_content_add(self, stanza, jingle, error, action): # self.contents[(content.creator, content.name)].destroy() self._raise_event('jingle-request-received', contents=contents)
- def __on_session_initiate(self, stanza, jingle, error, action): + def __on_session_initiate(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ We got a jingle session request from other entity, therefore we are the receiver... Unpack the data, inform the user @@ -619,7 +679,7 @@ def __on_session_initiate(self, stanza, jingle, error, action): self._raise_event('jingle-request-received', contents=contents)
# Check if it's an A/V call and add it to the archive - content_types = [] + content_types: list[str] = [] for item in contents: content_types.append(item.media) if not any(item in ('audio', 'video') for item in content_types): @@ -637,7 +697,12 @@ def __on_session_initiate(self, stanza, jingle, error, action): KindConstant.CALL_INCOMING, additional_data=additional_data)
- def __broadcast(self, stanza, jingle, error, action): + def __broadcast(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Broadcast the stanza contents to proper content handlers """ @@ -661,7 +726,12 @@ def __broadcast(self, stanza, jingle, error, action): cn = self.contents[(creator, name)] cn.on_stanza(stanza, content, error, action)
- def __on_session_terminate(self, stanza, jingle, error, action): + def __on_session_terminate(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: self.connection.get_module('Jingle').delete_jingle_session(self.sid) reason, text = self.__reason_from_stanza(jingle) if reason not in ('success', 'cancel', 'decline'): @@ -684,18 +754,28 @@ def __on_session_terminate(self, stanza, jingle, error, action): media=None, reason=text)
- def __broadcast_all(self, stanza, jingle, error, action): + def __broadcast_all(self, + stanza: nbxmpp.Node, + jingle: nbxmpp.Node, + error: Optional[nbxmpp.Node], + action: str + ) -> None: """ Broadcast the stanza to all content handlers """ for content in self.contents.values(): content.on_stanza(stanza, None, error, action)
- def __parse_contents(self, jingle): + def __parse_contents(self, + jingle: nbxmpp.Node + ) -> tuple[ + list[JingleContent], + list[tuple[str, str]], + Optional[str]]: # TODO: Needs some reworking - contents = [] - contents_rejected = [] - reasons = set() + contents: list[JingleContent] = [] + contents_rejected: list[tuple[str, str]] = [] + reasons: set[str] = set() for element in jingle.iterTags('content'): transport = get_jingle_transport(element.getTag('transport')) if transport: @@ -706,7 +786,8 @@ def __parse_contents(self, jingle): if transport: content = content_type(self, transport=transport) self.add_content(element['name'], - content, 'peer') + content, + 'peer') contents.append(content) else: reasons.add('unsupported-transports') @@ -725,14 +806,18 @@ def __parse_contents(self, jingle): break return (contents, contents_rejected, failure_reason)
- def __dispatch_error(self, error=None, text=None, type_=None): + def __dispatch_error(self, + error: Optional[str] = None, + text: Optional[str] = None, + type_: Optional[str] = None + ) -> None: if text: text = '%s (%s)' % (error, text) if type_ != 'modify': self._raise_event('jingle-error-received', reason=text or error)
@staticmethod - def __reason_from_stanza(stanza): + def __reason_from_stanza(stanza: nbxmpp.Node) -> tuple[str, str]: # TODO: Move to GUI? reason = 'success' reasons = [ @@ -752,7 +837,10 @@ def __reason_from_stanza(stanza): break return (reason, text)
- def __make_jingle(self, action, reason=None): + def __make_jingle(self, + action: str, + reason: Optional[nbxmpp.Node] = None + ) -> tuple[Iq, nbxmpp.Node]: stanza = nbxmpp.Iq(typ='set', to=nbxmpp.JID.from_string(self.peerjid), frm=self.ourjid) attrs = { @@ -766,7 +854,13 @@ def __make_jingle(self, action, reason=None): jingle.addChild(node=reason) return stanza, jingle
- def __send_error(self, stanza, error, jingle_error=None, text=None, type_=None): + def __send_error(self, + stanza: nbxmpp.Node, + error: Optional[str], + jingle_error: Optional[str] = None, + text: Optional[str] = None, + type_: Optional[str] = None + ) -> None: err_stanza = nbxmpp.Error(stanza, '%s %s' % (Namespace.STANZAS, error)) err = err_stanza.getTag('error') if type_: @@ -779,7 +873,7 @@ def __send_error(self, stanza, error, jingle_error=None, text=None, type_=None): self.__dispatch_error(jingle_error or error, text, type_)
@staticmethod - def __append_content(jingle, content): + def __append_content(jingle: nbxmpp.Node, content: JingleContent) -> None: """ Append <content/> element to <jingle/> element """ @@ -788,7 +882,7 @@ def __append_content(jingle, content): 'creator': content.creator, 'senders': content.senders})
- def __append_contents(self, jingle): + def __append_contents(self, jingle: nbxmpp.Node) -> None: """ Append all <content/> elements to <jingle/> """ @@ -798,7 +892,7 @@ def __append_contents(self, jingle): if content.is_ready(): self.__append_content(jingle, content)
- def __session_initiate(self): + def __session_initiate(self) -> None: assert self.state == JingleStates.ENDED stanza, jingle = self.__make_jingle('session-initiate') self.__append_contents(jingle) @@ -807,7 +901,7 @@ def __session_initiate(self): self.collect_iq_id(stanza.getID()) self.state = JingleStates.PENDING
- def __session_accept(self): + def __session_accept(self) -> None: assert self.state == JingleStates.PENDING stanza, jingle = self.__make_jingle('session-accept') self.__append_contents(jingle) @@ -816,33 +910,33 @@ def __session_accept(self): self.collect_iq_id(stanza.getID()) self.state = JingleStates.ACTIVE
- def __session_info(self, payload=None): + def __session_info(self, payload: Optional[nbxmpp.Node] = None) -> None: assert self.state != JingleStates.ENDED stanza, jingle = self.__make_jingle('session-info') if payload: jingle.addChild(node=payload) self.connection.connection.send(stanza)
- def _JingleFileTransfer__session_info(self, payload): + def _JingleFileTransfer__session_info(self, payload: nbxmpp.Node) -> None: # For some strange reason when I call # self.session.__session_info(payload) from the jingleFileTransfer object # within a thread, this method gets called instead. Even though, it # isn't being called explicitly. self.__session_info(payload)
- def _session_terminate(self, reason=None): + def _session_terminate(self, reason: Optional[nbxmpp.Node] = None) -> None: stanza, jingle = self.__make_jingle('session-terminate', reason=reason) self.__broadcast_all(stanza, jingle, None, 'session-terminate-sent') if self.connection.connection and self.connection.state.is_available: self.connection.connection.send(stanza) # TODO: Move to GUI? - reason, text = self.__reason_from_stanza(jingle) + reason_text, text = self.__reason_from_stanza(jingle) if reason not in ('success', 'cancel', 'decline'): - self.__dispatch_error(reason, text) + self.__dispatch_error(reason_text, text) if text: - text = '%s (%s)' % (reason, text) + text = f'{reason_text} ({text})' else: - text = reason + text = reason_text self.connection.get_module('Jingle').delete_jingle_session(self.sid) self._raise_event('jingle-disconnected-received', media=None, @@ -876,7 +970,10 @@ def __content_reject(self, content: JingleContent) -> None: media=content.media, reason='rejected')
- def __content_remove(self, content, reason=None): + def __content_remove(self, + content: JingleContent, + reason: Optional[nbxmpp.Node] = None + ) -> None: assert self.state != JingleStates.ENDED if self.connection.connection and self.connection.state.is_available: stanza, jingle = self.__make_jingle('content-remove', reason=reason) @@ -887,10 +984,10 @@ def __content_remove(self, content, reason=None): media=content.media, reason='removed')
- def content_negotiated(self, media): + def content_negotiated(self, media: str) -> None: self._raise_event('jingle-connected-received', media=media)
- def __transport_accept(self, transport): + def __transport_accept(self, transport: JingleTransport) -> None: assert self.state != JingleStates.ENDED stanza, jingle = self.__make_jingle('transport-accept') self.__append_contents(jingle) @@ -899,7 +996,7 @@ def __transport_accept(self, transport): self.collect_iq_id(stanza.getID()) self.state = JingleStates.ACTIVE
- def _raise_event(self, name: str, **kwargs): + def _raise_event(self, name: str, **kwargs: Any) -> None: jid, resource = app.get_room_and_nick_from_fjid( str(self.peerjid)) jid = JID.from_string(jid)
===================================== gajim/common/jingle_transport.py ===================================== @@ -31,13 +31,14 @@ from gajim.common import app from gajim.common.client import Client from gajim.common.file_props import FileProp +from gajim.common.jingle_content import JingleContent
log = logging.getLogger('gajim.c.jingle_transport')
transports: dict[str, Any] = {}
-def get_jingle_transport(node): +def get_jingle_transport(node: nbxmpp.Node): namespace = node.getNamespace() if namespace in transports: return transports[namespace](node) @@ -63,8 +64,8 @@ class JingleTransport:
def __init__(self, type_: TransportType) -> None: self.type_ = type_ - self.candidates = [] - self.remote_candidates = [] + self.candidates: list[dict[str, Any]] = [] + self.remote_candidates: list[dict[str, Any]] = []
self.connection: Optional[Client] = None self.file_props: Optional[FileProp] = None @@ -75,12 +76,14 @@ def _iter_candidates(self): for candidate in self.candidates: yield self.make_candidate(candidate)
- def make_candidate(self, candidate): + def make_candidate(self, candidate: dict[str, Any]) -> Any: """ Build a candidate stanza for the given candidate """
- def make_transport(self, candidates=None): + def make_transport(self, + candidates: Optional[list[dict[str, Any]]] = None + ) -> nbxmpp.Node: """ Build a transport stanza with the given candidates (or self.candidates if candidates is None) @@ -92,7 +95,7 @@ def make_transport(self, candidates=None): transport = nbxmpp.Node('transport', payload=candidates) return transport
- def parse_transport_stanza(self, transport): + def parse_transport_stanza(self, transport: nbxmpp.Node) -> list[Any]: """ Return the list of transport candidates from a transport stanza """ @@ -118,16 +121,16 @@ class JingleTransportSocks5(JingleTransport): Socks5 transport in jingle scenario Note: Don't forget to call set_file_props after initialization """ - def __init__(self, node=None): + def __init__(self, node: Optional[nbxmpp.Node] = None) -> None: JingleTransport.__init__(self, TransportType.SOCKS5) self.connection = None - self.remote_candidates = [] - self.sid = None + self.remote_candidates: list[dict[str, Any]] = [] + self.sid: Optional[str] = None if node and node.getAttr('sid'): self.sid = node.getAttr('sid')
- def make_candidate(self, candidate): + def make_candidate(self, candidate) -> nbxmpp.Node: log.info('candidate dict, %s', candidate) attrs = { 'cid': candidate['candidate_id'], @@ -140,7 +143,10 @@ def make_candidate(self, candidate):
return nbxmpp.Node('candidate', attrs=attrs)
- def make_transport(self, candidates=None, add_candidates=True): + def make_transport(self, + candidates: Optional[list[dict[str, Any]]] = None, + add_candidates: bool = True + ) -> nbxmpp.Node: if add_candidates: self._add_local_ips_as_candidates() self._add_additional_candidates() @@ -154,8 +160,10 @@ def make_transport(self, candidates=None, add_candidates=True): transport.setAttr('dstaddr', self.file_props.dstaddr) return transport
- def parse_transport_stanza(self, transport): - candidates = [] + def parse_transport_stanza(self, + transport: nbxmpp.Node + ) -> list[dict[str, Any]]: + candidates: list[dict[str, Any]] = [] for candidate in transport.iterTags('candidate'): cand = { 'state': 0, @@ -174,7 +182,7 @@ def parse_transport_stanza(self, transport): return candidates
- def _add_candidates(self, candidates): + def _add_candidates(self, candidates: list[dict[str, Any]]) -> None: for cand in candidates: in_remote = False for cand2 in self.remote_candidates: @@ -185,7 +193,7 @@ def _add_candidates(self, candidates): if not in_remote: self.candidates.append(cand)
- def _add_local_ips_as_candidates(self): + def _add_local_ips_as_candidates(self) -> None: if not app.settings.get_account_setting(self.connection.name, 'ft_send_local_ips'): return @@ -196,8 +204,8 @@ def _add_local_ips_as_candidates(self): type_preference = 126 priority = (2**16) * type_preference
- hosts = set() - local_ip_cand = [] + hosts: set[Optional[str]] = set() + local_ip_cand: list[dict[str, Any]] = []
my_ip = self.connection.local_address if my_ip is None: @@ -280,7 +288,7 @@ def _add_local_ips_as_candidates(self):
self._add_candidates(local_ip_cand)
- def _add_additional_candidates(self): + def _add_additional_candidates(self) -> None: if not self.connection: return type_preference = 126 @@ -306,7 +314,7 @@ def _add_additional_candidates(self):
self._add_candidates(additional_ip_cand)
- def _add_proxy_candidates(self): + def _add_proxy_candidates(self) -> None: if not self.connection: return type_preference = 10 @@ -333,12 +341,13 @@ def _add_proxy_candidates(self):
self._add_candidates(proxy_cand)
- def get_content(self): + def get_content(self) -> Optional[JingleContent]: sesn = self.connection.get_module('Jingle').get_jingle_session( self.ourjid, self.file_props.sid) for content in sesn.contents.values(): if content.transport == self: return content + return None
def _on_proxy_auth_ok(self, proxy): log.info('proxy auth ok for %s', str(proxy)) @@ -389,7 +398,10 @@ def _on_proxy_auth_ok(self, proxy):
class JingleTransportIBB(JingleTransport):
- def __init__(self, node=None, block_sz=None): + def __init__(self, + node: Optional[nbxmpp.Node] = None, + block_sz: Optional[str] = None + ) -> None:
JingleTransport.__init__(self, TransportType.IBB)
@@ -399,13 +411,11 @@ def __init__(self, node=None, block_sz=None): self.block_sz = '4096'
self.connection = None - self.sid = None + self.sid: Optional[str] = None if node and node.getAttr('sid'): self.sid = node.getAttr('sid')
- - def make_transport(self): - + def make_transport(self) -> nbxmpp.Node: transport = nbxmpp.Node('transport') transport.setNamespace(Namespace.JINGLE_IBB) transport.setAttr('block-size', self.block_sz) @@ -417,11 +427,12 @@ def make_transport(self): except ImportError: pass
+ class JingleTransportICEUDP(JingleTransport): - def __init__(self, node): + def __init__(self, node: Optional[nbxmpp.Node]) -> None: JingleTransport.__init__(self, TransportType.ICEUDP)
- def make_candidate(self, candidate): + def make_candidate(self, candidate) -> nbxmpp.Node: types = { Farstream.CandidateType.HOST: 'host', Farstream.CandidateType.SRFLX: 'srflx', @@ -429,7 +440,7 @@ def make_candidate(self, candidate): Farstream.CandidateType.RELAY: 'relay', Farstream.CandidateType.MULTICAST: 'multicast' } - attrs = { + attrs: dict[str, Any] = { 'component': candidate.component_id, 'foundation': '1', # hack 'generation': '0', @@ -448,7 +459,9 @@ def make_candidate(self, candidate): attrs['protocol'] = 'tcp' return nbxmpp.Node('candidate', attrs=attrs)
- def make_transport(self, candidates=None): + def make_transport(self, + candidates: Optional[list[dict[str, Any]]] = None + ) -> nbxmpp.Node: transport = JingleTransport.make_transport(self, candidates) transport.setNamespace(Namespace.JINGLE_ICE_UDP) if self.candidates and self.candidates[0].username and \ @@ -457,8 +470,10 @@ def make_transport(self, candidates=None): transport.setAttr('pwd', self.candidates[0].password) return transport
- def parse_transport_stanza(self, transport): - candidates = [] + def parse_transport_stanza(self, + transport: nbxmpp.Node + ) -> list[Farstream.Candidate]: + candidates: list[Farstream.Candidate] = [] for candidate in transport.iterTags('candidate'): foundation = str(candidate['foundation']) component_id = int(candidate['component'])
===================================== gajim/data/gui/file_transfer_jingle.ui ===================================== @@ -121,6 +121,8 @@ <property name="visible">True</property> <property name="can-focus">False</property> <property name="valign">start</property> + <property name="hhomogeneous">False</property> + <property name="vhomogeneous">False</property> <child> <object class="GtkBox"> <property name="visible">True</property>
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/fba9f814a8f66b6135512cad028706fb...