#!/usr/bin/env python """ Announce touchSCO-MIDI bridge via zeroconf. """ import socket import netifaces from time import sleep from zeroconf import Zeroconf, ServiceInfo import logging log = logging.getLogger(__name__) TOUCHOSC_BRIDGE = '_touchoscbridge._udp.local.' PORT = 12101 def default_route_interface(): """ Query netifaces for the default route's ip. Note: this only checks for IPv4 addresses. """ interface = netifaces.gateways()['default'] if interface: name = interface[netifaces.AF_INET][1] ip = netifaces.ifaddresses(name)[netifaces.AF_INET][0]['addr'] log.debug("found '{}:{}' as default route.".format(name, ip)) return ip else: raise RuntimeError("default interface not found. Check your network or use --ip switch.") def build_service_info(ip): """Create a zeroconf ServiceInfo for touchoscbridge on for `ip` or the guessed default route interface's IP. """ return ServiceInfo(type_=TOUCHOSC_BRIDGE, name="{}.{}".format( socket.gethostname(), TOUCHOSC_BRIDGE ), address=socket.inet_aton(ip), port=PORT, properties=dict(), server=socket.gethostname() + '.local.') class Advertisement(object): def __init__(self, ip=None): """ :ip: if string `ip` given, register on given IP (if None: default route's IP). """ self.zeroconf = Zeroconf() self.info = build_service_info(ip=ip or default_route_interface()) def register(self): """Registers the service on the network. """ self.zeroconf.register_service(self.info) log.debug("Registered {} on {}:{}".format( self.info.name, self.ip, self.info.port )) def unregister(self): """Unregisters the service. """ self.zeroconf.unregister_service(self.info) log.debug("Unregistered touchoscbridge.") def update(self, ip=None): """Re-register the the service on the network. :ip: if string `ip` is given, use given IP when registering. """ self.unregister() self.info = build_service_info(ip=ip or default_route_interface()) self.register() def close(self): """Free resources. Advertisement.unregister() should be called before closing. """ self.zeroconf.close() def get_ip(self): """:return: the service's IP as a string. """ return socket.inet_ntoa(self.info.address) ip = property(get_ip) if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) service = Advertisement() try: service.register() while True: sleep(0.1) except KeyboardInterrupt: service.unregister() service.close()