misc cleanups
[zanchey/dispense2.git] / sql-edition / servers / VendServer.py
index cea3cfa..974e0b4 100755 (executable)
@@ -3,15 +3,19 @@
 
 USE_DB = 0
 
 
 USE_DB = 0
 
-import sys, os, string, re, pwd
+import ConfigParser
+import sys, os, string, re, pwd, signal
+from traceback import print_tb
 if USE_DB: import pg
 from time import time, sleep
 from popen2 import popen2
 if USE_DB: import pg
 from time import time, sleep
 from popen2 import popen2
-from LATClient import LATClient
-from VendingMachine import VendingMachine
+from LATClient import LATClient, LATClientException
+from VendingMachine import VendingMachine, VendingException
 from HorizScroll import HorizScroll
 from random import random, seed
 from Idler import TrainIdler,GrayIdler
 from HorizScroll import HorizScroll
 from random import random, seed
 from Idler import TrainIdler,GrayIdler
+import socket
+from posix import geteuid
 
 GREETING = 'UCC SNACKS'
 PIN_LENGTH = 4
 
 GREETING = 'UCC SNACKS'
 PIN_LENGTH = 4
@@ -109,7 +113,7 @@ def verify_user_pin(uid, pin):
        else:
                return None
 
        else:
                return None
 
-def door_open_mode(vending_machine):
+def door_open_mode(v):
        print "Entering open door mode"
        v.display("-FEED  ME-")
        while True:
        print "Entering open door mode"
        v.display("-FEED  ME-")
        while True:
@@ -195,11 +199,11 @@ class MessageKeeper:
        def done(self):
                return len(self.scrolling_message) == 0
 
        def done(self):
                return len(self.scrolling_message) == 0
 
-def run_forever(rfh, wfh):
+def run_forever(rfh, wfh, options, cf):
        v = VendingMachine(rfh, wfh)
        print 'PING is', v.ping()
 
        v = VendingMachine(rfh, wfh)
        print 'PING is', v.ping()
 
-       if USE_DB: db = DispenseDatabase(v, DBServer, DBName, DBUser, DBPassword)
+       if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword)
        cur_user = ''
        cur_pin = ''
        cur_selection = ''
        cur_user = ''
        cur_pin = ''
        cur_selection = ''
@@ -337,7 +341,10 @@ def run_forever(rfh, wfh):
                                        # XXX this should move somewhere else:
                                        if cur_selection == '55':
                                                mk.set_message('OPENSESAME')
                                        # XXX this should move somewhere else:
                                        if cur_selection == '55':
                                                mk.set_message('OPENSESAME')
-                                               ret = os.system('su - "%s" -c "dispense door"'%username)
+                                               if geteuid() == 0:
+                                                       ret = os.system('su - "%s" -c "dispense door"'%username)
+                                               else:
+                                                       ret = os.system('dispense door')
                                                if ret == 0:
                                                        mk.set_message(center('DOOR OPEN'))
                                                else:
                                                if ret == 0:
                                                        mk.set_message(center('DOOR OPEN'))
                                                else:
@@ -361,11 +368,10 @@ def run_forever(rfh, wfh):
                                        cur_selection = ''
                                        time_to_autologout = time() + 8
 
                                        cur_selection = ''
                                        time_to_autologout = time() + 8
 
-# FIXME: a less ugly way of passing all these options would be nice
-def connect_to_vend(options, DBServer, DBName, DBUser, DBPassword, ServiceName, ServicePassword, ServerName, ConnectPassword, PrivPassword):
-       # Open vending machine via LAT
+def connect_to_vend(options, cf):
+       # Open vending machine via LAT?
        if options.use_lat:
        if options.use_lat:
-               latclient = LATClient(service = ServiceName, password = ServicePassword, server_name = ServerName, connect_password = ConnectPassword, priv_password = PrivPassword)
+               latclient = LATClient(service = cf.ServiceName, password = cf.ServicePassword, server_name = cf.ServerName, connect_password = cf.ConnectPassword, priv_password = cf.PrivPassword)
                rfh, wfh = latclient.get_fh()
        else:
                #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
                rfh, wfh = latclient.get_fh()
        else:
                #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
@@ -377,8 +383,7 @@ def connect_to_vend(options, DBServer, DBName, DBUser, DBPassword, ServiceName,
                
        return rfh, wfh
 
                
        return rfh, wfh
 
-if __name__ == '__main__':
-       from ConfigParser import ConfigParser
+def parse_args():
        from optparse import OptionParser
 
        op = OptionParser(usage="%prog [OPTION]...")
        from optparse import OptionParser
 
        op = OptionParser(usage="%prog [OPTION]...")
@@ -386,29 +391,92 @@ if __name__ == '__main__':
        op.add_option('-v', '--virtualvend', action='store_false', default=True, dest='use_lat', 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('-v', '--virtualvend', action='store_false', default=True, dest='use_lat', 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', action='store_true', default=False, help='log output to syslog')
+       op.add_option('-d', '--daemon', dest='daemon', action='store_true', default=False, help='run as a daemon')
        options, args = op.parse_args()
 
        if len(args) != 0:
                op.error('extra command line arguments: ' + ' '.join(args))
 
        options, args = op.parse_args()
 
        if len(args) != 0:
                op.error('extra command line arguments: ' + ' '.join(args))
 
-       cp = ConfigParser()
-       cp.read(options.config_file)
-       DBServer = cp.get('Database', 'Server')
-       DBName = cp.get('Database', 'Name')
-       DBUser = cp.get('VendingMachine', 'DBUser')
-       DBPassword = cp.get('VendingMachine', 'DBPassword')
+       return options
+
+config_options = {
+       'DBServer': ('Database', 'Server'),
+       'DBName': ('Database', 'Name'),
+       'DBUser': ('VendingMachine', 'DBUser'),
+       'DBPassword': ('VendingMachine', 'DBPassword'),
+       
+       'ServiceName': ('VendingMachine', 'ServiceName'),
+       'ServicePassword': ('VendingMachine', 'Password'),
+       
+       'ServerName': ('DecServer', 'Name'),
+       'ConnectPassword': ('DecServer', 'ConnectPassword'),
+       'PrivPassword': ('DecServer', 'PrivPassword'),
+       }
+
+class VendConfigFile:
+       def __init__(self, config_file, options):
+               try:
+                       cp = ConfigParser.ConfigParser()
+                       cp.read(config_file)
 
 
-       ServiceName = cp.get('VendingMachine', 'ServiceName')
-       ServicePassword = cp.get('VendingMachine', 'Password')
+                       for option in options:
+                               section, name = options[option]
+                               value = cp.get(section, name)
+                               self.__dict__[option] = value
+               
+               except ConfigParser.Error, e:
+                       print "Error reading config file "+config_file+": " + str(e)
+                       sys.exit(1)
 
 
-       ServerName = cp.get('DecServer', 'Name')
-       ConnectPassword = cp.get('DecServer', 'ConnectPassword')
-       PrivPassword = cp.get('DecServer', 'PrivPassword')
+def do_vend_server():
+       options = parse_args()
+       config_opts = VendConfigFile(options.config_file, config_options)
 
        while True:
 
        while True:
-               rfh, wfh = connect_to_vend(options, DBServer, DBName, DBUser, DBPassword, ServiceName, ServicePassword, ServerName, ConnectPassword, PrivPassword)
                try:
                try:
-                       run_forever(rfh, wfh)
+                       rfh, wfh = connect_to_vend(options, config_opts)
+               except (LATClientException, socket.error), e:
+                       (exc_type, exc_value, exc_traceback) = sys.exc_info()
+                       del exc_traceback
+                       print
+                       print "Connection error: "+str(exc_type)+" "+str(e)
+                       print "Trying again in 5 seconds."
+                       sleep(5)
+                       continue
+               try:
+                       run_forever(rfh, wfh, options, config_opts)
                except VendingException:
                except VendingException:
+                       print
                        print "Connection died, trying again..."
 
                        print "Connection died, trying again..."
 
+if __name__ == '__main__':
+       def do_nothing(signum, stack): pass
+       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)
+       while True:
+               try:
+                       do_vend_server()
+               except KeyboardInterrupt:
+                       print "Killed by signal."
+                       break
+               except SystemExit, e:
+                       raise e
+               except:
+                       (exc_type, exc_value, exc_traceback) = sys.exc_info()
+                       print
+                       print "Uh-oh, unhandled " + str(exc_type) + " exception"
+                       print "Message: ", str(exc_value)
+                       print
+                       print_tb(exc_traceback)
+                       del exc_traceback
+                       print
+                       print "This message should be considered a bug in the Vend Server."
+                       print "Please report this to someone who can fix it."
+                       sleep(10)
+                       print
+                       print "Trying again anyway (might not help, but hey...)"
+

UCC git Repository :: git.ucc.asn.au