Skip to content

Commit

Permalink
Merge pull request #11 from Postcard/v0.3.0
Browse files Browse the repository at this point in the history
V0.3.0
  • Loading branch information
benoitguigal committed May 4, 2015
2 parents df1b124 + 57e303b commit 3d5fcf0
Show file tree
Hide file tree
Showing 17 changed files with 577 additions and 367 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ resources/ticket.css
resources/ticket.html
db.*
zeosocket
ghostdriver.log
ghostdriver.log
celerybeat-schedule.db
16 changes: 7 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ RUN pip install selenium==2.44.0
RUN pip install pifacecommon==4.1.2
RUN pip install pifacedigitalio==3.0.5
RUN pip install jinja2==2.7.3
RUN pip install hashids==1.0.3
RUN pip install persistent==4.0.8
RUN pip install ZODB==4.1.0
RUN pip install ZODB3==3.11.0
Expand All @@ -70,20 +69,19 @@ RUN cd python-epson-printer-1.6 && python setup.py install
ADD figureraspbian /figure/figureraspbian
WORKDIR /figure
RUN mkdir -p media/images media/snapshots media/tickets resources
RUN mkdir -p /var/log /var/run /var/db /var/images /var/snapshots /var/tickets /var/rabbitmq
RUN mkdir -p /var/log /var/run /var/rabbitmq

ADD ./install-piface-real-time-clock.sh /install-piface-real-time-clock.sh

ENV LANG C.UTF-8
ENV C_FORCE_ROOT true
ENV DB_PATH /var/db/db.fs
ENV DB_PATH /var/data/db.fs
ENV FIGURE_DIR /figure/figureraspbian
ENV IMAGE_DIR /var/images
ENV IMAGE_DIR /data/images
ENV PHANTOMJS_PATH /phantomjs-linux-armv6l-master/phantomjs-1.9.0-linux-armv6l/bin/phantomjs
ENV RESOURCE_DIR /figure/resources
ENV SNAPSHOT_DIR /var/snapshots
ENV TICKET_CSS_PATH /var/ticket.css
ENV TICKET_HTML_PATH /var/ticket.html
ENV TICKET_DIR /var/tickets
ENV RESOURCE_DIR /data/resources
ENV SNAPSHOT_DIR /data/snapshots
ENV TICKET_DIR /data/tickets
ENV ZEO_SOCKET /var/run/zeo.sock

RUN pip install supervisor
Expand Down
14 changes: 4 additions & 10 deletions figureraspbian/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,10 @@ def get_listener():

logger.info("Initializing Figure application...")

# Make sure database is correctly initialized
with managed(Database()) as db:
if utils.internet_on():
logging.info("Got an internet connection. Initializing database...")
db.update()
elif db.is_initialized():
logging.info("No internet connection but database was already initialized during a previous runtime")
pass
else:
logging.warning("Database could not be initialized.")
logger.info("Initializing database...")
database = Database()
database.open()
database.close()

listener = get_listener()

Expand Down
29 changes: 13 additions & 16 deletions figureraspbian/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ def get_installation():
raise ApiException("Failed retrieving installation")


def get_scenario(scenario_id):
url = "%s/scenarios/%s/?fields=name,ticket_template" % (settings.API_HOST, scenario_id)
r = session.get(url=url, timeout=10)
def get_codes(installation):
url = "%s/installations/%s/codes/" % (settings.API_HOST, installation)
r = session.get(url=url, timeout=20)
if r.status_code == 200:
r.encoding = 'utf-8'
return json.loads(r.text)
return json.loads(r.text)['codes']
else:
raise ApiException("Failed retrieving scenario")
raise ApiException('Fail retrieving codes')


def download(url, path):
Expand All @@ -48,17 +48,14 @@ def download(url, path):
"""
local_name = url2name(url)
req = urllib2.Request(url)
try:
r = urllib2.urlopen(req, timeout=10)
if r.url != url:
# if we were redirected, the real file name we take from the final URL
local_name = url2name(r.url)
path_to_file = join(path, local_name)
with open(path_to_file, 'wb+') as f:
f.write(r.read())
return path_to_file
except urllib2.HTTPError as e:
raise ApiException('Failed downloading resource %s with error %s' % (url, e.msg))
r = urllib2.urlopen(req, timeout=10)
if r.url != url:
# if we were redirected, the real file name we take from the final URL
local_name = url2name(r.url)
path_to_file = join(path, local_name)
with open(path_to_file, 'wb+') as f:
f.write(r.read())
return path_to_file


def create_ticket(ticket):
Expand Down
167 changes: 121 additions & 46 deletions figureraspbian/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
import logging
logging.basicConfig(level='INFO')
logger = logging.getLogger(__name__)
import traceback
import time

from ZEO import ClientStorage
from ZODB import DB
from ZODB.POSException import ConflictError
from BTrees.OOBTree import OOBTree
import transaction
import persistent
from requests.exceptions import Timeout, ConnectionError
import urllib2


from . import settings, api

Expand All @@ -26,74 +31,144 @@ def managed(database):
database.close()


class Database(persistent.Persistent):
class Database(object):

def __init__(self):
storage = ClientStorage.ClientStorage(settings.ZEO_SOCKET)
self.db = DB(storage)
self.data = None
self.dbroot = None

def open(self):
self.data = self.db.open().root()
self.dbroot = self.db.open().root()
if 'installation' not in self.dbroot:
installation = Installation()
self.dbroot['installation'] = installation
transaction.commit()
installation.update()
if 'tickets' not in self.dbroot:
self.dbroot['tickets'] = TicketsGallery()
transaction.commit()

def close(self):
self.db.close()

def clear(self):
self.data.clear()
transaction.commit()

class Installation(persistent.Persistent):

def __init__(self):
self.id = None
self.codes = None
self.start = None
self.end = None
self.scenario = None
self.ticket_template = None

def update(self):
""" Update the installation from Figure API """
try:
installation = api.get_installation()
if installation is not None:
scenario = api.get_scenario(installation['scenario_obj']['id'])
ticket_template = scenario['ticket_template']
for image in ticket_template['images_objects']:
is_new = self.id != installation['id']
self.start = installation['start']
self.end = installation['end']
self.id = installation['id']
self.scenario = installation['scenario']
self.ticket_template = self.scenario['ticket_template']
for image in self.ticket_template['images']:
api.download(image['media'], settings.IMAGE_DIR)
for image_variable in ticket_template['image_variables_objects']:
for image_variable in self.ticket_template['image_variables']:
for image in image_variable['items']:
api.download(image['media'], settings.IMAGE_DIR)
ticket_css_url = "%s/%s" % (settings.API_HOST, 'static/css/ticket.css')
if is_new:
self.codes = api.get_codes(self.id)
api.download(ticket_css_url, settings.RESOURCE_DIR)
self.data['installation'] = installation
self.data['scenario'] = scenario
else:
self.id = None
self.codes = None
self.start = None
self.end = None
self.scenario = None
self.ticket_template = None
transaction.commit()
except (api.ApiException, Timeout, ConnectionError, ConflictError, urllib2.HTTPError) as e:
logger.exception(e)
transaction.abort()

def get_code(self):
# claim a code
while True:
try:
code = self.codes.pop()
self._p_changed = 1
transaction.commit()
except Exception:
logger.error(traceback.format_exc())
except ConflictError:
# Conflict occurred; this process should abort,
# wait for a little bit, then try again.
transaction.abort()
time.sleep(1)
else:
# No ConflictError exception raised, so break
# out of the enclosing while loop.
return code

def is_initialized(self):
return 'installation' in self.data

def check_initialized(func):
def check(self):
if self.is_initialized() is False:
raise NotInitializedError("Db was not yet initialized")
return func(self)
return check
class TicketsGallery(persistent.Persistent):

@check_initialized
def installation(self):
return self.data['installation']

@check_initialized
def scenario(self):
return self.data['scenario']

@check_initialized
def ticket_template(self):
return self.scenario()['ticket_template']

@check_initialized
def text_variables(self):
return self.ticket_template()['text_variables_objects']
def __init__(self):
self._tickets = OOBTree()

def add_ticket(self, ticket):
"""
Add a ticket to the gallery.
"""
while 1:
try:
self._tickets[ticket['dt']] = ticket
self._tickets[ticket['dt']]['uploaded'] = False
transaction.commit()
except ConflictError:
# Conflict occurred; this process should abort,
# wait for a little bit, then try again.
transaction.abort()
time.sleep(1)
else:
# No ConflictError exception raised, so break
# out of the enclosing while loop.
break

def upload_tickets(self):
"""
Upload tickets
"""

for _, ticket in self._tickets.items():
if not ticket['uploaded']:
try:
# upload ticket
api.create_ticket(ticket)
while True:
try:
ticket['uploaded'] = True
transaction.commit()
except ConflictError:
# Conflict occurred; this process should abort,
# wait for a little bit, then try again.
transaction.abort()
time.sleep(1)
else:
# No ConflictError exception raised, so break
# out of the enclosing while loop.
break
except api.ApiException as e:
# Api error, proceed with remaining tickets
logger.exception(e)
except (Timeout, ConnectionError) as e:
# We might have loose internet connection, break for loop
logger.exception(e)
break

@check_initialized
def image_variables(self):
return self.ticket_template()['image_variables_objects']

@check_initialized
def images(self):
return self.ticket_template()['images_objects']

def close(self):
self.db.close()


2 changes: 1 addition & 1 deletion figureraspbian/devices/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def capture(self, installation):
im = im.crop((left, top, right, bottom))
else:
raise Exception("Unknown camera type")
im = im.resize((512, 512), Image.ANTIALIAS)
im = im.resize((1024, 1024), Image.ANTIALIAS)
im.save(path)
return path

Expand Down
3 changes: 2 additions & 1 deletion figureraspbian/devices/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def flash_off(self):

class LEDPanelLight(Light):

pifacedigital = pifacedigitalio.PiFaceDigital()
def __init__(self):
self.pifacedigital = pifacedigitalio.PiFaceDigital()

def flash_on(self):
self.pifacedigital.output_pins[0].turn_on()
Expand Down
Loading

0 comments on commit 3d5fcf0

Please sign in to comment.