Skip to content

Commit

Permalink
Use workflow.background for updating
Browse files Browse the repository at this point in the history
  • Loading branch information
deanishe committed Aug 9, 2014
1 parent 446ee09 commit 10ac56e
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 106 deletions.
Binary file modified Convert.alfredworkflow
Binary file not shown.
1 change: 0 additions & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@

CURRENCY_CACHE_AGE = 3600 * 12 # 12 hours
CURRENCY_CACHE_NAME = 'exchange_rates'
UPDATE_STATUS_FILE = 'updating_exchange_rates'
45 changes: 19 additions & 26 deletions src/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@
from __future__ import print_function, unicode_literals

import sys
import os
import subprocess

from pint import UnitRegistry, UndefinedUnitError

from workflow import Workflow, ICON_WARNING, ICON_INFO
from currency import fetch_currency_rates
from config import CURRENCY_CACHE_AGE, CURRENCY_CACHE_NAME, UPDATE_STATUS_FILE
from workflow.background import run_in_background, is_running
from config import CURRENCY_CACHE_AGE, CURRENCY_CACHE_NAME

log = None

Expand Down Expand Up @@ -101,33 +99,28 @@ def main(wf):
query = wf.args[0].lower()
log.debug('query : %s', query)

cache_age = wf.cached_data_age(CURRENCY_CACHE_NAME)
if cache_age > 0: # Load data for now, regardless how stale
# EUR is reference
log.debug('Loading existing exchange rate data (%0.2f hours old)',
cache_age / 3600.0)
exchange_rates = wf.cached_data(CURRENCY_CACHE_NAME,
fetch_currency_rates, 0)
# Load cached data
exchange_rates = wf.cached_data(CURRENCY_CACHE_NAME, max_age=0)

if exchange_rates: # Add exchange rates to conversion database
ureg.define('euros = [currency] = eur = EUR')
for abbr, rate in exchange_rates.items():
ureg.define('{0} = eur / {1} = {2}'.format(abbr, rate,
abbr.lower()))
# log.debug('1 EUR = {0} {1}'.format(rate, abbr))

if cache_age > CURRENCY_CACHE_AGE or cache_age == 0: # Cache in background
# Update exchange rates in background process
dirpath = os.path.abspath(os.path.dirname(__file__))
cmd = ['/usr/bin/python',
os.path.join(dirpath, 'update_exchange_rates.py')]
log.debug('Excecuting background command : %s', cmd)
pid = subprocess.Popen(cmd).pid
log.debug('Update process PID : %d', pid)
# Report update if one's happening
if os.path.exists(wf.cachefile(UPDATE_STATUS_FILE)):
log.debug('cache file exists : %s' % UPDATE_STATUS_FILE)
wf.add_item('Updating exchange rates…', valid=False, icon=ICON_INFO)

if not wf.cached_data_fresh(CURRENCY_CACHE_NAME, CURRENCY_CACHE_AGE):
# Update currency rates
cmd = ['/usr/bin/python', wf.workflowfile('update_exchange_rates.py')]
run_in_background('update', cmd)

if is_running('update'):
if exchange_rates is None: # No data cached yet
wf.add_item('Fetching exchange rates…',
'Currency conversions will be momentarily possible',
icon=ICON_INFO)
else:
log.debug('cache file does not exists : %s' % UPDATE_STATUS_FILE)
wf.add_item('Updating exchange rates…',
icon=ICON_INFO)

error = None
conversion = None
Expand Down
83 changes: 4 additions & 79 deletions src/update_exchange_rates.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,94 +14,19 @@

from __future__ import print_function, unicode_literals

import os
import sys

from config import CURRENCY_CACHE_NAME, CURRENCY_CACHE_AGE, UPDATE_STATUS_FILE
from config import CURRENCY_CACHE_NAME, CURRENCY_CACHE_AGE
from currency import fetch_currency_rates
from workflow import Workflow


def daemonise(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
"""This forks the current process into a daemon.
The stdin, stdout, and stderr arguments are file names that
will be opened and be used to replace the standard file descriptors
in sys.stdin, sys.stdout, and sys.stderr.
These arguments are optional and default to /dev/null.
Note that stderr is opened unbuffered, so
if it shares a file with stdout then interleaved output
may not appear in the order that you expect.
"""

# Do first fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit first parent.
except OSError, e:
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
# Decouple from parent environment.
os.chdir("/")
os.umask(0)
os.setsid()
# Do second fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit second parent.
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
# Now I am a daemon!
# Redirect standard file descriptors.
si = file(stdin, 'r', 0)
so = file(stdout, 'a+', 0)
se = file(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())


def process_exists(pid):
"""Does a process with PID ``pid`` actually exist?
:returns: `True` or `False`
"""

try:
os.kill(pid, 0)
except OSError: # not running
return False
return True


def main(wf):
daemonise()
statuspath = wf.cachefile(UPDATE_STATUS_FILE)

# Check for running instance
if os.path.exists(statuspath):
pid = int(open(statuspath, 'rb').read())
if process_exists(pid):
wf.logger.debug('instance already running')
sys.exit(0)

# Save PID to file and update exchange rates
open(statuspath, 'wb').write('%s' % os.getpid())
# Insert delay to check info message is posted in Alfred
# import time
# time.sleep(10)
wf.logger.debug('Fetching exchange rates from ECB ...')
try:
exchange_rates = wf.cached_data(CURRENCY_CACHE_NAME,
fetch_currency_rates,
CURRENCY_CACHE_AGE)
finally:
if os.path.exists(statuspath):
os.unlink(statuspath)
exchange_rates = wf.cached_data(CURRENCY_CACHE_NAME,
fetch_currency_rates,
CURRENCY_CACHE_AGE)
wf.logger.debug('Exchange rates updated.')
for currency, rate in exchange_rates.items():
wf.logger.debug('1 EUR = {0} {1}'.format(rate, currency))
Expand Down
1 change: 1 addition & 0 deletions src/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1

0 comments on commit 10ac56e

Please sign in to comment.