4 import sys, os, string, re, pwd
6 from time import time, sleep
7 from popen2 import popen2
8 from LATClient import LATClient
9 from VendingMachine import VendingMachine
10 from ConfigParser import ConfigParser
12 GREETING = 'UCC SNACKS'
19 class DispenseDatabase:
20 def __init__(self, vending_machine, host, name, user, password):
21 self.vending_machine = vending_machine
22 self.db = pg.DB(dbname = name, host = host, user = user, passwd = password)
23 self.db.query('LISTEN vend_requests')
25 def process_requests(self):
27 query = 'SELECT request_id, request_slot FROM vend_requests WHERE request_handled = false'
29 outstanding = self.db.query(query).getresult()
30 except (pg.error,), db_err:
31 sys.stderr.write('Failed to query database: %s\n'%(db_err.strip()))
33 for (id, slot) in outstanding:
34 (worked, code, string) = self.vending_machine.vend(slot)
35 print (worked, code, string)
37 query = 'SELECT vend_success(%s)'%id
38 self.db.query(query).getresult()
40 query = 'SELECT vend_failed(%s)'%id
41 self.db.query(query).getresult()
43 def handle_events(self):
44 notifier = self.db.getnotify()
45 while notifier is not None:
46 self.process_requests()
47 notify = self.db.getnotify()
51 info = pwd.getpwuid(uid)
54 if info.pw_dir == None: return False
55 pinfile = os.path.join(info.pw_dir, '.pin')
68 if not re.search('^'+'[0-9]'*PIN_LENGTH+'$', pinstr):
72 def has_good_pin(uid):
73 return get_pin(uid) != None
75 def verify_user_pin(uid, pin):
76 if get_pin(uid) == pin:
77 info = pwd.getpwuid(uid)
82 def door_open_mode(vending_machine):
83 print "Entering open door mode"
84 v.display("DOOR OPEN")
90 if params == 1: # door closed
97 return ' '*((LEN-len(str))/2)+str
100 def __init__(self, vendie):
101 self.scrolling_message = []
103 self.next_update = None
105 def set_message(self, string):
106 self.scrolling_message = [(string, False, None)]
107 self.update_display(True)
109 def set_messages(self, strings):
110 self.scrolling_message = strings
111 self.update_display(True)
113 def update_display(self, forced = False):
114 if not forced and self.next_update != None and time() < self.next_update:
116 if len(self.scrolling_message) > 0:
117 newmsg = self.scrolling_message[0]
118 if newmsg[2] != None:
119 self.next_update = time() + newmsg[2]
121 self.next_update = None
122 self.v.display(self.scrolling_message[0][0])
123 if self.scrolling_message[0][1]:
124 self.scrolling_message.append(self.scrolling_message[0])
125 del self.scrolling_message[0]
127 if __name__ == '__main__':
129 cp.read('/etc/dispense/servers.conf')
130 DBServer = cp.get('Database', 'Server')
131 DBName = cp.get('Database', 'Name')
132 DBUser = cp.get('VendingMachine', 'DBUser')
133 DBPassword = cp.get('VendingMachine', 'DBPassword')
135 ServiceName = cp.get('VendingMachine', 'ServiceName')
136 ServicePassword = cp.get('VendingMachine', 'Password')
137 # Open vending machine via LAT
139 latclient = LATClient(service = ServiceName, password = ServicePassword)
140 (rfh, wfh) = latclient.get_fh()
142 #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
144 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
145 sock.connect(('localhost', 5150))
146 rfh = sock.makefile('r')
147 wfh = sock.makefile('w')
148 v = VendingMachine(rfh, wfh)
149 print 'PING is', v.ping()
151 db = DispenseDatabase(v, DBServer, DBName, DBUser, DBPassword)
156 mk = MessageKeeper(v)
157 mk.set_message(GREETING)
158 logout_timeout = None
159 last_timeout_refresh = None
164 if logout_timeout != None:
165 time_left = logout_timeout - time()
166 if time_left < 10 and last_timeout_refresh > time_left:
167 mk.set_message('LOGOUT: '+str(int(time_left)))
168 last_timeout_refresh = int(time_left)
170 if logout_timeout != None and logout_timeout - time() <= 0:
171 logout_timeout = None
175 mk.set_message(GREETING)
181 e = v.next_event(0.1)
191 mk.set_message(GREETING)
192 elif event == SWITCH:
193 # don't care right now.
197 # complicated key handling here:
198 if len(cur_user) < 5:
201 mk.set_message(GREETING)
203 cur_user += chr(key + ord('0'))
204 mk.set_message('UID: '+cur_user)
205 if len(cur_user) == 5:
207 if not has_good_pin(uid):
209 [(center('INVALID'), False, 0.7),
210 (center('PIN'), False, 0.7),
211 (center('SETUP'), False, 1.0),
212 (GREETING, False, None)])
217 mk.set_message('PIN: ')
219 elif len(cur_pin) < PIN_LENGTH:
223 mk.set_message(GREETING)
226 mk.set_message('PIN: ')
228 cur_pin += chr(key + ord('0'))
229 mk.set_message('PIN: '+'X'*len(cur_pin))
230 if len(cur_pin) == PIN_LENGTH:
231 username = verify_user_pin(int(cur_user), int(cur_pin))
236 msg = [(center('WELCOME'), False, 0.8),
237 (center(username), False, 0.9)]
238 msg.append(('CHOICES :', True, 1))
239 msg.append(('55 - DOOR', True, 1))
240 msg.append(('OR A SNACK', True, 1))
246 [(center('BAD PIN'), False, 1.0),
247 (center('SORRY'), False, 0.5),
248 (GREETING, False, None)])
252 elif len(cur_selection) == 0:
259 mk.set_message(GREETING)
261 cur_selection += chr(key + ord('0'))
262 mk.set_message('SELECT: '+cur_selection)
263 elif len(cur_selection) == 1:
266 mk.set_message('SELECT: ')
269 cur_selection += chr(key + ord('0'))
270 #make_selection(cur_selection)
271 # XXX this should move somewhere else:
272 if cur_selection == '55':
273 v.display('GOT DOOR?')
274 os.system('su - "%s" -c "dispense door"'%username)
275 elif cur_selection[1] == '8':
276 v.display('GOT COKE?')
277 os.system('su - "%s" -c "dispense %s"'%(username, cur_selection[0]))
279 v.display('HERES A '+cur_selection)
280 v.vend(cur_selection)
282 v.display('THANK YOU')
285 logout_timeout = time() + 10