75 |
76 |
76 def run(self): |
77 def run(self): |
77 """ |
78 """ |
78 Implement the main loop of the client. |
79 Implement the main loop of the client. |
79 """ |
80 """ |
80 while True: |
81 try: |
81 try: |
82 while True: |
82 header = self.connection.recv(8) # __IGNORE_EXCEPTION__ |
83 try: |
83 except socket.timeout: |
84 header = b'' |
84 continue |
85 while len(header) < 8: |
85 except socket.error: |
86 header += self.connection.recv(8 - len(header)) |
|
87 except socket.error: |
|
88 # Leave main loop if connection was closed. |
|
89 break |
86 # Leave main loop if connection was closed. |
90 # Leave main loop if connection was closed. |
87 break |
91 if not header: |
88 # Leave main loop if connection was closed. |
92 break |
89 if not header: |
93 |
90 break |
94 length, datahash = struct.unpack(b'!II', header) |
91 |
95 packedData = b'' |
92 length, datahash = struct.unpack(b'!II', header) |
96 while len(packedData) < length: |
93 packedData = b'' |
97 packedData += self.connection.recv( |
94 while len(packedData) < length: |
98 length - len(packedData)) |
95 packedData += self.connection.recv(length - len(packedData)) |
99 |
96 |
100 assert adler32(packedData) & 0xffffffff == datahash, \ |
97 assert adler32(packedData) & 0xffffffff == datahash, \ |
101 'Hashes not equal' |
98 'Hashes not equal' |
102 if sys.version_info[0] == 3: |
99 if sys.version_info[0] == 3: |
103 packedData = packedData.decode('utf-8') |
100 packedData = packedData.decode('utf-8') |
104 |
101 |
105 fx, fn, data = json.loads(packedData) |
102 fx, fn, data = json.loads(packedData) |
106 if fx == 'INIT': |
103 if fx == 'INIT': |
107 ret = self.__initClientService(fn, *data) |
104 ret = self.__initClientService(fn, *data) |
|
105 else: |
|
106 callback = self.services.get(fx) |
|
107 if callback: |
|
108 ret = callback(fn, *data) |
|
109 else: |
108 else: |
110 ret = 'Unknown service.' |
109 callback = self.services.get(fx) |
111 |
110 if callback: |
112 self.__send(fx, fn, ret) |
111 ret = callback(fn, *data) |
113 |
112 else: |
|
113 ret = 'Unknown service.' |
|
114 |
|
115 self.__send(fx, fn, ret) |
|
116 except: |
|
117 exctype, excval, exctb = sys.exc_info() |
|
118 tbinfofile = io.StringIO() |
|
119 traceback.print_tb(exctb, None, tbinfofile) |
|
120 tbinfofile.seek(0) |
|
121 tbinfo = tbinfofile.read() |
|
122 del exctb |
|
123 self.__send( |
|
124 'EXCEPTION', '?', [str(exctype), str(excval), tbinfo]) |
|
125 |
|
126 self.connection.shutdown(socket.SHUT_RDWR) |
114 self.connection.close() |
127 self.connection.close() |
115 sys.exit() |
|
116 |
|
117 def __unhandled_exception(self, exctype, excval, exctb): |
|
118 """ |
|
119 Private method called to report an uncaught exception. |
|
120 |
|
121 @param exctype the type of the exception |
|
122 @param excval data about the exception |
|
123 @param exctb traceback for the exception |
|
124 """ |
|
125 # TODO: Wrap arguments so they can be serialized by JSON |
|
126 self.__send( |
|
127 'EXCEPTION', '?', [str(exctype), str(excval), str(exctb)]) |
|
128 |
128 |
129 if __name__ == '__main__': |
129 if __name__ == '__main__': |
130 if len(sys.argv) != 3: |
130 if len(sys.argv) != 3: |
131 print('Host and port parameters are missing. Abort.') |
131 print('Host and port parameters are missing. Abort.') |
132 sys.exit(1) |
132 sys.exit(1) |
133 |
133 |
134 host, port = sys.argv[1:] |
134 host, port = sys.argv[1:] |
135 backgroundClient = BackgroundClient(host, int(port)) |
135 backgroundClient = BackgroundClient(host, int(port)) |
136 # set the system exception handling function to ensure, that |
|
137 # we report on all unhandled exceptions |
|
138 sys.excepthook = backgroundClient._BackgroundClient__unhandled_exception |
|
139 # Start the main loop |
136 # Start the main loop |
140 backgroundClient.run() |
137 backgroundClient.run() |