fixed json overwrite
This commit is contained in:
parent
e778108834
commit
c70c501fdd
12 changed files with 283 additions and 25 deletions
|
@ -38,6 +38,7 @@ written in pure Python3.
|
||||||
- Changing nospam
|
- Changing nospam
|
||||||
- File resuming
|
- File resuming
|
||||||
- Read receipts
|
- Read receipts
|
||||||
|
- uses gevent
|
||||||
- NGC groups
|
- NGC groups
|
||||||
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|
@ -82,6 +83,7 @@ Weechat has a Jabber plugin to enable XMPP:
|
||||||
/help jabber
|
/help jabber
|
||||||
```
|
```
|
||||||
so you can have Tox, IRC and XMPP in the same application!
|
so you can have Tox, IRC and XMPP in the same application!
|
||||||
|
See docs/ToxygenWeechat.md
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
5
ToDo.md
5
ToDo.md
|
@ -55,8 +55,11 @@ line.
|
||||||
|
|
||||||
Migrate PyQt5 to qtpy - almost done.
|
Migrate PyQt5 to qtpy - almost done.
|
||||||
|
|
||||||
Maybe migrate gevent to asyncio, or look at https://pypi.org/project/asyncio-gevent/
|
Maybe migrate gevent to asyncio, and migrate to
|
||||||
|
[qasync](https://github.com/CabbageDevelopment/qasync)
|
||||||
|
(see https://git.plastiras.org/emdee/phantompy ).
|
||||||
|
|
||||||
|
(Also look at https://pypi.org/project/asyncio-gevent/ but it's dead).
|
||||||
|
|
||||||
## Standards
|
## Standards
|
||||||
|
|
||||||
|
|
153
docs/ToxygenWeechat.md
Normal file
153
docs/ToxygenWeechat.md
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
## Toxygen Weechat
|
||||||
|
|
||||||
|
You can have a [weechat](https://github.com/weechat/qweechat)
|
||||||
|
console so that you can have IRC and jabber in a window as well as Tox.
|
||||||
|
There's a copy of qweechat in ```thirdparty/qweechat``` backported to
|
||||||
|
PyQt5 and integrated into toxygen. Follow the normal instructions for
|
||||||
|
adding a ```relay``` to [weechat](https://github.com/weechat/weechat)
|
||||||
|
```
|
||||||
|
/relay add ipv4.ssl.weechat 9001
|
||||||
|
/relay start ipv4.ssl.weechat
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
/set relay.network.ipv6 off
|
||||||
|
/set relay.network.password password
|
||||||
|
/relay add weechat 9000
|
||||||
|
/relay start weechat
|
||||||
|
```
|
||||||
|
and use the Plugins/Weechat Console to start weechat under Toxygen.
|
||||||
|
Then use the File/Connect menu item of the Console to connect to weechat.
|
||||||
|
|
||||||
|
Weechat has a Jabber plugin to enable XMPP:
|
||||||
|
```
|
||||||
|
/python load jabber.el
|
||||||
|
/help jabber
|
||||||
|
```
|
||||||
|
so you can have Tox, IRC and XMPP in the same application!
|
||||||
|
|
||||||
|
### Creating servers for IRC over Tor
|
||||||
|
|
||||||
|
Create a proxy called tor
|
||||||
|
```
|
||||||
|
/proxy add tor socks5 127.0.0.1 9050
|
||||||
|
```
|
||||||
|
|
||||||
|
It should now show up in the list of proxies.
|
||||||
|
```
|
||||||
|
/proxy list
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
/nick SyniTox
|
||||||
|
```
|
||||||
|
|
||||||
|
## TLS certificates
|
||||||
|
|
||||||
|
[Create a Self-signed Certificate](https://www.oftc.net/NickServ/CertFP/)
|
||||||
|
|
||||||
|
Choose a SyniTox you will identify as.
|
||||||
|
|
||||||
|
Create a directory for your certificates ~/.config/weechat/ssl/
|
||||||
|
and make a subdirectory for each server ~/.config/weechat/ssl/irc.oftc.net/
|
||||||
|
|
||||||
|
Change to the server directory and use openssl to make a keypair and answer the questions:
|
||||||
|
```
|
||||||
|
openssl req -nodes -newkey rsa:2048 -keyout SyniTox.key -x509 -days 3650 -out SyniTox.cer
|
||||||
|
chmod 400 SyniTox.key
|
||||||
|
```
|
||||||
|
We now combine certificate and key to a single file SyniTox.pem
|
||||||
|
```
|
||||||
|
cat SyniTox.cer SyniTox.key > SyniTox.pem
|
||||||
|
chmod 400 SyniTox.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Do this for each server you want to connect to, or just use one for all of them.
|
||||||
|
|
||||||
|
### Libera TokTok channel
|
||||||
|
|
||||||
|
The main discussion forum for Tox is the #TokTok channel on libera.
|
||||||
|
|
||||||
|
libera has an onion server so we can map an address in tor. Add this
|
||||||
|
to your /etc/tor/torrc
|
||||||
|
```
|
||||||
|
MapAddress palladium.libera.chat libera75jm6of4wxpxt4aynol3xjmbtxgfyjpu34ss4d7r7q2v5zrpyd.onion
|
||||||
|
```
|
||||||
|
|
||||||
|
Define the server in weechat
|
||||||
|
https://www.weechat.org/files/doc/stable/weechat_user.en.html#irc_sasl_authentication
|
||||||
|
```
|
||||||
|
/server remove libera
|
||||||
|
/server add libera palladium.libera.chat/6697 -tls -tls_verify
|
||||||
|
/set irc.server.libera.ipv6 off
|
||||||
|
/set irc.server.libera.proxy tor
|
||||||
|
/set irc.server.libera.username SyniTox
|
||||||
|
/set irc.server.libera.nicks SyniTox
|
||||||
|
/set irc.server.libera.tls on
|
||||||
|
/set irc.server.libera.tls_cert "${weechat_config_dir}/ssl/libera.chat/SyniTox.pem"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
/set irc.server.libera.sasl_mechanism ecdsa-nist256p-challenge
|
||||||
|
/set irc.server.libera.sasl_username "SyniTox"
|
||||||
|
/set irc.server.libera.sasl_key "${weechat_config_dir}/ssl/libera.chat/SyniTox.pem"
|
||||||
|
```
|
||||||
|
|
||||||
|
Disconnect and connect back to the server.
|
||||||
|
```
|
||||||
|
/disconnect libera
|
||||||
|
/connect libera
|
||||||
|
```
|
||||||
|
|
||||||
|
/msg nickserv identify password SyniTox
|
||||||
|
|
||||||
|
|
||||||
|
### oftc.net
|
||||||
|
|
||||||
|
To use oftc.net over tor, you need to authenticate by SSL certificates.
|
||||||
|
|
||||||
|
|
||||||
|
Define the server in weechat
|
||||||
|
```
|
||||||
|
/server remove irc.oftc.net
|
||||||
|
/server add OFTC irc.oftc.net/6697 -tls -tls_verify
|
||||||
|
/set irc.server.OFTC.ipv6 off
|
||||||
|
/set irc.server.OFTC.proxy tor
|
||||||
|
/set irc.server.OFTC.username SyniTox
|
||||||
|
/set irc.server.OFTC.nicks SyniTox
|
||||||
|
/set irc.server.OFTC.tls on
|
||||||
|
/set irc.server.OFTC.tls_cert "${weechat_config_dir}/ssl/irc.oftc.chat/SyniTox.pem"
|
||||||
|
|
||||||
|
# Disconnect and connect back to the server.
|
||||||
|
/disconnect OFTC
|
||||||
|
/connect OFTC
|
||||||
|
```
|
||||||
|
You must be identified in order to validate using certs
|
||||||
|
```
|
||||||
|
/msg nickserv identify password SyniTox
|
||||||
|
```
|
||||||
|
To allow NickServ to identify you based on this certificate you need
|
||||||
|
to associate the certificate fingerprint with your nick. To do this
|
||||||
|
issue the command cert add to Nickserv (try /msg nickserv helpcert).
|
||||||
|
```
|
||||||
|
/msg nickserv cert add
|
||||||
|
```
|
||||||
|
|
||||||
|
### Privacy
|
||||||
|
|
||||||
|
[Add somes settings bellow to weechat](https://szorfein.github.io/weechat/tor/configure-weechat/).
|
||||||
|
Detail from [faq](https://weechat.org/files/doc/weechat_faq.en.html#security).
|
||||||
|
|
||||||
|
```
|
||||||
|
/set irc.server_default.msg_part ""
|
||||||
|
/set irc.server_default.msg_quit ""
|
||||||
|
/set irc.ctcp.clientinfo ""
|
||||||
|
/set irc.ctcp.finger ""
|
||||||
|
/set irc.ctcp.source ""
|
||||||
|
/set irc.ctcp.time ""
|
||||||
|
/set irc.ctcp.userinfo ""
|
||||||
|
/set irc.ctcp.version ""
|
||||||
|
/set irc.ctcp.ping ""
|
||||||
|
/plugin unload xfer
|
||||||
|
/set weechat.plugin.autoload "*,!xfer"
|
||||||
|
```
|
67
docs/todo.md
Normal file
67
docs/todo.md
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# Toxygen ToDo List
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
1. There is an agravating bug where new messages are not put in the
|
||||||
|
current window, and a messages waiting indicator appears. You have
|
||||||
|
to focus out of the window and then back in the window. this may be
|
||||||
|
fixed already
|
||||||
|
|
||||||
|
2. The tray icon is flaky and has been disabled - look in app.py
|
||||||
|
for bSHOW_TRAY
|
||||||
|
|
||||||
|
## Fix history
|
||||||
|
|
||||||
|
## Fix Audio
|
||||||
|
|
||||||
|
The code is in there but it's not working. It looks like audio input
|
||||||
|
is working but not output. The code is all in there; I may have broken
|
||||||
|
it trying to wire up the ability to set the audio device from the
|
||||||
|
command line.
|
||||||
|
|
||||||
|
## Fix Video
|
||||||
|
|
||||||
|
The code is in there but it's not working. I may have broken it
|
||||||
|
trying to wire up the ability to set the video device from the command
|
||||||
|
line.
|
||||||
|
|
||||||
|
## NGC Groups
|
||||||
|
|
||||||
|
1. peer_id There has been a change of API on a field named
|
||||||
|
```group.peer_id``` The code is broken in places because I have not
|
||||||
|
seen the path to change from the old API ro the new one.
|
||||||
|
|
||||||
|
|
||||||
|
## Plugin system
|
||||||
|
|
||||||
|
1. Needs better documentation and checking.
|
||||||
|
|
||||||
|
2. There's something broken in the way some of them plug into Qt menus.
|
||||||
|
|
||||||
|
3. Should the plugins be in toxygen or a separate repo?
|
||||||
|
|
||||||
|
4. There needs to be a uniform way for plugins to wire into callbacks.
|
||||||
|
|
||||||
|
## check toxygen_wrapper
|
||||||
|
|
||||||
|
1. I've broken out toxygen_wrapper to be standalone,
|
||||||
|
https://git.plastiras.org/emdee/toxygen_wrapper but the tox.py
|
||||||
|
needs each call double checking.
|
||||||
|
|
||||||
|
2. https://git.plastiras.org/emdee/toxygen_wrapper needs packaging
|
||||||
|
and making a dependency.
|
||||||
|
|
||||||
|
## Migration
|
||||||
|
|
||||||
|
Migrate PyQt5 to qtpy - almost done.
|
||||||
|
|
||||||
|
Maybe migrate gevent to asyncio, and migrate to
|
||||||
|
[qasync](https://github.com/CabbageDevelopment/qasync)
|
||||||
|
(see https://git.plastiras.org/emdee/phantompy ).
|
||||||
|
|
||||||
|
(Also look at https://pypi.org/project/asyncio-gevent/ but it's dead).
|
||||||
|
|
||||||
|
## Standards
|
||||||
|
|
||||||
|
There's a standard for Tox clients that this has not been tested against:
|
||||||
|
https://tox.gitbooks.io/tox-client-standard/content/general_requirements/general_requirements.html
|
|
@ -6,6 +6,8 @@ import logging
|
||||||
import signal
|
import signal
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from gevent import monkey; monkey.patch_all(); del monkey # noqa
|
||||||
|
|
||||||
import faulthandler
|
import faulthandler
|
||||||
faulthandler.enable()
|
faulthandler.enable()
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import threading
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from gevent import monkey; monkey.patch_all(); del monkey # noqa
|
|
||||||
import gevent
|
import gevent
|
||||||
|
|
||||||
from qtpy import QtWidgets, QtGui, QtCore
|
from qtpy import QtWidgets, QtGui, QtCore
|
||||||
|
@ -182,6 +181,7 @@ class App:
|
||||||
if uri is not None and uri.startswith('tox:'):
|
if uri is not None and uri.startswith('tox:'):
|
||||||
self._uri = uri[4:]
|
self._uri = uri[4:]
|
||||||
self._history = None
|
self._history = None
|
||||||
|
self.bAppExiting = False
|
||||||
|
|
||||||
# Public methods
|
# Public methods
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ class App:
|
||||||
def _stop_app(self) -> None:
|
def _stop_app(self) -> None:
|
||||||
LOG.debug("_stop_app")
|
LOG.debug("_stop_app")
|
||||||
self._save_profile()
|
self._save_profile()
|
||||||
#? self._history.save_history()
|
self._history.save_history()
|
||||||
|
|
||||||
self._plugin_loader.stop()
|
self._plugin_loader.stop()
|
||||||
try:
|
try:
|
||||||
|
@ -304,10 +304,16 @@ class App:
|
||||||
except (Exception, RuntimeError):
|
except (Exception, RuntimeError):
|
||||||
# RuntimeError: cannot join current thread
|
# RuntimeError: cannot join current thread
|
||||||
pass
|
pass
|
||||||
|
# I think there are threads still running here leading to a SEGV
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1401 in run
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1045 in _bootstrap_inner
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1002 in _bootstrap
|
||||||
|
|
||||||
if hasattr(self, '_tray') and self._tray:
|
if hasattr(self, '_tray') and self._tray:
|
||||||
self._tray.hide()
|
self._tray.hide()
|
||||||
self._settings.close()
|
self._settings.close()
|
||||||
|
|
||||||
|
self.bAppExiting = True
|
||||||
LOG.debug(f"stop_app: Killing {self._tox}")
|
LOG.debug(f"stop_app: Killing {self._tox}")
|
||||||
self._kill_toxav()
|
self._kill_toxav()
|
||||||
self._kill_tox()
|
self._kill_tox()
|
||||||
|
@ -522,18 +528,21 @@ class App:
|
||||||
return ls.result
|
return ls.result
|
||||||
|
|
||||||
def _load_existing_profile(self, profile_path) -> None:
|
def _load_existing_profile(self, profile_path) -> None:
|
||||||
|
profile_path = profile_path.replace('.json', '.tox')
|
||||||
LOG.info("_load_existing_profile " +repr(profile_path))
|
LOG.info("_load_existing_profile " +repr(profile_path))
|
||||||
assert os.path.exists(profile_path), profile_path
|
assert os.path.exists(profile_path), profile_path
|
||||||
self._profile_manager = ProfileManager(self._toxes, profile_path)
|
self._profile_manager = ProfileManager(self._toxes, profile_path, app=self)
|
||||||
data = self._profile_manager.open_profile()
|
data = self._profile_manager.open_profile()
|
||||||
if self._toxes.is_data_encrypted(data):
|
if self._toxes.is_data_encrypted(data):
|
||||||
LOG.debug("_entering password")
|
LOG.debug("_entering password")
|
||||||
data = self._enter_password(data)
|
data = self._enter_password(data)
|
||||||
LOG.debug("_entered password")
|
LOG.debug("_entered password")
|
||||||
json_file = profile_path.replace('.tox', '.json')
|
json_file = profile_path.replace('.tox', '.json')
|
||||||
assert os.path.exists(json_file), json_file
|
if os.path.exists(json_file):
|
||||||
LOG.debug("creating _settings from: " +json_file)
|
LOG.debug("creating _settings from: " +json_file)
|
||||||
self._settings = Settings(self._toxes, json_file, self)
|
self._settings = Settings(self._toxes, json_file, self)
|
||||||
|
else:
|
||||||
|
|
||||||
self._tox = self._create_tox(data, self._settings)
|
self._tox = self._create_tox(data, self._settings)
|
||||||
LOG.debug("created _tox")
|
LOG.debug("created _tox")
|
||||||
|
|
||||||
|
@ -683,7 +692,8 @@ class App:
|
||||||
self._contacts_provider = ContactProvider(self._tox,
|
self._contacts_provider = ContactProvider(self._tox,
|
||||||
self._friend_factory,
|
self._friend_factory,
|
||||||
self._group_factory,
|
self._group_factory,
|
||||||
self._group_peer_factory)
|
self._group_peer_factory,
|
||||||
|
app=self)
|
||||||
self._profile = Profile(self._profile_manager,
|
self._profile = Profile(self._profile_manager,
|
||||||
self._tox,
|
self._tox,
|
||||||
self._ms,
|
self._ms,
|
||||||
|
|
|
@ -11,12 +11,13 @@ from av.calls import LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_TRACE
|
||||||
|
|
||||||
class ContactProvider(tox_save.ToxSave):
|
class ContactProvider(tox_save.ToxSave):
|
||||||
|
|
||||||
def __init__(self, tox, friend_factory, group_factory, group_peer_factory):
|
def __init__(self, tox, friend_factory, group_factory, group_peer_factory, app=None):
|
||||||
super().__init__(tox)
|
super().__init__(tox)
|
||||||
self._friend_factory = friend_factory
|
self._friend_factory = friend_factory
|
||||||
self._group_factory = group_factory
|
self._group_factory = group_factory
|
||||||
self._group_peer_factory = group_peer_factory
|
self._group_peer_factory = group_peer_factory
|
||||||
self._cache = {} # key - contact's public key, value - contact instance
|
self._cache = {} # key - contact's public key, value - contact instance
|
||||||
|
self._app = app
|
||||||
|
|
||||||
# Friends
|
# Friends
|
||||||
|
|
||||||
|
@ -41,6 +42,8 @@ class ContactProvider(tox_save.ToxSave):
|
||||||
return friend
|
return friend
|
||||||
|
|
||||||
def get_all_friends(self):
|
def get_all_friends(self):
|
||||||
|
if self._app and self._app.bAppExiting:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
friend_numbers = self._tox.self_get_friend_list()
|
friend_numbers = self._tox.self_get_friend_list()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -6,6 +6,7 @@ import common.tox_save as tox_save
|
||||||
from middleware.threads import invoke_in_main_thread
|
from middleware.threads import invoke_in_main_thread
|
||||||
|
|
||||||
iUMAXINT = 4294967295
|
iUMAXINT = 4294967295
|
||||||
|
iRECONNECT = 50
|
||||||
|
|
||||||
global LOG
|
global LOG
|
||||||
import logging
|
import logging
|
||||||
|
@ -15,7 +16,7 @@ class Profile(basecontact.BaseContact, tox_save.ToxSave):
|
||||||
"""
|
"""
|
||||||
Profile of current toxygen user.
|
Profile of current toxygen user.
|
||||||
"""
|
"""
|
||||||
def __init__(self, profile_manager, tox, screen, contacts_provider, reset_action):
|
def __init__(self, profile_manager, tox, screen, contacts_provider, reset_action, app=None):
|
||||||
"""
|
"""
|
||||||
:param tox: tox instance
|
:param tox: tox instance
|
||||||
:param screen: ref to main screen
|
:param screen: ref to main screen
|
||||||
|
@ -34,32 +35,33 @@ class Profile(basecontact.BaseContact, tox_save.ToxSave):
|
||||||
self._reset_action = reset_action
|
self._reset_action = reset_action
|
||||||
self._waiting_for_reconnection = False
|
self._waiting_for_reconnection = False
|
||||||
self._timer = None
|
self._timer = None
|
||||||
|
self._app = app
|
||||||
|
|
||||||
# Edit current user's data
|
# Edit current user's data
|
||||||
|
|
||||||
def change_status(self):
|
def change_status(self) -> None:
|
||||||
"""
|
"""
|
||||||
Changes status of user (online, away, busy)
|
Changes status of user (online, away, busy)
|
||||||
"""
|
"""
|
||||||
if self._status is not None:
|
if self._status is not None:
|
||||||
self.set_status((self._status + 1) % 3)
|
self.set_status((self._status + 1) % 3)
|
||||||
|
|
||||||
def set_status(self, status):
|
def set_status(self, status) -> None:
|
||||||
super().set_status(status)
|
super().set_status(status)
|
||||||
if status is not None:
|
if status is not None:
|
||||||
self._tox.self_set_status(status)
|
self._tox.self_set_status(status)
|
||||||
elif not self._waiting_for_reconnection:
|
elif not self._waiting_for_reconnection:
|
||||||
self._waiting_for_reconnection = True
|
self._waiting_for_reconnection = True
|
||||||
self._timer = threading.Timer(50, self._reconnect)
|
self._timer = threading.Timer(iRECONNECT, self._reconnect)
|
||||||
self._timer.start()
|
self._timer.start()
|
||||||
|
|
||||||
def set_name(self, value):
|
def set_name(self, value) -> None:
|
||||||
if self.name == value:
|
if self.name == value:
|
||||||
return
|
return
|
||||||
super().set_name(value)
|
super().set_name(value)
|
||||||
self._tox.self_set_name(self._name)
|
self._tox.self_set_name(self._name)
|
||||||
|
|
||||||
def set_status_message(self, value):
|
def set_status_message(self, value) -> None:
|
||||||
super().set_status_message(value)
|
super().set_status_message(value)
|
||||||
self._tox.self_set_status_message(self._status_message)
|
self._tox.self_set_status_message(self._status_message)
|
||||||
|
|
||||||
|
@ -72,19 +74,34 @@ class Profile(basecontact.BaseContact, tox_save.ToxSave):
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
|
|
||||||
def restart(self):
|
def restart(self) -> None:
|
||||||
"""
|
"""
|
||||||
Recreate tox instance
|
Recreate tox instance
|
||||||
"""
|
"""
|
||||||
self.status = None
|
self.status = None
|
||||||
invoke_in_main_thread(self._reset_action)
|
invoke_in_main_thread(self._reset_action)
|
||||||
|
|
||||||
def _reconnect(self):
|
def _reconnect(self) -> None:
|
||||||
self._waiting_for_reconnection = False
|
self._waiting_for_reconnection = False
|
||||||
|
if self._app and self._app.bAppExiting:
|
||||||
|
# dont do anything after the app has been shipped
|
||||||
|
# there's a segv that results
|
||||||
|
return
|
||||||
contacts = self._contacts_provider.get_all_friends()
|
contacts = self._contacts_provider.get_all_friends()
|
||||||
all_friends_offline = all(list(map(lambda x: x.status is None, contacts)))
|
all_friends_offline = all(list(map(lambda x: x.status is None, contacts)))
|
||||||
if self.status is None or (all_friends_offline and len(contacts)):
|
if self.status is None or (all_friends_offline and len(contacts)):
|
||||||
self._waiting_for_reconnection = True
|
self._waiting_for_reconnection = True
|
||||||
self.restart()
|
self.restart()
|
||||||
self._timer = threading.Timer(50, self._reconnect)
|
self._timer = threading.Timer(iRECONNECT, self._reconnect)
|
||||||
self._timer.start()
|
self._timer.start()
|
||||||
|
|
||||||
|
# Current thread 0x00007901a13ccb80 (most recent call first):
|
||||||
|
# File "/usr/local/lib/python3.11/site-packages/tox_wrapper/tox.py", line 826 in self_get_friend_list_size
|
||||||
|
# File "/usr/local/lib/python3.11/site-packages/tox_wrapper/tox.py", line 838 in self_get_friend_list
|
||||||
|
# File "/mnt/o/var/local/src/toxygen/toxygen/contacts/contact_provider.py", line 45 in get_all_friends
|
||||||
|
# File "/mnt/o/var/local/src/toxygen/toxygen/contacts/profile.py", line 90 in _reconnect
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1401 in run
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1045 in _bootstrap_inner
|
||||||
|
# File "/usr/lib/python3.11/threading.py", line 1002 in _bootstrap
|
||||||
|
#
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,15 +1,15 @@
|
||||||
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
||||||
from qtpy import QtCore, QtGui, QtWidgets, uic
|
from qtpy import QtCore, QtGui, QtWidgets, uic
|
||||||
|
|
||||||
|
import tox_wrapper.tests.support_testing as ts
|
||||||
|
with ts.ignoreStderr(): # not out
|
||||||
|
import pyaudio
|
||||||
|
|
||||||
from user_data.settings import *
|
from user_data.settings import *
|
||||||
from utils.util import *
|
from utils.util import *
|
||||||
from ui.widgets import CenteredWidget, DataLabel, LineEdit, RubberBandWindow
|
from ui.widgets import CenteredWidget, DataLabel, LineEdit, RubberBandWindow
|
||||||
import updater.updater as updater
|
import updater.updater as updater
|
||||||
import utils.ui as util_ui
|
import utils.ui as util_ui
|
||||||
import tox_wrapper.tests.support_testing as ts
|
|
||||||
with ts.ignoreStderr():
|
|
||||||
import pyaudio
|
|
||||||
from user_data import settings
|
from user_data import settings
|
||||||
|
|
||||||
global LOG
|
global LOG
|
||||||
|
|
|
@ -15,11 +15,12 @@ class ProfileManager:
|
||||||
"""
|
"""
|
||||||
Class with methods for search, load and save profiles
|
Class with methods for search, load and save profiles
|
||||||
"""
|
"""
|
||||||
def __init__(self, toxes, path):
|
def __init__(self, toxes, path, app=None):
|
||||||
assert path
|
assert path
|
||||||
self._toxes = toxes
|
self._toxes = toxes
|
||||||
self._path = path
|
self._path = path
|
||||||
assert path
|
assert path
|
||||||
|
self._app = app
|
||||||
self._directory = os.path.dirname(path)
|
self._directory = os.path.dirname(path)
|
||||||
self._profile_saved_event = Event()
|
self._profile_saved_event = Event()
|
||||||
# create /avatars if not exists:
|
# create /avatars if not exists:
|
||||||
|
|
|
@ -138,7 +138,7 @@ class Settings(dict):
|
||||||
self._args = app._args
|
self._args = app._args
|
||||||
self._oArgs = app._args
|
self._oArgs = app._args
|
||||||
self._log = lambda l: LOG.log(self._oArgs.loglevel, l)
|
self._log = lambda l: LOG.log(self._oArgs.loglevel, l)
|
||||||
self._profile_path = app._path # json_path.replace('.json', '.tox')
|
self._profile_path = json_path.replace('.json', '.tox')
|
||||||
|
|
||||||
self._settings_saved_event = Event()
|
self._settings_saved_event = Event()
|
||||||
path = json_path.replace('.tox', '.json')
|
path = json_path.replace('.tox', '.json')
|
||||||
|
|
Loading…
Reference in a new issue