Source code for net.api

# -*- coding: utf-8 -*-
"""
api module
----------

Contains the general network interactions for net.
"""

__all__ = [
    'peers'
]

# std imports
import re
import math
import threading
import subprocess

# package imports
import net

# local imports
from net.imports import ConnectionRefusedError, PermissionError


# threading
LOCK = threading.Lock()
IP_REGEX = re.compile(r'\d+\.\d+\.\d\.\d+')


# cache
PEERS = None


[docs]def peers(refresh=False, groups=None): """ Get a list of all peers on your network. This is a cached values since the call to graph the network can be long. The initial call to this will hang for a few seconds. Under the hood, it is making a shell call to ``arp -a`` which will walk your network and find all hosts. Standard call to get the peers on your network. .. code-block:: python all_peers = net.peers() Refresh all peers in the cache .. code-block:: python all_peers = net.peers(refresh=True) Refresh the cache with peers in group1 .. code-block:: python all_peers = net.peers("group1", refresh=True) :param refresh: Bool :param groups: str :return: """ if PEERS is None or refresh: get_peers(groups) return PEERS
def local_network(): """ Runs ``arp -a`` to get all hosts. :return: list of ip address on the local network """ raw_output = bytes(subprocess.check_output('arp -a', shell=True)).decode('ascii') return IP_REGEX.findall(raw_output) def find_peers_in_block(ips, groups=None): """ Sniffs out peers in the defined group based on the list of ip's :param ips: list of ip addresses :param groups: the list of groups you'd like to filter with. Defaults to the same as the current peer. :return: List of peer addresses """ global PEERS if not groups: groups = [net.Peer().group] # loop over all the addresses for address in ips: # loop over ports for port in net.Peer().ports(): # loop over ports for group in groups: # generate the peer foreign_peer_id = net.Peer().generate_id(port, address, group) if foreign_peer_id == net.Peer().id: continue try: # ping the peer and if it responds with the proper info, # register it. Shut off the logger for this so we dont spam # the console. net.LOGGER.disabled = True info = net.info(peer=foreign_peer_id, time_out=0.1) net.LOGGER.disabled = False LOCK.acquire() PEERS[foreign_peer_id] = info LOCK.release() except (PermissionError, ConnectionRefusedError, OSError): net.LOGGER.disabled = False def get_peers(groups=None): """ Get a list of all valid remote peers. :param groups: List of groups :return: List of peer addresses """ global PEERS PEERS = {} # get this peer for pinging peer = net.Peer() # groups if not groups: groups = [peer.group] # create subnet network = local_network() # logging help total_hosts = len(network) total_ports = len(peer.ports()) total_threads = net.THREAD_LIMIT net.LOGGER.debug( "Calculated network sweep: {0} hosts X {1} ports = {2} pings".format( total_hosts, total_ports, total_hosts * total_ports ) ) # skip the threading integration if the environment does not call for it. if total_threads <= 0: return find_peers_in_block(network, groups) # calculate thread chunk thread_chunks = int(math.ceil(total_hosts/total_threads)) # loop over and spawn threads start = 0 threads = [] for chunk in range(0, total_threads): end = start + thread_chunks # spawn thread with network chunk calculated. thread = threading.Thread( target=find_peers_in_block, args=(network[start:end], groups) ) thread.daemon = True threads.append(thread) thread.start() start = end # wait for all worker threads to finish for thread in threads: thread.join() return PEERS