mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 01:14:15 +02:00
fix: not internet connection scenario when reading installed and searching
This commit is contained in:
@@ -47,12 +47,13 @@ class SoftwareManager(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int, only_apps: bool, pkg_types: Set[Type[SoftwarePackage]]) -> SearchResult:
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int, only_apps: bool, pkg_types: Set[Type[SoftwarePackage]], internet_available: bool) -> SearchResult:
|
||||
"""
|
||||
:param disk_loader: a running disk loader thread that loads application data from the disk asynchronously
|
||||
:param limit: the max number of packages to be retrieved. <= 1 should retrieve everything
|
||||
:param only_apps: if only application packages should be retrieved
|
||||
:param pkg_types: use 'None' to bring any or specify some
|
||||
:param internet_available: if there is internet connection
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -28,7 +28,11 @@ class HttpClient:
|
||||
|
||||
if self.sleep > 0:
|
||||
time.sleep(self.sleep)
|
||||
except:
|
||||
except Exception as e:
|
||||
if isinstance(e, requests.exceptions.ConnectionError):
|
||||
self.logger.error('Internet seems to be off')
|
||||
raise
|
||||
|
||||
self.logger.error("Could not retrieve data from '{}'".format(url))
|
||||
traceback.print_exc()
|
||||
continue
|
||||
|
||||
16
bauh/commons/internet.py
Normal file
16
bauh/commons/internet.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import logging
|
||||
|
||||
import requests
|
||||
|
||||
from bauh.api.http import HttpClient
|
||||
|
||||
|
||||
def is_available(client: HttpClient, logger: logging.Logger) -> bool:
|
||||
try:
|
||||
client.get('https://google.com')
|
||||
return True
|
||||
except requests.exceptions.ConnectionError:
|
||||
if logger:
|
||||
logger.warning('Internet connection seems to be off')
|
||||
return False
|
||||
|
||||
@@ -7,6 +7,8 @@ from pathlib import Path
|
||||
from threading import Thread
|
||||
from typing import List, Set, Type
|
||||
|
||||
import requests
|
||||
|
||||
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext
|
||||
from bauh.api.abstract.disk import DiskCacheLoader
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
@@ -103,19 +105,40 @@ class ArchManager(SoftwareManager):
|
||||
res.total = len(res.installed) + len(res.new)
|
||||
return res
|
||||
|
||||
def _fill_aur_pkgs(self, not_signed: dict, apps: list, disk_loader: DiskCacheLoader):
|
||||
def _fill_aur_pkgs(self, not_signed: dict, pkgs: list, disk_loader: DiskCacheLoader, internet_available: bool):
|
||||
downgrade_enabled = git.is_enabled()
|
||||
|
||||
if internet_available:
|
||||
try:
|
||||
pkgsinfo = self.aur_client.get_info(not_signed.keys())
|
||||
|
||||
if pkgsinfo:
|
||||
for pkgdata in pkgsinfo:
|
||||
pkg = self.mapper.map_api_data(pkgdata, not_signed)
|
||||
pkg.downgrade_enabled = downgrade_enabled
|
||||
|
||||
if disk_loader:
|
||||
disk_loader.fill(pkg)
|
||||
pkg.status = PackageStatus.READY
|
||||
|
||||
apps.append(pkg)
|
||||
pkgs.append(pkg)
|
||||
|
||||
return
|
||||
except requests.exceptions.ConnectionError:
|
||||
self.logger.warning('Could not retrieve installed AUR packages API data. It seems the internet connection is off.')
|
||||
self.logger.info("Reading only local AUR packages data")
|
||||
|
||||
for name, data in not_signed.items():
|
||||
pkg = ArchPackage(name=name, version=data.get('version'),
|
||||
latest_version=data.get('version'), description=data.get('description'),
|
||||
installed=True, mirror='aur')
|
||||
pkg.downgrade_enabled = downgrade_enabled
|
||||
|
||||
if disk_loader:
|
||||
disk_loader.fill(pkg)
|
||||
pkg.status = PackageStatus.READY
|
||||
|
||||
pkgs.append(pkg)
|
||||
|
||||
def _fill_mirror_pkgs(self, mirrors: dict, apps: list):
|
||||
# TODO
|
||||
@@ -126,13 +149,13 @@ class ArchManager(SoftwareManager):
|
||||
app.update = False # TODO
|
||||
apps.append(app)
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
||||
installed = pacman.list_and_map_installed()
|
||||
|
||||
apps = []
|
||||
if installed and installed['not_signed']:
|
||||
self.dcache_updater.join()
|
||||
self._fill_aur_pkgs(installed['not_signed'], apps, disk_loader)
|
||||
self._fill_aur_pkgs(installed['not_signed'], apps, disk_loader, internet_available)
|
||||
|
||||
return SearchResult(apps, None, len(apps))
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ from bauh.commons import resource
|
||||
|
||||
from bauh.gems.arch import ROOT_DIR
|
||||
|
||||
CACHED_ATTRS = {'command', 'icon_path', 'mirror', 'maintainer', 'desktop_entry'}
|
||||
|
||||
|
||||
class ArchPackage(SoftwarePackage):
|
||||
|
||||
@@ -77,20 +79,17 @@ class ArchPackage(SoftwarePackage):
|
||||
cache = {}
|
||||
|
||||
# required attrs to cache
|
||||
for a in {'command', 'icon_path', 'mirror'}:
|
||||
for a in CACHED_ATTRS:
|
||||
val = getattr(self, a)
|
||||
|
||||
if val:
|
||||
cache[a] = val
|
||||
|
||||
if self.desktop_entry:
|
||||
cache['desktop_entry'] = self.desktop_entry
|
||||
|
||||
return cache
|
||||
|
||||
def fill_cached_data(self, data: dict):
|
||||
if data:
|
||||
for a in {'command', 'icon_path', 'mirror', 'desktop_entry'}:
|
||||
for a in CACHED_ATTRS:
|
||||
val = data.get(a)
|
||||
if val:
|
||||
setattr(self, a, val)
|
||||
@@ -100,7 +99,7 @@ class ArchPackage(SoftwarePackage):
|
||||
|
||||
def can_be_run(self) -> bool:
|
||||
# only returns if there is a desktop entry set for the application to avoid running command-line applications
|
||||
return bool(self.command) and bool(self.desktop_entry)
|
||||
return bool(self.desktop_entry) and bool(self.command)
|
||||
|
||||
def get_publisher(self):
|
||||
return self.maintainer
|
||||
|
||||
@@ -31,6 +31,7 @@ class AURIndexUpdater(Thread):
|
||||
def run(self):
|
||||
while True:
|
||||
self.logger.info('Pre-indexing AUR packages in memory')
|
||||
try:
|
||||
res = self.http_client.get(URL_INDEX)
|
||||
|
||||
if res and res.text:
|
||||
@@ -38,6 +39,8 @@ class AURIndexUpdater(Thread):
|
||||
self.logger.info('Pre-indexed {} AUR package names in memory'.format(len(self.man.names_index)))
|
||||
else:
|
||||
self.logger.warning('No data returned from: {}'.format(URL_INDEX))
|
||||
except ConnectionError:
|
||||
self.logger.warning('No internet connection: could not pre-index packages')
|
||||
|
||||
time.sleep(5 * 60) # updates every 5 minutes
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from threading import Thread
|
||||
from typing import List, Set, Type
|
||||
@@ -27,7 +26,7 @@ class FlatpakManager(SoftwareManager):
|
||||
def get_managed_types(self) -> Set["type"]:
|
||||
return {FlatpakApplication}
|
||||
|
||||
def _map_to_model(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader) -> FlatpakApplication:
|
||||
def _map_to_model(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader, internet: bool = True) -> FlatpakApplication:
|
||||
|
||||
app = FlatpakApplication(**app_json)
|
||||
app.installed = installed
|
||||
@@ -39,6 +38,8 @@ class FlatpakManager(SoftwareManager):
|
||||
if not app.runtime:
|
||||
if disk_loader:
|
||||
disk_loader.fill(app) # preloading cached disk data
|
||||
|
||||
if internet:
|
||||
FlatpakAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self, context=self.context).start()
|
||||
|
||||
else:
|
||||
@@ -73,22 +74,28 @@ class FlatpakManager(SoftwareManager):
|
||||
def _add_updates(self, version: str, output: list):
|
||||
output.append(flatpak.list_updates_as_str(version))
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
||||
version = flatpak.get_version()
|
||||
|
||||
updates = []
|
||||
|
||||
if internet_available:
|
||||
thread_updates = Thread(target=self._add_updates, args=(version, updates))
|
||||
thread_updates.start()
|
||||
else:
|
||||
thread_updates = None
|
||||
|
||||
installed = flatpak.list_installed(version)
|
||||
models = []
|
||||
|
||||
if installed:
|
||||
if thread_updates:
|
||||
thread_updates.join()
|
||||
|
||||
for app_json in installed:
|
||||
model = self._map_to_model(app_json=app_json, installed=True, disk_loader=disk_loader)
|
||||
model.update = app_json['ref'] in updates[0]
|
||||
model = self._map_to_model(app_json=app_json, installed=True,
|
||||
disk_loader=disk_loader, internet=internet_available)
|
||||
model.update = app_json['ref'] in updates[0] if updates else None
|
||||
models.append(model)
|
||||
|
||||
return SearchResult(models, None, len(models))
|
||||
|
||||
@@ -8,6 +8,7 @@ from bauh.api.abstract.disk import DiskCacheLoader
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
||||
SuggestionPriority
|
||||
from bauh.commons import internet
|
||||
from bauh.commons.system import SystemProcess, ProcessHandler
|
||||
from bauh.gems.snap import snap, suggestions
|
||||
from bauh.gems.snap.constants import SNAP_API_URL
|
||||
@@ -26,7 +27,7 @@ class SnapManager(SoftwareManager):
|
||||
self.http_client = context.http_client
|
||||
self.logger = context.logger
|
||||
|
||||
def map_json(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader) -> SnapApplication:
|
||||
def map_json(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader, internet: bool = True) -> SnapApplication:
|
||||
app = SnapApplication(publisher=app_json.get('publisher'),
|
||||
rev=app_json.get('rev'),
|
||||
notes=app_json.get('notes'),
|
||||
@@ -49,6 +50,7 @@ class SnapManager(SoftwareManager):
|
||||
if disk_loader and app.installed:
|
||||
disk_loader.fill(app)
|
||||
|
||||
if internet:
|
||||
SnapAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self, context=self.context).start()
|
||||
else:
|
||||
app.fill_cached_data(api_data)
|
||||
@@ -79,9 +81,10 @@ class SnapManager(SoftwareManager):
|
||||
else:
|
||||
return SearchResult([], [], 0)
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
|
||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
||||
if snap.is_snapd_running():
|
||||
installed = [self.map_json(app_json, installed=True, disk_loader=disk_loader) for app_json in snap.read_installed()]
|
||||
internet_available = internet.is_available(self.http_client, self.logger)
|
||||
installed = [self.map_json(app_json, installed=True, disk_loader=disk_loader, internet=internet_available) for app_json in snap.read_installed()]
|
||||
return SearchResult(installed, None, len(installed))
|
||||
else:
|
||||
return SearchResult([], None, 0)
|
||||
|
||||
@@ -8,6 +8,8 @@ from bauh.api.abstract.controller import SoftwareManager, SearchResult, Applicat
|
||||
from bauh.api.abstract.disk import DiskCacheLoader
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion, PackageAction
|
||||
from bauh.api.exception import NoInternetException
|
||||
from bauh.commons import internet
|
||||
|
||||
SUGGESTIONS_LIMIT = 5
|
||||
|
||||
@@ -93,6 +95,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
|
||||
res = SearchResult([], [], 0)
|
||||
|
||||
if internet.is_available(self.context.http_client, self.context.logger):
|
||||
norm_word = word.strip().lower()
|
||||
disk_loader = self.disk_loader_factory.new()
|
||||
disk_loader.start()
|
||||
@@ -114,6 +117,8 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
res.installed = self._sort(res.installed, norm_word)
|
||||
res.new = self._sort(res.new, norm_word)
|
||||
res.total = len(res.installed) + len(res.new)
|
||||
else:
|
||||
raise NoInternetException()
|
||||
|
||||
tf = time.time()
|
||||
self.logger.info('Took {0:.2f} seconds'.format(tf - ti))
|
||||
@@ -130,10 +135,21 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
def can_work(self) -> bool:
|
||||
return True
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None) -> SearchResult:
|
||||
def _is_internet_available(self, res: dict):
|
||||
res['available'] = internet.is_available(self.context.http_client, self.context.logger)
|
||||
|
||||
def _get_internet_check(self, res: dict) -> Thread:
|
||||
t = Thread(target=self._is_internet_available, args=(res,))
|
||||
t.start()
|
||||
return t
|
||||
|
||||
def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
||||
ti = time.time()
|
||||
self._wait_to_be_ready()
|
||||
|
||||
internet_available = {}
|
||||
thread_internet_check = self._get_internet_check(internet_available)
|
||||
|
||||
res = SearchResult([], None, 0)
|
||||
|
||||
disk_loader = None
|
||||
@@ -145,8 +161,9 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
disk_loader = self.disk_loader_factory.new()
|
||||
disk_loader.start()
|
||||
|
||||
thread_internet_check.join()
|
||||
mti = time.time()
|
||||
man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None)
|
||||
man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=internet_available['available'])
|
||||
mtf = time.time()
|
||||
self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti))
|
||||
|
||||
@@ -163,8 +180,9 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
disk_loader = self.disk_loader_factory.new()
|
||||
disk_loader.start()
|
||||
|
||||
thread_internet_check.join()
|
||||
mti = time.time()
|
||||
man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None)
|
||||
man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=internet_available['available'])
|
||||
mtf = time.time()
|
||||
self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti))
|
||||
|
||||
@@ -310,7 +328,7 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
suggestions.extend(man_sugs)
|
||||
|
||||
def list_suggestions(self, limit: int) -> List[PackageSuggestion]:
|
||||
if self.managers:
|
||||
if self.managers and internet.is_available(self.context.http_client, self.context.logger):
|
||||
suggestions, threads = [], []
|
||||
for man in self.managers:
|
||||
t = Thread(target=self._fill_suggestions, args=(suggestions, man, SUGGESTIONS_LIMIT))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Type, Set
|
||||
@@ -14,6 +15,8 @@ from bauh.api.exception import NoInternetException
|
||||
from bauh.view.qt import commons
|
||||
from bauh.view.qt.view_model import PackageView
|
||||
|
||||
RE_VERSION_IN_NAME = re.compile(r'\s+version\s+[\w\.]+\s*$')
|
||||
|
||||
|
||||
class AsyncAction(QThread, ProcessWatcher):
|
||||
|
||||
@@ -87,7 +90,10 @@ class UpdateSelectedApps(AsyncAction):
|
||||
if self.apps_to_update:
|
||||
updated, updated_types = 0, set()
|
||||
for app in self.apps_to_update:
|
||||
self.change_status('{} {} {}...'.format(self.locale_keys['manage_window.status.upgrading'], app.model.name, app.model.version))
|
||||
|
||||
name = app.model.name if not RE_VERSION_IN_NAME.findall(app.model.name) else app.model.name.split('version')[0].strip()
|
||||
|
||||
self.change_status('{} {} {}...'.format(self.locale_keys['manage_window.status.upgrading'], name, app.model.version))
|
||||
success = bool(self.manager.update(app.model, self.root_password, self))
|
||||
|
||||
if not success:
|
||||
@@ -223,13 +229,17 @@ class SearchPackages(AsyncAction):
|
||||
self.manager = manager
|
||||
|
||||
def run(self):
|
||||
apps_found = []
|
||||
search_res = {'pkgs_found': [], 'error': None}
|
||||
|
||||
if self.word:
|
||||
try:
|
||||
res = self.manager.search(self.word)
|
||||
apps_found.extend(res.installed)
|
||||
apps_found.extend(res.new)
|
||||
self.notify_finished(apps_found)
|
||||
search_res['pkgs_found'].extend(res.installed)
|
||||
search_res['pkgs_found'].extend(res.new)
|
||||
except NoInternetException:
|
||||
search_res['error'] = 'internet.required'
|
||||
finally:
|
||||
self.notify_finished(search_res)
|
||||
self.word = None
|
||||
|
||||
|
||||
|
||||
@@ -846,10 +846,14 @@ class ManageWindow(QWidget):
|
||||
self.thread_search.word = word
|
||||
self.thread_search.start()
|
||||
|
||||
def _finish_search(self, pkgs_found: List[SoftwarePackage]):
|
||||
def _finish_search(self, res: dict):
|
||||
self.finish_action()
|
||||
|
||||
if not res['error']:
|
||||
self.ref_bt_upgrade.setVisible(False)
|
||||
self.update_pkgs(pkgs_found, as_installed=False, ignore_updates=True)
|
||||
self.update_pkgs(res['pkgs_found'], as_installed=False, ignore_updates=True)
|
||||
else:
|
||||
dialog.show_message(title=self.i18n['warning'].capitalize(), body=self.i18n[res['error']], type_=MessageType.WARNING)
|
||||
|
||||
def install(self, pkg: PackageView):
|
||||
pwd = None
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
manage_window.title=Applications Manager
|
||||
manage_window.title=my applications
|
||||
manage_window.columns.latest_version=Latest Version
|
||||
manage_window.columns.update=Upgrade ?
|
||||
manage_window.apps_table.row.actions.info=Information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
manage_window.title=Administrador de Aplicativos
|
||||
manage_window.title=mis aplicativos
|
||||
manage_window.columns.latest_version=Ultima Versión
|
||||
manage_window.columns.update=Actualizar ?
|
||||
manage_window.columns.installed=Instalado
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
manage_window.title=Gerenciador de Aplicativos
|
||||
manage_window.title=meus aplicativos
|
||||
manage_window.columns.latest_version=Última Versão
|
||||
manage_window.columns.update=Atualizar ?
|
||||
manage_window.columns.installed=Instalado
|
||||
|
||||
Reference in New Issue
Block a user