app.py and main.py refactoring and fixes

This commit is contained in:
ingvar1995 2018-04-17 21:08:22 +03:00
parent 8a2665ed4d
commit 0ba1aadf70
5 changed files with 160 additions and 142 deletions

View File

@ -1,6 +1,7 @@
from middleware import threads
import middleware.callbacks as callbacks
from PyQt5 import QtWidgets, QtGui, QtCore
import ui.password_screen as passwordscreen
import ui.password_screen as password_screen
from util.util import *
import updater.updater as updater
import os
@ -20,32 +21,30 @@ class App:
def __init__(self, version, path_to_profile=None, uri=None):
self._version = version
self._app = None
self._tox = self._ms = self._init = self._app = self.tray = self._main_loop = self._av_loop = None
self.uri = self._toxes = self._tray = None
self._app = self._settings = self._profile_manager = self._plugin_loader = None
self._tox = self._ms = self._init = self.tray = self._main_loop = self._av_loop = None
self._uri = self._toxes = self._tray = None
if uri is not None and uri.startswith('tox:'):
self.uri = uri[4:]
self._uri = uri[4:]
self._path = path_to_profile
def enter_pass(self, data):
"""
Show password screen
"""
p = passwordscreen.PasswordScreen(self._toxes, data)
p = password_screen.PasswordScreen(self._toxes, data)
p.show()
self._app.lastWindowClosed.connect(self._app.quit)
self._app.exec_()
result = p.result
if result is None:
raise SystemExit()
else:
return result
if p.result is not None:
return p.result
raise SystemExit()
def main(self):
"""
Main function of app. loads login screen if needed and starts main screen
"""
self._app= QtWidgets.QApplication([])
self._app = QtWidgets.QApplication([])
icon_file = os.path.join(get_images_directory(), 'icon.png')
self._app.setWindowIcon(QtGui.QIcon(icon_file))
@ -59,28 +58,13 @@ class App:
encrypt_save = tox_encrypt_save.ToxEncryptSave()
self._toxes = user_data.toxes.ToxES(encrypt_save)
if self._path is not None:
path = os.path.dirname(self._path) + '/'
name = os.path.basename(self._path)[:-4]
self._settings = Settings(self._toxes, self._path.replace('.tox', '.json'))
self._profile_manager = ProfileManager(self._settings, self._toxes, path)
data = self._profile_manager.open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
self._tox = self.create_tox(data)
if self._path is not None: # toxygen was started with path to profile
self.load_existing_profile(self._path)
else:
auto_profile = Settings.get_auto_profile()
if not auto_profile[0]:
if auto_profile is None: # no default profile
# show login screen if default profile not found
current_locale = QtCore.QLocale()
curr_lang = current_locale.languageToString(current_locale.language())
langs = Settings.supported_languages()
if curr_lang in langs:
lang_path = langs[curr_lang]
translator = QtCore.QTranslator()
translator.load(get_translations_directory() + lang_path)
self._app.installTranslator(translator)
self._app.translator = translator
self.load_login_screen_translations()
ls = LoginScreen()
ls.setWindowIconText("Toxygen")
profiles = ProfileManager.find_profiles()
@ -90,59 +74,25 @@ class App:
result = ls.result
if result is None:
return
elif result.is_new_profile(): # create new profile
name = get_profile_name_from_path(result.profile_path) or 'toxygen_user'
pr = map(lambda x: x[1], ProfileManager.find_profiles())
if name in list(pr):
util_ui.message_box(util_ui.tr('Profile with this name already exists'),
util_ui.tr('Error'))
return
self._tox = tox_factory()
self._tox.self_set_name(bytes(name, 'utf-8') if name else b'Toxygen User')
self._tox.self_set_status_message(b'Toxing on Toxygen')
# TODO: set profile password
path = result.profile_path
self._profile_manager = ProfileManager(self._toxes, path)
try:
self._profile_manager.save_profile(self._tox.get_savedata())
except Exception as ex:
print(str(ex))
log('Profile creation exception: ' + str(ex))
text = util_ui.tr('Profile saving error! Does Toxygen have permission to write to this directory?')
util_ui.message_box(text, util_ui.tr('Error'))
return
path = Settings.get_default_path()
self._settings = Settings()
if curr_lang in langs:
self._settings['language'] = curr_lang
self._settings.save()
if result.is_new_profile(): # create new profile
self.create_new_profile(result.profile_path)
else: # load existing profile
path = result.profile_path
if result.load_as_default:
Settings.set_auto_profile(path)
self._settings = Settings(self._toxes, path.replace('.tox', '.json'))
self._profile_manager = ProfileManager(self._settings, self._toxes, path)
data = self._profile_manager.open_profile()
if self._toxes.is_data_encrypted(data):
data = self.enter_pass(data)
self._tox = self.create_tox(data)
else:
self.load_existing_profile(result.profile_path)
self._path = result.profile_path
else: # default profile
path, name = auto_profile
self._settings = Settings(self._toxes, path + name + '.json')
self._profile_manager = ProfileManager(self._settings, self._toxes, path)
data = self._profile_manager.open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
self.tox = self.create_tox(data)
self._path = os.path.join(path, name + '.tox')
self.load_existing_profile(self._path)
if Settings.is_active_profile(path, get_profile_name_from_path(path)): # profile is in use
title = util_ui.tr('Profile {}').format(name)
if Settings.is_active_profile(self._path): # profile is in use
profile_name = get_profile_name_from_path(self._path)
title = util_ui.tr('Profile {}').format(profile_name)
text = util_ui.tr('Other instance of Toxygen uses this profile or profile was not properly closed. Continue?')
reply = util_ui.question(text, title)
if not reply:
return
else:
self._settings.set_active_profile()
self._settings.set_active_profile()
self.load_app_styles()
self.load_app_translations()
@ -151,17 +101,21 @@ class App:
return
self._ms = MainWindow(self._settings, self._tox, self.reset, self._tray)
self._profile = self._ms.profile
profile = self._ms.profile
self._ms.show()
self._tray = tray.init_tray(self._profile, self._settings, self._ms)
self._tray = tray.init_tray(profile, self._settings, self._ms)
self._tray.show()
self._plugin_loader = PluginLoader(self._tox, self._toxes, self._profile, self._settings) # plugins support
self._plugin_loader.load() # TODO; move to separate thread?
self._plugin_loader = PluginLoader(self._tox, self._toxes, profile, self._settings) # plugins support
self.start_threads()
if self.uri is not None:
self._ms.add_contact(self.uri)
# callbacks initialization
callbacks.init_callbacks(self._tox, profile, self._settings, self._plugin_loader, None, None, None,
self._ms, self._tray)
if self._uri is not None:
self._ms.add_contact(self._uri)
self._app.lastWindowClosed.connect(self._app.quit)
self._app.exec_()
@ -169,8 +123,7 @@ class App:
self._plugin_loader.stop()
self.stop_threads()
self._tray.hide()
data = self._tox.get_savedata()
self._profile_manager.save_profile(data)
self.save_profile()
self._settings.close()
del self._tox
@ -181,10 +134,10 @@ class App:
"""
self.stop_threads()
data = self._tox.get_savedata()
self._profile_manager.save_profile(data)
self.save_profile(data)
del self._tox
# create new tox instance
self._tox = tox_factory(data, self._settings)
self._tox = self.create_tox(data)
self.start_threads()
self._plugin_loader.set_tox(self._tox)
@ -199,25 +152,41 @@ class App:
style = fl.read()
self._app.setStyleSheet(style)
def load_login_screen_translations(self):
current_language, supported_languages = self.get_languages()
if current_language in supported_languages:
lang_path = supported_languages[current_language]
translator = QtCore.QTranslator()
translator.load(get_translations_directory() + lang_path)
self._app.installTranslator(translator)
self._app.translator = translator
@staticmethod
def get_languages():
current_locale = QtCore.QLocale()
curr_language = current_locale.languageToString(current_locale.language())
supported_languages = Settings.supported_languages()
return curr_language, supported_languages
def load_app_translations(self):
lang = Settings.supported_languages()[self._settings['language']]
translator = QtCore.QTranslator()
translator.load(curr_directory(__file__) + '/translations/' + lang)
translator.load(os.path.join(get_translations_directory(), lang))
self._app.installTranslator(translator)
self._app.translator = translator
def try_to_update(self):
updating = updater.start_update_if_needed(self._version, self._settings)
if updating:
data = self._tox.get_savedata()
self._profile_manager.save_profile(data)
self.save_profile()
self._settings.close()
del self._tox
return updating
def start_threads(self):
# init thread
self._init = threads.InitThread(self._tox, self._ms, self._tray)
self._init = threads.InitThread(self._tox, self._plugin_loader)
self._init.start()
# starting threads for tox iterate and toxav iterate
@ -226,11 +195,52 @@ class App:
self._av_loop = threads.ToxAVIterateThread(self._tox.AV)
self._av_loop.start()
threads.start_file_transfer_thread()
def stop_threads(self):
self._init.stop_thread()
self._main_loop.stop_thread()
self._av_loop.stop_thread()
self._main_loop.stop_thread()
threads.stop_file_transfer_thread()
def create_tox(self, data):
return tox_factory(data, self._settings)
def load_existing_profile(self, profile_path):
self._settings = Settings(self._toxes, profile_path.replace('.tox', '.json'))
self._profile_manager = ProfileManager(self._settings, self._toxes, profile_path)
data = self._profile_manager.open_profile()
if self._toxes.is_data_encrypted(data):
data = self.enter_pass(data)
self._tox = self.create_tox(data)
def create_new_profile(self, profile_path):
name = get_profile_name_from_path(profile_path) or 'toxygen_user'
if os.path.isfile(profile_path):
util_ui.message_box(util_ui.tr('Profile with this name already exists'),
util_ui.tr('Error'))
return
self._tox = tox_factory()
self._tox.self_set_name(bytes(name, 'utf-8') if name else b'Toxygen User')
self._tox.self_set_status_message(b'Toxing on Toxygen')
# TODO: set profile password
self._settings = Settings(self._toxes, self._path.replace('.tox', '.json'))
self._profile_manager = ProfileManager(self._settings, self._toxes, profile_path)
try:
self.save_profile()
except Exception as ex:
print(ex)
log('Profile creation exception: ' + str(ex))
text = util_ui.tr('Profile saving error! Does Toxygen have permission to write to this directory?')
util_ui.message_box(text, util_ui.tr('Error'))
return
current_language, supported_languages = self.get_languages()
if current_language in supported_languages:
self._settings['language'] = current_language
self._settings.save()
def save_profile(self, data=None):
data = data or self._tox.get_savedata()
self._profile_manager.save_profile(data)

View File

@ -1,4 +1,3 @@
import sys
import app
from user_data.settings import *
from util.util import curr_directory, remove
@ -11,7 +10,7 @@ __version__ = '0.5.0'
def clean():
"""Removes all windows libs from libs folder"""
d = curr_directory() + '/libs/'
d = os.path.join(curr_directory(__file__), 'libs')
remove(d)
@ -25,10 +24,11 @@ def print_toxygen_version():
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--version', help='Prints Toxygen version')
parser.add_argument('--clean', help='Deletes toxcore libs from libs folder')
parser.add_argument('--reset', help='Resets default profile')
parser.add_argument('profile_path', nargs='?', default=None, help='Resets default profile')
parser.add_argument('--version', action='store_true', help='Prints Toxygen version')
parser.add_argument('--clean', action='store_true', help='Deletes toxcore libs from libs folder')
parser.add_argument('--reset', action='store_true', help='Resets default profile')
parser.add_argument('--uri', help='Adds specified TOX ID to friends')
parser.add_argument('profile', nargs='?', default=None, help='Path to TOX profile')
args = parser.parse_args()
if args.version:
@ -43,7 +43,7 @@ def main():
reset()
return
toxygen = app.App(__version__, path_to_profile=args.profile_path)
toxygen = app.App(__version__, args.profile, args.uri)
toxygen.main()

View File

@ -1,15 +1,18 @@
from PyQt5 import QtGui
from PyQt5 import QtGui, QtCore
from user_data.settings import Settings
from contacts.profile import Profile
from wrapper.toxcore_enums_and_consts import *
from wrapper.toxav_enums import *
from wrapper.tox import bin_to_string
from plugin_support.plugin_support import PluginLoader
import util.ui as util_ui
import util.util as util
import cv2
import numpy as np
from middleware.threads import invoke_in_main_thread, execute
from notifications.tray import tray_notification
from notifications.sound import *
# TODO: use closures
# TODO: gc callbacks and refactoring
# -----------------------------------------------------------------------------------------------------------------
# Callbacks - current user
@ -111,7 +114,8 @@ def friend_message(profile, settings, window, tray):
invoke_in_main_thread(tray_notification, friend.name, message, tray, window)
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
icon = os.path.join(util.get_images_directory(), 'icon_new_messages.png')
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
return wrapped
@ -169,11 +173,12 @@ def tox_file_recv(window, tray, profile, file_transfer_handler, contacts_manager
if not window.isActiveWindow():
friend = contacts_manager.get_friend_by_number(friend_number)
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked:
file_from = QtWidgets.QApplication.translate("Callback", "File from")
file_from = util_ui.tr("File from")
invoke_in_main_thread(tray_notification, file_from + ' ' + friend.name, file_name, tray, window)
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['FILE_TRANSFER'])
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
icon = os.path.join(util.get_images_directory(), 'icon_new_messages.png')
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
else: # AVATAR
print('Avatar')
invoke_in_main_thread(file_transfer_handler.incoming_avatar,
@ -240,8 +245,7 @@ def lossy_packet(plugin_loader):
Incoming lossy packet
"""
data = data[:length]
plugin = PluginLoader.get_instance()
invoke_in_main_thread(plugin.callback_lossy, friend_number, data)
invoke_in_main_thread(plugin_loader.callback_lossy, friend_number, data)
return wrapped
@ -358,7 +362,8 @@ def show_gc_notification(window, tray, message, group_number, peer_number):
invoke_in_main_thread(tray_notification, chat.name + ' ' + peer_name, message, tray, window)
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
icon = os.path.join(util.get_images_directory(), 'icon_new_messages.png')
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
# -----------------------------------------------------------------------------------------------------------------
# Callbacks - initialization
@ -366,17 +371,20 @@ def show_gc_notification(window, tray, message, group_number, peer_number):
def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
calls_manager, file_transfer_handler, window, tray):
calls_manager, file_transfer_handler, main_window, tray):
"""
Initialization of all callbacks.
:param tox: tox instance
:param window: main window
:param tox: Tox instance
:param profile: Profile instance
:param settings: Settings instance
:param plugin_loader: PluginLoader instance
:param main_window: main window screen
:param tray: tray (for notifications)
"""
tox.callback_self_connection_status(self_connection_status(tox, profile), 0)
tox.callback_friend_status(friend_status(profile, settings), 0)
tox.callback_friend_message(friend_message(profile, settings, window, tray), 0)
tox.callback_friend_message(friend_message(profile, settings, main_window, tray), 0)
tox.callback_friend_connection_status(friend_connection_status(profile, settings, plugin_loader), 0)
tox.callback_friend_name(friend_name(profile), 0)
tox.callback_friend_status_message(friend_status_message(profile), 0)
@ -384,11 +392,13 @@ def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
tox.callback_friend_typing(friend_typing(contacts_manager), 0)
tox.callback_friend_read_receipt(friend_read_receipt(contacts_manager), 0)
tox.callback_file_recv(tox_file_recv(window, tray, profile, file_transfer_handler, contacts_manager, settings), 0)
tox.callback_file_recv(tox_file_recv(main_window, tray, profile, file_transfer_handler,
contacts_manager, settings), 0)
tox.callback_file_recv_chunk(file_recv_chunk(file_transfer_handler), 0)
tox.callback_file_chunk_request(file_chunk_request(file_transfer_handler), 0)
tox.callback_file_recv_control(file_recv_control(file_transfer_handler), 0)
toxav = tox.AV
toxav.callback_call_state(call_state(calls_manager), 0)
toxav.callback_call(call(calls_manager), 0)
toxav.callback_audio_receive_frame(callback_audio(calls_manager), 0)

View File

@ -9,44 +9,44 @@ class BaseThread(threading.Thread):
def __init__(self):
super().__init__()
self._stop = False
self._stop_thread = False
def stop_thread(self):
self._stop = True
self._stop_thread = True
self.join()
class InitThread(BaseThread):
def __init__(self, tox, ms, tray):
def __init__(self, tox, plugin_loader):
super().__init__()
self.tox, self.ms, self.tray = tox, ms, tray
self._tox, self._plugin_loader = tox, plugin_loader
def run(self):
# initializing callbacks
init_callbacks(self.tox, self.ms, self.tray)
# download list of nodes if needed
download_nodes_list()
# start plugins
self._plugin_loader.load()
# bootstrap
try:
for data in generate_nodes():
if self._stop:
if self._stop_thread:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
self._tox.bootstrap(*data)
self._tox.add_tcp_relay(*data)
except:
pass
for _ in range(10):
if self._stop:
if self._stop_thread:
return
time.sleep(1)
while not self.tox.self_get_connection_status():
while not self._tox.self_get_connection_status():
try:
for data in generate_nodes():
if self._stop:
if self._stop_thread:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
self._tox.bootstrap(*data)
self._tox.add_tcp_relay(*data)
except:
pass
finally:
@ -60,7 +60,7 @@ class ToxIterateThread(BaseThread):
self._tox = tox
def run(self):
while not self._stop:
while not self._stop_thread:
self._tox.iterate()
time.sleep(self._tox.iteration_interval() / 1000)
@ -72,7 +72,7 @@ class ToxAVIterateThread(BaseThread):
self._toxav = toxav
def run(self):
while not self._stop:
while not self._stop_thread:
self._toxav.iterate()
time.sleep(self._toxav.iteration_interval() / 1000)
@ -88,7 +88,7 @@ class FileTransfersThread(BaseThread):
self._queue.put((func, args, kwargs))
def run(self):
while not self._stop:
while not self._stop_thread:
try:
func, args, kwargs = self._queue.get(timeout=self._timeout)
func(*args, **kwargs)
@ -103,11 +103,11 @@ class FileTransfersThread(BaseThread):
_thread = FileTransfersThread()
def start():
def start_file_transfer_thread():
_thread.start()
def stop():
def stop_file_transfer_thread():
_thread.stop_thread()

View File

@ -1,9 +1,7 @@
from platform import system
import json
import os
from util.util import log, curr_directory, append_slash
from util.util import log, get_base_directory, append_slash, get_platform
import pyaudio
from user_data.toxes import ToxES
import smileys.smileys as smileys
@ -60,7 +58,7 @@ class Settings(dict):
name = str(auto['name'])
if os.path.isfile(append_slash(path) + name + '.tox'):
return path, name
return '', ''
return None
@staticmethod
def set_auto_profile(path, name):
@ -92,9 +90,8 @@ class Settings(dict):
fl.write(json.dumps(data))
@staticmethod
def is_active_profile(path, name):
path = path + name + '.lock'
return os.path.isfile(path)
def is_active_profile(profile_path):
return os.path.isfile(profile_path + '.lock')
@staticmethod
def get_default_settings():
@ -204,13 +201,14 @@ class Settings(dict):
@staticmethod
def get_global_settings_path():
return curr_directory() + '/toxygen.json'
return os.path.join(get_base_directory(), 'toxygen.json')
@staticmethod
def get_default_path():
if system() == 'Windows':
system = get_platform()
if system == 'Windows':
return os.getenv('APPDATA') + '/Tox/'
elif system() == 'Darwin':
elif system == 'Darwin':
return os.getenv('HOME') + '/Library/Application Support/Tox/'
else:
return os.getenv('HOME') + '/.config/tox/'