3232================================================================================
3333PyWebIO Application Remote Access
3434
35- Remote access address: https://{address}
36-
37- The remote access service is provided by localhost.run (https://localhost.run/).
38- The remote access address will be reset in every 6 hours and only one
39- application can enable remote access at the same time, if you use the free tier.
40-
41- To set up and manage custom domains go to https://admin.localhost.run/
42-
35+ Remote access address: {address}
4336================================================================================
4437"""
4538
46- ssh_key_gen_msg = """
47- ===============================================================================
48- PyWebIO Application Remote Access Error
49-
50- You need an SSH key to access the remote access service.
51- Please follow Gitlab's most excellent howto to generate an SSH key pair:
52- https://docs.gitlab.com/ee/ssh/
53- Note that only rsa and ed25519 keys are supported.
54- ===============================================================================
55- """
56-
5739_ssh_process = None # type: Popen
5840
5941
60- def remote_access_service (local_port = 8080 , setup_timeout = 60 , key_path = None , custom_domain = None , need_exist = None ):
42+ def remote_access_service (local_port = 8080 , server = 'app.pywebio.online' , server_port = 1022 , setup_timeout = 60 ,
43+ need_exit = None ):
6144 """
6245 :param local_port: ssh local listen port
46+ :param server: ssh server domain
47+ :param server_port: ssh server port
6348 :param setup_timeout: If the service can't setup successfully in `setup_timeout` seconds, then exit.
64- :param key_path: Use a custom ssh key, the default key path is ~/.ssh/id_xxx. Note that only rsa and ed25519 keys are supported.
65- :param custom_domain: Use a custom domain for your remote access address. This need a subscription to localhost.run
66- :param callable need_exist: The service will call this function periodicity, when it return True, then exit the service.
49+ :param callable need_exit: The service will call this function periodicity, when it return True, then exit the service.
6750 """
6851
6952 global _ssh_process
7053
71- domain_part = '%s:' % custom_domain if custom_domain is not None else ''
72- key_path_arg = '-i %s' % key_path if key_path is not None else ''
73- cmd = "ssh %s -oStrictHostKeyChecking=no -R %s80:localhost:%s localhost.run -- --output json" % (
74- key_path_arg , domain_part , local_port )
54+ cmd = "ssh -oStrictHostKeyChecking=no -R 80:localhost:%s -p %s %s -- --output json" % (
55+ local_port , server_port , server )
7556 args = shlex .split (cmd )
7657 logger .debug ('remote access service command: %s' , cmd )
7758
@@ -87,6 +68,7 @@ def timeout_killer(wait_sec):
8768 threading .Thread (target = timeout_killer , kwargs = dict (wait_sec = setup_timeout ), daemon = True ).start ()
8869
8970 stdout = _ssh_process .stdout .readline ().decode ('utf8' )
71+ logger .debug ('ssh server stdout: %s' , stdout )
9072 connection_info = {}
9173 try :
9274 connection_info = json .loads (stdout )
@@ -103,7 +85,7 @@ def timeout_killer(wait_sec):
10385 print (success_msg .format (address = connection_info ['address' ]))
10486
10587 # wait ssh or parent process exit
106- while not need_exist () and _ssh_process .poll () is None :
88+ while not need_exit () and _ssh_process .poll () is None :
10789 time .sleep (1 )
10890
10991 if _ssh_process .poll () is None : # parent process exit, kill ssh process
@@ -112,30 +94,21 @@ def timeout_killer(wait_sec):
11294 else : # ssh process exit by itself or by timeout killer
11395 stderr = _ssh_process .stderr .read ().decode ('utf8' )
11496 logger .debug ("Stderr from ssh process: %s" , stderr )
115- conn_id = re .search (r'connection id is (.*?),' , stderr )
116- logger .debug ('Remote access connection id: %s' , conn_id .group (1 ) if conn_id else '' )
117- try :
118- ssh_error_msg = stderr .rsplit ('**' , 1 )[- 1 ].rsplit ('===' , 1 )[- 1 ].lower ().strip ()
119- except Exception :
120- ssh_error_msg = stderr
121- if 'permission denied' in ssh_error_msg :
122- print (ssh_key_gen_msg )
123- elif ssh_error_msg :
124- print (ssh_error_msg )
97+ if stderr :
98+ print (stderr )
12599 else :
126100 print ('PyWebIO application remote access service exit.' )
127101
128102
129- def start_remote_access_service_ (local_port , setup_timeout , ssh_key_path , custom_domain ):
103+ def start_remote_access_service_ (** kwargs ):
130104 ppid = os .getppid ()
131105
132- def need_exist ():
106+ def need_exit ():
133107 # only for unix
134108 return os .getppid () != ppid
135109
136110 try :
137- remote_access_service (local_port = local_port , setup_timeout = setup_timeout ,
138- key_path = ssh_key_path , custom_domain = custom_domain , need_exist = need_exist )
111+ remote_access_service (** kwargs , need_exit = need_exit )
139112 except KeyboardInterrupt : # ignore KeyboardInterrupt
140113 pass
141114 finally :
@@ -145,8 +118,15 @@ def need_exist():
145118 raise SystemExit
146119
147120
148- def start_remote_access_service (local_port = 8080 , setup_timeout = 60 , ssh_key_path = None , custom_domain = None ):
149- multiprocessing .Process (target = start_remote_access_service_ , kwargs = locals ()).start ()
121+ def start_remote_access_service (** kwargs ):
122+ server = os .environ .get ('PYWEBIO_REMOTE_ACCESS' , 'app.pywebio.online:1022' )
123+ if ':' not in server :
124+ server_port = 22
125+ else :
126+ server , server_port = server .split (':' , 1 )
127+ kwargs .setdefault ('server' , server )
128+ kwargs .setdefault ('server_port' , server_port )
129+ multiprocessing .Process (target = start_remote_access_service_ , kwargs = kwargs ).start ()
150130
151131
152132if __name__ == '__main__' :
@@ -156,10 +136,10 @@ def start_remote_access_service(local_port=8080, setup_timeout=60, ssh_key_path=
156136
157137 parser = argparse .ArgumentParser (description = "localhost.run Remote Access service" )
158138 parser .add_argument ("--local-port" , help = "the local port to connect the tunnel to" , type = int , default = 8080 )
159- parser .add_argument ("--custom-domain" , help = "optionally connect a tunnel to a custom domain" , default = None )
160- parser .add_argument ("--key-path" , help = "custom SSH key path" , default = None )
139+ parser .add_argument ("--server" , help = "the local port to connect the tunnel to" , type = str ,
140+ default = 'app.pywebio.online' )
141+ parser .add_argument ("--server-port" , help = "the local port to connect the tunnel to" , type = int , default = 1022 )
161142 args = parser .parse_args ()
162143
163- start_remote_access_service (local_port = args .local_port , ssh_key_path = args .key_path ,
164- custom_domain = args .custom_domain )
144+ start_remote_access_service (local_port = args .local_port , server = args .server , server_port = args .server_port )
165145 os .wait () # Wait for completion of a child process
0 commit comments