Skip to content

Commit

Permalink
move version checker to a thread (#421)
Browse files Browse the repository at this point in the history
* move version checker to a thread

* add binary version via version.txt

* fix version comparison
  • Loading branch information
stepansnigirev committed Sep 21, 2020
1 parent 5af4a80 commit bd89c8c
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ key.pem
*.dmg
pyinstaller/specterd
pyinstaller/release
pyinstaller/version.txt
.DS_Store
1 change: 1 addition & 0 deletions pyinstaller/build-osx.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# pass version number as an argument

echo $1 > version.txt
pip install -e ..
pip install -r requirements.txt
rm -rf build/ dist/ release/
Expand Down
1 change: 1 addition & 0 deletions pyinstaller/build-unix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# pass version number as an argument

echo $1 > version.txt
pip install -e ..
pip install -r requirements.txt
rm -rf build/ dist/ release/
Expand Down
1 change: 1 addition & 0 deletions pyinstaller/build-win.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@ECHO OFF
echo %1 > version.txt
pip install -e ..
pip install -r requirements.txt
rmdir /s /q .\dist\
Expand Down
1 change: 1 addition & 0 deletions pyinstaller/specter_desktop.spec
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ a = Analysis(['specter_desktop.py'],
('../src/cryptoadvance/specter/static', 'static'),
("./icons", "icons"),
(mnemonic_path, 'mnemonic/wordlist'),
("version.txt", "."),
],
hiddenimports=[
'pkg_resources.py2_warn',
Expand Down
1 change: 1 addition & 0 deletions pyinstaller/specterd.spec
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ a = Analysis(['specterd.py'],
datas=[('../src/cryptoadvance/specter/templates', 'templates'),
('../src/cryptoadvance/specter/static', 'static'),
(mnemonic_path, 'mnemonic/wordlist'),
("version.txt", "."),
],
hiddenimports=[
'pkg_resources.py2_warn',
Expand Down
13 changes: 5 additions & 8 deletions src/cryptoadvance/specter/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from flask_login.config import EXEMPT_METHODS


from .helpers import (alias, get_devices_with_keys_by_type,
get_loglevel, get_version_info, run_shell, set_loglevel,
from .helpers import (alias, get_devices_with_keys_by_type,
get_loglevel, run_shell, set_loglevel,
bcur2base64, get_txid, generate_mnemonic,
get_startblock_by_chain, fslock)
from .specter import Specter
Expand Down Expand Up @@ -1484,9 +1484,6 @@ def notify_upgrade():
that there is an upgrade to specter.desktop
:return the current version
'''
version_info={}
version_info["current"], version_info["latest"], version_info["upgrade"] = get_version_info()
app.logger.info("Upgrade? {}".format(version_info["upgrade"]))
if version_info["upgrade"]:
flash("There is a new version available. Consider strongly to upgrade to the new version {} with \"pip3 install cryptoadvance.specter --upgrade\"".format(version_info["latest"]), "info")
return version_info["current"]
if app.specter.version.upgrade:
flash(f"Upgrade notification: new version {app.specter.version.latest} is available.", "info")
return app.specter.version.current
31 changes: 0 additions & 31 deletions src/cryptoadvance/specter/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,37 +156,6 @@ def get_loglevel(app):
return loglevels[app.logger.getEffectiveLevel()]


def get_version_info():
''' Returns a triple of the current version (of the pip-package cryptoadvance.specter and
the latest version and whether you should upgrade
'''
name="cryptoadvance.specter"
try:
# fail right away if it's a binary
if getattr(sys, 'frozen', False):
raise RuntimeError("Using frozen binary, verision unavailable")
latest_version = str(subprocess.run([sys.executable, '-m', 'pip', 'install', '{}==random'.format(name)], capture_output=True, text=True))
latest_version = latest_version[latest_version.find('(from versions:')+15:]
latest_version = latest_version[:latest_version.find(')')]
latest_version = latest_version.replace(' ','').split(',')[-1]

current_version = str(subprocess.run([sys.executable, '-m', 'pip', 'show', '{}'.format(name)], capture_output=True, text=True))
current_version = current_version[current_version.find('Version:')+8:]
current_version = current_version[:current_version.find('\\n')].replace(' ','')
# master?
if current_version == 'vx.y.z-get-replaced-by-release-script':
current_version = 'custom'

if re.search(r"v?([\d+]).([\d+]).([\d+]).*", current_version):
return current_version, latest_version, latest_version != current_version
return current_version, latest_version, False
except Exception as exc:
# if pip is not installed or we are using python3.6 or below
# we just don't show the version
logger.error(exc)
return "unknown", "unknown", False


def hwi_get_config(specter):
config = {
'whitelisted_domains': 'http://127.0.0.1:25441/'
Expand Down
6 changes: 6 additions & 0 deletions src/cryptoadvance/specter/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .hwi_server import hwi_server
from .user import User
from .config import DATA_FOLDER
from .util.version import VersionChecker

logger = logging.getLogger()

Expand Down Expand Up @@ -51,6 +52,11 @@ def init_app(app, hwibridge=False, specter=None):
app.logger.info("Initializing Specter")
specter = Specter(DATA_FOLDER)

# version checker
# checks for new versions once per hour
specter.version = VersionChecker()
specter.version.start()

login_manager = LoginManager()
login_manager.init_app(app) # Enable Login
login_manager.login_view = "login" # Enable redirects if unauthorized
Expand Down
8 changes: 1 addition & 7 deletions src/cryptoadvance/specter/specter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import time
import zipfile
from io import BytesIO
from .helpers import deep_update, clean_psbt, get_version_info
from .helpers import deep_update, clean_psbt
from .rpc import autodetect_rpc_confs, get_default_datadir, RpcError
from .rpc import BitcoinRPC
from .device_manager import DeviceManager
Expand Down Expand Up @@ -470,9 +470,3 @@ def specter_backup_file(self):
def restore_from_backup(self):
pass

@property
def specter_version(self):
if not self._current_version:
self._current_version = get_version_info()[0]
return self._current_version

Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
<p class="warning mobile-only">&#9432;<br><b>Specter "Watch Only" Mode.</b><br>You are using Specter from a small-screen device for which some functionalities, including sending funds and creating new wallets are not yet supported.</p>
<br>
<div class="footer">
<span>Specter Version: <strong>{{ specter.specter_version }}</strong></span>
<span>Specter Version: <strong>{{ specter.version.current }}</strong></span>
<a style="color: #fff; font-size: 1.1em; margin: 10px; text-align: center;" href="/about">
About Specter<br>
<img src="/static/img/icon.png" style="width: 35px;"/>
Expand Down
121 changes: 121 additions & 0 deletions src/cryptoadvance/specter/util/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import subprocess
import sys
import logging
import re
import threading
import time
import os
import requests

logger = logging.getLogger(__name__)


class VersionChecker:
def __init__(self, name="cryptoadvance.specter"):
self.name = name
self.current = "unknown"
self.latest = "unknown"
self.upgrade = False
self.running = False

def start(self):
if not self.running:
self.running = True
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True
self.thread.start()

def stop(self):
self.running = False

@property
def info(self):
return {
"current": self.current,
"latest": self.latest,
"upgrade": self.upgrade,
}

def loop(self, dt=3600):
"""Checks for updates once per hour"""
while self.running:
self.current, self.latest, self.upgrade = self.get_version_info()
logger.info(f"version checked. upgrade: {self.upgrade}")
time.sleep(dt)

def get_binary_version(self):
"""
Get binary version: current, latest.
Fails if version.txt is not present.
Returns latest = "unknown" if fetch failed.
"""
version_file = "version.txt"
if getattr(sys, 'frozen', False):
version_file = os.path.join(sys._MEIPASS, 'version.txt')
with open(version_file) as f:
current = f.read().strip()
try:
releases = requests.get("https://api.github.com/repos/cryptoadvance/specter-desktop/releases").json()
latest = releases[0]["name"]
except:
latest = "unknown"
return current, latest

def get_pip_version(self):
latest = str(subprocess.run([
sys.executable, '-m', 'pip',
'install', f'{self.name}==random'],
capture_output=True, text=True))
latest = latest[latest.find(
'(from versions:')+15:]
latest = latest[:latest.find(')')]
latest = latest.replace(' ', '').split(',')[-1]

current = str(subprocess.run([
sys.executable, '-m', 'pip',
'show', f'{self.name}'],
capture_output=True, text=True))
current = current[current.find(
'Version:')+8:]
current = current[:current.find(
'\\n')].replace(' ', '')
# master?
if current == 'vx.y.z-get-replaced-by-release-script':
current = 'custom'
# no need to check upgrades
self.running = False
return current, latest

def get_version_info(self):
'''
Returns a triple of the current version
of the pip-package cryptoadvance.specter and
the latest version and whether you should upgrade.
'''
# check if we have version.txt file
# this is the case for binaries
current = "unknown"
latest = "unknown"
# check binary version
try:
current, latest = self.get_binary_version()
# if file not found
except FileNotFoundError as exc:
try:
current, latest = self.get_pip_version()
except Exception as exc:
logger.error(exc)
# other exceptions
except Exception as exc:
logger.error(exc)

# check that both current and latest versions match the pattern
if (re.search(r"v?([\d+]).([\d+]).([\d+]).*", current) and
re.search(r"v?([\d+]).([\d+]).([\d+]).*", latest)):
return (
current,
latest,
# check without leading v so v1.2.3 = 1.2.3
latest.replace("v","") != current.replace("v","")
)
return current, latest, False

0 comments on commit bd89c8c

Please sign in to comment.