Utilities/BackgroundClient.py

branch
BgService
changeset 3159
02cb2adb4868
child 3173
1fb284abe46e
equal deleted inserted replaced
3146:14721e0f3b5b 3159:02cb2adb4868
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2013 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a Qt free version of a background client for the various
8 checkers and other python interpreter dependent functions.
9 """
10
11 from __future__ import unicode_literals
12 try:
13 bytes = unicode #__IGNORE_WARNING__
14 except NameError:
15 pass
16
17 import json
18 import os
19 import socket
20 import struct
21 import sys
22 from zlib import adler32
23
24 if __name__ == '__main__':
25 # Add Eric basepath to sys.path to be able to import modules which are
26 # laying not only below Utilities
27 path = os.path.dirname(sys.argv[0])
28 path = os.path.dirname(path)
29 sys.path.append(path)
30
31 from Plugins.CheckerPlugins.SyntaxChecker import SyntaxCheck
32
33
34 class BackgroundClient(object):
35 """
36 Class implementing the main part of the background client.
37 """
38 def __init__(self, host, port):
39 """
40 Constructor of the BackgroundClient class.
41
42 @param host ip address the background service is listening
43 @param port port of the background service
44 """
45 self.connection = socket.create_connection((host, port))
46 ver = b'2' if sys.version_info[0] == 2 else b'3'
47 self.connection.sendall(ver)
48 self.connection.settimeout(0.25)
49
50 def __send(self, fx, fn, data):
51 """
52 Private method to send a job response back to the BackgroundService.
53
54 @param fx remote function name to execute (str)
55 @param fn filename for identification (str)
56 @param data return value(s) (any basic datatype)
57 """
58 packedData = json.dumps([fx, fn, data])
59 if sys.version_info[0] == 3:
60 packedData = bytes(packedData, 'utf-8')
61 header = struct.pack(
62 b'!II', len(packedData), adler32(packedData) & 0xffffffff)
63 self.connection.sendall(header)
64 self.connection.sendall(packedData)
65
66 def run(self):
67 """
68 Implement the main loop of the client.
69 """
70 while True:
71 try:
72 header = self.connection.recv(8) # __IGNORE_EXCEPTION__
73 except socket.timeout:
74 continue
75 except socket.error:
76 # Leave main loop if connection was closed.
77 break
78 # Leave main loop if connection was closed.
79 if not header:
80 break
81
82 length, datahash = struct.unpack(b'!II', header)
83
84 packedData = b''
85 while len(packedData) < length:
86 packedData += self.connection.recv(length - len(packedData))
87
88 assert adler32(packedData) & 0xffffffff == datahash, \
89 'Hashes not equal'
90 if sys.version_info[0] == 3:
91 packedData = packedData.decode('utf-8')
92 fx, fn, data = json.loads(packedData)
93 if fx == 'syntax':
94 ret = SyntaxCheck.syntaxAndPyflakesCheck(fn, *data)
95 elif fx == 'style':
96 print(data)
97 elif fx == 'indent':
98 pass
99 else:
100 continue
101
102 self.__send(fx, fn, ret)
103
104 self.connection.close()
105 sys.exit()
106
107 def __unhandled_exception(self, exctype, excval, exctb):
108 """
109 Private method called to report an uncaught exception.
110
111 @param exctype the type of the exception
112 @param excval data about the exception
113 @param exctb traceback for the exception
114 """
115 # TODO: Wrap arguments so they can be serialized by JSON
116 self.__send(
117 'exception', '?', [str(exctype), str(excval), str(exctb)])
118
119 if __name__ == '__main__':
120 if len(sys.argv) != 3:
121 print('Host and port parameters are missing. Abort.')
122 sys.exit(1)
123
124 host, port = sys.argv[1:]
125 backgroundClient = BackgroundClient(host, int(port))
126 # set the system exception handling function to ensure, that
127 # we report on all unhandled exceptions
128 sys.excepthook = backgroundClient._BackgroundClient__unhandled_exception
129 # Start the main loop
130 backgroundClient.run()

eric ide

mercurial