From 1b8b26eafc32b8352a9c92cdf7b0a5796058a900 Mon Sep 17 00:00:00 2001 From: emdee Date: Sat, 5 Nov 2022 01:16:25 +0000 Subject: [PATCH] Fixes --- README.md | 4 +- toxygen/app.py | 30 ++++++----- toxygen/av/calls.py | 17 +++--- toxygen/contacts/contact.py | 7 ++- toxygen/contacts/contact_provider.py | 79 ++++++++++++++++++++++------ toxygen/contacts/contacts_manager.py | 33 +++++++----- toxygen/contacts/group_factory.py | 4 +- toxygen/groups/groups_service.py | 6 ++- toxygen/messenger/messenger.py | 5 +- toxygen/middleware/callbacks.py | 14 +++-- toxygen/ui/av_widgets.py | 2 +- toxygen/ui/widgets.py | 15 ++++-- toxygen/user_data/settings.py | 1 + 13 files changed, 152 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index f829245..6f0488d 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Toxygen is powerful cross-platform [Tox](https://tox.chat/) client written in pu This hard-forked from https://github.com/toxygen-project/toxygen ```next_gen``` branch. - + https://git.plastiras.org/emdee/toxygen_wrapper needs packaging is making a dependency. Just download it and copy the two directories ```wrapper``` and ```wrapper_tests``` into ```toxygen/toxygen```. @@ -56,4 +56,4 @@ is making a dependency. Just download it and copy the two directories See ToDo.md to the current ToDo list. Work on this project is suspended until the -[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me! \ No newline at end of file +[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me! diff --git a/toxygen/app.py b/toxygen/app.py index 20510e3..f3e06b4 100644 --- a/toxygen/app.py +++ b/toxygen/app.py @@ -903,13 +903,14 @@ class App: while i < iMax: # if oThread and oThread._stop_thread: return i = i + 1 - LOG.debug(f"bootstrapping status # {i}") - self._test_bootstrap(lUdpElts) - if hasattr(self._oArgs, 'proxy_type') and self._oArgs.proxy_type > 0: + LOG.debug(f"bootstrapping status proxy={self._oArgs.proxy_type} # {i}") + if self._oArgs.proxy_type == 0: + self._test_bootstrap(lUdpElts) + else: + self._test_bootstrap([lUdpElts[0]]) LOG.debug(f"relaying status # {i}") self._test_relays(self._settings['current_nodes_tcp']) status = self._tox.self_get_connection_status() - LOG.debug(f"connecting status # {i}" +' : ' +repr(status)) if status > 0: LOG.info(f"Connected # {i}" +' : ' +repr(status)) break @@ -956,8 +957,8 @@ class App: LOG.debug(f"_test_relays {len(lElts)}") ts.bootstrap_tcp(lElts[:iNODES], [self._tox]) - def _test_socks(self, lElts=None): - LOG.debug("_test_socks") + def _test_nmap(self, lElts=None): + LOG.debug("_test_nmap") if not self._tox: return title = 'Extended Test Suite' text = 'Run the Extended Test Suite?\nThe program may freeze for 1-10 minutes.' @@ -968,14 +969,19 @@ class App: if not reply: return if lElts is None: - lElts = self._settings['current_nodes_tcp'] + if self._oArgs.proxy_type == 0: + sProt = "udp4" + lElts = self._settings['current_nodes_tcp'] + else: + sProt = "tcp4" + lElts = self._settings['current_nodes_tcp'] shuffle(lElts) try: - bootstrap_iNodeInfo(lElts) + ts.bootstrap_iNmapInfo(lElts, self._oArgs, sProt) + self._ms.log_console() except Exception as e: - # json.decoder.JSONDecodeError - LOG.error(f"test_tox ' +' : {e}") - LOG.error('_test_tox(): ' \ + LOG.error(f"test_nmap ' +' : {e}") + LOG.error('_test_nmap(): ' \ +'\n' + traceback.format_exc()) title = 'Test Suite Error' text = 'Error: ' + str(e) @@ -986,7 +992,7 @@ class App: def _test_main(self): from tests.tests_socks import main as tests_main - LOG.debug("_test_socks") + LOG.debug("_test_main") if not self._tox: return title = 'Extended Test Suite' text = 'Run the Extended Test Suite?\nThe program may freeze for 20-60 minutes.' diff --git a/toxygen/av/calls.py b/toxygen/av/calls.py index ae96848..7c3046c 100644 --- a/toxygen/av/calls.py +++ b/toxygen/av/calls.py @@ -299,6 +299,7 @@ class AV(common.tox_save.ToxAvSave): self._video_width = s['video']['width'] self._video_height = s['video']['height'] + # dunno if True or s['video']['device'] == -1: self._video = screen_sharing.DesktopGrabber(s['video']['x'], s['video']['y'], @@ -404,6 +405,7 @@ class AV(common.tox_save.ToxAvSave): if self._calls[friend_num].out_audio: try: # app.av.calls ERROR Error send_audio: One of the frame parameters was invalid. E.g. the resolution may be too small or too large, or the audio sampling rate may be unsupported + # app.av.calls ERROR Error send_audio audio_send_frame: This client is currently not in a call with the friend. self._toxav.audio_send_frame(friend_num, pcm, count, @@ -412,9 +414,9 @@ class AV(common.tox_save.ToxAvSave): except Exception as e: LOG.error(f"Error send_audio audio_send_frame: {e}") LOG.debug(f"send_audio self._audio_rate_tox={self._audio_rate_tox} self._audio_channels={self._audio_channels}") - invoke_in_main_thread(util_ui.message_box, - str(e), - util_ui.tr("Error send_audio audio_send_frame")) +# invoke_in_main_thread(util_ui.message_box, +# str(e), +# util_ui.tr("Error send_audio audio_send_frame")) pass def send_audio(self): @@ -432,9 +434,10 @@ class AV(common.tox_save.ToxAvSave): else: self.send_audio_data(pcm, count) except: - pass + LOG_DEBUG(f"error send_audio {i}") + else: + LOG_TRACE(f"send_audio {i}") i += 1 - LOG.debug(f"send_audio {i}") sleep(0.01) def send_video(self): @@ -454,7 +457,7 @@ class AV(common.tox_save.ToxAvSave): LOG.warn(f"send_video video_send_frame _video.read result={result} frame={frame}") continue else: - LOG.debug(f"send_video video_send_frame _video.read result={result}") + LOG_TRACE(f"send_video video_send_frame _video.read result={result}") height, width, channels = frame.shape friends = [] for friend_num in self._calls: @@ -463,7 +466,7 @@ class AV(common.tox_save.ToxAvSave): if len(friends) == 0: LOG.warn(f"send_video video_send_frame no friends") else: - LOG.debug(f"send_video video_send_frame {friends}") + LOG_TRACE(f"send_video video_send_frame {friends}") friend_num = friends[0] try: y, u, v = self.convert_bgr_to_yuv(frame) diff --git a/toxygen/contacts/contact.py b/toxygen/contacts/contact.py index b680c58..83ce315 100644 --- a/toxygen/contacts/contact.py +++ b/toxygen/contacts/contact.py @@ -141,11 +141,14 @@ class Contact(basecontact.BaseContact): return list(messages) def mark_as_sent(self, tox_message_id): + message = list(filter(lambda m: m.author is not None + and m.author.type == MESSAGE_AUTHOR['NOT_SENT'] + and m.tox_message_id == tox_message_id, + self._corr))[0] try: - message = list(filter(lambda m: m.author is not None and m.author.type == MESSAGE_AUTHOR['NOT_SENT'] - and m.tox_message_id == tox_message_id, self._corr))[0] message.mark_as_sent() except Exception as ex: + # wrapped C/C++ object of type QLabel has been deleted LOG.error(f"Mark as sent: {ex!s}") # ----------------------------------------------------------------------------------------------------------------- diff --git a/toxygen/contacts/contact_provider.py b/toxygen/contacts/contact_provider.py index 564d2fe..37ac7c3 100644 --- a/toxygen/contacts/contact_provider.py +++ b/toxygen/contacts/contact_provider.py @@ -6,6 +6,18 @@ global LOG import logging LOG = logging.getLogger(__name__) +# callbacks can be called in any thread so were being careful +def LOG_ERROR(l): print('EROR< '+l) +def LOG_WARN(l): print('WARN< '+l) +def LOG_INFO(l): + bIsVerbose = hasattr(__builtins__, 'app') and app.oArgs.loglevel <= 20-1 + if bIsVerbose: print('INFO< '+l) +def LOG_DEBUG(l): + bIsVerbose = hasattr(__builtins__, 'app') and app.oArgs.loglevel <= 10-1 + if bIsVerbose: print('DBUG< '+l) +def LOG_TRACE(l): + bIsVerbose = hasattr(__builtins__, 'app') and app.oArgs.loglevel < 10-1 + pass # print('TRACE+ '+l) class ContactProvider(tox_save.ToxSave): @@ -24,6 +36,7 @@ class ContactProvider(tox_save.ToxSave): try: public_key = self._tox.friend_get_public_key(friend_number) except Exception as e: + LOG_WARN(f"get_friend_by_number NO {friend_number} {e} ") return None return self.get_friend_by_public_key(public_key) @@ -33,6 +46,7 @@ class ContactProvider(tox_save.ToxSave): return friend friend = self._friend_factory.create_friend_by_public_key(public_key) self._add_to_cache(public_key, friend) + LOG_INFO(f"get_friend_by_public_key ADDED {friend} ") return friend @@ -40,6 +54,7 @@ class ContactProvider(tox_save.ToxSave): try: friend_numbers = self._tox.self_get_friend_list() except Exception as e: + LOG_WARN(f"get_all_friends NO {friend_numbers} {e} ") return None friends = map(lambda n: self.get_friend_by_number(n), friend_numbers) @@ -50,38 +65,70 @@ class ContactProvider(tox_save.ToxSave): # ----------------------------------------------------------------------------------------------------------------- def get_all_groups(self): + """from callbacks""" try: - group_numbers = range(self._tox.group_get_number_groups()) + len_groups = self._tox.group_get_number_groups() + group_numbers = range(len_groups) except Exception as e: return None - groups = map(lambda n: self.get_group_by_number(n), group_numbers) - - return list(groups) + groups = list(map(lambda n: self.get_group_by_number(n), group_numbers)) + # failsafe in case there are bogus None groups? + fgroups = list(filter(lambda x: x, groups)) + if len(fgroups) != len_groups: + LOG_WARN(f"are there are bogus None groups in libtoxcore? {len(fgroups)} != {len_groups}") + for group_num in group_numbers: + group = self.get_group_by_number(group_num) + if group is None: + LOG_ERROR(f"there are bogus None groups in libtoxcore {group_num}!") + # fixme: do something + groups = fgroups + return groups def get_group_by_number(self, group_number): + group = None try: - if True: - # original code - public_key = self._tox.group_get_chat_id(group_number) -# LOG.info(f"group_get_chat_id {group_number} {public_key}") - return self.get_group_by_public_key(public_key) + LOG_INFO(f"group_get_number {group_number} ") + # original code + chat_id = self._tox.group_get_chat_id(group_number) + if not chat_id: + LOG_ERROR(f"get_group_by_number NULL number ({group_number})") else: - # guessing - chat_id = self._tox.group_get_chat_id(group_number) -# LOG.info(f"group_get_chat_id {group_number} {chat_id}") - group = self.get_contact_by_tox_id(chat_id) - return group + LOG_INFO(f"group_get_number {group_number} {chat_id}") + group = self.get_group_by_chat_id(chat_id) + if not group: + LOG_ERROR(f"get_group_by_number NULL group ({chat_id})") + if group is None: + + LOG_WARN(f"get_group_by_number leaving ({group_number})") + #? iRet = self._tox.group_leave(group_number) + # invoke in main thread? + # self._contacts_manager.delete_group(group_number) + return group except Exception as e: - LOG.warn(f"group_get_chat_id {group_number} {e}") + LOG_WARN(f"group_get_number {group_number} {e}") return None + def get_group_by_chat_id(self, chat_id): + group = self._get_contact_from_cache(chat_id) + if group is not None: + return group + group = self._group_factory.create_group_by_chat_id(chat_id) + if group is None: + LOG_ERROR(f"get_group_by_chat_id NULL chat_id={chat_id}") + else: + self._add_to_cache(chat_id, group) + + return group def get_group_by_public_key(self, public_key): group = self._get_contact_from_cache(public_key) if group is not None: return group group = self._group_factory.create_group_by_public_key(public_key) - self._add_to_cache(public_key, group) + if group is None: + LOG_ERROR(f"get_group_by_public_key NULL group public_key={get_group_by_chat_id}") + else: + self._add_to_cache(public_key, group) return group diff --git a/toxygen/contacts/contacts_manager.py b/toxygen/contacts/contacts_manager.py index 04e12d3..cc8a07e 100644 --- a/toxygen/contacts/contacts_manager.py +++ b/toxygen/contacts/contacts_manager.py @@ -54,7 +54,8 @@ class ContactsManager(ToxSave): self._tox_dns = tox_dns self._messages_items_factory = messages_items_factory self._messages = screen.messages - self._contacts, self._active_contact = [], -1 + self._contacts = [] + self._active_contact = -1 self._active_contact_changed = Event() self._sorting = settings['sorting'] self._filter_string = '' @@ -92,17 +93,16 @@ class ContactsManager(ToxSave): return self.get_curr_contact().number == group_number def is_contact_active(self, contact): - if not self._active_contact: + if self._active_contact == -1: # LOG.debug("No self._active_contact") return False - if self._active_contact not in self._contacts: - LOG.warn(f"_active_contact={self._active_contact} not in contacts len={len(self._contacts)}") + if self._active_contact >= len(self._contacts): + LOG.warn(f"ERROR _active_contact={self._active_contact} >= contacts len={len(self._contacts)}") return False if not self._contacts[self._active_contact]: - LOG.debug(f"{self._contacts[self._active_contact]} {contact.tox_id}") + LOG.warn(f"ERROR NULL {self._contacts[self._active_contact]} {contact.tox_id}") return False - LOG.debug(f"{self._contacts[self._active_contact].tox_id} == {contact.tox_id}") return self._contacts[self._active_contact].tox_id == contact.tox_id # ----------------------------------------------------------------------------------------------------------------- @@ -145,7 +145,7 @@ class ContactsManager(ToxSave): current_contact.remove_messages_widgets() # TODO: if required self._unsubscribe_from_events(current_contact) - if self._active_contact + 1 and self._active_contact != value: + if self._active_contact >= 0 and self._active_contact != value: try: current_contact.curr_text = self._screen.messageEdit.toPlainText() except: @@ -180,7 +180,7 @@ class ContactsManager(ToxSave): self._set_current_contact_data(contact) self._active_contact_changed(contact) except Exception as ex: # no friend found. ignore - LOG.warn(f"no friend found. Friend value: {value!s}") + LOG.warn(f"no friend found. Friend value: {value!s}") LOG.error('in set active: ' + str(ex)) # gulp raise @@ -368,7 +368,10 @@ class ContactsManager(ToxSave): """ friend = self._contacts[num] self._cleanup_contact_data(friend) - self._tox.friend_delete(friend.number) + try: + self._tox.friend_delete(friend.number) + except Exception as e: + LOG.warn(f"'There was no friend with the given friend number {e}") self._delete_contact(num) def add_friend(self, tox_id): @@ -418,7 +421,8 @@ class ContactsManager(ToxSave): def add_group(self, group_number): index = len(self._contacts) group = self._contact_provider.get_group_by_number(group_number) - if not group: + # group num >= 0? + if group is None: LOG.warn(f"CM.add_group: NO group {group_number}") else: LOG.info(f"CM.add_group: Adding group {group._name}") @@ -517,7 +521,8 @@ class ContactsManager(ToxSave): title = 'Friend add exception' text = 'Friend request exception with ' + str(ex) self._log(text) - LOG.error(traceback.format_exc()) + LOG.exception(text) + LOG.warn(f"DELETE {sToxPkOrId} ?") retval = str(ex) title = util_ui.tr(title) text = util_ui.tr(text) @@ -586,9 +591,11 @@ class ContactsManager(ToxSave): self.set_active(0) # filter(lambda c: not c.has_avatar(), self._contacts) for (i, contact) in enumerate(self._contacts): - if not contact: - LOG.warn("_load_contacts NULL contact {i}") + if contact is None: + LOG.warn(f"_load_contacts NULL contact {i}") + LOG.info(f"_load_contacts deleting NULL {self._contacts[i]}") del self._contacts[i] + #? self.save_profile() continue if contact.has_avatar(): continue contact.reset_avatar(self._settings['identicons']) diff --git a/toxygen/contacts/group_factory.py b/toxygen/contacts/group_factory.py index b1c935d..c1f0985 100644 --- a/toxygen/contacts/group_factory.py +++ b/toxygen/contacts/group_factory.py @@ -17,9 +17,11 @@ class GroupFactory(ToxSave): self._db = db self._items_factory = items_factory + def create_group_by_chat_id(self, chat_id): + return self.create_group_by_public_key(chat_id) + def create_group_by_public_key(self, public_key): group_number = self._get_group_number_by_chat_id(public_key) - return self.create_group_by_number(group_number) def create_group_by_number(self, group_number): diff --git a/toxygen/groups/groups_service.py b/toxygen/groups/groups_service.py index 80ed87d..d329d6d 100644 --- a/toxygen/groups/groups_service.py +++ b/toxygen/groups/groups_service.py @@ -281,14 +281,16 @@ class GroupsService(tox_save.ToxSave): if invite in self._group_invites: self._group_invites.remove(invite) - def _join_gc_via_invite(self, invite_data, friend_number, nick, status, password): + # status should be dropped + def _join_gc_via_invite(self, invite_data, friend_number, nick, status='', password=''): LOG.debug(f"_join_gc_via_invite friend_number={friend_number} nick={nick} datalen={len(invite_data)}") if nick is None: nick = '' if invite_data is None: invite_data = b'' try: - group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, status, password) + # status should be dropped + group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, password=password) except Exception as e: LOG.error(f"_join_gc_via_invite ERROR {e}") return diff --git a/toxygen/messenger/messenger.py b/toxygen/messenger/messenger.py index 95f639b..6208df4 100644 --- a/toxygen/messenger/messenger.py +++ b/toxygen/messenger/messenger.py @@ -76,7 +76,7 @@ class Messenger(tox_save.ToxSave): if self._contacts_manager.is_active_a_friend(): self.send_message_to_friend(text, message_type) elif self._contacts_manager.is_active_a_group(): - self.send_message_to_group(text, message_type) + self.send_message_to_group('~'+text, message_type) elif self._contacts_manager.is_active_a_group_chat_peer(): self.send_message_to_group_peer(text, message_type) else: @@ -353,11 +353,12 @@ class Messenger(tox_save.ToxSave): LOG.warn("_add_message null contact") return if self._contacts_manager.is_contact_active(contact): # add message to list +# LOG.debug("_add_message is_contact_active(contact)") self._create_message_item(text_message) self._screen.messages.scrollToBottom() self._contacts_manager.get_curr_contact().append_message(text_message) else: - LOG.debug("_add_message not is_contact_active(contact)") +# LOG.debug("_add_message not is_contact_active(contact)") contact.inc_messages() contact.append_message(text_message) if not contact.visibility: diff --git a/toxygen/middleware/callbacks.py b/toxygen/middleware/callbacks.py index 1545ae2..2aed257 100644 --- a/toxygen/middleware/callbacks.py +++ b/toxygen/middleware/callbacks.py @@ -529,27 +529,35 @@ def group_invite(window, settings, tray, profile, groups_service, contacts_provi def group_self_join(contacts_provider, contacts_manager, groups_service): sSlot = 'group_self_join' def wrapped(tox, group_number, user_data): + if group_number is None: + LOG_ERROR(f"group_self_join NULL group_number #{group_number}") + return + LOG_DEBUG(f"group_self_join #{group_number}") key = f"group_number {group_number}" if bTooSoon(key, sSlot, 10): return - LOG_DEBUG(f"group_self_join #{group_number}") group = contacts_provider.get_group_by_number(group_number) + if group is None: + LOG_ERROR(f"group_self_join NULL group #{group}") + return invoke_in_main_thread(group.set_status, TOX_USER_STATUS['NONE']) invoke_in_main_thread(groups_service.update_group_info, group) invoke_in_main_thread(contacts_manager.update_filtration) return wrapped - def group_peer_join(contacts_provider, groups_service): sSlot = "group_peer_join" def wrapped(tox, group_number, peer_id, user_data): key = f"group_peer_join #{group_number} peer_id={peer_id}" if bTooSoon(key, sSlot, 20): return group = contacts_provider.get_group_by_number(group_number) + if group is None: + LOG_ERROR(f"group_peer_join NULL group #{group} group_number={group_number}") + return if peer_id > group._peers_limit: LOG_ERROR(key +f" {peer_id} > {group._peers_limit}") return - LOG_DEBUG(key) + LOG_DEBUG(f"group_peer_join group={group}") group.add_peer(peer_id) invoke_in_main_thread(groups_service.generate_peers_list) invoke_in_main_thread(groups_service.update_group_info, group) diff --git a/toxygen/ui/av_widgets.py b/toxygen/ui/av_widgets.py index a441fb7..717b022 100644 --- a/toxygen/ui/av_widgets.py +++ b/toxygen/ui/av_widgets.py @@ -63,7 +63,7 @@ class IncomingCallWidget(widgets.CenteredWidget): self.accept_video.clicked.connect(self.accept_call_with_video) self.decline.clicked.connect(self.decline_call) - output_device_index = self._settings._args.audio['output'] + output_device_index = self._settings._oArgs.audio['output'] if False and self._settings['calls_sound']: class SoundPlay(QtCore.QThread): diff --git a/toxygen/ui/widgets.py b/toxygen/ui/widgets.py index 32ebfe4..8789ad1 100644 --- a/toxygen/ui/widgets.py +++ b/toxygen/ui/widgets.py @@ -3,6 +3,9 @@ from PyQt5 import QtCore, QtGui, QtWidgets import utils.ui as util_ui import logging +global LOG +LOG = logging.getLogger('app') + class DataLabel(QtWidgets.QLabel): """ Label with elided text @@ -11,13 +14,17 @@ class DataLabel(QtWidgets.QLabel): try: text = ''.join('\u25AF' if len(bytes(str(c), 'utf-8')) >= 4 else c for c in str(text)) except Exception as e: - logging.error(f"DataLabel::setText: {e}") + LOG.error(f"DataLabel::setText: {e}") return - metrics = QtGui.QFontMetrics(self.font()) - text = metrics.elidedText(str(text), QtCore.Qt.ElideRight, self.width()) - super().setText(text) + try: + metrics = QtGui.QFontMetrics(self.font()) + text = metrics.elidedText(str(text), QtCore.Qt.ElideRight, self.width()) + except Exception as e: + # RuntimeError: wrapped C/C++ object of type DataLabel has been deleted + text = str(text) + super().setText(text) class ComboBox(QtWidgets.QComboBox): diff --git a/toxygen/user_data/settings.py b/toxygen/user_data/settings.py index caf454c..ca75f8f 100644 --- a/toxygen/user_data/settings.py +++ b/toxygen/user_data/settings.py @@ -138,6 +138,7 @@ class Settings(dict): self._profile_path = path.replace('.json', '.tox') self._toxes = toxes self._app = app + self._args = app._oArgs self._oArgs = app._oArgs self._log = lambda l: LOG.log(self._oArgs.loglevel, l)