Below is the file 'fourstar.py' from this revision. You can also download the file.
#!/usr/bin/env python # Commands # fourstar # connect <file name> # status # create <file name> # # # chart # exit # details <ledger id> # list # create # find # balance # # # ledger # balance <ledger id> # print # exit # journal # find # details <journal id> # balance <journal id> # exit # create # header # line # review # delline # # post # exit # #### create???? # # system # export # import from System import System from SystemInterface import SystemInterface from ChartInterface import ChartInterface from LedgerInterface import LedgerInterface from JournalInterface import JournalInterface from States import * # print "Hello Cruel World!" # real code below here #!/usr/bin/python # vim:ts=4 # USE_DB = 0 import ConfigParser import sys, os, string, re, pwd, signal, math, syslog import logging, logging.handlers from traceback import format_tb from time import time, sleep, mktime, localtime class FS_State: def __init__(self,v): self.state_table = {} self.state = STATE_IDLE self.counter = 1 #self.mk = MessageKeeper(v) self.cur_user = '' self.cur_pin = '' self.username = '' self.cur_selection = '' self.time_to_autologout = None self.last_timeout_refresh = None def change_state(self,newstate,newcounter=None): if self.state != newstate: #print "Changing state from: ", #print self.state, #print " to ", #print newstate self.state = newstate if newcounter is not None and self.counter != newcounter: #print "Changing counter from: ", #print self.counter, #print " to ", #print newcounter self.counter = newcounter def do_nothing(state, event, params, v, vstatus): print "doing nothing (s,e,p)", state, " ", event, " ", params pass def quit(state, event, params, v, vstatus): print "bye bye (s,e,p)", state, " ", event, " ", params sys.exit(0) def create_state_table(vstatus): si = SystemInterface() ci = ChartInterface() li = LedgerInterface() ji = JournalInterface() vstatus.state_table[(STATE_IDLE,TICK,1)] = si.fourstar_prompt vstatus.state_table[(STATE_IDLE,TICK,2)] = si.command_input vstatus.state_table[(STATE_IDLE,TICK,3)] = si.parse_command vstatus.state_table[(STATE_QUIT,TICK,1)] = quit vstatus.state_table[(STATE_CONNECT,TICK,1)] = si.connect vstatus.state_table[(STATE_CREATE,TICK,1)] = si.create vstatus.state_table[(STATE_STATUS,TICK,1)] = si.status vstatus.state_table[(STATE_CHART_IDLE,TICK,1)] = ci.chart_prompt vstatus.state_table[(STATE_CHART_IDLE,TICK,2)] = ci.command_input vstatus.state_table[(STATE_CHART_IDLE,TICK,3)] = ci.parse_command vstatus.state_table[(STATE_CHART_BALANCE,TICK,1)] = ci.balance vstatus.state_table[(STATE_CHART_LIST,TICK,1)] = ci.list vstatus.state_table[(STATE_CHART_DETAILS,TICK,1)] = ci.details vstatus.state_table[(STATE_CHART_CREATE,TICK,1)] = ci.create vstatus.state_table[(STATE_CHART_FIND,TICK,1)] = ci.find vstatus.state_table[(STATE_LEDGER_IDLE,TICK,1)] = li.ledger_prompt vstatus.state_table[(STATE_LEDGER_IDLE,TICK,2)] = li.command_input vstatus.state_table[(STATE_LEDGER_IDLE,TICK,3)] = li.parse_command vstatus.state_table[(STATE_LEDGER_BALANCE,TICK,1)] = li.balance vstatus.state_table[(STATE_LEDGER_PRINT,TICK,1)] = li.printledger vstatus.state_table[(STATE_JOURNAL_IDLE,TICK,1)] = ji.journal_prompt vstatus.state_table[(STATE_JOURNAL_IDLE,TICK,2)] = ji.command_input vstatus.state_table[(STATE_JOURNAL_IDLE,TICK,3)] = ji.parse_command vstatus.state_table[(STATE_JOURNAL_BALANCE,TICK,1)] = ji.balance vstatus.state_table[(STATE_JOURNAL_DETAILS,TICK,1)] = ji.details vstatus.state_table[(STATE_JOURNAL_CREATE,TICK,1)] = ji.create vstatus.state_table[(STATE_JOURNAL_FIND,TICK,1)] = ji.find vstatus.state_table[(STATE_JOURNAL_CREATE_IDLE,TICK,1)] = ji.create_journal_prompt vstatus.state_table[(STATE_JOURNAL_CREATE_IDLE,TICK,2)] = ji.create_command_input vstatus.state_table[(STATE_JOURNAL_CREATE_IDLE,TICK,3)] = ji.create_parse_command vstatus.state_table[(STATE_JOURNAL_CREATE_HEADER,TICK,1)] = ji.header vstatus.state_table[(STATE_JOURNAL_CREATE_LINE,TICK,1)] = ji.line vstatus.state_table[(STATE_JOURNAL_CREATE_REVIEW,TICK,1)] = ji.review vstatus.state_table[(STATE_JOURNAL_CREATE_DELLINE,TICK,1)] = ji.delline vstatus.state_table[(STATE_JOURNAL_CREATE_POST,TICK,1)] = ji.post vstatus.state_table[(STATE_JOURNAL_CREATE_EXIT,TICK,1)] = ji.exit # vstatus.state_table[(STATE_IDLE,KEY,1)] = do_nothing # vstatus.state_table[(STATE_IDLE,DOOR,1)] = do_nothing # # vstatus.state_table[(STATE_DOOR_OPENING,TICK,1)] = handle_door_idle # vstatus.state_table[(STATE_DOOR_OPENING,DOOR,1)] = handle_door_event # vstatus.state_table[(STATE_DOOR_OPENING,KEY,1)] = do_nothing # # vstatus.state_table[(STATE_DOOR_CLOSING,TICK,1)] = return_to_idle # vstatus.state_table[(STATE_DOOR_CLOSING,DOOR,1)] = handle_door_event # vstatus.state_table[(STATE_DOOR_CLOSING,KEY,1)] = do_nothing # # vstatus.state_table[(STATE_GETTING_UID,TICK,1)] = handle_getting_uid_idle # vstatus.state_table[(STATE_GETTING_UID,DOOR,1)] = do_nothing # vstatus.state_table[(STATE_GETTING_UID,KEY,1)] = handle_getting_uid_key # # vstatus.state_table[(STATE_GETTING_PIN,TICK,1)] = handle_getting_pin_idle # vstatus.state_table[(STATE_GETTING_PIN,DOOR,1)] = do_nothing # vstatus.state_table[(STATE_GETTING_PIN,KEY,1)] = handle_getting_pin_key # # vstatus.state_table[(STATE_GET_SELECTION,TICK,1)] = handle_get_selection_idle # vstatus.state_table[(STATE_GET_SELECTION,DOOR,1)] = do_nothing # vstatus.state_table[(STATE_GET_SELECTION,KEY,1)] = handle_get_selection_key # # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,1)] = handle_idle_grandfather_tick # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,2)] = handle_grandfather_tick # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,1)] = do_nothing # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = do_nothing # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,1)] = do_nothing # vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,2)] = do_nothing def get_state_table_handler(vstatus, state, event, counter): return vstatus.state_table[(state,event,counter)] def run_forever(options, cf): # get system, status object v = System() vstatus = FS_State(v) create_state_table(vstatus) # This main loop was hideous and the work of the devil. # This has now been fixed (mostly) - mtearle # # # notes for later surgery # (event, counter, ' ') # V # d[ ] = (method) # # ( return state - not currently implemented ) while True: timeout = 0 e = v.next_event(timeout) (event, params) = e run_handler(event, params, v, vstatus) def run_handler(event, params, v, vstatus): handler = get_state_table_handler(vstatus,vstatus.state,event,vstatus.counter) if handler: handler(vstatus.state, event, params, v, vstatus) def parse_args(): from optparse import OptionParser op = OptionParser(usage="%prog [OPTION]...") op.add_option('-f', '--config-file', default='fourstar.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of fourstar.conf') # op.add_option('--serial', action='store_true', default=True, dest='use_serial', help='use the serial port') # op.add_option('--lat', action='store_true', default=False, dest='use_lat', help='use LAT') # op.add_option('--virtualvend', action='store_false', default=True, dest='use_serial', help='use the virtual vending server instead of LAT') # op.add_option('-n', '--hostname', dest='host', default='localhost', help='the hostname to connect to for virtual vending machine mode (default: localhost)') # op.add_option('-p', '--port', dest='port', default=5150, type='int', help='the port number to connect to (default: 5150)') op.add_option('-l', '--log-file', metavar='FILE', dest='log_file', default='', help='log output to the specified file') op.add_option('-s', '--syslog', dest='syslog', metavar='FACILITY', default=None, help='log output to given syslog facility') # op.add_option('-d', '--daemon', dest='daemon', action='store_true', default=False, help='run as a daemon') op.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='spit out lots of debug output') op.add_option('-q', '--quiet', dest='quiet', action='store_true', default=False, help='only report errors') op.add_option('--pid-file', dest='pid_file', metavar='FILE', default='', help='store daemon\'s pid in the given file') options, args = op.parse_args() if len(args) != 0: op.error('extra command line arguments: ' + ' '.join(args)) return options config_options = { } class FS_ConfigFile: def __init__(self, config_file, options): try: cp = ConfigParser.ConfigParser() cp.read(config_file) for option in options: section, name = options[option] value = cp.get(section, name) self.__dict__[option] = value except ConfigParser.Error, e: raise SystemExit("Error reading config file "+config_file+": " + str(e)) def set_stuff_up(): def do_nothing(signum, stack): signal.signal(signum, do_nothing) def stop_server(signum, stack): raise KeyboardInterrupt signal.signal(signal.SIGHUP, do_nothing) signal.signal(signal.SIGTERM, stop_server) signal.signal(signal.SIGINT, stop_server) options = parse_args() config_opts = FS_ConfigFile(options.config_file, config_options) # if options.daemon: become_daemon() set_up_logging(options) if options.pid_file != '': create_pid_file(options.pid_file) return options, config_opts def clean_up_nicely(options, config_opts): if options.pid_file != '': try: os.unlink(options.pid_file) logging.debug('Removed pid file '+options.pid_file) except OSError: pass # if we can't delete it, meh def set_up_logging(options): logger = logging.getLogger() # if not options.daemon: # stderr_logger = logging.StreamHandler(sys.stderr) # stderr_logger.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) # logger.addHandler(stderr_logger) if options.log_file != '': try: file_logger = logging.FileHandler(options.log_file) file_logger.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s')) logger.addHandler(file_logger) except IOError, e: logger.warning('unable to write to log file '+options.log_file+': '+str(e)) if options.syslog != None: sys_logger = logging.handlers.SysLogHandler('/dev/log', options.syslog) sys_logger.setFormatter(logging.Formatter('fourstar[%d]'%(os.getpid()) + ' %(levelname)s: %(message)s')) logger.addHandler(sys_logger) if options.quiet: logger.setLevel(logging.WARNING) elif options.verbose: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) #def become_daemon(): # dev_null = file('/dev/null') # fd = dev_null.fileno() # os.dup2(fd, 0) # os.dup2(fd, 1) # os.dup2(fd, 2) # try: # if os.fork() != 0: # sys.exit(0) # os.setsid() # except OSError, e: # raise SystemExit('failed to fork: '+str(e)) def do_FS_server(options, config_opts): while True: # try: run_forever(options, config_opts) # except VendingException: # logging.error("Connection died, trying again...") # logging.info("Trying again in 5 seconds.") # sleep(5) if __name__ == '__main__': options, config_opts = set_stuff_up() while True: try: logging.warning('Starting FS Server') do_FS_server(options, config_opts) logging.error('FS Server finished unexpectedly, restarting') except KeyboardInterrupt: logging.info("Killed by signal, cleaning up") clean_up_nicely(options, config_opts) logging.warning("FS Server stopped") break except SystemExit: break except: (exc_type, exc_value, exc_traceback) = sys.exc_info() tb = format_tb(exc_traceback, 20) del exc_traceback logging.critical("Uh-oh, unhandled " + str(exc_type) + " exception") logging.critical("Message: " + str(exc_value)) logging.critical("Traceback:") for event in tb: for line in event.split('\n'): logging.critical(' '+line) logging.critical("This message should be considered a bug in the FS Server.") logging.critical("Please report this to someone who can fix it.") sleep(10) logging.warning("Trying again anyway (might not help, but hey...)")