yunohost/data/other/mdns.py
tituspijean 654690b427 Add interfaces selection for mDNS broadcast
- System setting added
- Loop through list of interfaces
2021-07-11 14:17:15 +00:00

120 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""
WIP
Pythonic declaration of mDNS .local domains for YunoHost
Based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py
"""
import os
import sys
import argparse
import asyncio
import logging
import socket
import time
from typing import List
sys.path.insert(0, "/usr/lib/moulinette/")
from yunohost.domain import domain_list
from yunohost.utils.network import get_network_interfaces
from yunohost.settings import settings_get
from moulinette import m18n
from moulinette.interfaces.cli import get_locale
from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf
async def register_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None:
tasks = [aiozc.async_register_service(info) for info in infos]
background_tasks = await asyncio.gather(*tasks)
await asyncio.gather(*background_tasks)
async def unregister_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None:
tasks = [aiozc.async_unregister_service(info) for info in infos]
background_tasks = await asyncio.gather(*tasks)
await asyncio.gather(*background_tasks)
async def close_aiozc(aiozc: AsyncZeroconf) -> None:
await aiozc.async_close()
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
if args.debug:
logging.getLogger('zeroconf').setLevel(logging.DEBUG)
local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ]
m18n.load_namespace("yunohost")
m18n.set_locale(get_locale())
if settings_get('mdns.interfaces'):
wanted_interfaces = settings_get('mdns.interfaces').split()
else:
wanted_interfaces = []
print('No interface listed for broadcast.')
aiozcs = []
interfaces = get_network_interfaces()
for interface in wanted_interfaces:
infos = []
ips = [] # Human-readable IPs
b_ips = [] # Binary-convered IPs
# Parse the IPs and prepare their binary version
try:
ip = interfaces[interface]['ipv4'].split('/')[0]
ips.append(ip)
b_ips.append(socket.inet_pton(socket.AF_INET, ip))
except:
pass
try:
ip = interfaces[interface]['ipv6'].split('/')[0]
ips.append(ip)
b_ips.append(socket.inet_pton(socket.AF_INET6, ip))
except:
pass
# Create a ServiceInfo object for each .local domain
for d in local_domains:
d_domain=d.replace('.local','')
infos.append(
AsyncServiceInfo(
type_="_device-info._tcp.local.",
name=d_domain+f"._device-info._tcp.local.",
addresses=b_ips,
port=80,
server=d+'.',
)
)
print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface)
# Create an AsyncZeroconf object, store it, and start Service registration
aiozc = AsyncZeroconf(interfaces=ips)
aiozcs.append(aiozc)
print("Registration on interface "+interface+"...")
loop = asyncio.get_event_loop()
loop.run_until_complete(register_services(aiozc, infos))
# We are done looping among the interfaces
print("Registration complete. Press Ctrl-c to exit...")
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
pass
finally:
print("Unregistering...")
for aiozc in aiozcs:
loop.run_until_complete(unregister_services(aiozc, infos))
loop.run_until_complete(close_aiozc(aiozc))
print("Unregistration complete.")