This commit is contained in:
emdee 2022-11-05 01:16:25 +00:00
parent a073dd9bc9
commit 1b8b26eafc
13 changed files with 152 additions and 65 deletions

View file

@ -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!
[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me!

View file

@ -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.'

View file

@ -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)

View file

@ -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}")
# -----------------------------------------------------------------------------------------------------------------

View file

@ -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

View file

@ -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'])

View file

@ -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):

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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):

View file

@ -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):

View file

@ -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)