32
32
================================================================================
33
33
PyWebIO Application Remote Access
34
34
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}
43
36
================================================================================
44
37
"""
45
38
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
-
57
39
_ssh_process = None # type: Popen
58
40
59
41
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 ):
61
44
"""
62
45
:param local_port: ssh local listen port
46
+ :param server: ssh server domain
47
+ :param server_port: ssh server port
63
48
: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.
67
50
"""
68
51
69
52
global _ssh_process
70
53
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 )
75
56
args = shlex .split (cmd )
76
57
logger .debug ('remote access service command: %s' , cmd )
77
58
@@ -87,6 +68,7 @@ def timeout_killer(wait_sec):
87
68
threading .Thread (target = timeout_killer , kwargs = dict (wait_sec = setup_timeout ), daemon = True ).start ()
88
69
89
70
stdout = _ssh_process .stdout .readline ().decode ('utf8' )
71
+ logger .debug ('ssh server stdout: %s' , stdout )
90
72
connection_info = {}
91
73
try :
92
74
connection_info = json .loads (stdout )
@@ -103,7 +85,7 @@ def timeout_killer(wait_sec):
103
85
print (success_msg .format (address = connection_info ['address' ]))
104
86
105
87
# 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 :
107
89
time .sleep (1 )
108
90
109
91
if _ssh_process .poll () is None : # parent process exit, kill ssh process
@@ -112,30 +94,21 @@ def timeout_killer(wait_sec):
112
94
else : # ssh process exit by itself or by timeout killer
113
95
stderr = _ssh_process .stderr .read ().decode ('utf8' )
114
96
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 )
125
99
else :
126
100
print ('PyWebIO application remote access service exit.' )
127
101
128
102
129
- def start_remote_access_service_ (local_port , setup_timeout , ssh_key_path , custom_domain ):
103
+ def start_remote_access_service_ (** kwargs ):
130
104
ppid = os .getppid ()
131
105
132
- def need_exist ():
106
+ def need_exit ():
133
107
# only for unix
134
108
return os .getppid () != ppid
135
109
136
110
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 )
139
112
except KeyboardInterrupt : # ignore KeyboardInterrupt
140
113
pass
141
114
finally :
@@ -145,8 +118,15 @@ def need_exist():
145
118
raise SystemExit
146
119
147
120
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 ()
150
130
151
131
152
132
if __name__ == '__main__' :
@@ -156,10 +136,10 @@ def start_remote_access_service(local_port=8080, setup_timeout=60, ssh_key_path=
156
136
157
137
parser = argparse .ArgumentParser (description = "localhost.run Remote Access service" )
158
138
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 )
161
142
args = parser .parse_args ()
162
143
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 )
165
145
os .wait () # Wait for completion of a child process
0 commit comments