2ch commited on
Commit
0c95886
·
verified ·
1 Parent(s): eceaf2c

Create revprx_lnks.py

Browse files
Files changed (1) hide show
  1. revprx_lnks.py +511 -0
revprx_lnks.py ADDED
@@ -0,0 +1,511 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from atexit import register as exit_register
2
+ from os import close, read, name as os_name
3
+ from pathlib import Path
4
+ from pty import openpty
5
+ from re import compile, search
6
+ from shutil import move
7
+ from subprocess import PIPE, Popen, STDOUT, check_output, CalledProcessError
8
+ from sys import stdout
9
+ from time import sleep, time
10
+ from urllib.parse import unquote, urlparse
11
+
12
+ from requests import get as get_url, head as get_head
13
+ from requests.structures import CaseInsensitiveDict
14
+
15
+ WORK_FOLDER = Path('/content')
16
+
17
+ zrok_bin = WORK_FOLDER / 'zrok'
18
+ zrok_fallback_tokens = [
19
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
20
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
21
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
22
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
23
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
24
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
25
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
26
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
27
+ 'твои токены на https://myzrok.io', 'твои токены на https://myzrok.io',
28
+ ]
29
+ claudflare_bin = WORK_FOLDER / 'claudflared'
30
+ tmole_bin = WORK_FOLDER / 'tmole'
31
+ tunwg_bin = WORK_FOLDER / 'tunwg'
32
+ go_localt_bin = WORK_FOLDER / 'go_localt'
33
+ gradio_bin = WORK_FOLDER / 'frpc_linux_amd64'
34
+ colab_native_url = WORK_FOLDER / 'colab_url.txt'
35
+
36
+ links_file = WORK_FOLDER / 'links.txt'
37
+
38
+
39
+ def is_list(variable) -> bool:
40
+ return isinstance(variable, list)
41
+
42
+
43
+ def is_str(variable) -> bool:
44
+ return isinstance(variable, str)
45
+
46
+
47
+ def determine_archive_format(filepath: str | Path) -> str | None:
48
+ filepath = Path(filepath)
49
+ zip_signature = bytes([0x50, 0x4B, 0x03, 0x04])
50
+ seven_z_signature = bytes([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])
51
+ lzma_xz_signature = bytes([0xFD, 0x37, 0x7A, 0x58, 0x5A])
52
+ tgz_signature = bytes([0x1F, 0x8B])
53
+ tbz_signature = bytes([0x42, 0x5A, 0x68])
54
+ ustar_signature = bytes([0x75, 0x73, 0x74, 0x61, 0x72])
55
+ with filepath.open('rb') as file:
56
+ header = file.read(262)
57
+ if header.startswith(zip_signature):
58
+ return 'zip'
59
+ elif header.startswith(seven_z_signature) or header.startswith(lzma_xz_signature):
60
+ return '7z'
61
+ elif header.startswith(tgz_signature):
62
+ return 'tar.gz'
63
+ elif header.startswith(tbz_signature):
64
+ return 'tar.bz2'
65
+ elif header[0x101:0x101 + len(ustar_signature)] == ustar_signature:
66
+ return 'tar'
67
+ return None
68
+
69
+
70
+ def unpack_archive(archive_path: str | Path, dest_path: str | Path, rm_archive: bool = True):
71
+ if str(archive_path).startswith(('https://', 'http://')):
72
+ archive_path = download(archive_path, save_path=WORK_FOLDER, progress=False)
73
+ if not Path(archive_path).exists():
74
+ raise RuntimeError(f'архив {archive_path} не найден.')
75
+ archive_path = Path(archive_path)
76
+ dest_path = Path(dest_path)
77
+
78
+ if not archive_path.exists():
79
+ raise RuntimeError(f'архив {archive_path} не найден.')
80
+
81
+ determine_format = determine_archive_format(archive_path)
82
+
83
+ print(determine_format, str(archive_path))
84
+
85
+ try:
86
+ if determine_format == '7z' or archive_path.suffix == '.7z':
87
+ run(f'7z -bso0 -bd -slp -y x {str(archive_path)} -o{str(dest_path)}')
88
+ archive_path.unlink(missing_ok=True) if rm_archive else None
89
+ elif determine_format == 'tar' or archive_path.suffix in ['.tar']:
90
+ run(f'tar -xvpf {str(archive_path)} -C {str(dest_path)}')
91
+ archive_path.unlink(missing_ok=True) if rm_archive else None
92
+ elif determine_format == 'tar.gz' or archive_path.suffix in ['.tar.gz', '.tar.bz2', '.tar.xz']:
93
+ result = run(f'tar -xvzpf {str(archive_path)} -C {str(dest_path)}')
94
+ if result['status_code'] != 0:
95
+ run(f'gzip -d {str(archive_path)}', dest_path)
96
+ archive_path.unlink(missing_ok=True) if rm_archive else None
97
+ elif determine_format == 'zip' or archive_path.suffix == '.zip':
98
+ run(f'unzip {str(archive_path)} -d {str(dest_path)}')
99
+ archive_path.unlink(missing_ok=True) if rm_archive else None
100
+ else:
101
+ run(f'7z -bso0 -bd -slp -y x {str(archive_path)} -o{str(dest_path)}')
102
+ archive_path.unlink(missing_ok=True) if rm_archive else None
103
+ except:
104
+ try:
105
+ run(f'7z -bso0 -bd -mmt4 -slp -y x {str(archive_path)} -o{str(dest_path)}')
106
+ archive_path.unlink(missing_ok=True) if rm_archive else None
107
+ except:
108
+ raise RuntimeError(
109
+ f'формат архива {archive_path.suffix} не определен, нужно зад��ть формат в "determine_format".')
110
+
111
+
112
+ def run(command: str, cwd: str | Path | None = None) -> dict:
113
+ process = Popen(command, shell=True, cwd=cwd, stdout=PIPE, stderr=STDOUT)
114
+ encodings = ['iso-8859-5', 'windows-1251', 'iso-8859-1', 'cp866', 'koi8-r', 'mac_cyrillic']
115
+ is_progress_bar_pattern = r'\d+%|\d+/\d+'
116
+
117
+ def decode_output(output_data):
118
+ for encoding in encodings:
119
+ try:
120
+ return output_data.decode(encoding)
121
+ except UnicodeDecodeError:
122
+ continue
123
+ return output_data.decode('utf-8', errors='replace')
124
+
125
+ final_output = []
126
+ last_progress_bar = ''
127
+
128
+ def process_output():
129
+ nonlocal last_progress_bar
130
+ for line in iter(process.stdout.readline, b''):
131
+ try:
132
+ line_decoded = line.decode('utf-8').strip()
133
+ except UnicodeDecodeError:
134
+ line_decoded = decode_output(line.strip())
135
+
136
+ if search(is_progress_bar_pattern, line_decoded):
137
+ last_progress_bar = line_decoded
138
+ stdout.write('\r' + line_decoded)
139
+ else:
140
+ final_output.append(line_decoded)
141
+ stdout.write('\n' + line_decoded)
142
+ stdout.flush()
143
+
144
+ process_output()
145
+ process.wait()
146
+ if last_progress_bar:
147
+ final_output.append(last_progress_bar)
148
+ return {
149
+ 'status_code': process.returncode,
150
+ 'output': '\n'.join(final_output)
151
+ }
152
+
153
+
154
+ def is_valid_url(url: str) -> bool:
155
+ headers = None
156
+ for attempt in range(2):
157
+ try:
158
+ with get_url(url, headers=headers, allow_redirects=True, stream=True) as response:
159
+ if 200 <= response.status_code < 300:
160
+ return True
161
+ except:
162
+ try:
163
+ response = get_head(url, headers=headers, allow_redirects=True)
164
+ if 200 <= response.status_code < 300:
165
+ return True
166
+ except:
167
+ pass
168
+ else:
169
+ break
170
+ return False
171
+
172
+
173
+ def get_filename_from_headers(requests_headers: CaseInsensitiveDict) -> str | None:
174
+ content_disposition = requests_headers.get('content-disposition')
175
+ if not content_disposition:
176
+ return requests_headers.get('filename')
177
+ parts = content_disposition.split(';')
178
+ filename = None
179
+ for part in parts:
180
+ part = part.strip()
181
+ if part.startswith('filename*='):
182
+ encoding, _, encoded_filename = part[len('filename*='):].partition("''")
183
+ filename = unquote(encoded_filename, encoding=encoding)
184
+ break
185
+ elif part.startswith('filename='):
186
+ filename = part[len('filename='):].strip('"')
187
+ break
188
+ return filename
189
+
190
+
191
+ def download(url: str, filename: str | Path | None = None, save_path: str | Path | None = None,
192
+ progress: bool = True) -> Path | None:
193
+ headers = None
194
+ url_with_header = url.replace('"', '').replace("'", '').split('--header=')
195
+ if len(url_with_header) > 1:
196
+ url = (url_with_header[0]).strip()
197
+ header = url_with_header[1]
198
+ headers = {
199
+ header.split(':')[0].strip(): header.split(':')[1].strip()
200
+ }
201
+ if is_valid_url(url):
202
+ save_path = Path(save_path) if save_path else Path.cwd()
203
+ save_path.mkdir(parents=True, exist_ok=True)
204
+
205
+ with get_url(url, stream=True, allow_redirects=True, headers=headers) as request:
206
+ file_size = int(request.headers.get('content-length', 0))
207
+ file_name = filename or get_filename_from_headers(request.headers) or Path(urlparse(request.url).path).name
208
+ file_path = save_path / file_name
209
+
210
+ chunk_size = max(4096, file_size // 2000)
211
+ downloaded_size = 0
212
+ try:
213
+ with open(file_path, 'wb') as fp:
214
+ start = time()
215
+ for chunk in request.iter_content(chunk_size=chunk_size):
216
+ if chunk:
217
+ fp.write(chunk)
218
+ if progress:
219
+ downloaded_size += len(chunk)
220
+ percent_completed = downloaded_size / file_size * 100
221
+ elapsed_time = time() - start
222
+ print(f'\rзагрузка {file_name}: {percent_completed:.2f}% | {elapsed_time:.2f} сек.',
223
+ end='')
224
+ except Exception as e:
225
+ raise RuntimeError(f'не удалось загрузить файл по ссылке {url}:\n{e}')
226
+ return file_path
227
+ else:
228
+ raise RuntimeError(f'недействительная ссылка на файл: {url}')
229
+
230
+
231
+ def is_process_running(process_name: str | Path) -> bool:
232
+ try:
233
+ output = check_output(['pgrep', '-f', str(process_name)], text=True)
234
+ return len(output.strip().split('\n')) > 0
235
+ except CalledProcessError:
236
+ return False
237
+
238
+
239
+ def move_path(old_path: Path | str, new_path: Path | str):
240
+ old, new = Path(old_path), Path(new_path)
241
+ if old_path.exists():
242
+ try:
243
+ old_path.replace(new)
244
+ except:
245
+ try:
246
+ move(old, new)
247
+ except:
248
+ if os_name == 'posix':
249
+ run(f'mv "{old}" "{new}"')
250
+ else:
251
+ run(f'move "{old}" "{new}"')
252
+ else:
253
+ raise RuntimeError(f'не найден исходный путь для перемещения: {old}')
254
+
255
+
256
+ def terminate_process(process_name: str, process_obj: Popen):
257
+ process_obj.stdout.close()
258
+ process_obj.stderr.close()
259
+ process_obj.terminate()
260
+ run(f'pkill -f {process_name}')
261
+
262
+
263
+ def is_ipv4(address: str) -> bool:
264
+ ipv4_pattern = compile(r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
265
+ if ipv4_pattern.match(address):
266
+ return True
267
+ else:
268
+ return False
269
+
270
+
271
+ def get_revproxy_url(bin_url: str, need_unpack: bool, bin_path: Path, start_commands: list, read_from_stderr: bool,
272
+ lines_to_read: int, url_pattern: str = r'https://\S+', write_link: bool = False) -> str:
273
+ if not bin_path.exists():
274
+ files_before = {item.name for item in WORK_FOLDER.iterdir() if item.is_file()}
275
+ if need_unpack:
276
+ unpack_archive(download(bin_url, progress=False), WORK_FOLDER, rm_archive=True)
277
+ else:
278
+ download(bin_url, save_path=bin_path.parent, progress=False)
279
+ files_after = {item.name for item in WORK_FOLDER.iterdir() if item.is_file()}
280
+ new_files = files_after - files_before
281
+ if len(new_files) == 1:
282
+ unpacked_file = WORK_FOLDER / new_files.pop()
283
+ move_path(unpacked_file, bin_path)
284
+ else:
285
+ unpacked_files = ', '.join(new_files)
286
+ raise RuntimeError(f'ошибка при определении нового файла после распаковки!\n'
287
+ f'ожидалось что за время работы добавится один файл (распакованный бинарник),\n'
288
+ f'а добавилсь эти: {unpacked_files}')
289
+ bin_path.chmod(0o777)
290
+
291
+ if is_process_running(bin_path.name):
292
+ run(f'pkill -f {bin_path.name}')
293
+
294
+ process = Popen(start_commands, stdout=PIPE, stderr=PIPE, text=True)
295
+ lines = []
296
+ stream = process.stderr if read_from_stderr else process.stdout
297
+ for _ in range(lines_to_read):
298
+ line = stream.readline()
299
+ # print(f'# {line}')
300
+ if len(lines) == lines_to_read or not line:
301
+ break
302
+ lines.append(line.strip())
303
+
304
+ ipv4 = next((line for line in lines if is_ipv4(line)), None)
305
+
306
+ urls = [search(url_pattern, url).group() for url in lines if search(url_pattern, url)]
307
+
308
+ if urls:
309
+ exit_register(terminate_process, bin_path.name, process)
310
+ if write_link:
311
+ links_file.write_text(urls[0])
312
+ return f'{urls[0]}\n пароль(IP): {ipv4}' if ipv4 else urls[0]
313
+ else:
314
+ run(f'pkill -f {bin_path.name}')
315
+ output = '\n'.join(lines)
316
+ raise RuntimeError(f'ссылку получить не удалось, вывод работы бинарника:\n{output}')
317
+
318
+
319
+ def get_tmole_url(port: int) -> str:
320
+ return get_revproxy_url(
321
+ bin_url='https://tunnelmole.com/downloads/tmole-linux.gz',
322
+ need_unpack=True,
323
+ bin_path=Path(tmole_bin),
324
+ start_commands=[str(Path(tmole_bin)), str(port)],
325
+ read_from_stderr=False,
326
+ lines_to_read=5
327
+ )
328
+
329
+
330
+ def get_tunwg_url(port: int) -> str:
331
+ return get_revproxy_url(
332
+ bin_url='https://github.com/ntnj/tunwg/releases/latest/download/tunwg',
333
+ need_unpack=False,
334
+ bin_path=Path(tunwg_bin),
335
+ start_commands=[f'{tunwg_bin}', f'--forward=http://127.0.0.1:{port}'],
336
+ read_from_stderr=True,
337
+ lines_to_read=2
338
+ )
339
+
340
+
341
+ def get_cloudflared_url(port: int) -> str:
342
+ return get_revproxy_url(
343
+ bin_url='https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64',
344
+ need_unpack=False,
345
+ bin_path=Path(claudflare_bin),
346
+ start_commands=[f'{claudflare_bin}', 'tunnel', '--url', f'http://127.0.0.1:{port}'],
347
+ read_from_stderr=True,
348
+ lines_to_read=6,
349
+ url_pattern=r'(?P<url>https?://\S+\.trycloudflare\.com)'
350
+ )
351
+
352
+
353
+ def get_localt_url(port: int) -> str:
354
+ return get_revproxy_url(
355
+ bin_url='https://huggingface.co/prolapse/go_localt/resolve/main/go_localt',
356
+ need_unpack=False,
357
+ bin_path=Path(go_localt_bin),
358
+ start_commands=[f'{go_localt_bin}', f'{port}'],
359
+ read_from_stderr=False,
360
+ lines_to_read=2
361
+ )
362
+
363
+
364
+ def zrok_token_is_valid(zrok_token: str) -> bool:
365
+ try:
366
+ run(f'./{zrok_bin.name} disable', cwd=zrok_bin.parent)
367
+ except:
368
+ pass
369
+ master, slave = openpty()
370
+ process = Popen(f'./{zrok_bin.name} enable {zrok_token}', shell=True, cwd=zrok_bin.parent, stdin=slave,
371
+ stdout=slave, stderr=slave, text=True)
372
+ close(slave)
373
+ output = []
374
+ try:
375
+ while True:
376
+ try:
377
+ data = read(master, 1024)
378
+ except OSError:
379
+ break
380
+ if not data:
381
+ break
382
+ output.append(data.decode('utf-8'))
383
+ except:
384
+ pass
385
+ close(master)
386
+ process.wait()
387
+ full_output = ''.join(output)
388
+ if 'successfully enabled' in full_output:
389
+ return True
390
+
391
+ return False
392
+
393
+
394
+ def get_zrok_token() -> str:
395
+ for token in zrok_fallback_tokens:
396
+ if zrok_token_is_valid(token):
397
+ zrok_token = token
398
+ break
399
+ else:
400
+ raise RuntimeError('не удалось найти валидный zrok-токен.')
401
+ return zrok_token
402
+
403
+
404
+ def get_zrok_url(port: int) -> str:
405
+ zrok_bin_url = 'https://huggingface.co/prolapse/zrok/resolve/main/zrok.tar'
406
+ if not zrok_bin.exists():
407
+ unpack_archive(download(zrok_bin_url, progress=False), WORK_FOLDER, rm_archive=True)
408
+ get_zrok_token()
409
+ com = f'{zrok_bin} share public http://localhost:{port}/ --headless'.split(' ')
410
+ return get_revproxy_url(
411
+ bin_url=zrok_bin_url,
412
+ need_unpack=True,
413
+ bin_path=Path(zrok_bin),
414
+ start_commands=com,
415
+ read_from_stderr=True,
416
+ lines_to_read=2,
417
+ url_pattern=r'(?P<url>https?://\S+\.share\.zrok\.io)'
418
+ )
419
+
420
+
421
+ def get_gradio_url(port: int) -> str | None:
422
+ max_attempts = 3
423
+ for attempt in range(max_attempts):
424
+ try:
425
+ response = get_url('https://api.gradio.app/v2/tunnel-request')
426
+ if response and response.status_code == 200:
427
+ remote_host, remote_port = response.json()[0]['host'], int(response.json()[0]['port'])
428
+ com = [f'{gradio_bin}', 'http', '-n', 'random', '-l', f'{port}', '-i', '127.0.0.1', '--uc', '--sd',
429
+ 'random', '--ue', '--server_addr', f'{remote_host}:{remote_port}', '--disable_log_color']
430
+ return get_revproxy_url(
431
+ bin_url='https://cdn-media.huggingface.co/frpc-gradio-0.1/frpc_linux_amd64',
432
+ need_unpack=False,
433
+ bin_path=Path(gradio_bin),
434
+ start_commands=com,
435
+ read_from_stderr=False,
436
+ lines_to_read=3,
437
+ )
438
+ except Exception as e:
439
+ if attempt < max_attempts - 1:
440
+ print(f'попытка {attempt + 1} получить ссылку градио провалилась: {e}. пробуем еще...')
441
+ sleep(5)
442
+ return None
443
+ else:
444
+ raise RuntimeError(f'после трех попыток поднять туннель градио не удалось: {e}')
445
+ return None
446
+
447
+
448
+ proxies_functions = {
449
+ 'zrok': get_zrok_url,
450
+ 'tmole': get_tmole_url,
451
+ 'tunwg': get_tunwg_url,
452
+ 'cloudflared': get_cloudflared_url,
453
+ 'localt': get_localt_url,
454
+ 'gradio': get_gradio_url
455
+ }
456
+
457
+
458
+ def try_all(port: int) -> str:
459
+ results = []
460
+ for proxy_name, proxy_func in proxies_functions.items():
461
+ try:
462
+ url = proxy_func(port)
463
+ results.append(url)
464
+ except Exception as e:
465
+ print(f'{proxy_name}: {e}')
466
+ return '\n'.join(results)
467
+
468
+
469
+ def get_share_link(host: str, port: int) -> str:
470
+ if host in proxies_functions:
471
+ return proxies_functions[host](port)
472
+ elif host == 'all':
473
+ return try_all(port)
474
+ else:
475
+ available_proxies_functions = ', '.join([func.__name__ for func in proxies_functions.values()])
476
+ return f'у меня нет функции ассоциированной с {host}, доступные функции:\n{available_proxies_functions}'
477
+
478
+
479
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
480
+
481
+ """
482
+
483
+ # как использовать:
484
+
485
+ port = 7860 # порт, на котором запущен веб-интерфейс
486
+
487
+ # чтобы использовать определенный прокси-сервер, нужно передать его название как первый аргумент:
488
+
489
+ link = get_share_link('gradio', port)
490
+ print(link)
491
+
492
+ link = get_share_link('zrok', port)
493
+ print(link)
494
+
495
+ link = get_share_link('cloudflared', port)
496
+ print(link)
497
+
498
+ link = get_share_link('tmole', port)
499
+ print(link)
500
+
501
+ link = get_share_link('tunwg', port)
502
+ print(link)
503
+
504
+ link = get_share_link('localt', port)
505
+ print(link)
506
+
507
+ # или все сразу (не рекомендуется):
508
+ all_possible_links = get_share_link('all', port)
509
+ print(all_possible_links)
510
+
511
+ """