D'oh. This was slowing it down like hell.
[zanchey/dispense2.git] / sql-edition / servers / VendServer.py
1 #!/usr/bin/python
2 # vim:ts=4
3
4 import sys, os, string, time, re, pwd
5 import pg
6 from LATClient import LATClient
7 from VendingMachine import VendingMachine
8 from ConfigParser import ConfigParser
9
10 GREETING = 'UCC SNACKS'
11 PIN_LENGTH = 4
12
13 DOOR = 1
14 SWITCH = 2
15 KEY = 3
16
17 class DispenseDatabase:
18         def __init__(self, vending_machine, host, name, user, password):
19                 self.vending_machine = vending_machine
20                 self.db = pg.DB(dbname = name, host = host, user = user, passwd = password)
21                 self.db.query('LISTEN vend_requests')
22
23         def process_requests(self):
24                 print 'processing'
25                 query = 'SELECT request_id, request_slot FROM vend_requests WHERE request_handled = false'
26                 try:
27                         outstanding = self.db.query(query).getresult()
28                 except (pg.error,), db_err:
29                         sys.stderr.write('Failed to query database: %s\n'%(db_err.strip()))
30                         return
31                 for (id, slot) in outstanding:
32                         (worked, code, string) = self.vending_machine.vend(slot)
33                         print (worked, code, string)
34                         if worked:
35                                 query = 'SELECT vend_success(%s)'%id
36                                 self.db.query(query).getresult()
37                         else:
38                                 query = 'SELECT vend_failed(%s)'%id
39                                 self.db.query(query).getresult()
40
41         def handle_events(self):
42                 notifier = self.db.getnotify()
43                 while notifier is not None:
44                         self.process_requests()
45                         notify = self.db.getnotify()
46
47 def get_pin(uid):
48         try:
49                 info = pwd.getpwuid(uid)
50         except KeyError:
51                 return None
52         if info.pw_dir == None: return False
53         pinfile = os.path.join(info.pw_dir, '.pin')
54         try:
55                 s = os.stat(pinfile)
56         except OSError:
57                 return None
58         if s.st_mode & 077:
59                 return None
60         try:
61                 f = file(pinfile)
62         except IOError:
63                 return None
64         pinstr = f.readline()
65         f.close()
66         if not re.search('^'+'[0-9]'*PIN_LENGTH+'$', pinstr):
67                 return None
68         return int(pinstr)
69
70 def has_good_pin(uid):
71         return get_pin(uid) != None
72
73 def verify_user_pin(uid, pin):
74         if get_pin(uid) == pin:
75                 info = pwd.getpwuid(uid)
76                 return info.pw_name
77         else:
78                 return None
79
80 def door_open_mode(vending_machine):
81         print "Entering open door mode"
82         v.display("DOOR  OPEN")
83         while True:
84                 e = v.next_event()
85                 if e == None: break
86                 (event, params) = e
87                 if event == DOOR:
88                         if params == 1: # door closed
89                                 v.display("BYE BYE!")
90                                 time.sleep(1)
91                                 return
92
93 def center(str):
94         LEN = 10
95         return ' '*((LEN-len(str))/2)+str
96
97 if __name__ == '__main__':
98         cp = ConfigParser()
99         cp.read('/etc/dispense/servers.conf')
100         DBServer = cp.get('Database', 'Server')
101         DBName = cp.get('Database', 'Name')
102         DBUser = cp.get('VendingMachine', 'DBUser')
103         DBPassword = cp.get('VendingMachine', 'DBPassword')
104
105         ServiceName = cp.get('VendingMachine', 'ServiceName')
106         ServicePassword = cp.get('VendingMachine', 'Password')
107         # Open vending machine via LAT
108         latclient = LATClient(service = ServiceName, password = ServicePassword)
109         (rfh, wfh) = latclient.get_fh()
110         v = VendingMachine(rfh, wfh)
111         print 'PING is', v.ping()
112         #print 'BEEP is', v.beep()
113         #print 'VEND 11 is', v.vend('11')
114         #print 'SILENCE is', v.silence()
115         #print 'DISPLAY is', v.display('WELCOME')
116         print 'S is', v.get_switches()
117
118         db = DispenseDatabase(v, DBServer, DBName, DBUser, DBPassword)
119         db.process_requests()
120         cur_user = ''
121         cur_pin = ''
122         cur_selection = ''
123
124         scrolling_message = [GREETING]
125         scrolling_wraps = False
126         need_repaint = True
127         timeout = None
128         last_tick = time.time()
129
130         while True:
131                 if time.time() > last_tick+1:
132                         if timeout != None and timeout > 0: timeout -= 1
133                         if len(scrolling_message) > 0:
134                                 need_repaint = True
135                         last_tick = time.time()
136                 if need_repaint and len(scrolling_message) > 0:
137                         v.display(scrolling_message[0])
138                         if scrolling_wraps:
139                                 scrolling_message.append(scrolling_message[0])
140                         del scrolling_message[0]
141                         need_repaint = False
142                 if timeout == 0:
143                         timeout = None
144                         cur_user = ''
145                         cur_pin = ''
146                         cur_selection = ''
147                         scrolling_message = [GREETING]
148                         scrolling_wraps = False
149                         need_repaint = True
150                         continue
151
152                 while True:
153                         #print 'waiting for event'
154                         e = v.next_event(0)
155                         if e == None:
156                                 #print 'waiting harder for event'
157                                 e = v.next_event(0.1)
158                                 if e == None:
159                                         #print 'no event. passing'
160                                         break
161                         #print 'got event'
162                         (event, params) = e
163                         print e
164                         if event == DOOR:
165                                 if params == 0:
166                                         door_open_mode(v);
167                                         cur_user = ''
168                                         cur_pin = ''
169                                         scrolling_message = [GREETING]
170                                         scrolling_wraps = False
171                                         need_repaint = True
172                         elif event == SWITCH:
173                                 # don't care right now.
174                                 pass
175                         elif event == KEY:
176                                 key = params
177                                 # complicated key handling here:
178                                 if len(cur_user) < 5:
179                                         if key == 11:
180                                                 cur_user = ''
181                                                 scrolling_message = [GREETING]
182                                                 scrolling_wraps = False
183                                                 need_repaint = True
184                                                 continue
185                                         cur_user += chr(key + ord('0'))
186                                         scrolling_message = []
187                                         v.display('UID: '+cur_user)
188                                         if len(cur_user) == 5:
189                                                 uid = int(cur_user)
190                                                 if not has_good_pin(uid):
191                                                         scrolling_message = map(center, ['INVALID','PIN','SETUP',GREETING])
192                                                         scrolling_wraps = False
193                                                         need_repaint = True
194                                                         cur_user = ''
195                                                         cur_pin = ''
196                                                         continue
197                                                 cur_pin = ''
198                                                 v.display('PIN: ')
199                                                 scrolling_message = []
200                                                 continue
201                                 elif len(cur_pin) < PIN_LENGTH:
202                                         if key == 11:
203                                                 if cur_pin == '':
204                                                         cur_user = ''
205                                                         scrolling_message = [GREETING]
206                                                         scrolling_wraps = False
207                                                         need_repaint = True
208                                                         continue
209                                                 cur_pin = ''
210                                                 v.display('PIN: ')
211                                                 scrolling_message = []
212                                                 continue
213                                         cur_pin += chr(key + ord('0'))
214                                         v.display('PIN: '+'X'*len(cur_pin))
215                                         scrolling_message = []
216                                         if len(cur_pin) == PIN_LENGTH:
217                                                 username = verify_user_pin(int(cur_user), int(cur_pin))
218                                                 if username:
219                                                         v.beep(0, False)
220                                                         cur_selection = ''
221
222                                                         scrolling_message = [' WELCOME  ', username]
223                                                         scrolling_message.append('OR A SNACK')
224                                                         scrolling_wraps = True
225                                                         need_repaint = True
226                                                         continue
227                                                 else:
228                                                         v.beep(40, False)
229                                                         scrolling_message = [' BAD PIN  ', '  SORRY   ', GREETING]
230                                                         scrolling_wraps = False
231                                                         need_repaint = True
232
233                                                         cur_user = ''
234                                                         cur_pin = ''
235                                                         continue
236                                 elif len(cur_selection) == 0:
237                                         if key == 11:
238                                                 cur_pin = ''
239                                                 cur_user = ''
240                                                 cur_selection = ''
241                                                 v.display('BYE!')
242                                                 time.sleep(0.5)
243                                                 scrolling_message = [GREETING]
244                                                 scrolling_wraps = False
245                                                 need_repaint = True
246                                                 continue
247                                         cur_selection += chr(key + ord('0'))
248                                         scrolling_message = []
249                                         v.display('SELECT: '+cur_selection)
250                                 elif len(cur_selection) == 1:
251                                         if key == 11:
252                                                 cur_selection = ''
253                                                 scrolling_message = []
254                                                 v.display('SELECT: ')
255                                                 continue
256                                         else:
257                                                 cur_selection += chr(key + ord('0'))
258                                                 #make_selection(cur_selection)
259                                                 # XXX this should move somewhere else:
260                                                 if cur_selection == '55':
261                                                         v.display('GOT DOOR?')
262                                                         os.system('su - "%s" -c "dispense door"'%username)
263                                                 elif cur_selection[1] == '8':
264                                                         v.display('GOT COKE?')
265                                                         os.system('su - "%s" -c "dispense %s"'%(username, cur_selection[0]))
266                                                 else:
267                                                         v.display('HERES A '+cur_selection)
268                                                         v.vend(cur_selection)
269                                                 time.sleep(0.5)
270                                                 v.display('THANK YOU')
271                                                 time.sleep(0.5)
272                                                 cur_selection = ''
273                                                 scrolling_message = [
274                                                         'LOGOUT: 5',
275                                                         'LOGOUT: 4',
276                                                         'LOGOUT: 3',
277                                                         'LOGOUT: 2',
278                                                         'LOGOUT: 1',
279                                                         'BYE BYE!']
280                                                 timeout = 7
281                                                 scrolling_wraps = True
282                                                 need_repaint = True
283
284                 db.handle_events()

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