core, quick_frontends: android compatibility hacks:

a couple of hacks have been used so backend can be launched on android using kivy
    - config file (sat.conf) is been read on a specific dir, using a detection of Cagou domains in constants.py
    - fixed crash when using sys.stdout.isatty in log_config.py
    - Q&D fix for logging encoding issue on android
    - when android is detected, the path/pattern to load plugins is modified
    - SRV is not working at the moment on android. If the platform is detected, the host is used directly with default port. A hosts_dir configuration can be used in [android] section to map a specific ip to a host
    - getRepositoryData in tools/utils return constant string on android. Proper repository data need to be copied during package building.
    - [quick app] more robust failure handling on asyncConnect error
    - [quick chat] default to utf-8 when getlocale doesn't return the actual locale.
This commit is contained in:
Goffi 2016-12-04 18:16:48 +01:00
commit 2618d48e7b
7 changed files with 81 additions and 24 deletions

View file

@ -402,10 +402,22 @@ class QuickApp(object):
if not errback:
def errback(failure):
log.error(_(u"Can't connect profile [%s]") % failure)
if failure.module.startswith('twisted.words.protocols.jabber') and failure.condition == "not-authorized":
try:
module = failure.module
except AttributeError:
module = ''
try:
message = failure.message
except AttributeError:
message = 'error'
try:
fullname = failure.fullname
except AttributeError:
fullname = 'error'
if module.startswith('twisted.words.protocols.jabber') and failure.condition == "not-authorized":
self.launchAction(C.CHANGE_XMPP_PASSWD_ID, {}, profile=profile)
else:
self.showDialog(failure.message, failure.fullname, 'error')
self.showDialog(message, fullname, 'error')
self.bridge.asyncConnect(profile, callback=callback, errback=errback)
def plug_profiles(self, profiles):

View file

@ -122,7 +122,7 @@ class Message(object):
# if the message was sent before today, we print the full date
timestamp = time.localtime(self.timestamp)
time_format = u"%c" if timestamp < self.parent.day_change else u"%H:%M"
return time.strftime(time_format, timestamp).decode(getlocale()[1])
return time.strftime(time_format, timestamp).decode(getlocale()[1] or 'utf-8')
@property
def avatar(self):
@ -470,7 +470,7 @@ class QuickChat(quick_widgets.QuickWidget):
self._onHistoryPrinted()
def _historyGetEb(err):
log.error(_(u"Can't get history"))
log.error(_(u"Can't get history: {}").format(err))
self._onHistoryPrinted()
self.host.bridge.historyGet(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, filters, profile, callback=_historyGetCb, errback=_historyGetEb)

View file

@ -132,20 +132,32 @@ class Const(object):
## Configuration ##
if BaseDirectory: # skipped when xdg module is not available (should not happen in backend)
if "org.goffi.cagou.cagou" in BaseDirectory.__file__:
# FIXME: hack to make config read from the right location on Android
# TODO: fix it in a more proper way
BaseDirectory = None
DEFAULT_CONFIG = {
'local_dir': '/data/data/org.goffi.cagou.cagou/',
'media_dir': '/data/data/org.goffi.cagou.cagou/files/media',
'pid_dir': '%(local_dir)s',
'log_dir': '%(local_dir)s',
}
CONFIG_FILES = ['/data/data/org.goffi.cagou.cagou/files/' + APP_NAME_FILE + '.conf']
else:
## Configuration ##
DEFAULT_CONFIG = {
'media_dir': '/usr/share/' + APP_NAME_FILE + '/media',
'local_dir': BaseDirectory.save_data_path(APP_NAME_FILE),
'pid_dir': '%(local_dir)s',
'log_dir': '%(local_dir)s',
}
## Configuration ##
DEFAULT_CONFIG = {
'media_dir': '/usr/share/' + APP_NAME_FILE + '/media',
'local_dir': BaseDirectory.save_data_path(APP_NAME_FILE),
'pid_dir': '%(local_dir)s',
'log_dir': '%(local_dir)s',
}
# List of the configuration filenames sorted by ascending priority
CONFIG_FILES = [realpath(expanduser(path) + APP_NAME_FILE + '.conf') for path in
['/etc/', '~/', '~/.', '', '.'] +
['%s/' % path for path in list(BaseDirectory.load_config_paths(APP_NAME_FILE))]
]
# List of the configuration filenames sorted by ascending priority
CONFIG_FILES = [realpath(expanduser(path) + APP_NAME_FILE + '.conf') for path in
['/etc/', '~/', '~/.', '', '.'] +
['%s/' % path for path in list(BaseDirectory.load_config_paths(APP_NAME_FILE))]
]
## Plugins ##

View file

@ -47,7 +47,11 @@ class ConfigureBasic(log.ConfigureBase):
super(ConfigureBasic, self).configureColors(colors, force_colors, levels_taints_dict)
if colors:
import sys
if force_colors or sys.stdout.isatty(): # FIXME: isatty should be tested on each handler, not globaly
try:
isatty = sys.stdout.isatty()
except AttributeError:
isatty = False
if force_colors or isatty: # FIXME: isatty should be tested on each handler, not globaly
# we need colors
log.Logger.post_treat = lambda logger, level, message: self.ansiColors(level, message)
elif force_colors:
@ -262,6 +266,7 @@ class ConfigureStandard(ConfigureBasic):
def configureFormat(self, fmt):
super(ConfigureStandard, self).configureFormat(fmt)
import logging
import sys
class SatFormatter(logging.Formatter):
u"""Formatter which manage SàT specificities"""
@ -287,7 +292,12 @@ class ConfigureStandard(ConfigureBasic):
s = super(SatFormatter, self).format(record)
if do_color:
s = ConfigureStandard.ansiColors(record.levelname, s)
return s
if sys.platform == "android":
# FIXME: dirty hack to workaround android encoding issue on log
# need to be fixed properly
return s.encode('ascii', 'ignore')
else:
return s
self.formatterClass = SatFormatter

View file

@ -150,13 +150,20 @@ class SAT(service.Service):
ui_contact_list.ContactList(self)
ui_profile_manager.ProfileManager(self)
self.initialised.callback(None)
log.info(_("Backend is ready"))
log.info(_(u"Backend is ready"))
def _import_plugins(self):
"""Import all plugins found in plugins directory"""
import sat.plugins
plugins_path = os.path.dirname(sat.plugins.__file__)
plug_lst = [os.path.splitext(plugin)[0] for plugin in map(os.path.basename, glob(os.path.join(plugins_path, "plugin*.py")))]
if sys.platform == "android":
# FIXME: android hack to load plugins from proper path
# TODO: move this in a separate module and/or use sat.conf to specify path
plugins_path = "/data/data/org.goffi.cagou.cagou/files/sat/plugins"
plugin_glob = "plugin*.pyo"
else:
import sat.plugins
plugins_path = os.path.dirname(sat.plugins.__file__)
plugin_glob = "plugin*.py"
plug_lst = [os.path.splitext(plugin)[0] for plugin in map(os.path.basename, glob(os.path.join(plugins_path, plugin_glob)))]
plugins_to_import = {} # plugins we still have to import
for plug in plug_lst:
plugin_path = 'sat.plugins.' + plug

View file

@ -34,6 +34,7 @@ from zope.interface import implements
import time
import calendar
import uuid
import sys
class SatXMPPClient(wokkel_client.XMPPClient):
@ -42,6 +43,17 @@ class SatXMPPClient(wokkel_client.XMPPClient):
def __init__(self, host_app, profile, user_jid, password, host=None, port=C.XMPP_C2S_PORT, max_retries=C.XMPP_MAX_RETRIES):
# XXX: DNS SRV records are checked when the host is not specified.
# If no SRV record is found, the host is directly extracted from the JID.
if sys.platform == "android":
# FIXME: temporary hack as SRV is not working on android
# TODO: remove this hack and fix SRV
log.info(u"FIXME: Android hack, ignoring SRV")
host = user_jid.host
hosts_map = host_app.memory.getConfig("android", "hosts_dict", {})
if host in hosts_map:
log.info(u"using {host_to_use} for host {host_ori} as requested in config".format(
host_ori = host,
host_to_use = hosts_map[host]))
host = hosts_map[host]
wokkel_client.XMPPClient.__init__(self, user_jid, password, host or None, port or C.XMPP_C2S_PORT)
self.factory.clientConnectionLost = self.connectionLost
self.factory.maxRetries = max_retries

View file

@ -25,6 +25,7 @@ from sat.core.log import getLogger
log = getLogger(__name__)
import datetime
import time
import sys
def clean_ustr(ustr):
@ -78,6 +79,9 @@ def getRepositoryData(module, as_string=True, is_path=False, save_dir_path=None)
- date: ISO 8601 format date
- tag: latest tag used in hierarchie
"""
if sys.platform == "android":
# FIXME: workaround to avoid trouble on android, need to be fixed properly
return u"Cagou android build"
from distutils.spawn import find_executable
import subprocess
KEYS=("node", "node_short", "branch", "date", "tag")