keep going when the connection to the vending machine is lost
[uccvend-vendserver.git] / sql-edition / servers / VendServer.py
index c48d2bc..ff17122 100755 (executable)
@@ -1,14 +1,17 @@
 #!/usr/bin/python
 # vim:ts=4
 
 #!/usr/bin/python
 # vim:ts=4
 
+USE_DB = 0
+
 import sys, os, string, re, pwd
 import sys, os, string, re, pwd
-import pg
+if USE_DB: import pg
 from time import time, sleep
 from popen2 import popen2
 from LATClient import LATClient
 from VendingMachine import VendingMachine
 from time import time, sleep
 from popen2 import popen2
 from LATClient import LATClient
 from VendingMachine import VendingMachine
-from ConfigParser import ConfigParser
 from HorizScroll import HorizScroll
 from HorizScroll import HorizScroll
+from random import random, seed
+from Idler import TrainIdler,GrayIdler
 
 GREETING = 'UCC SNACKS'
 PIN_LENGTH = 4
 
 GREETING = 'UCC SNACKS'
 PIN_LENGTH = 4
@@ -54,8 +57,13 @@ def scroll_options(username, mk, welcome = False):
        else:
                msg = []
        choices = ' '*10+'CHOICES: '
        else:
                msg = []
        choices = ' '*10+'CHOICES: '
-       coke_machine = file('/home/other/coke/coke_contents')
-       cokes = coke_machine.readlines()
+       try:
+               coke_machine = file('/home/other/coke/coke_contents')
+               cokes = coke_machine.readlines()
+               coke_machine.close()
+       except:
+               cokes = []
+               pass
        for c in cokes:
                c = c.strip()
                (slot_num, price, slot_name) = c.split(' ', 2)
        for c in cokes:
                c = c.strip()
                (slot_num, price, slot_name) = c.split(' ', 2)
@@ -63,7 +71,8 @@ def scroll_options(username, mk, welcome = False):
                choices += '%s8-%s (%sc) '%(slot_num, slot_name, price)
        choices += '55-DOOR '
        choices += 'OR A SNACK. '
                choices += '%s8-%s (%sc) '%(slot_num, slot_name, price)
        choices += '55-DOOR '
        choices += 'OR A SNACK. '
-       choices += '99 TO READ AGAIN.'
+       choices += '99 TO READ AGAIN. '
+       choices += 'CHOICE?   '
        msg.append((choices, False, None))
        mk.set_messages(msg)
 
        msg.append((choices, False, None))
        mk.set_messages(msg)
 
@@ -102,17 +111,41 @@ def verify_user_pin(uid, pin):
 
 def door_open_mode(vending_machine):
        print "Entering open door mode"
 
 def door_open_mode(vending_machine):
        print "Entering open door mode"
-       v.display("DOOR  OPEN")
+       v.display("-FEED  ME-")
        while True:
                e = v.next_event()
                if e == None: break
                (event, params) = e
                if event == DOOR:
                        if params == 1: # door closed
        while True:
                e = v.next_event()
                if e == None: break
                (event, params) = e
                if event == DOOR:
                        if params == 1: # door closed
-                               v.display("BYE BYE!")
+                               v.display("-YUM YUM!-")
                                sleep(1)
                                return
 
                                sleep(1)
                                return
 
+def cookie(v):
+       seed(time())
+       messages = ['  WASSUP! ', 'PINK FISH ', ' SECRETS ', '  ESKIMO  ', ' FORTUNES ', 'MORE MONEY']
+       choice = int(random()*len(messages))
+       msg = messages[choice]
+       left = range(len(msg))
+       for i in range(len(msg)):
+               if msg[i] == ' ': left.remove(i)
+       reveal = 1
+       while left:
+               s = ''
+               for i in range(0, len(msg)):
+                       if i in left:
+                               if reveal == 0:
+                                       left.remove(i)
+                                       s += msg[i]
+                               else:
+                                       s += chr(int(random()*26)+ord('A'))
+                               reveal += 1
+                               reveal %= 17
+                       else:
+                               s += msg[i]
+               v.display(s)
+
 def center(str):
        LEN = 10
        return ' '*((LEN-len(str))/2)+str
 def center(str):
        LEN = 10
        return ' '*((LEN-len(str))/2)+str
@@ -140,7 +173,7 @@ class MessageKeeper:
                        if len(self.scrolling_message[0][0]) > 10:
                                (m, r, t) = self.scrolling_message[0]
                                a = []
                        if len(self.scrolling_message[0][0]) > 10:
                                (m, r, t) = self.scrolling_message[0]
                                a = []
-                               exp = HorizScroll(m).expand(padding = 10)
+                               exp = HorizScroll(m).expand(padding = 0, wraparound = True)
                                if t == None:
                                        t = 0.1
                                else:
                                if t == None:
                                        t = 0.1
                                else:
@@ -162,60 +195,50 @@ class MessageKeeper:
        def done(self):
                return len(self.scrolling_message) == 0
 
        def done(self):
                return len(self.scrolling_message) == 0
 
-if __name__ == '__main__':
-       cp = ConfigParser()
-       cp.read('/etc/dispense/servers.conf')
-       DBServer = cp.get('Database', 'Server')
-       DBName = cp.get('Database', 'Name')
-       DBUser = cp.get('VendingMachine', 'DBUser')
-       DBPassword = cp.get('VendingMachine', 'DBPassword')
-
-       ServiceName = cp.get('VendingMachine', 'ServiceName')
-       ServicePassword = cp.get('VendingMachine', 'Password')
-       # Open vending machine via LAT
-       if 0:
-               latclient = LATClient(service = ServiceName, password = ServicePassword)
-               (rfh, wfh) = latclient.get_fh()
-       else:
-               #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
-               import socket
-               sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
-               sock.connect(('localhost', 5150))
-               rfh = sock.makefile('r')
-               wfh = sock.makefile('w')
+def run_forever(rfh, wfh):
        v = VendingMachine(rfh, wfh)
        print 'PING is', v.ping()
 
        v = VendingMachine(rfh, wfh)
        print 'PING is', v.ping()
 
-       db = DispenseDatabase(v, DBServer, DBName, DBUser, DBPassword)
+       if USE_DB: db = DispenseDatabase(v, DBServer, DBName, DBUser, DBPassword)
        cur_user = ''
        cur_pin = ''
        cur_selection = ''
 
        mk = MessageKeeper(v)
        mk.set_message(GREETING)
        cur_user = ''
        cur_pin = ''
        cur_selection = ''
 
        mk = MessageKeeper(v)
        mk.set_message(GREETING)
-       logout_timeout = None
+       time_to_autologout = None
+       #idler = TrainIdler(v)
+       #idler = GrayIdler(v)
+       idler = GrayIdler(v,one="*",zero="-")
+       time_to_idle = None
        last_timeout_refresh = None
 
        while True:
        last_timeout_refresh = None
 
        while True:
-               db.handle_events()
+               if USE_DB: db.handle_events()
 
 
-               if logout_timeout != None:
-                       time_left = logout_timeout - time()
-                       if time_left < 10 and (last_timeout_refresh > time_left or last_timeout_refresh is None):
+               if time_to_autologout != None:
+                       time_left = time_to_autologout - time()
+                       if time_left < 6 and (last_timeout_refresh is None or last_timeout_refresh > time_left):
                                mk.set_message('LOGOUT: '+str(int(time_left)))
                                last_timeout_refresh = int(time_left)
                                mk.set_message('LOGOUT: '+str(int(time_left)))
                                last_timeout_refresh = int(time_left)
+                               cur_selection = ''
 
 
-               if logout_timeout != None and logout_timeout - time() <= 0:
-                       logout_timeout = None
+               if time_to_autologout != None and time_to_autologout - time() <= 0:
+                       time_to_autologout = None
                        cur_user = ''
                        cur_pin = ''
                        cur_selection = ''
                        mk.set_message(GREETING)
 
                        cur_user = ''
                        cur_pin = ''
                        cur_selection = ''
                        mk.set_message(GREETING)
 
-               if logout_timeout and not mk.done(): logout_timeout = None
-               if cur_user and cur_pin and mk.done() and logout_timeout == None:
+               if time_to_autologout and not mk.done(): time_to_autologout = None
+               if cur_user == '' and time_to_autologout: time_to_autologout = None
+               if len(cur_pin) == PIN_LENGTH and mk.done() and time_to_autologout == None:
                        # start autologout
                        # start autologout
-                       logout_timeout = time() + 10
+                       time_to_autologout = time() + 15
+
+               if time_to_idle == None and cur_user == '': time_to_idle = time() + 60
+               if time_to_idle != None and cur_user != '': time_to_idle = None
+               if time_to_idle is not None and time() > time_to_idle: idler.next()
 
                mk.update_display()
 
 
                mk.update_display()
 
@@ -224,6 +247,7 @@ if __name__ == '__main__':
                        e = v.next_event(0.1)
                        if e == None:
                                continue
                        e = v.next_event(0.1)
                        if e == None:
                                continue
+               time_to_idle = None
                (event, params) = e
                print e
                if event == DOOR:
                (event, params) = e
                print e
                if event == DOOR:
@@ -248,10 +272,13 @@ if __name__ == '__main__':
                                if len(cur_user) == 5:
                                        uid = int(cur_user)
                                        if not has_good_pin(uid):
                                if len(cur_user) == 5:
                                        uid = int(cur_user)
                                        if not has_good_pin(uid):
+                                               #mk.set_messages(
+                                                       #[(center('INVALID'), False, 0.7),
+                                                        #(center('PIN'), False, 0.7),
+                                                        #(center('SETUP'), False, 1.0),
+                                                        #(GREETING, False, None)])
                                                mk.set_messages(
                                                mk.set_messages(
-                                                       [(center('INVALID'), False, 0.7),
-                                                        (center('PIN'), False, 0.7),
-                                                        (center('SETUP'), False, 1.0),
+                                                       [(' '*10+'INVALID PIN SETUP'+' '*10, False, 3),
                                                         (GREETING, False, None)])
                                                cur_user = ''
                                                cur_pin = ''
                                                         (GREETING, False, None)])
                                                cur_user = ''
                                                cur_pin = ''
@@ -291,15 +318,17 @@ if __name__ == '__main__':
                                        cur_pin = ''
                                        cur_user = ''
                                        cur_selection = ''
                                        cur_pin = ''
                                        cur_user = ''
                                        cur_selection = ''
-                                       v.display('BYE!')
-                                       sleep(0.5)
-                                       mk.set_message(GREETING)
+                                       mk.set_messages(
+                                               [(center('BYE!'), False, 1.5),
+                                                (GREETING, False, None)])
                                        continue
                                cur_selection += chr(key + ord('0'))
                                mk.set_message('SELECT: '+cur_selection)
                                        continue
                                cur_selection += chr(key + ord('0'))
                                mk.set_message('SELECT: '+cur_selection)
+                               time_to_autologout = None
                        elif len(cur_selection) == 1:
                                if key == 11:
                                        cur_selection = ''
                        elif len(cur_selection) == 1:
                                if key == 11:
                                        cur_selection = ''
+                                       time_to_autologout = None
                                        scroll_options(username, mk)
                                        continue
                                else:
                                        scroll_options(username, mk)
                                        continue
                                else:
@@ -307,8 +336,15 @@ if __name__ == '__main__':
                                        #make_selection(cur_selection)
                                        # XXX this should move somewhere else:
                                        if cur_selection == '55':
                                        #make_selection(cur_selection)
                                        # XXX this should move somewhere else:
                                        if cur_selection == '55':
-                                               v.display('GOT DOOR?')
-                                               os.system('su - "%s" -c "dispense door"'%username)
+                                               mk.set_message('OPENSESAME')
+                                               ret = os.system('su - "%s" -c "dispense door"'%username)
+                                               if ret == 0:
+                                                       mk.set_message(center('DOOR OPEN'))
+                                               else:
+                                                       mk.set_message(center('BAD DOOR'))
+                                               sleep(1)
+                                       elif cur_selection == '91':
+                                               cookie(v)
                                        elif cur_selection == '99':
                                                scroll_options(username, mk)
                                                cur_selection = ''
                                        elif cur_selection == '99':
                                                scroll_options(username, mk)
                                                cur_selection = ''
@@ -323,4 +359,52 @@ if __name__ == '__main__':
                                        v.display('THANK YOU')
                                        sleep(0.5)
                                        cur_selection = ''
                                        v.display('THANK YOU')
                                        sleep(0.5)
                                        cur_selection = ''
-                                       logout_timeout = time() + 10
+                                       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):
+       # Open vending machine via LAT
+       if options.use_lat:
+               latclient = LATClient(service = ServiceName, password = ServicePassword)
+               rfh, wfh = latclient.get_fh()
+       else:
+               #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
+               import socket
+               sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+               sock.connect((options.host, options.port))
+               rfh = sock.makefile('r')
+               wfh = sock.makefile('w')
+               
+       return rfh, wfh
+
+if __name__ == '__main__':
+       from ConfigParser import ConfigParser
+       from optparse import OptionParser
+
+       op = OptionParser(usage="%prog [OPTION]...")
+       op.add_option('-f', '--config-file', default='/etc/dispense/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
+       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)')
+       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')
+
+       ServiceName = cp.get('VendingMachine', 'ServiceName')
+       ServicePassword = cp.get('VendingMachine', 'Password')
+
+       while True:
+               rfh, wfh = connect_to_vend(options, DBServer, DBName, DBUser, DBPassword, ServiceName, ServicePassword)
+               try:
+                       run_forever(rfh, wfh)
+               except VendingException:
+                       print "Connection died, trying again..."
+

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