mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 05:01:14 -07:00
Update portend-3.0.0
This commit is contained in:
parent
f3f4f9edf6
commit
edd2f21ce1
1 changed files with 44 additions and 26 deletions
|
@ -1,11 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A simple library for managing the availability of ports.
|
A simple library for managing the availability of ports.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function, division
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -13,17 +9,23 @@ import sys
|
||||||
import itertools
|
import itertools
|
||||||
import contextlib
|
import contextlib
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
try:
|
|
||||||
from collections import abc
|
from collections import abc
|
||||||
except ImportError:
|
import urllib.parse
|
||||||
import collections as abc
|
|
||||||
|
|
||||||
from tempora import timing
|
from tempora import timing
|
||||||
|
|
||||||
|
|
||||||
def client_host(server_host):
|
def client_host(server_host):
|
||||||
"""Return the host on which a client can connect to the given listener."""
|
"""
|
||||||
|
Return the host on which a client can connect to the given listener.
|
||||||
|
|
||||||
|
>>> client_host('192.168.0.1')
|
||||||
|
'192.168.0.1'
|
||||||
|
>>> client_host('0.0.0.0')
|
||||||
|
'127.0.0.1'
|
||||||
|
>>> client_host('::')
|
||||||
|
'::1'
|
||||||
|
"""
|
||||||
if server_host == '0.0.0.0':
|
if server_host == '0.0.0.0':
|
||||||
# 0.0.0.0 is INADDR_ANY, which should answer on localhost.
|
# 0.0.0.0 is INADDR_ANY, which should answer on localhost.
|
||||||
return '127.0.0.1'
|
return '127.0.0.1'
|
||||||
|
@ -64,7 +66,7 @@ class Checker(object):
|
||||||
if port is None and isinstance(host, abc.Sequence):
|
if port is None and isinstance(host, abc.Sequence):
|
||||||
host, port = host[:2]
|
host, port = host[:2]
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
host = client_host(host)
|
host = client_host(host) # pragma: nocover
|
||||||
info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
|
info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
|
||||||
list(itertools.starmap(self._connect, info))
|
list(itertools.starmap(self._connect, info))
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ class Checker(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
# the connect succeeded, so the port isn't free
|
# the connect succeeded, so the port isn't free
|
||||||
port, host = sa[:2]
|
host, port = sa[:2]
|
||||||
tmpl = "Port {port} is in use on {host}."
|
tmpl = "Port {port} is in use on {host}."
|
||||||
raise PortNotFree(tmpl.format(**locals()))
|
raise PortNotFree(tmpl.format(**locals()))
|
||||||
|
|
||||||
|
@ -103,6 +105,11 @@ def free(host, port, timeout=float('Inf')):
|
||||||
If timeout is None or ∞, the routine will run indefinitely.
|
If timeout is None or ∞, the routine will run indefinitely.
|
||||||
|
|
||||||
>>> free('localhost', find_available_local_port())
|
>>> free('localhost', find_available_local_port())
|
||||||
|
|
||||||
|
>>> free(None, None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Host values of '' or None are not allowed.
|
||||||
"""
|
"""
|
||||||
if not host:
|
if not host:
|
||||||
raise ValueError("Host values of '' or None are not allowed.")
|
raise ValueError("Host values of '' or None are not allowed.")
|
||||||
|
@ -121,9 +128,6 @@ def free(host, port, timeout=float('Inf')):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
wait_for_free_port = free
|
|
||||||
|
|
||||||
|
|
||||||
def occupied(host, port, timeout=float('Inf')):
|
def occupied(host, port, timeout=float('Inf')):
|
||||||
"""
|
"""
|
||||||
Wait for the specified port to become occupied (accepting requests).
|
Wait for the specified port to become occupied (accepting requests).
|
||||||
|
@ -137,6 +141,11 @@ def occupied(host, port, timeout=float('Inf')):
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Timeout: Port ... not bound on localhost.
|
Timeout: Port ... not bound on localhost.
|
||||||
|
|
||||||
|
>>> occupied(None, None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Host values of '' or None are not allowed.
|
||||||
"""
|
"""
|
||||||
if not host:
|
if not host:
|
||||||
raise ValueError("Host values of '' or None are not allowed.")
|
raise ValueError("Host values of '' or None are not allowed.")
|
||||||
|
@ -155,9 +164,6 @@ def occupied(host, port, timeout=float('Inf')):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
wait_for_occupied_port = occupied
|
|
||||||
|
|
||||||
|
|
||||||
def find_available_local_port():
|
def find_available_local_port():
|
||||||
"""
|
"""
|
||||||
Find a free port on localhost.
|
Find a free port on localhost.
|
||||||
|
@ -188,20 +194,33 @@ class HostPort(str):
|
||||||
|
|
||||||
>>> len(hp)
|
>>> len(hp)
|
||||||
15
|
15
|
||||||
|
|
||||||
|
>>> hp = HostPort('[::1]:32768')
|
||||||
|
|
||||||
|
>>> hp.host
|
||||||
|
'::1'
|
||||||
|
|
||||||
|
>>> hp.port
|
||||||
|
32768
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host(self):
|
def host(self):
|
||||||
host, sep, port = self.partition(':')
|
return urllib.parse.urlparse(f'//{self}').hostname
|
||||||
return host
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def port(self):
|
def port(self):
|
||||||
host, sep, port = self.partition(':')
|
return urllib.parse.urlparse(f'//{self}').port
|
||||||
return int(port)
|
|
||||||
|
@classmethod
|
||||||
|
def from_addr(cls, addr):
|
||||||
|
listen_host, port = addr[:2]
|
||||||
|
plain_host = client_host(listen_host)
|
||||||
|
host = f'[{plain_host}]' if ':' in plain_host else plain_host
|
||||||
|
return cls(':'.join([host, str(port)]))
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main(args=None):
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
def global_lookup(key):
|
def global_lookup(key):
|
||||||
|
@ -210,7 +229,7 @@ def _main():
|
||||||
parser.add_argument('target', metavar='host:port', type=HostPort)
|
parser.add_argument('target', metavar='host:port', type=HostPort)
|
||||||
parser.add_argument('func', metavar='state', type=global_lookup)
|
parser.add_argument('func', metavar='state', type=global_lookup)
|
||||||
parser.add_argument('-t', '--timeout', default=None, type=float)
|
parser.add_argument('-t', '--timeout', default=None, type=float)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args(args)
|
||||||
try:
|
try:
|
||||||
args.func(args.target.host, args.target.port, timeout=args.timeout)
|
args.func(args.target.host, args.target.port, timeout=args.timeout)
|
||||||
except Timeout as timeout:
|
except Timeout as timeout:
|
||||||
|
@ -218,5 +237,4 @@ def _main():
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
__name__ == '__main__' and _main()
|
||||||
_main()
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue