2
2
3
3
import base64
4
4
import hashlib
5
+ import json
6
+ import os
7
+ # import pyudev
5
8
import re
6
9
import select
10
+ import serial
11
+ import serial .tools .list_ports
7
12
import socket
8
- import ssl
9
13
import struct
14
+ import ssl
10
15
import sys
11
16
import threading
12
17
import time
13
18
import logging
14
- import json
15
- import os
16
19
17
- from receipts import ReceiptPrinter
20
+ from barlink . receipts import ReceiptPrinter
18
21
19
22
20
23
def readlines (sock , recv_buffer = 4096 , delim = '\n ' ):
@@ -29,12 +32,15 @@ def readlines(sock, recv_buffer=4096, delim='\n'):
29
32
yield line
30
33
return
31
34
35
+
32
36
class SocketClosedException (Exception ):
33
37
pass
34
38
39
+
35
40
def header_split (line ):
36
41
return map (lambda x : x .strip (), line .split (':' , 1 ))
37
42
43
+
38
44
class WebSocketConnection :
39
45
WEBSOCK_GUID = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
40
46
@@ -61,17 +67,16 @@ def __init__(self, socket, remote_addr):
61
67
@property
62
68
def addr (self ):
63
69
return self .remote_addr , self .remote_port
64
-
70
+
65
71
def upgrade (self ):
66
72
result = self .handshake ()
67
- if result == True :
73
+ if result is True :
68
74
return True
69
75
else :
70
- if result == False :
76
+ if result is False :
71
77
self .handshakeReject ()
72
78
return False
73
79
74
-
75
80
def handshake (self ):
76
81
reply = ''
77
82
self .request_path = ''
@@ -88,23 +93,25 @@ def handshake(self):
88
93
self .write ('HTTP/1.1 405 Method not allowed\r \n \r \n ' )
89
94
return 405
90
95
continue
91
- if not ':' in line :
96
+ if ':' not in line :
92
97
continue
93
98
key , value = header_split (line )
94
99
self .headers [key ] = value
95
100
# print(key, value)
96
101
# if line.startswith('Sec-WebSocket'):
97
102
# print(line)
98
103
# if key == 'Sec-WebSocket-Key':
99
-
104
+
100
105
if self .headers .get ('Sec-WebSocket-Version' , None ) != '13' :
101
106
return False
102
107
key = self .headers .get ('Sec-WebSocket-Key' , None )
103
108
if not key :
104
109
logging .warn ('KEY MISSING' )
105
110
return False
106
111
107
- reply = base64 .b64encode (hashlib .sha1 (key .encode ('ascii' ) + self .WEBSOCK_GUID ).digest ()).decode ('ascii' )
112
+ reply = base64 .b64encode (
113
+ hashlib .sha1 (key .encode ('ascii' ) + self .WEBSOCK_GUID ).digest ()
114
+ ).decode ('ascii' )
108
115
109
116
if len (reply ) == 0 :
110
117
logging .warn ('REPLY FAILED' )
@@ -127,10 +134,16 @@ def write(self, data, encode=True):
127
134
128
135
def sendMessage (self , message = '' , opcode = 0x01 ):
129
136
opcode_str = self .opcode_map [opcode ] if opcode in self .opcode_map else opcode
130
- logging .info ('{}:{} SEND {}; opcode: {}; length: {}; payload: "{}"' .format (self .remote_addr , self .remote_port , self .request_path , opcode_str , len (message ), message ))
137
+ logging .info ('{}:{} SEND {}; opcode: {}; length: {}; payload: "{}"' .format (
138
+ self .remote_addr ,
139
+ self .remote_port ,
140
+ self .request_path ,
141
+ opcode_str ,
142
+ len (message ),
143
+ message ))
131
144
data = bytearray ()
132
- data .append (0x80 | (opcode & 0x0F )) # FIN
133
-
145
+ data .append (0x80 | (opcode & 0x0F )) # FIN
146
+
134
147
length = len (message )
135
148
136
149
if length <= 125 :
@@ -181,7 +194,7 @@ def receiveMessage(self):
181
194
for i in range (len (payload )):
182
195
payload2 .append (payload [i ] ^ masking_key [i % 4 ])
183
196
payload = payload2
184
-
197
+
185
198
opcode_str = opcode
186
199
if opcode in self .opcode_map :
187
200
opcode_str = self .opcode_map [opcode ]
@@ -196,7 +209,13 @@ def receiveMessage(self):
196
209
payload = payload .decode ('utf-8' )
197
210
except UnicodeDecodeError :
198
211
pass
199
- logging .info ('{}:{} RECV {}; opcode: {}; length: {}; payload: "{}"' .format (self .remote_addr , self .remote_port , self .request_path , opcode_str , length , payload ))
212
+ logging .info ('{}:{} RECV {}; opcode: {}; length: {}; payload: "{}"' .format (
213
+ self .remote_addr ,
214
+ self .remote_port ,
215
+ self .request_path ,
216
+ opcode_str ,
217
+ length ,
218
+ payload ))
200
219
201
220
if opcode == self .OPCODE_CLOSE :
202
221
raise SocketClosedException
@@ -207,13 +226,12 @@ def receiveMessage(self):
207
226
self .socket .close ()
208
227
return False
209
228
210
-
211
229
def close (self ):
212
230
self .socket .close ()
213
231
214
232
215
233
class WebSocketServer (threading .Thread ):
216
- def __init__ (self , monitors , ssl = False ):
234
+ def __init__ (self , monitors , use_ssl = False ):
217
235
super ().__init__ ()
218
236
219
237
self ._stop_event = threading .Event ()
@@ -224,7 +242,7 @@ def __init__(self, monitors, ssl=False):
224
242
monitor .start ()
225
243
226
244
self .sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
227
- if ssl :
245
+ if use_ssl :
228
246
self .sock = ssl .wrap_socket (self .sock , server_side = True , certfile = 'bar.pem' , keyfile = 'bar.pem' )
229
247
self .sock .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
230
248
self .sock .bind (('localhost' , 1234 ))
@@ -261,7 +279,7 @@ def run(self):
261
279
for sock in r :
262
280
conn = [conn for conn in self .conn if conn .socket == sock ][0 ]
263
281
msg = conn .receiveMessage ()
264
- if msg != False :
282
+ if msg is not False :
265
283
opcode , payload = msg
266
284
if opcode == WebSocketConnection .OPCODE_TEXT :
267
285
self .process_text_message (conn .request_path , payload )
@@ -280,7 +298,7 @@ def stop(self):
280
298
for monitor in self .monitors :
281
299
monitor .stop ()
282
300
for conn in self .conn :
283
- conn .sendMessage (opcode = WebSocketConnection .OPCODE_CLOSE ) # opcode close
301
+ conn .sendMessage (opcode = WebSocketConnection .OPCODE_CLOSE ) # opcode close
284
302
self ._stop_event .set ()
285
303
286
304
def on_message (self , message ):
@@ -292,12 +310,13 @@ def sendAll(self, message='', opcode=0x01):
292
310
conn .sendMessage (message , opcode )
293
311
except Exception as e :
294
312
print (e )
295
- c .error = True
313
+ self .error = True
296
314
self .cleanConnections ()
297
315
298
316
def cleanConnections (self ):
299
317
self .conn [:] = [c for c in self .conn if not c .error ]
300
318
319
+
301
320
class Barlink (WebSocketServer ):
302
321
def __init__ (self , * args , printer = None , ** kwargs ):
303
322
super ().__init__ (* args , ** kwargs )
@@ -309,12 +328,12 @@ def process_text_message(self, conn, payload):
309
328
except json .JSONDecodeError :
310
329
logging .exception ('Failed to parse received payload as JSON.' )
311
330
return
312
- if not 'action' in data :
331
+ if 'action' not in data :
313
332
logging .warning ('Invalid JSON: action field not set.' )
314
333
return
315
334
action = data ['action' ]
316
335
if action == 'receipt' :
317
- if not 'products' in data :
336
+ if 'products' not in data :
318
337
logging .warning ('Invalid request: receipt with no products' )
319
338
return
320
339
if 'customer_name' in data :
@@ -331,6 +350,7 @@ def process_text_message(self, conn, payload):
331
350
else :
332
351
logging .warning ('Invalid action: "{}"' .format (action ))
333
352
353
+
334
354
def print_receipt (printer , customer_name , products ):
335
355
printer .init ()
336
356
printer .set_code_table ('cp858' )
@@ -367,15 +387,9 @@ def print_receipt(printer, customer_name, products):
367
387
368
388
printer .cut (0 )
369
389
370
- import serial
371
- import serial .tools .list_ports
372
- import select
373
- import threading
374
- import time
375
- # import pyudev
376
390
377
391
class PortDetect :
378
- def __init__ (self ): # , notify_event, vid='16c0', pid='0483'):
392
+ def __init__ (self ): # , notify_event, vid='16c0', pid='0483'):
379
393
# self.devices = [[vid, pid]]
380
394
# self.notify_event = notify_event
381
395
context = pyudev .Context ()
@@ -396,14 +410,17 @@ def __init__(self): #, notify_event, vid='16c0', pid='0483'):
396
410
# import sys
397
411
# sys.exit(0)
398
412
413
+
399
414
class Monitor (threading .Thread ):
400
415
def __init__ (self ):
401
416
super ().__init__ ()
402
417
self ._stop_event = threading .Event ()
403
418
self .server = None
404
419
self .buffer = b''
420
+
405
421
def stop (self ):
406
422
self ._stop_event .set ()
423
+
407
424
def set_server (self , server ):
408
425
self .server = server
409
426
@@ -430,7 +447,7 @@ def reconnect(self):
430
447
pass
431
448
try :
432
449
# print('Connecting to {}...'.format(self.port))
433
- self .serial = serial .Serial (self .port , 19200 , timeout = 0 )
450
+ self .serial = serial .Serial (self .port , 19200 , timeout = 0 )
434
451
return True
435
452
except Exception as e :
436
453
# print('Error in port {}: {}'.format(self.port, e))
@@ -453,12 +470,12 @@ def reconnect(self):
453
470
pass
454
471
# print('No ports found!')
455
472
return False
456
-
473
+
457
474
def processInput (self , data ):
458
475
try :
459
476
data = data .decode ('ascii' )
460
- except AsciiDecodeError as e :
461
- print ('AsciiDecodeError : {}' .format (e ))
477
+ except UnicodeDecodeError as e :
478
+ print ('UnicodeDecodeError : {}' .format (e ))
462
479
data = data .strip ()
463
480
if len (data ) == 0 :
464
481
return
@@ -468,10 +485,10 @@ def processInput(self, data):
468
485
data = 'ibutton{' + old_ibutton .group (1 ) + '}'
469
486
self .notify (data )
470
487
471
- def run ( self ):
488
+ def run (self ):
472
489
while not self ._stop_event .is_set ():
473
490
try :
474
- r , w , e = select .select ([self .serial ],[],[], 0.01 )
491
+ r , w , e = select .select ([self .serial ], [], [], 0.01 )
475
492
if len (r ) > 0 :
476
493
try :
477
494
self .buffer += self .serial .read ()
@@ -487,40 +504,48 @@ def run( self ):
487
504
if self .serial :
488
505
self .serial .close ()
489
506
507
+
490
508
class ConsoleMonitor (Monitor ):
491
509
def run (self ):
492
510
while not self ._stop_event .is_set ():
493
- while sys .stdin in select .select ([sys .stdin ],[],[], 0.1 )[0 ]:
511
+ while sys .stdin in select .select ([sys .stdin ], [], [], 0.1 )[0 ]:
494
512
line = sys .stdin .readline ().strip ()
495
513
if not line :
496
514
self .stop ()
497
515
break
498
516
self .notify (line )
499
517
time .sleep (0.1 )
500
518
501
- if __name__ == '__main__' :
519
+
520
+ def main (argv = None ):
521
+ if not argv :
522
+ argv = sys .argv [1 :]
502
523
logging .basicConfig (format = '%(asctime)s %(levelname)s %(message)s' , level = logging .INFO )
503
524
serial_monitor = SerialMonitor ()
504
525
console_monitor = ConsoleMonitor ()
505
526
506
527
try :
507
- import settings
528
+ from barlink import settings
508
529
except ImportError :
509
530
logging .warning ('No settings found.' )
510
531
settings = None
511
532
512
533
receipt_printer = None
513
534
514
- try :
515
- if settings :
535
+ if settings :
536
+ try :
516
537
receipt_printer = ReceiptPrinter (settings .RECEIPT_PRINTER_PORT )
517
- except serial .SerialException :
518
- logging .exception ('Cannot connect to receipt printer' )
538
+ logging .info ('Configured receipt printer on {}.' .format (settings .RECEIPT_PRINTER_PORT ))
539
+ except serial .SerialException :
540
+ logging .exception ('Cannot connect to receipt printer' )
519
541
520
- print (settings , receipt_printer )
521
542
s = Barlink ([serial_monitor , console_monitor ], printer = receipt_printer )
522
543
try :
523
544
s .start ()
524
545
s .join ()
525
546
except KeyboardInterrupt :
526
- s .stop ()
547
+ s .stop ()
548
+
549
+
550
+ if __name__ == '__main__' :
551
+ main ()
0 commit comments