1 """Given a pair of pipes with a python process at each end, this module
2 allows one end to make calls on the other. This is used by the su module
3 to allow control of a subprocess running as another user, but it may also
4 be useful in other situations. The caller end should use the master_proxy
10 from __future__
import generators
11 # Note: do not import rox or gtk. Needs to work without DISPLAY.
15 from select
import select
16 import cPickle
as pickle
19 def __init__(self
, to_peer
, from_peer
, slave_object
= None):
20 if not hasattr(to_peer
, 'fileno'):
21 to_peer
= os
.fdopen(to_peer
, 'w')
22 if not hasattr(from_peer
, 'fileno'):
23 from_peer
= os
.fdopen(from_peer
, 'r')
24 self
.to_peer
= to_peer
25 self
.from_peer
= from_peer
29 self
.enable_read_watch()
31 def enable_read_watch(self
):
33 g
.input_add(self
.from_peer
, g
.gdk
.INPUT_READ
,
34 lambda src
, cond
: self
.read_ready())
36 def enable_write_watch(self
):
38 INPUT_WRITE
= 0x14 # g.gdk.INPUT_WRITE sometimes wrong!!
39 g
.input_add(self
.to_peer
.fileno(), INPUT_WRITE
,
40 lambda src
, cond
: self
.write_ready())
42 def write_object(self
, object):
43 if self
.to_peer
is None:
44 raise Exception('Peer is defunct')
45 if not self
.out_buffer
:
46 self
.enable_write_watch()
48 s
= pickle
.dumps(object)
49 s
= str(len(s
)) + ":" + s
52 def write_ready(self
):
53 """Returns True if the buffer is not empty on exit."""
54 while self
.out_buffer
:
55 w
= select([], [self
.to_peer
], [], 0)[1]
57 print "Not ready for writing"
59 n
= os
.write(self
.to_peer
.fileno(), self
.out_buffer
)
60 self
.out_buffer
= self
.out_buffer
[n
:]
64 new
= os
.read(self
.from_peer
.fileno(), 1000)
67 self
.lost_connection()
69 while ':' in self
.in_buffer
:
70 l
, rest
= self
.in_buffer
.split(':', 1)
73 return True # Haven't got everything yet
75 self
.in_buffer
= rest
[l
:]
76 value
= pickle
.loads(s
)
81 self
.to_slave
= self
.from_slave
= None
83 def lost_connection(self
):
84 raise Exception("Lost connection to peer!")
86 class SlaveProxy(Proxy
):
87 """Methods invoked on MasterProxy.root will be invoked on
88 slave_object. The result is a master_proxy.RequestBlocker."""
89 def __init__(self
, to_master
, from_master
, slave_object
):
90 Proxy
.__init
__(self
, to_master
, from_master
)
91 self
.slave_object
= slave_object
93 def _dispatch(self
, value
):
94 serial
, method
, args
= value
96 result
= getattr(self
.slave_object
, method
)(*args
)
99 self
.write_object((serial
, result
))
101 def lost_connection(self
):