- srv -- Server module
- cli -- Client module
- - perf -- Library for implementing object for the PERF protocol
+ - perf -- Library for implementing objects for the PERF protocol
The protocol allows multiple management subprotocols for different
modes of operation. Currently, the following two management protocols
accepts arbitrary Python code, executes it in the daemon process,
and returns its replies, all in text form. The protocol is simple,
generic, and has few failure modes, but is hardly suitable for
- programmatic interaction. See the documentation for pdm.srv.repl
- and pdm.cli.replclient for further details.
+ programmatic interaction. See the documentation for L{pdm.srv.repl}
+ and L{pdm.cli.replclient} for further details.
- The PERF protocol is intended for programmatic interaction with the
daemon process. Various Python modules may expose objects that
implement one or several of a few pre-defined interfaces that allow
for various forms of inspection and management of the program
- state. See the documentation for pdm.srv.perf and
- pdm.cli.perfclient for further details.
+ state. See the documentation for L{pdm.srv.perf} and
+ L{pdm.cli.perfclient} for further details.
"""
return spec
sk = None
try:
- if "/" in spec:
+ if ":" in spec:
+ p = spec.rindex(":")
+ first, second = spec[:p], spec[p + 1:]
+ if "/" in second:
+ import sshsock
+ sk = sshsock.sshsocket(first, second)
+ else:
+ sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sk.connect((first, second))
+ elif "/" in spec:
sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sk.connect(spec)
elif spec.isdigit():
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(("localhost", int(spec)))
- elif ":" in spec:
- sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- p = spec.rindex(":")
- sk.connect((spec[:p], int(spec[p + 1:])))
else:
raise Exception("Unknown target specification %r" % spec)
rv = sk
--- /dev/null
+import sys, os
+import subprocess, socket, fcntl, select
+
+class sshsocket(object):
+ def __init__(self, host, path, user = None, port = None):
+ args = ["ssh"]
+ if user is not None:
+ args += ["-u", str(user)]
+ if port is not None:
+ args += ["-p", str(int(port))]
+ args += [host]
+ args += ["python", "-m", "pdm.sshsock", path]
+ self.proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)
+ fcntl.fcntl(self.proc.stdout, fcntl.F_SETFL, fcntl.fcntl(self.proc.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+ def close(self):
+ if self.proc is not None:
+ self.proc.stdin.close()
+ self.proc.stdout.close()
+ self.proc.wait()
+ self.proc = None
+
+ def send(self, data, flags = 0):
+ self.proc.stdin.write(data)
+ return len(data)
+
+ def recv(self, buflen, flags = 0):
+ if (flags & socket.MSG_DONTWAIT) == 0:
+ select.select([self.proc.stdout], [], [])
+ return self.proc.stdout.read(buflen)
+
+ def fileno(self):
+ return self.proc.stdout.fileno()
+
+ def __del__(self):
+ self.close()
+
+def cli():
+ fcntl.fcntl(sys.stdin, fcntl.F_SETFL, fcntl.fcntl(sys.stdin, fcntl.F_GETFL) | os.O_NONBLOCK)
+ sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ try:
+ sk.connect(sys.argv[1])
+ buf1 = ""
+ buf2 = ""
+ while True:
+ wfd = []
+ if buf1: wfd.append(sk)
+ if buf2: wfd.append(sys.stdout)
+ rfd, wfd, efd = select.select([sk, sys.stdin], wfd, [])
+ if sk in rfd:
+ ret = sk.recv(65536)
+ if ret == "":
+ break
+ else:
+ buf2 += ret
+ if sys.stdin in rfd:
+ ret = sys.stdin.read()
+ if ret == "":
+ break
+ else:
+ buf1 = ret
+ if sk in wfd:
+ ret = sk.send(buf1)
+ buf1 = buf1[ret:]
+ if sys.stdout in wfd:
+ sys.stdout.write(buf2)
+ sys.stdout.flush()
+ buf2 = ""
+ finally:
+ sk.close()
+
+if __name__ == "__main__":
+ cli()