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 # # # chart # list # create # find # details <ledger id> # balance # ledger # balance <ledger id> # print # journal # find # details <journal id> # balance <journal id> # post #### create???? # # system # init # export # import from System import System from Store import Store from Interface 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 #DOOR = 1 #KEY = 3 TICK = 4 ( STATE_IDLE, STATE_DOOR_OPENING, STATE_DOOR_CLOSING, STATE_GETTING_UID, STATE_GETTING_PIN, STATE_GET_SELECTION, STATE_GRANDFATHER_CLOCK, ) = range(1,8) 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 create_state_table(vstatus): vstatus.state_table[(STATE_IDLE,TICK,1)] = fourstar_prompt vstatus.state_table[(STATE_IDLE,TICK,2)] = command_input vstatus.state_table[(STATE_IDLE,TICK,3)] = do_nothing # 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...)")