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()
70 while ':' in self
.in_buffer
:
71 l
, rest
= self
.in_buffer
.split(':', 1)
74 return True # Haven't got everything yet
76 self
.in_buffer
= rest
[l
:]
77 value
= pickle
.loads(s
)
82 self
.to_slave
= self
.from_slave
= None
84 def lost_connection(self
):
85 raise Exception("Lost connection to peer!")
87 class SlaveProxy(Proxy
):
88 """Methods invoked on MasterProxy.root will be invoked on
89 slave_object. The result is a master_proxy.RequestBlocker."""
90 def __init__(self
, to_master
, from_master
, slave_object
):
91 Proxy
.__init
__(self
, to_master
, from_master
)
92 self
.slave_object
= slave_object
94 def _dispatch(self
, value
):
95 serial
, method
, args
= value
97 result
= getattr(self
.slave_object
, method
)(*args
)
100 self
.write_object((serial
, result
))
102 def lost_connection(self
):