Giant blob of minor changes
[dotfiles/.git] / .local / bin / rpyc_classic.py
1 #!/usr/bin/python
2 """
3 classic rpyc server (threaded, forking or std) running a SlaveService
4 usage:
5     rpyc_classic.py                         # default settings
6     rpyc_classic.py -m forking -p 12345     # custom settings
7
8     # ssl-authenticated server (keyfile and certfile are required)
9     rpyc_classic.py --ssl-keyfile keyfile.pem --ssl-certfile certfile.pem --ssl-cafile cafile.pem
10 """
11 import sys
12 import os
13 import rpyc
14 from plumbum import cli
15 from rpyc.utils.server import ThreadedServer, ForkingServer, OneShotServer
16 from rpyc.utils.classic import DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT
17 from rpyc.utils.registry import REGISTRY_PORT
18 from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
19 from rpyc.utils.authenticators import SSLAuthenticator
20 from rpyc.lib import setup_logger
21 from rpyc.core import SlaveService
22
23
24 class ClassicServer(cli.Application):
25     mode = cli.SwitchAttr(["-m", "--mode"], cli.Set("threaded", "forking", "stdio", "oneshot"),
26                           default="threaded", help="The serving mode (threaded, forking, or 'stdio' for "
27                           "inetd, etc.)")
28
29     port = cli.SwitchAttr(["-p", "--port"], cli.Range(0, 65535), default=None,
30                           help="The TCP listener port (default = %s, default for SSL = %s)" %
31                           (DEFAULT_SERVER_PORT, DEFAULT_SERVER_SSL_PORT), group="Socket Options")
32     host = cli.SwitchAttr(["--host"], str, default="", help="The host to bind to. "
33                           "The default is localhost", group="Socket Options")
34     ipv6 = cli.Flag(["--ipv6"], help="Enable IPv6", group="Socket Options")
35
36     logfile = cli.SwitchAttr("--logfile", str, default=None, help="Specify the log file to use; "
37                              "the default is stderr", group="Logging")
38     quiet = cli.Flag(["-q", "--quiet"], help="Quiet mode (only errors will be logged)",
39                      group="Logging")
40
41     ssl_keyfile = cli.SwitchAttr("--ssl-keyfile", cli.ExistingFile,
42                                  help="The keyfile to use for SSL. Required for SSL", group="SSL",
43                                  requires=["--ssl-certfile"])
44     ssl_certfile = cli.SwitchAttr("--ssl-certfile", cli.ExistingFile,
45                                   help="The certificate file to use for SSL. Required for SSL", group="SSL",
46                                   requires=["--ssl-keyfile"])
47     ssl_cafile = cli.SwitchAttr("--ssl-cafile", cli.ExistingFile,
48                                 help="The certificate authority chain file to use for SSL. "
49                                 "Optional; enables client-side authentication",
50                                 group="SSL", requires=["--ssl-keyfile"])
51
52     auto_register = cli.Flag("--register", help="Asks the server to attempt registering with "
53                              "a registry server. By default, the server will not attempt to register",
54                              group="Registry")
55     registry_type = cli.SwitchAttr("--registry-type", cli.Set("UDP", "TCP"),
56                                    default="UDP", help="Specify a UDP or TCP registry", group="Registry")
57     registry_port = cli.SwitchAttr("--registry-port", cli.Range(0, 65535), default=REGISTRY_PORT,
58                                    help="The registry's UDP/TCP port", group="Registry")
59     registry_host = cli.SwitchAttr("--registry-host", str, default=None,
60                                    help="The registry host machine. For UDP, the default is 255.255.255.255; "
61                                    "for TCP, a value is required", group="Registry")
62
63     def main(self):
64         if not self.host:
65             self.host = "::1" if self.ipv6 else "127.0.0.1"
66
67         if self.registry_type == "UDP":
68             if self.registry_host is None:
69                 self.registry_host = "255.255.255.255"
70             self.registrar = UDPRegistryClient(ip=self.registry_host, port=self.registry_port)
71         else:
72             if self.registry_host is None:
73                 raise ValueError("With TCP registry, you must specify --registry-host")
74             self.registrar = TCPRegistryClient(ip=self.registry_host, port=self.registry_port)
75
76         if self.ssl_keyfile:
77             self.authenticator = SSLAuthenticator(self.ssl_keyfile, self.ssl_certfile,
78                                                   self.ssl_cafile)
79             default_port = DEFAULT_SERVER_SSL_PORT
80         else:
81             self.authenticator = None
82             default_port = DEFAULT_SERVER_PORT
83         if self.port is None:
84             self.port = default_port
85
86         setup_logger(self.quiet, self.logfile)
87
88         if self.mode == "threaded":
89             self._serve_mode(ThreadedServer)
90         elif self.mode == "forking":
91             self._serve_mode(ForkingServer)
92         elif self.mode == "oneshot":
93             self._serve_oneshot()
94         elif self.mode == "stdio":
95             self._serve_stdio()
96
97     def _serve_mode(self, factory):
98         t = factory(SlaveService, hostname=self.host, port=self.port,
99                     reuse_addr=True, ipv6=self.ipv6, authenticator=self.authenticator,
100                     registrar=self.registrar, auto_register=self.auto_register)
101         t.start()
102
103     def _serve_oneshot(self):
104         t = OneShotServer(SlaveService, hostname=self.host, port=self.port,
105                           reuse_addr=True, ipv6=self.ipv6, authenticator=self.authenticator,
106                           registrar=self.registrar, auto_register=self.auto_register)
107         t._listen()
108         sys.stdout.write("rpyc-oneshot\n")
109         sys.stdout.write("%s\t%s\n" % (t.host, t.port))
110         sys.stdout.flush()
111         t.start()
112
113     def _serve_stdio(self):
114         origstdin = sys.stdin
115         origstdout = sys.stdout
116         sys.stdin = open(os.devnull, "r")
117         sys.stdout = open(os.devnull, "w")
118         sys.stderr = open(os.devnull, "w")
119         conn = rpyc.classic.connect_pipes(origstdin, origstdout)
120         try:
121             try:
122                 conn.serve_all()
123             except KeyboardInterrupt:
124                 print("User interrupt!")
125         finally:
126             conn.close()
127
128
129 if __name__ == "__main__":
130     ClassicServer.run()