10 """A simple protocol for sending strings across a socket"""
13 def __init__(self
, sock
):
23 """Encode buf and write it on the socket"""
25 VERBOSE
.write('send %d:%s\n' % (len(buf
), `buf`
))
26 self
.sock
.send('%d:%s' % (len(buf
), buf
))
28 def receive(self
, timeout
=0):
29 """Get next complete string from socket or return None
33 buf
= self
._read
_from
_buffer
()
36 recvbuf
= self
._read
_from
_socket
(timeout
)
39 if recvbuf
== '' and self
._buffer
== '':
42 VERBOSE
.write('recv %s\n' % `recvbuf`
)
43 self
._buffer
= self
._buffer
+ recvbuf
44 r
= self
._read
_from
_buffer
()
47 def _read_from_socket(self
, timeout
):
51 if timeout
is not None:
52 r
, w
, x
= select
.select([self
.sock
], [], [], timeout
)
53 if timeout
is None or r
:
54 return self
.sock
.recv(self
.BUF_SIZE
)
58 def _read_from_buffer(self
):
64 enclen
= i
+ 1 + buflen
65 if len(buf
) >= enclen
:
67 self
._buffer
= buf
[enclen
:]
73 # helpers for registerHandler method below
78 attr
= getattr(obj
, name
)
81 if type(obj
) == types
.InstanceType
:
82 methods
= methods
+ get_methods(obj
.__class
__)
83 if type(obj
) == types
.ClassType
:
84 for super in obj
.__bases
__:
85 methods
= methods
+ get_methods(super)
88 class CommandProtocol
:
89 def __init__(self
, sockp
):
98 def registerHandler(self
, handler
):
99 """A Handler is an object with handle_XXX methods"""
100 for methname
in get_methods(handler
):
101 if methname
[:7] == "handle_":
103 self
.handlers
[name
] = getattr(handler
, methname
)
105 def send(self
, cmd
, arg
='', seqno
=None):
107 msg
= "%s %s" % (cmd
, arg
)
111 seqno
= self
.get_seqno()
112 msgbuf
= self
.encode_seqno(seqno
) + msg
113 self
.sockp
.send(msgbuf
)
116 reply
= self
.sockp
.receive(timeout
=None)
117 r_cmd
, r_arg
, r_seqno
= self
._decode
_msg
(reply
)
118 assert r_seqno
== seqno
and r_cmd
== "reply", "bad reply"
121 def _decode_msg(self
, msg
):
122 seqno
= self
.decode_seqno(msg
[:self
.SEQNO_ENC_LEN
])
123 msg
= msg
[self
.SEQNO_ENC_LEN
:]
124 parts
= msg
.split(" ", 2)
131 return cmd
, arg
, seqno
134 msg
= self
.sockp
.receive()
137 cmd
, arg
, seqno
= self
._decode
_msg
(msg
)
138 self
._current
_reply
= seqno
139 h
= self
.handlers
.get(cmd
, self
.default_handler
)
142 except TypeError, msg
:
143 raise TypeError, "handle_%s: %s" % (cmd
, msg
)
144 if self
._current
_reply
is None:
146 sys
.stderr
.write("ignoring %s return value type %s\n" % \
147 (cmd
, type(r
).__name
__))
151 if type(r
) != types
.StringType
:
152 raise ValueError, "invalid return type for %s" % cmd
153 self
.send("reply", r
, seqno
=seqno
)
155 def reply(self
, arg
=''):
156 """Send a reply immediately
158 otherwise reply will be sent when handler returns
160 self
.send("reply", arg
, self
._current
_reply
)
161 self
._current
_reply
= None
163 def default_handler(self
, arg
):
164 sys
.stderr
.write("WARNING: unhandled message %s\n" % arg
)
171 self
.seqno
= seqno
+ 1
174 def encode_seqno(self
, seqno
):
175 return struct
.pack("I", seqno
)
177 def decode_seqno(self
, buf
):
178 return struct
.unpack("I", buf
)[0]
181 class StdioRedirector
:
182 """Redirect sys.std{in,out,err} to a set of file-like objects"""
184 def __init__(self
, stdin
, stdout
, stderr
):
191 sys
.stdin
= self
.stdin
192 sys
.stdout
= self
.stdout
193 sys
.stderr
= self
.stderr
196 self
._stdin
= sys
.stdin
197 self
._stdout
= sys
.stdout
198 self
._stderr
= sys
.stderr
201 sys
.stdin
= self
._stdin
202 sys
.stdout
= self
._stdout
203 sys
.stderr
= self
._stderr
206 """Send output from a file-like object across a SocketProtocol
208 XXX Should this be more tightly integrated with the CommandProtocol?
211 def __init__(self
, name
, cmdp
):
216 class InputWrapper(IOWrapper
):
217 def write(self
, buf
):
218 # XXX what should this do on Windows?
219 raise IOError, (9, '[Errno 9] Bad file descriptor')
221 def read(self
, arg
=None):
227 return self
.cmdp
.send(self
.name
, "read,%s" % arg
)
230 return self
.cmdp
.send(self
.name
, "readline")
232 class OutputWrapper(IOWrapper
):
233 def write(self
, buf
):
234 self
.cmdp
.send(self
.name
, buf
)
236 def read(self
, arg
=None):
240 def __init__(self
, sock
):
241 self
._sock
= SocketProtocol(sock
)
242 self
._cmd
= CommandProtocol(self
._sock
)
243 self
._cmd
.registerHandler(self
)
252 def handle_execfile(self
, arg
):
254 io
= StdioRedirector(InputWrapper("stdin", self
._cmd
),
255 OutputWrapper("stdout", self
._cmd
),
256 OutputWrapper("stderr", self
._cmd
))
258 execfile(arg
, {'__name__':'__main__'})
260 self
._cmd
.send("terminated")
262 def handle_quit(self
, arg
):
266 def startRemoteInterp(id):
268 # UNIX domain sockets are simpler for starters
269 sock
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
270 sock
.bind("/var/tmp/ri.%s" % id)
273 cli
, addr
= sock
.accept()
274 rinterp
= RemoteInterp(cli
)
277 os
.unlink("/var/tmp/ri.%s" % id)
280 """Client of the remote interpreter"""
281 def __init__(self
, sock
):
282 self
._sock
= SocketProtocol(sock
)
283 self
._cmd
= CommandProtocol(self
._sock
)
284 self
._cmd
.registerHandler(self
)
286 def execfile(self
, file):
287 self
._cmd
.send("execfile", file)
296 def handle_stdout(self
, buf
):
297 sys
.stdout
.write(buf
)
298 ## sys.stdout.flush()
300 def handle_stderr(self
, buf
):
301 sys
.stderr
.write(buf
)
303 def handle_stdin(self
, arg
):
304 if arg
== "readline":
305 return sys
.stdin
.readline()
306 i
= arg
.find(",") + 1
309 return sys
.stdin
.read()
311 return sys
.stdin
.read(bytes
)
313 def handle_terminated(self
, arg
):
315 self
._cmd
.send("quit")
318 def riExec(id, file):
319 sock
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
320 sock
.connect("/var/tmp/ri.%s" % id)
325 if __name__
== "__main__":
330 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'cv')
339 startRemoteInterp(id)