Difference between revisions of "XTS"

From EUTC Wiki
(Setting Up a Development Server: Additions regarding new crypto library.)
(Migrating content to opentheatre.org.uk)
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
== XTS has a home! ==
 +
 +
Because XTS might be useful to other theatres and is taking code contributions from multiple people, XTS now has it's own website at http://www.opentheatre.org.uk. The content on this page is being migrated to the new site, where it should be better updated and made more comprehensive.
 +
 
== eXtensible Ticketing System ==
 
== eXtensible Ticketing System ==
  
Line 5: Line 9:
 
If you are just looking for help using the software to sell tickets, try [[Using XTS]].
 
If you are just looking for help using the software to sell tickets, try [[Using XTS]].
  
This page is a stub. I intend to document as much of the ticketing system as possible but keep forgetting things that I want to write about. Until it's completed, here's a list of sections that I intend to write under. This article is currently aimed at people who want to maintain the source code, NOT people who want to learn how to sell tickets.
+
== What I planned to write about ==
 
 
== What I plan to write about ==
 
  
 
* History / Motivation
 
* History / Motivation
Line 107: Line 109:
 
The [[#Javascript Client]] uses the XTS API to make a nice box office interface for selling tickets to customers.
 
The [[#Javascript Client]] uses the XTS API to make a nice box office interface for selling tickets to customers.
  
If you know a little XML and HTTP you can write programs that interact with the API yourself.
+
If you know a little XML you can write programs that interact with the API yourself. You can write your programs in Java, PHP, Python, Ruby -- whatever. So long as you can make an HTTP connection and deal with a little XML, you're good to go.
  
 
See [[XTS API]] for further information and full documentation.
 
See [[XTS API]] for further information and full documentation.
Line 114: Line 116:
  
 
The ticket server uses host and password authentication to decide who can do what using the API. Full details are in the [[XTS API|API documentation]].
 
The ticket server uses host and password authentication to decide who can do what using the API. Full details are in the [[XTS API|API documentation]].
 +
 +
XTS also has a built-in secure proxy (security.py, part of [[#XWF]]), based on AES with a preshared key. It allows trusted remote hosts privileged access to the ticketing server over an encrypted connection.
 +
 +
Applications that want to use the secure method of connecting to the server use a special URL (/v1/secure/v1/connect) and then "trade secrets" with the ticketing server in order to prove it's trustworthiness and verify the trustworthiness of the server. It's all very ingenious and you really shouldn't try doing it yourself until you've taken Computer Security (a really good course) or are Bruce Schneier.
 +
 +
To be honest, it's quite voodoo - but it's also crucial when doing anything regarding ticket sales over the internet. So, really, don't mess with it until you quite know what you're doing.
  
 
==== Error Handling ====
 
==== Error Handling ====
Line 126: Line 134:
  
 
Where possible, error numbers correspond to the [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html HTTP status code definitions]. This is mostly because I'm perverse and think it's funny that when something isn't there you get a 404 error. However, it can be useful when writing your client software in that a 4xx error indicates that the client probably did something wrong whereas 5xx errors indicate that something went wrong on the server (which is potentially much more serious).
 
Where possible, error numbers correspond to the [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html HTTP status code definitions]. This is mostly because I'm perverse and think it's funny that when something isn't there you get a 404 error. However, it can be useful when writing your client software in that a 4xx error indicates that the client probably did something wrong whereas 5xx errors indicate that something went wrong on the server (which is potentially much more serious).
 +
 +
==== XWF ====
 +
 +
XWF is a python module of useful bits of code for writing web applications. The thinking is that only XTS code should be in the XTS module. So if there's some code which does something more generic - like writing log files or providing security - this code should be written in a different module where it doesn't clutter up the code that actually matters.
 +
 +
At time of writing, XWF includes xml.py, which is a lightweight set of functions for very quickly writing XML documents, and security.py, which provides a security layer for remote hosts that need trust and secrecy when talking to the Ticket Server (see [[#Security]]).
  
 
==== Source ====
 
==== Source ====
Line 144: Line 158:
 
data.py provides an interface to the database. Wherever XTS needs to get information from the database, it does it by calling a function in data.py. data.py then takes care of turning the information request into SQL, and if necessary, post-processing the response into a useful form for the caller.
 
data.py provides an interface to the database. Wherever XTS needs to get information from the database, it does it by calling a function in data.py. data.py then takes care of turning the information request into SQL, and if necessary, post-processing the response into a useful form for the caller.
  
You should be able to port XTS to another datastore simply by replacing data.py.
+
You should be able to port XTS to another datastore simply by replacing data.py and stats.py.
  
 
===== exceptions.py =====
 
===== exceptions.py =====
Line 163: Line 177:
  
 
printer.py is an abstraction layer with one synchronous public function, printTicket(). It takes care of sending the ticket to the [[#Print Server]] and making sure that the printer got the ticket. If the print can't be confirmed it throws a SnewtsError.
 
printer.py is an abstraction layer with one synchronous public function, printTicket(). It takes care of sending the ticket to the [[#Print Server]] and making sure that the printer got the ticket. If the print can't be confirmed it throws a SnewtsError.
 +
 +
===== reflection.py =====
 +
 +
reflection.py is a silly bit of code with some functions for counting lines in code. It's used to provide some of the statistics you get when you look at the XTS "about" page, such as how many TODO comments are still left in the code.
 +
 +
reflection.py should be refactored into the XWF module - none of the code is specific to XTS itself, so it shouldn't be cluttering up the snewts module.
  
 
===== report.py =====
 
===== report.py =====
Line 171: Line 191:
  
 
snewts.py does the job of recognising requests from clients, checking that the clients are authorised to make the requests, and sending back responses. Simple requests (ie. getPerformances) are fulfilled by getting data from [[#data.py]] directly. More complicated requests are fulfilled by calling business logic in [[#logic.py]] or getting [[#report.py]] to generate reports.
 
snewts.py does the job of recognising requests from clients, checking that the clients are authorised to make the requests, and sending back responses. Simple requests (ie. getPerformances) are fulfilled by getting data from [[#data.py]] directly. More complicated requests are fulfilled by calling business logic in [[#logic.py]] or getting [[#report.py]] to generate reports.
 +
 +
===== stats.py =====
 +
 +
stats.py contains code for calculating various metrics and statistics with regards to the XTS database (such as "how many tickets have been sold?" and "of all of the seats that have been available for all of the shows ever, what percentage of them did we actually sell?"). stats.py accesses the database directly, because otherwise all of the code in stats.py would have to be in data.py, and that would make data.py even bigger than it already is.
  
 
===== status.py =====
 
===== status.py =====
Line 206: Line 230:
  
 
This is much easier than making a new layout. Just replace C:\Xander\ticketlogo.bmp with your new logo. It should have the same dimensions and should probably be just black and white.
 
This is much easier than making a new layout. Just replace C:\Xander\ticketlogo.bmp with your new logo. It should have the same dimensions and should probably be just black and white.
 
== Making Improvements - a HOWTO ==
 
 
=== Getting Started ===
 
 
==== Setting Up a Development Server ====
 
 
These are the steps I needed to take (and didn't need to take, but that you will need to on other platforms) to set up a development server on a new MacBook on 2008-08-27.
 
 
You need to be familiar with Terminal, and you'll be using the sudo command to do things as root. If these things sound frightening you should start by googling around a little.
 
 
* Install '''XCode Tools'''. You're going to need XCode so that you can build the Python/MySQL adapter and the PyCrypto library later. You can download XCode from http://developer.apple.com/tools/xcode/. It's free, but it's a big download. While you're downloading it, move onto the next couple of steps.
 
 
* '''Python 2.5''' is already installed on Mac OS X 10.5. Rejoice.
 
 
* '''easy_install''' is already installed on Mac OS X 10.5. Aren't you glad you bought a Mac?
 
 
* Install a '''MySQL database server'''. It's free and open-source. http://dev.mysql.com
 
 
* '''Add the MySQL server binaries to your path'''. To do this you need to create a bash profile.
 
  $ sudo emacs ~/.bash_profile
 
Then, put this in the new file you've just created in EMACS:
 
  export PATH=$PATH:/usr/local/mysql/bin
 
Then save and close your new profile by pressing CTRL-X, CTRL-S, CTRL-X, CTRL-C. Then to make use of your new profile, close and re-open your terminal.
 
 
* So long as the previous step went well you should now be able to '''start up your MySQL server''' by typing:
 
  $ sudo safe_mysqld
 
If that fails to work, you didn't manage to reconfigure your path properly. Google for help.
 
 
* Install '''web.py'''
 
  $ sudo easy_install web.py
 
 
* Install "Python Crypto"
 
  $ sudo easy_install pycrypto
 
Installing PyCrypto under Windows is not so trivial. You will need to install MinGW, then perform the install manually (or tweak the easy_install configuration). [http://jintoreedwine.wordpress.com/2008/07/20/python-25-and-encryption-pycrypto-under-windows/ This page summarises how to get the job done quickly].
 
 
* In order to run the administration interface, install '''Django'''. http://www.djangoproject.com/download/
 
 
* Build a '''Python/MySQL adapter'''. Download the tarball from http://sourceforge.net/projects/mysql-python. Then untar it, patch _mysql.c by hand and install. Sounds hard? It is. Hopefully by the time you come to do this, installing the mysql adapter will be as easy as sudo easy_install mysql_python. See http://forums.mysql.com/read.php?50,175059,219216#msg-219216 for more info.
 
  $ tar -xvf MySQL-python-1.2.2.tar
 
  $ cd MySQL-python-1.2.2
 
  $ emacs _mysql.c (... and patch as shown on teh internets -- you need to comment out lines 37-39)
 
  $ sudo python setup.py install
 
  $ sudo mkdir /usr/local/mysql/lib/mysql
 
  $ sudo cp /usr/local/mysql/lib/libmysqlclient_r.15.dylib /usr/local/mysql/lib/mysql/libmysqlclient_r.15.dylib
 
 
 
Hilariously, on Windows, this step is much easier. Just get the binary installer from Sourceforge: http://sourceforge.net/projects/mysql-python
 
 
You've now finished installing all of the required software. Next you need to set up the initial data and permissions in the database.
 
 
* Download '''CocoaMySQL''', or an alternative MySQL client of your choosing.
 
 
* '''Log into your own MySQL server''' as root.
 
 
* '''Create a database''' called "xts".
 
 
* '''Import a database backup''' from Maude. It's the fastest way to get up and running with plenty of real-world data.
 
 
* '''Set permissions''' so that the anonymous user on localhost ("@localhost") has full access to the xts database. These are very lax permissions, but they'll do for a development server.
 
 
* Finally, '''run the XTS server'''. In whatever directory you have a copy of the XTS source, run:
 
  $ python server.py
 
You can now visit http://localhost:8080 in a web browser on your own computer to play around. So long as the version signature under the XTS logo shows "DEV", you're looking at your own server.
 
 
* Get hacking.
 

Latest revision as of 12:03, 27 February 2009

XTS has a home!

Because XTS might be useful to other theatres and is taking code contributions from multiple people, XTS now has it's own website at http://www.opentheatre.org.uk. The content on this page is being migrated to the new site, where it should be better updated and made more comprehensive.

eXtensible Ticketing System

XTS is the Bedlam Theatre's new ticketing system. It's key feature is extensibility, meaning that if it doesn't do something you want it to do, you (or a suitably inclined geek) should easily be able to add it. Read on for more key features and read further for technical information that will help you maintain and make changes to the system if that is your want.

If you are just looking for help using the software to sell tickets, try Using XTS.

What I planned to write about

  • History / Motivation
  • Things you should know before you start
    • Key Concepts and Terminology
      • "Reserved" vs. "Booked".
      • "Holding" tickets.
      • "Ticket Prototypes"
      • Verifying bookings
      • "Snewts"
      • How XTS handles times between 0AM and 3AM.
    • Principles
      • Portability (OS Transparency)
      • Accessibility (Network Transparency)
      • Extensibility
      • Readability
      • Simplicity (Minimum Complexity in the Layers that Matter)
      • High-Level Scripting
  • Technologies in use
    • HTTP
    • XML
    • HTML
    • CSS
    • Python
    • Java
    • Crypto - Rjindael (AES)
  • Parts of the system
    • DONE Database
      • DONE Scheduled Database Backup
    • DONE Ticket Server
      • DONE Web.py
      • DONE API
    • DONE Print Server
      • DONE API
      • DONE Making new ticket layouts
      • DONE Changing the ticket logo
    • Static Server
      • Apache 2.2
    • Administration Server
    • Javascript Client
      • Ami
      • Snewts
      • Prism
    • Reporting
      • XSLT
    • HTTPProxy
      • Protecting the ticketing server from the proxy
    • Startup - Windows Services
      • JSWrapper
  • Directory Structure (C:\XTS\)
  • Installing XTS
  • Making Improvements - A HOWTO
    • Known Issues / Things you might like to work on
      • Sniffing attacks
      • No test suite, no TDD
      • Transactions (there aren't any)
      • Printing - it's pretty crap
      • Reports - XSLT, but not as it should be
    • Familiarisation
      • Grokking the Source
    • Tools You Must Use
      • Firebug
      • IPython
    • Things You Must Do
      • DONE Setting up your own dev version from trunk
      • Keeping the documentation up-to-date
    • Safe and Unsafe
      • Where is the money?
    • Versioning
    • Fun Ideas For Improvements or Otherwise
      • Booking from portable devices for producers ("Would you like to come? I'll book you a ticket now.")
      • XTS-controlled DMX for Box Office Lighting Fun Times
      • Heads-up displays for show times and sold out info a-la every cinema you've ever been to

Documentation

Parts of the System

Database

XTS uses a MySQL database. It should be very easy to port XTS to other databases, most access is abstracted through #web.py's db module but there may be some report-generating SQL queries that are specific to MySQL in the XTS source. See #data.py for more info.

The schema is called "xts".

Scheduled Database Backups

As of 2008-07-18, Maude is configured to take nightly backups of the XTS database to C:\XTS\Backups. These backups should be scaled back to weeklies or slower at the end of Fringe 2008 or they will eventually consume all available disk space on the machine. Furthermore the database should occasionally be backed up "off-site" in case of hard disk failure.

Ticket Server

The ticket server does the hard work of allocating, booking and selling tickets of various types for various performances of various shows. The ticket server is written in #Python. It is implemented on top of a web server (web.py]), allowing clients to interact with the server via #HTTP using #XML for data exchange.

The ticket server is accessible via HTTP on port 8080.

API

API stands for Application Programming Interface. It tells you how you can write programs that talk to the ticket server in order to do useful things (like get show information, or sell tickets online).

The #Javascript Client uses the XTS API to make a nice box office interface for selling tickets to customers.

If you know a little XML you can write programs that interact with the API yourself. You can write your programs in Java, PHP, Python, Ruby -- whatever. So long as you can make an HTTP connection and deal with a little XML, you're good to go.

See XTS API for further information and full documentation.

Security

The ticket server uses host and password authentication to decide who can do what using the API. Full details are in the API documentation.

XTS also has a built-in secure proxy (security.py, part of #XWF), based on AES with a preshared key. It allows trusted remote hosts privileged access to the ticketing server over an encrypted connection.

Applications that want to use the secure method of connecting to the server use a special URL (/v1/secure/v1/connect) and then "trade secrets" with the ticketing server in order to prove it's trustworthiness and verify the trustworthiness of the server. It's all very ingenious and you really shouldn't try doing it yourself until you've taken Computer Security (a really good course) or are Bruce Schneier.

To be honest, it's quite voodoo - but it's also crucial when doing anything regarding ticket sales over the internet. So, really, don't mess with it until you quite know what you're doing.

Error Handling

When the server encounters an error (for instance, a ticket that you are selling has already been sold), internally it throws a SnewtsError exception.

SnewtsErrors are caught by the request dispatcher (snewtsUrlInvocation in server.py) and turned into an XML-formatted error that is sent back to the client.

SnewtsErrors consist of an error number (useful to computers) and an error message (useful to people). Errors are grouped into types. For instance, all errors that start with the number 404 represent a requested thing not being there ("Not Found"). However, 404.1 specifically means that it was a ticket that wasn't found. 404.2 means a performance wasn't found and so on.

This is important when writing software that talk to the ticket server via the #API. When reading responses from the server the client software can have a default way of handling 404 errors but additionally can have a specific way of handling 404.5 errors.

Where possible, error numbers correspond to the HTTP status code definitions. This is mostly because I'm perverse and think it's funny that when something isn't there you get a 404 error. However, it can be useful when writing your client software in that a 4xx error indicates that the client probably did something wrong whereas 5xx errors indicate that something went wrong on the server (which is potentially much more serious).

XWF

XWF is a python module of useful bits of code for writing web applications. The thinking is that only XTS code should be in the XTS module. So if there's some code which does something more generic - like writing log files or providing security - this code should be written in a different module where it doesn't clutter up the code that actually matters.

At time of writing, XWF includes xml.py, which is a lightweight set of functions for very quickly writing XML documents, and security.py, which provides a security layer for remote hosts that need trust and secrecy when talking to the Ticket Server (see #Security).

Source

Alphabetically:

constants.py

Contains various useful constants used in the rest of the XTS source. This makes the code more readable. In the database, the number 2 represents a ticket that is booked. However, instead of using the number 2 to refer to such tickets in the source code, we use the expression ticketstates['BOOKED']. This makes the code (a lot) more readable.

Funnily enough, it's generally a bad idea to change the constants. However, you should add to them where appropriate, for instance, if you intend to record new kinds of events in the log.

There is nothing technically constant about the variables in constants.py - they could easily be modified at runtime. If you know how to define constants that are actually constant, or just of a better general approach, then this might be an area of the server that you could improve. --Xander 17:21, 18 July 2008 (BST)

data.py

data.py provides an interface to the database. Wherever XTS needs to get information from the database, it does it by calling a function in data.py. data.py then takes care of turning the information request into SQL, and if necessary, post-processing the response into a useful form for the caller.

You should be able to port XTS to another datastore simply by replacing data.py and stats.py.

exceptions.py

exceptions.py defines the SnewtsError exception type. For more information, see #Error_Handling.

helpers.py

helpers.py contains various functions that help to solve common and recurring problems in the Snewts application (for instance, turning datetime objects into human-readable date strings). This unclutters #logic.py, which should just contain the business logic of how to sell tickets properly. Functions in helpers.py should ideally be moved into #XWF, but who really cares?

logic.py

logic.py sits between the client request and the database. When the client asks to sell a ticket, logic.py makes sure that the show actually exists, the ticket is valid for the performance, there are enough tickets left and anything else that needs making sure of. If any one bit of XTS is going to get something critically wrong, it's going to be in logic.py.

logic.py never talks to the database directly. To get data from the database and make changes to the database it must call functions in #data.py.

printer.py

printer.py is an abstraction layer with one synchronous public function, printTicket(). It takes care of sending the ticket to the #Print Server and making sure that the printer got the ticket. If the print can't be confirmed it throws a SnewtsError.

reflection.py

reflection.py is a silly bit of code with some functions for counting lines in code. It's used to provide some of the statistics you get when you look at the XTS "about" page, such as how many TODO comments are still left in the code.

reflection.py should be refactored into the XWF module - none of the code is specific to XTS itself, so it shouldn't be cluttering up the snewts module.

report.py

report.py contains all of the code that formats statistics gathered from the database into XML reports. It also does a little math. See #Reporting.

snewts.py

snewts.py does the job of recognising requests from clients, checking that the clients are authorised to make the requests, and sending back responses. Simple requests (ie. getPerformances) are fulfilled by getting data from #data.py directly. More complicated requests are fulfilled by calling business logic in #logic.py or getting #report.py to generate reports.

stats.py

stats.py contains code for calculating various metrics and statistics with regards to the XTS database (such as "how many tickets have been sold?" and "of all of the seats that have been available for all of the shows ever, what percentage of them did we actually sell?"). stats.py accesses the database directly, because otherwise all of the code in stats.py would have to be in data.py, and that would make data.py even bigger than it already is.

status.py

status.py contains definitions of all of the errors that XTS may reply with when something goes wrong. If you're writing client software, you need to anticipate these coming back at you.

Print Server

The print server is a separate entity from the ticketing server that handles ticket printing. It listens on the network for messages instructing it to print tickets.

It is written in pure Java for the convenience of Java's layout and printing library. It uses the effective users' default printer for printing (so this printer needs to be set to the ticket printer).

API

The print server listens for tickets to print on port . Tickets are sent to the printer as UDP messages on port 8301. The UDP message format consists of six strings terminated by the NULL character. It does not support UTF8 encoding. It is very fail. The strings are, in order:

  • Show Name
  • Date (expected format: ddd YYYY-MM-DD)
  • Time (expected format: HH:MM)
  • Booking name (can be an empty string)
  • Ticket serial
  • Ticket type (ie. "Student")

When the print server receives your ticket and succeeds in dispatching it to the printer it will reply with a UDP packet containing the ticket serial you specified.

Making new ticket layouts

You need to know Java to write new ticket layouts.

Make a pair of new classes implementing uk.org.opentheatre.xts.Ticket and uk.org.opentheatre.xts.TicketFactory. The former must lay out the ticket, the latter must create instances of the ticket. Look at existing ticket classes for examples on how to do this.

Then, modify the uk.co.bedlamtheatre.BedlamTicketPrintServer to use your new TicketFactory class. You're now done. You can run your modified BedlamTicketPrintServer straight from your IDE and use the taskbar icon that appears to print test tickets and receive tickets from the XTS Ticket Server (if the print service isn't running - see #Startup - Windows Services). When you're happy with your new layout, replace the classes in C:\XTS\PrinterInterface\bin and either restart the Windows Service or just reboot.

This is much easier than making a new layout. Just replace C:\Xander\ticketlogo.bmp with your new logo. It should have the same dimensions and should probably be just black and white.