Fixed history database

This commit is contained in:
emdee 2022-10-11 16:36:09 +00:00
parent b75aafe638
commit fd7f2620ba
12 changed files with 164 additions and 120 deletions

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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