XTS
Contents
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.
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 plan 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
- Key Concepts and Terminology
- Technologies in use
- HTTP
- XML
- HTML
- CSS
- Python
- Java
- 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
- DONE Database
- 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
- Setting up your own dev version from trunk
- Working on a test data set
- 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
- Known Issues / Things you might like to work on
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 and HTTP you can write programs that interact with the API yourself.
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.
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).
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.
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.
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.
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.
Changing the Ticket Logo
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 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, XTRL-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
- 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 mysql 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
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.