Fixed history database
This commit is contained in:
parent
b75aafe638
commit
fd7f2620ba
12 changed files with 164 additions and 120 deletions
|
@ -49,5 +49,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.
|
||||
|
||||
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!
|
18
ToDo.md
18
ToDo.md
|
@ -6,15 +6,16 @@ The code is in there but it's not working.
|
|||
|
||||
## Fix Audio
|
||||
|
||||
The code is in there but it's not working.
|
||||
I may have broken it trying to wire up the ability to
|
||||
set the audio device from the command line.
|
||||
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 audio device from the command line.
|
||||
The code is in there but it's not working. I may have broken it
|
||||
trying to wire up the ability to set the audio device from the command
|
||||
line.
|
||||
|
||||
## Groups
|
||||
|
||||
|
@ -22,9 +23,6 @@ set the audio device from the command line.
|
|||
```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.
|
||||
|
||||
2. There is no way to delete a group in the UI
|
||||
|
||||
3. Distinguish between Frieds, Groups and Whispers in the UI.
|
||||
|
||||
## Plugin system
|
||||
|
||||
|
@ -34,6 +32,8 @@ set the audio device from the command line.
|
|||
|
||||
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,
|
||||
|
|
131
toxygen/app.py
131
toxygen/app.py
|
@ -86,29 +86,29 @@ iNODES=8
|
|||
|
||||
def setup_logging(oArgs):
|
||||
global LOG
|
||||
logging._defaultFormatter = logging.Formatter(datefmt='%m-%d %H:%M:%S',
|
||||
fmt='%(levelname)s:%(name)s %(message)s')
|
||||
logging._defaultFormatter.default_time_format = '%m-%d %H:%M:%S'
|
||||
logging._defaultFormatter.default_msec_format = ''
|
||||
|
||||
if coloredlogs:
|
||||
aKw = dict(level=oArgs.loglevel,
|
||||
logger=LOG,
|
||||
fmt='%(name)s %(levelname)s %(message)s')
|
||||
if oArgs.logfile:
|
||||
oFd = open(oArgs.logfile, 'wt')
|
||||
setattr(oArgs, 'log_oFd', oFd)
|
||||
aKw['stream'] = oFd
|
||||
aKw['stream'] = sys.stdout
|
||||
coloredlogs.install(**aKw)
|
||||
|
||||
else:
|
||||
aKw = dict(level=oArgs.loglevel,
|
||||
format='%(name)s %(levelname)-4s %(message)s')
|
||||
if oArgs.logfile:
|
||||
aKw['filename'] = oArgs.logfile
|
||||
aKw['stream'] = sys.stdout
|
||||
logging.basicConfig(**aKw)
|
||||
if not oArgs.logfile:
|
||||
oHandler = logging.StreamHandler(stream=sys.stdout)
|
||||
LOG.addHandler(oHandler)
|
||||
|
||||
logging._defaultFormatter = logging.Formatter(datefmt='%m-%d %H:%M:%S')
|
||||
logging._defaultFormatter.default_time_format = '%m-%d %H:%M:%S'
|
||||
logging._defaultFormatter.default_msec_format = ''
|
||||
if oArgs.logfile:
|
||||
oFd = open(oArgs.logfile, 'wt')
|
||||
setattr(oArgs, 'log_oFd', oFd)
|
||||
oHandler = logging.StreamHandler(stream=oFd)
|
||||
LOG.addHandler(oHandler)
|
||||
|
||||
LOG.setLevel(oArgs.loglevel)
|
||||
LOG.trace = lambda l: LOG.log(0, repr(l))
|
||||
|
@ -124,7 +124,6 @@ logging.getLogger('PyQt5.uic').setLevel(logging.ERROR)
|
|||
logging.getLogger('PyQt5.uic.uiparser').setLevel(logging.ERROR)
|
||||
logging.getLogger('PyQt5.uic.properties').setLevel(logging.ERROR)
|
||||
|
||||
|
||||
global iI
|
||||
iI = 0
|
||||
|
||||
|
@ -155,7 +154,7 @@ class App:
|
|||
def __init__(self, version, oArgs):
|
||||
global LOG
|
||||
self._args = oArgs
|
||||
self.oArgs = oArgs
|
||||
self._oArgs = oArgs
|
||||
self._path = path_to_profile = oArgs.profile
|
||||
uri = oArgs.uri
|
||||
logfile = oArgs.logfile
|
||||
|
@ -179,18 +178,21 @@ class App:
|
|||
self._group_factory = self._groups_service = self._profile = None
|
||||
if uri is not None and uri.startswith('tox:'):
|
||||
self._uri = uri[4:]
|
||||
self._history = None
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def set_trace(self):
|
||||
"""unused"""
|
||||
LOG.debug('pdb.set_trace ')
|
||||
sys.stdin = sys.__stdin__
|
||||
sys.stdout = sys.__stdout__
|
||||
import pdb; pdb.set_trace()
|
||||
|
||||
def ten(self, i=0):
|
||||
"""unused"""
|
||||
global iI
|
||||
iI += 1
|
||||
if logging.getLogger('app').getEffectiveLevel() != 10:
|
||||
|
@ -219,11 +221,11 @@ class App:
|
|||
# this throws everything as errors
|
||||
if not self._select_and_load_profile():
|
||||
return 2
|
||||
if hasattr(self._args, 'update') and self._args.update:
|
||||
if hasattr(self._oArgs, 'update') and self._oArgs.update:
|
||||
if self._try_to_update(): return 3
|
||||
|
||||
self._load_app_styles()
|
||||
if self._args.language != 'English':
|
||||
if self._oArgs.language != 'English':
|
||||
# > /var/local/src/toxygen/toxygen/app.py(303)_load_app_translations()->None
|
||||
# -> self._app.translator = translator
|
||||
# (Pdb) Fatal Python error: Segmentation fault
|
||||
|
@ -271,26 +273,34 @@ class App:
|
|||
|
||||
def quit(self, retval=0):
|
||||
LOG.debug("quit")
|
||||
oArgs = self._args
|
||||
if hasattr(oArgs, 'log_oFd'):
|
||||
oArgs.log_oFd.close()
|
||||
delattr(oArgs, 'log_oFd')
|
||||
self._stop_app()
|
||||
|
||||
# failsafe: segfaults on exit
|
||||
if hasattr(self, '_tox'):
|
||||
if self._tox and hasattr(self._tox, 'kill'):
|
||||
LOG.debug(f"quit: Killing {self._tox}")
|
||||
self._tox.kill()
|
||||
del self._tox
|
||||
|
||||
self._stop_app()
|
||||
if hasattr(self, '_app'):
|
||||
self._app.quit()
|
||||
del self._app.quit
|
||||
del self._app
|
||||
|
||||
sys.stderr.write('quit raising SystemExit' +'\n')
|
||||
# hanging on gevents
|
||||
# Thread 1 "python3.9" received signal SIGSEGV, Segmentation fault.
|
||||
#44 0x00007ffff7fb2f93 in () at /usr/lib/python3.9/site-packages/greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so
|
||||
#45 0x00007ffff7fb31ef in () at /usr/lib/python3.9/site-packages/greenlet/_greenlet.cpython-39-x86_64-linux-gnu.so
|
||||
#46 0x00007ffff452165c in hb_shape_plan_create_cached2 () at /usr/lib64/libharfbuzz.so.0
|
||||
|
||||
raise SystemExit(retval)
|
||||
|
||||
def _stop_app(self):
|
||||
LOG.debug("_stop_app")
|
||||
self._save_profile()
|
||||
#? self._history.save_history()
|
||||
|
||||
self._plugin_loader.stop()
|
||||
try:
|
||||
self._stop_threads(is_app_closing=True)
|
||||
|
@ -299,31 +309,38 @@ class App:
|
|||
pass
|
||||
if hasattr(self, '_tray') and self._tray:
|
||||
self._tray.hide()
|
||||
self._save_profile()
|
||||
self._settings.close()
|
||||
|
||||
LOG.debug(f"stop_app: Killing {self._tox}")
|
||||
self._kill_toxav()
|
||||
self._kill_tox()
|
||||
sys.stderr.write('_stop_app end' +'\n')
|
||||
del self._tox
|
||||
|
||||
oArgs = self._oArgs
|
||||
if hasattr(oArgs, 'log_oFd'):
|
||||
LOG.debug(f"Closing {oArgs.log_oFd}")
|
||||
oArgs.log_oFd.close()
|
||||
delattr(oArgs, 'log_oFd')
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# App loading
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def _load_base_style(self):
|
||||
if self._args.theme in ['', 'default']: return
|
||||
if self._oArgs.theme in ['', 'default']: return
|
||||
|
||||
if qdarkstyle:
|
||||
LOG.debug("_load_base_style qdarkstyle " +self._args.theme)
|
||||
LOG.debug("_load_base_style qdarkstyle " +self._oArgs.theme)
|
||||
# QDarkStyleSheet
|
||||
if self._args.theme == 'light':
|
||||
if self._oArgs.theme == 'light':
|
||||
from qdarkstyle.light.palette import LightPalette
|
||||
style = qdarkstyle.load_stylesheet(palette=LightPalette)
|
||||
else:
|
||||
from qdarkstyle.dark.palette import DarkPalette
|
||||
style = qdarkstyle.load_stylesheet(palette=DarkPalette)
|
||||
else:
|
||||
LOG.debug("_load_base_style qss " +self._args.theme)
|
||||
name = self._args.theme + '.qss'
|
||||
LOG.debug("_load_base_style qss " +self._oArgs.theme)
|
||||
name = self._oArgs.theme + '.qss'
|
||||
with open(util.join_path(util.get_styles_directory(), name)) as fl:
|
||||
style = fl.read()
|
||||
style += '\n' +sSTYLE
|
||||
|
@ -337,9 +354,9 @@ class App:
|
|||
if self._settings['theme'] != theme:
|
||||
continue
|
||||
if qdarkstyle:
|
||||
LOG.debug("_load_base_style qdarkstyle " +self._args.theme)
|
||||
LOG.debug("_load_base_style qdarkstyle " +self._oArgs.theme)
|
||||
# QDarkStyleSheet
|
||||
if self._args.theme == 'light':
|
||||
if self._oArgs.theme == 'light':
|
||||
from qdarkstyle.light.palette import LightPalette
|
||||
style = qdarkstyle.load_stylesheet(palette=LightPalette)
|
||||
else:
|
||||
|
@ -356,7 +373,7 @@ class App:
|
|||
LOG.debug('_load_app_styles: loading theme file ' + file_path)
|
||||
style += '\n' +sSTYLE
|
||||
self._app.setStyleSheet(style)
|
||||
LOG.info('_load_app_styles: loaded theme ' +self._args.theme)
|
||||
LOG.info('_load_app_styles: loaded theme ' +self._oArgs.theme)
|
||||
break
|
||||
|
||||
def _load_login_screen_translations(self):
|
||||
|
@ -503,7 +520,7 @@ class App:
|
|||
|
||||
def _select_profile(self):
|
||||
LOG.debug("_select_profile")
|
||||
if self._args.language != 'English':
|
||||
if self._oArgs.language != 'English':
|
||||
self._load_login_screen_translations()
|
||||
ls = LoginScreen()
|
||||
profiles = ProfileManager.find_profiles()
|
||||
|
@ -542,7 +559,7 @@ class App:
|
|||
util_ui.tr('Error'))
|
||||
return False
|
||||
name = profile_name or 'toxygen_user'
|
||||
assert self._args
|
||||
assert self._oArgs
|
||||
self._path = profile_path
|
||||
if result.password:
|
||||
self._toxes.set_password(result.password)
|
||||
|
@ -644,7 +661,7 @@ class App:
|
|||
|
||||
def _create_dependencies(self):
|
||||
LOG.info(f"_create_dependencies toxygen version {self._version}")
|
||||
if hasattr(self._args, 'update') and self._args.update:
|
||||
if hasattr(self._oArgs, 'update') and self._oArgs.update:
|
||||
self._backup_service = BackupService(self._settings,
|
||||
self._profile_manager)
|
||||
self._smiley_loader = SmileyLoader(self._settings)
|
||||
|
@ -697,9 +714,11 @@ class App:
|
|||
self._ms,
|
||||
self._profile_manager,
|
||||
self._contacts_provider,
|
||||
history, self._tox_dns,
|
||||
history,
|
||||
self._tox_dns,
|
||||
messages_items_factory)
|
||||
history.set_contacts_manager(self._contacts_manager)
|
||||
self._history = history
|
||||
self._calls_manager = CallsManager(self._tox.AV,
|
||||
self._settings,
|
||||
self._ms,
|
||||
|
@ -754,14 +773,14 @@ class App:
|
|||
self._ms.show()
|
||||
|
||||
# FixMe:
|
||||
self._log = lambda line: LOG.log(self._args.loglevel,
|
||||
self._log = lambda line: LOG.log(self._oArgs.loglevel,
|
||||
self._ms.status(line))
|
||||
self._ms._log = self._log # used in callbacks.py
|
||||
self.LOG = self._log # backwards
|
||||
|
||||
if False:
|
||||
self.status_handler = logging.Handler()
|
||||
self.status_handler.setLevel(logging.INFO) # self._args.loglevel
|
||||
self.status_handler.setLevel(logging.INFO) # self._oArgs.loglevel
|
||||
self.status_handler.handle = self._ms.status
|
||||
|
||||
self._init_callbacks()
|
||||
|
@ -780,9 +799,9 @@ class App:
|
|||
|
||||
def _create_tox(self, data, settings_):
|
||||
LOG.info("_create_tox calling tox_factory")
|
||||
assert self._args
|
||||
assert self._oArgs
|
||||
retval = tox_factory(data=data, settings=settings_,
|
||||
args=self._args, app=self)
|
||||
args=self._oArgs, app=self)
|
||||
LOG.debug("_create_tox succeeded")
|
||||
self._tox = retval
|
||||
return retval
|
||||
|
@ -807,12 +826,12 @@ class App:
|
|||
self._profile.reset_avatar(self._settings['identicons'])
|
||||
|
||||
def _kill_toxav(self):
|
||||
LOG.debug("_kill_toxav")
|
||||
# LOG_debug("_kill_toxav")
|
||||
self._calls_manager.set_toxav(None)
|
||||
self._tox.AV.kill()
|
||||
|
||||
def _kill_tox(self):
|
||||
LOG.debug("_kill_tox")
|
||||
# LOG.debug("_kill_tox")
|
||||
self._tox.kill()
|
||||
|
||||
def loop(self, n):
|
||||
|
@ -832,17 +851,17 @@ class App:
|
|||
|
||||
def test_net(self, lElts=None, oThread=None, iMax=4):
|
||||
|
||||
LOG.debug("test_net " +self._args.network)
|
||||
LOG.debug("test_net " +self._oArgs.network)
|
||||
# bootstrap
|
||||
LOG.debug('Calling generate_nodes: udp')
|
||||
lNodes = ts.generate_nodes(oArgs=self._args,
|
||||
lNodes = ts.generate_nodes(oArgs=self._oArgs,
|
||||
ipv='ipv4',
|
||||
udp_not_tcp=True)
|
||||
self._settings['current_nodes_udp'] = lNodes
|
||||
if not lNodes:
|
||||
LOG.warn('empty generate_nodes udp')
|
||||
LOG.debug('Calling generate_nodes: tcp')
|
||||
lNodes = ts.generate_nodes(oArgs=self._args,
|
||||
lNodes = ts.generate_nodes(oArgs=self._oArgs,
|
||||
ipv='ipv4',
|
||||
udp_not_tcp=False)
|
||||
self._settings['current_nodes_tcp'] = lNodes
|
||||
|
@ -850,8 +869,8 @@ class App:
|
|||
LOG.warn('empty generate_nodes tcp')
|
||||
|
||||
# if oThread and oThread._stop_thread: return
|
||||
LOG.debug("test_net network=" +self._args.network +' iMax=' +str(iMax))
|
||||
if self._args.network not in ['local', 'localnew', 'newlocal']:
|
||||
LOG.debug("test_net network=" +self._oArgs.network +' iMax=' +str(iMax))
|
||||
if self._oArgs.network not in ['local', 'localnew', 'newlocal']:
|
||||
b = ts.bAreWeConnected()
|
||||
if b is None:
|
||||
i = os.system('ip route|grep ^def')
|
||||
|
@ -860,22 +879,22 @@ class App:
|
|||
else:
|
||||
b = True
|
||||
if not b:
|
||||
LOG.warn("No default route for network " +self._args.network)
|
||||
LOG.warn("No default route for network " +self._oArgs.network)
|
||||
text = 'You have no default route - are you connected?'
|
||||
reply = util_ui.question(text, "Are you connected?")
|
||||
if not reply: return
|
||||
iMax = 1
|
||||
else:
|
||||
LOG.debug("Have default route for network " +self._args.network)
|
||||
LOG.debug("Have default route for network " +self._oArgs.network)
|
||||
|
||||
LOG.debug(f"test_net {self._args.network} iMax= {iMax}")
|
||||
LOG.debug(f"test_net {self._oArgs.network} iMax= {iMax}")
|
||||
i = 0
|
||||
while i < iMax:
|
||||
# if oThread and oThread._stop_thread: return
|
||||
i = i + 1
|
||||
LOG.debug(f"bootstrapping status # {i}")
|
||||
self._test_bootstrap(self._settings['current_nodes_udp'])
|
||||
if hasattr(self._args, 'proxy_type') and self._args.proxy_type > 0:
|
||||
if hasattr(self._oArgs, 'proxy_type') and self._oArgs.proxy_type > 0:
|
||||
LOG.debug(f"relaying status # {i}")
|
||||
self._test_relays(self._settings['current_nodes_tcp'])
|
||||
status = self._tox.self_get_connection_status()
|
||||
|
@ -906,16 +925,14 @@ class App:
|
|||
+_settings['proxy_host'] +':' \
|
||||
+str(_settings['proxy_port']))
|
||||
lElts = _settings['current_nodes_tcp']
|
||||
LOG.debug(f"test_env {len(lElts)}")
|
||||
# LOG.debug(f"test_env {len(lElts)}")
|
||||
return env
|
||||
|
||||
def _test_bootstrap(self, lElts=None):
|
||||
env = self._test_env()
|
||||
if lElts is None:
|
||||
lElts = self._settings['current_nodes_udp']
|
||||
shuffle(lElts)
|
||||
LOG.debug(f"_test_bootstrap #Elts={len(lElts)}")
|
||||
shuffle(lElts)
|
||||
ts.bootstrap_good(lElts[:iNODES], [self._tox])
|
||||
LOG.info("Connected status: " +repr(self._tox.self_get_connection_status()))
|
||||
|
||||
|
@ -962,10 +979,10 @@ class App:
|
|||
text = 'Run the Extended Test Suite?\nThe program may freeze for 20-60 minutes.'
|
||||
reply = util_ui.question(text, title)
|
||||
if reply:
|
||||
if hasattr(self._args, 'proxy_type') and self._args.proxy_type:
|
||||
lArgs = ['--proxy_host', self._args.proxy_host,
|
||||
'--proxy_port', str(self._args.proxy_port),
|
||||
'--proxy_type', str(self._args.proxy_type), ]
|
||||
if hasattr(self._oArgs, 'proxy_type') and self._oArgs.proxy_type:
|
||||
lArgs = ['--proxy_host', self._oArgs.proxy_host,
|
||||
'--proxy_port', str(self._oArgs.proxy_port),
|
||||
'--proxy_type', str(self._oArgs.proxy_type), ]
|
||||
else:
|
||||
lArgs = list()
|
||||
try:
|
||||
|
|
|
@ -18,6 +18,18 @@ from middleware.threads import BaseThread
|
|||
global LOG
|
||||
import logging
|
||||
LOG = logging.getLogger('app.'+__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)
|
||||
|
||||
TIMER_TIMEOUT = 30.0
|
||||
bSTREAM_CALLBACK = False
|
||||
|
@ -27,6 +39,7 @@ class AV(common.tox_save.ToxAvSave):
|
|||
|
||||
def __init__(self, toxav, settings):
|
||||
super().__init__(toxav)
|
||||
self._toxav = toxav
|
||||
self._settings = settings
|
||||
self._running = True
|
||||
s = settings
|
||||
|
@ -62,7 +75,10 @@ class AV(common.tox_save.ToxAvSave):
|
|||
self._video_width = 320
|
||||
self._video_height = 240
|
||||
|
||||
iOutput = self._settings._args.audio['output']
|
||||
# was iOutput = self._settings._args.audio['output']
|
||||
iInput = self._settings['audio']['input']
|
||||
self.lPaSampleratesI = ts.lSdSamplerates(iInput)
|
||||
iOutput = self._settings['audio']['output']
|
||||
self.lPaSampleratesO = ts.lSdSamplerates(iOutput)
|
||||
global oPYA
|
||||
oPYA = self._audio = pyaudio.PyAudio()
|
||||
|
@ -180,33 +196,35 @@ class AV(common.tox_save.ToxAvSave):
|
|||
def start_audio_thread(self):
|
||||
"""
|
||||
Start audio sending
|
||||
from a callback
|
||||
"""
|
||||
global oPYA
|
||||
iInput = self._settings._args.audio['input']
|
||||
# was iInput = self._settings._args.audio['input']
|
||||
iInput = self._settings['audio']['input']
|
||||
if self._audio_thread is not None:
|
||||
LOG.warn(f"start_audio_thread device={iInput}")
|
||||
LOG_WARN(f"start_audio_thread device={iInput}")
|
||||
return
|
||||
iInput = self._settings._args.audio['input']
|
||||
LOG.debug(f"start_audio_thread device={iInput}")
|
||||
LOG_DEBUG(f"start_audio_thread device={iInput}")
|
||||
lPaSamplerates = ts.lSdSamplerates(iInput)
|
||||
if not(len(lPaSamplerates)):
|
||||
e = f"No supported sample rates for device: audio[input]={iInput!r}"
|
||||
LOG.error(f"No supported sample rates {e}")
|
||||
raise RuntimeError(e)
|
||||
LOG_ERROR(f"start_audio_thread {e}")
|
||||
#?? dunno - cancel call?
|
||||
return
|
||||
if not self._audio_rate_pa in lPaSamplerates:
|
||||
LOG.warn(f"{self._audio_rate_pa} not in {lPaSamplerates!r}")
|
||||
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates!r}")
|
||||
if False:
|
||||
self._audio_rate_pa = oPYA.get_device_info_by_index(iInput)['defaultSampleRate']
|
||||
else:
|
||||
LOG.warn(f"Setting audio_rate to: {lPaSamplerates[0]}")
|
||||
LOG_WARN(f"Setting audio_rate to: {lPaSamplerates[0]}")
|
||||
self._audio_rate_pa = lPaSamplerates[0]
|
||||
|
||||
try:
|
||||
LOG.debug( f"start_audio_thread framerate: {self._audio_rate_pa}" \
|
||||
LOG_DEBUG( f"start_audio_thread framerate: {self._audio_rate_pa}" \
|
||||
+f" device: {iInput}"
|
||||
+f" supported: {lPaSamplerates!r}")
|
||||
if self._audio_rate_pa not in lPaSamplerates:
|
||||
LOG.warn(f"PAudio sampling rate was {self._audio_rate_pa} changed to {lPaSamplerates[0]}")
|
||||
LOG_WARN(f"PAudio sampling rate was {self._audio_rate_pa} changed to {lPaSamplerates[0]}")
|
||||
self._audio_rate_pa = lPaSamplerates[0]
|
||||
|
||||
if bSTREAM_CALLBACK:
|
||||
|
@ -244,10 +262,12 @@ class AV(common.tox_save.ToxAvSave):
|
|||
input=True,
|
||||
input_device_index=iInput,
|
||||
frames_per_buffer=self._audio_sample_count_pa * 10)))
|
||||
# catcher in place in calls_manager
|
||||
raise RuntimeError(e)
|
||||
# catcher in place in calls_manager? not if from a callback
|
||||
# calls_manager._call.toxav_call_state_cb(friend_number, mask)
|
||||
# raise RuntimeError(e)
|
||||
return
|
||||
else:
|
||||
LOG.debug(f"start_audio_thread {self._audio_stream!r}")
|
||||
LOG_DEBUG(f"start_audio_thread {self._audio_stream!r}")
|
||||
|
||||
def stop_audio_thread(self):
|
||||
|
||||
|
@ -339,7 +359,8 @@ class AV(common.tox_save.ToxAvSave):
|
|||
"""
|
||||
|
||||
if self._out_stream is None:
|
||||
iOutput = self._settings._args.audio['output']
|
||||
# was iOutput = self._settings._args.audio['output']
|
||||
iOutput = self._settings['audio']['output']
|
||||
if not rate in self.lPaSampleratesO:
|
||||
LOG.warn(f"{rate} not in {self.lPaSampleratesO!r}")
|
||||
if False:
|
||||
|
@ -362,7 +383,8 @@ class AV(common.tox_save.ToxAvSave):
|
|||
self.stop()
|
||||
return
|
||||
|
||||
LOG.debug(f"audio_chunk output_device_index={self._settings._args.audio['input']} rate={rate} channels={channels_count}")
|
||||
iOutput = self._settings['audio']['output']
|
||||
LOG.debug(f"audio_chunk output_device_index={iOutput} rate={rate} channels={channels_count}")
|
||||
self._out_stream.write(samples)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -16,7 +16,8 @@ LOG = logging.getLogger('app.'+__name__)
|
|||
class CallsManager:
|
||||
|
||||
def __init__(self, toxav, settings, main_screen, contacts_manager, app=None):
|
||||
self._call = av.calls.AV(toxav, settings) # object with data about calls
|
||||
self._callav = av.calls.AV(toxav, settings) # object with data about calls
|
||||
self._call = self._callav
|
||||
self._call_widgets = {} # dict of incoming call widgets
|
||||
self._incoming_calls = set()
|
||||
self._settings = settings
|
||||
|
@ -27,7 +28,7 @@ class CallsManager:
|
|||
self._app = app
|
||||
|
||||
def set_toxav(self, toxav):
|
||||
self._call.set_toxav(toxav)
|
||||
self._callav.set_toxav(toxav)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Events
|
||||
|
@ -52,13 +53,13 @@ class CallsManager:
|
|||
num = self._contacts_manager.get_active_number()
|
||||
if not self._contacts_manager.is_active_a_friend():
|
||||
return
|
||||
if num not in self._call and self._contacts_manager.is_active_online(): # start call
|
||||
if num not in self._callav and self._contacts_manager.is_active_online(): # start call
|
||||
if not self._settings['audio']['enabled']:
|
||||
return
|
||||
self._call(num, audio, video)
|
||||
self._callav(num, audio, video)
|
||||
self._main_screen.active_call()
|
||||
self._call_started_event(num, audio, video, True)
|
||||
elif num in self._call: # finish or cancel call if you call with active friend
|
||||
elif num in self._callav: # finish or cancel call if you call with active friend
|
||||
self.stop_call(num, False)
|
||||
|
||||
def incoming_call(self, audio, video, friend_number):
|
||||
|
@ -89,7 +90,7 @@ class CallsManager:
|
|||
sys.stdout.flush()
|
||||
|
||||
try:
|
||||
self._call.call_accept_call(friend_number, audio, video)
|
||||
self._callav.call_accept_call(friend_number, audio, video)
|
||||
except Exception as e:
|
||||
LOG.error(f"accept_call _call.accept_call ERROR for {friend_number} {e}")
|
||||
self._main_screen.call_finished()
|
||||
|
@ -139,14 +140,14 @@ class CallsManager:
|
|||
else:
|
||||
is_declined = False
|
||||
self._main_screen.call_finished()
|
||||
self._call.finish_call(friend_number, by_friend) # finish or decline call
|
||||
self._callav.finish_call(friend_number, by_friend) # finish or decline call
|
||||
if friend_number in self._call_widgets:
|
||||
self._call_widgets[friend_number].close()
|
||||
del self._call_widgets[friend_number]
|
||||
|
||||
def destroy_window():
|
||||
#??? FixMed
|
||||
is_video = self._call.is_video_call(friend_number)
|
||||
is_video = self._callav.is_video_call(friend_number)
|
||||
if is_video:
|
||||
import cv2
|
||||
cv2.destroyWindow(str(friend_number))
|
||||
|
@ -155,8 +156,8 @@ class CallsManager:
|
|||
self._call_finished_event(friend_number, is_declined)
|
||||
|
||||
def friend_exit(self, friend_number):
|
||||
if friend_number in self._call:
|
||||
self._call.finish_call(friend_number, True)
|
||||
if friend_number in self._callav:
|
||||
self._callav.finish_call(friend_number, True)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Private methods
|
||||
|
|
|
@ -28,7 +28,7 @@ class BaseContact:
|
|||
self._kind = kind
|
||||
self._status, self._widget = None, widget
|
||||
self._tox_id = tox_id
|
||||
|
||||
|
||||
self._name_changed_event = event.Event()
|
||||
self._status_message_changed_event = event.Event()
|
||||
self._status_changed_event = event.Event()
|
||||
|
|
|
@ -93,7 +93,7 @@ class ContactsManager(ToxSave):
|
|||
return False
|
||||
if not self._contacts[self._active_contact]:
|
||||
return False
|
||||
|
||||
|
||||
return self._contacts[self._active_contact].tox_id == contact.tox_id
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
@ -198,7 +198,7 @@ class ContactsManager(ToxSave):
|
|||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Filtration
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def filtration_and_sorting(self, sorting=0, filter_str=''):
|
||||
"""
|
||||
Filtration of friends list
|
||||
|
@ -245,7 +245,7 @@ class ContactsManager(ToxSave):
|
|||
else:
|
||||
self._contacts = sorted(self._contacts, key=lambda x: x.name.lower())
|
||||
|
||||
|
||||
|
||||
# change item widgets
|
||||
for index, contact in enumerate(self._contacts):
|
||||
list_item = self._screen.friends_list.item(index)
|
||||
|
|
|
@ -53,7 +53,7 @@ class GroupsService(tox_save.ToxSave):
|
|||
try:
|
||||
group_number = self._tox.group_join(chat_id, password, nick, status)
|
||||
assert type(group_number) == int, group_number
|
||||
assert group_number < UINT32_MAX, group_number
|
||||
assert group_number < UINT32_MAX, group_number
|
||||
except Exception as e:
|
||||
# gui
|
||||
title = f"join_gc_by_id {chat_id}"
|
||||
|
@ -73,7 +73,7 @@ class GroupsService(tox_save.ToxSave):
|
|||
return
|
||||
group.status = constants.TOX_USER_STATUS['NONE']
|
||||
self._contacts_manager.update_filtration()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Groups reconnect and leaving
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -6,20 +6,16 @@ import utils.util as util
|
|||
# LOG=util.log
|
||||
global LOG
|
||||
import logging
|
||||
LOG = logging.getLogger('app.'+__name__)
|
||||
log = lambda x: LOG.info(x)
|
||||
LOG = logging.getLogger('app.db')
|
||||
|
||||
TIMEOUT = 11
|
||||
|
||||
SAVE_MESSAGES = 500
|
||||
|
||||
MESSAGE_AUTHOR = {
|
||||
'ME': 0,
|
||||
'FRIEND': 1,
|
||||
'NOT_SENT': 2,
|
||||
'GC_PEER': 3
|
||||
}
|
||||
|
||||
CONTACT_TYPE = {
|
||||
'FRIEND': 0,
|
||||
'GC_PEER': 1,
|
||||
|
@ -54,6 +50,7 @@ class Database:
|
|||
except Exception as ex:
|
||||
LOG.error('Db writing error: ' +path +' ' + str(ex))
|
||||
os.remove(path)
|
||||
LOG.info('Db opened: ' +path)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
|
@ -75,6 +72,7 @@ class Database:
|
|||
data = self._toxes.pass_encrypt(data)
|
||||
with open(new_path, 'wb') as fout:
|
||||
fout.write(data)
|
||||
LOG.info('Db exported: ' +new_path)
|
||||
|
||||
def add_friend_to_db(self, tox_id):
|
||||
db = self._connect()
|
||||
|
@ -91,11 +89,12 @@ class Database:
|
|||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("dd_friend_to_db " +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"add_friend_to_db {tox_id}")
|
||||
|
||||
def delete_friend_from_db(self, tox_id):
|
||||
db = self._connect()
|
||||
|
@ -105,11 +104,12 @@ class Database:
|
|||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("delete_friend_from_db " +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"delete_friend_from_db {tox_id}")
|
||||
|
||||
def save_messages_to_db(self, tox_id, messages_iter):
|
||||
db = self._connect()
|
||||
|
@ -117,15 +117,16 @@ class Database:
|
|||
cursor = db.cursor()
|
||||
cursor.executemany('INSERT INTO id' + tox_id +
|
||||
'(message, author_name, author_type, unix_time, message_type) ' +
|
||||
'VALUES (?, ?, ?, ?, ?, ?);', messages_iter)
|
||||
'VALUES (?, ?, ?, ?, ?);', messages_iter)
|
||||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"save_messages_to_db {tox_id}")
|
||||
|
||||
def update_messages(self, tox_id, message_id):
|
||||
db = self._connect()
|
||||
|
@ -136,11 +137,12 @@ class Database:
|
|||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"update_messages {tox_id}")
|
||||
|
||||
def delete_message(self, tox_id, unique_id):
|
||||
db = self._connect()
|
||||
|
@ -150,11 +152,12 @@ class Database:
|
|||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"delete_message {tox_id}")
|
||||
|
||||
def delete_messages(self, tox_id):
|
||||
db = self._connect()
|
||||
|
@ -164,11 +167,12 @@ class Database:
|
|||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
LOG("ERROR: " +self._name +' Database exception! ' +str(e))
|
||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
||||
db.rollback()
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
LOG.debug(f"delete_messages {tox_id}")
|
||||
|
||||
def messages_getter(self, tox_id):
|
||||
self.add_friend_to_db(tox_id)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
||||
from history.history_logs_generators import *
|
||||
|
||||
|
||||
class History:
|
||||
|
||||
def __init__(self, contact_provider, db, settings, main_screen, messages_items_factory):
|
||||
|
@ -28,7 +27,7 @@ class History:
|
|||
Save history to db
|
||||
"""
|
||||
# me a mistake? was _db not _history
|
||||
if self._settings['save_history'] or self._settings['save_db']:
|
||||
if self._settings['save_history']:
|
||||
for friend in self._contact_provider.get_all_friends():
|
||||
self._db.add_friend_to_db(friend.tox_id)
|
||||
if not self._settings['save_unsent_only']:
|
||||
|
|
|
@ -21,7 +21,7 @@ iMAX = 70
|
|||
try:
|
||||
# https://github.com/pyqtconsole/pyqtconsole
|
||||
from pyqtconsole.console import PythonConsole
|
||||
import pyqtconsole.highlighter as hl
|
||||
import pyqtconsole.highlighter as hl
|
||||
except Exception as e:
|
||||
LOG.warn(e)
|
||||
PythonConsole = None
|
||||
|
@ -39,12 +39,12 @@ else:
|
|||
_format.setFontWeight(QFont.Bold)
|
||||
if 'italic' in style:
|
||||
_format.setFontItalic(True)
|
||||
|
||||
|
||||
_fgcolor = QColor()
|
||||
_fgcolor.setNamedColor('white')
|
||||
_format.setForeground(_fgcolor)
|
||||
return _format
|
||||
|
||||
|
||||
aFORMATS = {
|
||||
'keyword': hl.format('blue', 'bold'),
|
||||
'operator': hl.format('red'),
|
||||
|
@ -59,7 +59,7 @@ else:
|
|||
'outprompt': hl.format('darkRed', 'bold'),
|
||||
}
|
||||
|
||||
|
||||
|
||||
class QTextEditLogger(logging.Handler):
|
||||
def __init__(self, parent, app):
|
||||
super().__init__()
|
||||
|
@ -194,7 +194,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
|
||||
self.actionAdd_friend = QtWidgets.QAction(window)
|
||||
self.actionAdd_friend.setObjectName("actionAdd_friend")
|
||||
|
||||
|
||||
self.actionProfile_settings = QtWidgets.QAction(window)
|
||||
self.actionProfile_settings.setObjectName("actionProfile_settings")
|
||||
self.actionPrivacy_settings = QtWidgets.QAction(window)
|
||||
|
@ -621,10 +621,10 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
else:
|
||||
size = 12
|
||||
font_name = "Courier New"
|
||||
|
||||
|
||||
size = font_width = 10
|
||||
font_name = "DejaVu Sans Mono"
|
||||
|
||||
|
||||
try:
|
||||
if not self._pe:
|
||||
self._pe = PythonConsole(sFont=font_name,
|
||||
|
|
|
@ -360,7 +360,6 @@ class Settings(dict):
|
|||
'y': 400,
|
||||
'message_font_size': 14,
|
||||
'unread_color': 'red',
|
||||
'save_unsent_only': False,
|
||||
'compact_mode': False,
|
||||
'identicons': True,
|
||||
'show_welcome_screen': True,
|
||||
|
|
Loading…
Reference in a new issue