I'm trying to port some code, that currently uses the Avahi raw dbus interface, to using the Avahi gobject interface (via gobject introspection from python.)
I have gotten the ServiceBrowser, but I can't get the ServiceResolver to work. Here is my code:
#!/usr/bin/env python
import logging
from gi.repository import Avahi
logging.basicConfig(level=logging.DEBUG)
ac_log = logging.getLogger('Avahi.Client')
sb_log = logging.getLogger('Avahi.ServiceBrowser')
sr_log = logging.getLogger('Avahi.ServiceResolver')
def ac_state_changed(client, state):
ac_log.debug('state_changed: {}'.format(state))
avahi_client = Avahi.Client(flags=0,)
avahi_client.connect('state-changed', ac_state_changed)
avahi_client.start()
def sb_new_service(browser, interface, protocol, name, type, domain, flags ):
sb_log.debug('new: {}'.format(name))
if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
sb_log.debug('resolving: {}'.format(name))
service_resolver = Avahi.ServiceResolver(
interface=interface,
protocol=protocol,
name=name,
type=type,
domain=domain,
aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC,
flags=0,)
service_resolver.connect('found', sr_found)
service_resolver.connect('failure', sr_failure)
service_resolver.attach(avahi_client)
def sb_all_for_now(*args):
sb_log.debug('all_for_now')
seen_all = True
def sb_failure(*args):
sb_log.error('failure: {}'.format(args))
def sr_found(*args):
sr_log.debug('found: {}'.format(args))
def sr_failure(*args):
sr_log.error('failure: {}'.format(args))
service_browser = Avahi.ServiceBrowser(
domain='local',
flags=0,
interface=-1,
protocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC,
type='_workstation._tcp')
service_browser.connect("new_service", sb_new_service)
service_browser.connect("failure", sb_failure)
service_browser.attach(avahi_client)
from gi.repository import GObject
mainloop = GObject.MainLoop()
mainloop.run()
example output:
DEBUG:Avahi.Client:state_changed: <enum GA_CLIENT_STATE_S_RUNNING of type GaClientState>
DEBUG:Avahi.ServiceBrowser:new: Mobi [d8:d3:85:e8:26:3d]
DEBUG:Avahi.ServiceBrowser:resolving: Mobi [d8:d3:85:e8:26:3d]
DEBUG:Avahi.ServiceBrowser:new: garyvdm [00:1d:09:a5:10:54]
DEBUG:Avahi.ServiceBrowser:new: noddy [00:15:c5:c6:46:4b]
DEBUG:Avahi.ServiceBrowser:resolving: noddy [00:15:c5:c6:46:4b]
DEBUG:Avahi.ServiceBrowser:new: crack [00:1c:26:20:e0:1d]
DEBUG:Avahi.ServiceBrowser:resolving: crack [00:1c:26:20:e0:1d]
DEBUG:Avahi.ServiceBrowser:new: opium [00:1d:09:c1:ed:cf]
DEBUG:Avahi.ServiceBrowser:resolving: opium [00:1d:09:c1:ed:cf]
DEBUG:Avahi.ServiceBrowser:new: gerard-vm [00:0c:29:d0:2a:af]
DEBUG:Avahi.ServiceBrowser:resolving: gerard-vm [00:0c:29:d0:2a:af]
DEBUG:Avahi.ServiceBrowser:all_for_now
^CTraceback (most recent call last):
File "pacshare/xfer.py", line 65, in <module>
mainloop.run()
KeyboardInterrupt
I left it running for about 1min before I pressed ctrl-c. As you can see, I'm calling the ServiceResolver, but the sr_found and sr_failure methods never get called. How can I get this to work?
(I can't find any other code that does this on http://code.ohloh.net/, so I suspect I may be the first person trying to do this)
Basically your code works just right. The only problem it has is reference counting.
When the python interpreter reaches the end of sb_new_service()
, it will delete all objects that are no longer being referenced. As you have specified service_resolver
as a local variable, this object will also be deleted.
To prevent this from happening, you could just add service_resolver
to a (global) list of resolvers like this:
resolvers = []
def sb_new_service(browser, interface, protocol, name, type, domain, flags ):
sb_log.debug('new: {}'.format(name))
if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
sb_log.debug('resolving: {}'.format(name))
service_resolver = Avahi.ServiceResolver(
interface=interface,
protocol=protocol,
name=name,
type=type,
domain=domain,
aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC,
flags=0,)
service_resolver.connect('found', sr_found)
service_resolver.connect('failure', sr_failure)
service_resolver.attach(avahi_client)
global resolvers
resolvers.append(service_resolver)
Then your code should work fine.