On Jan 29, 2008 9:09 AM, Chris AtLee <[EMAIL PROTECTED]> wrote:
> I'll give Cliff's suggestion a try and see how that goes. The avahi
> bindings for python are pretty barebones, I was hoping not to have to
> get into that :)
I think I've got it working with the python bindings. I had to fork
off another process since gobject's event loop interferes with pylons'
threading. And this means that I need to check the new process'
parent process id periodically. When it gets set to 1 that means the
old parent has died, so the avahi registration process needs to die as
well. I think the same method could be used to kill off a running
avahi-publish-service process if one didn't want to use the python
bindings.
I'm putting the call to this in config/middleware.py right now, just
after the configuration is loaded. Is this the right place for this
sort of thing? e.g.
# Configure the Pylons environment
load_environment(global_conf, app_conf)
a = AvahiRegistration(config.get("package"), config.get("publish_url"))
a.run()
# The Pylons WSGI app
app = PylonsApp()
Cheers,
Chris
# lib/publish.py
"""
Publish this application via avahi.
Based on example at http://www.avahi.org/wiki/PythonPublishExample
and adapted for use with Pylons
"""
import urlparse
import os, sys
import logging
import signal
import dbus
import gobject
import avahi
from dbus.mainloop.glib import DBusGMainLoop
log = logging.getLogger(__name__)
class AvahiRegistration:
"""
A class to advertise a server on a network via avahi.
Typical usage:
# In config/middleware.py just after load_environment()...
>>> a = AvahiRegistration(config['package'], config['publish_url'])
>>> a.run()
``name``: the name of this server. This will also be used to
create the DNS-SD service type which will be
published as "_<name>._tcp"
``publish_url``: the url that external clients can use to access
this application.
"""
def __init__(self, name, publish_url):
s = urlparse.urlparse(publish_url)
self.hostname = s.hostname
self.port = s.port
self.url = s.path
self.serviceName = name
self.serviceType = "_%s._tcp" % self.serviceName
self.bus = None
self.group = None
self.server = None
self.rename_count = 12
def _add_service(self):
if self.group is None:
self.group = dbus.Interface(
self.bus.get_object( avahi.DBUS_NAME,
self.server.EntryGroupNew()),
avahi.DBUS_INTERFACE_ENTRY_GROUP)
self.group.connect_to_signal('StateChanged',
self._entry_group_state_changed)
log.info("Adding service '%s' of type '%s' ...", self.serviceName,
self.serviceType)
domain = ""
self.group.AddService(
avahi.IF_UNSPEC, #interface
avahi.PROTO_UNSPEC, #protocol
0, #flags
self.serviceName, self.serviceType,
domain, self.hostname,
dbus.UInt16(self.port),
avahi.string_array_to_txt_array(self.url))
self.group.Commit()
def _remove_service(self):
if not self.group is None:
self.group.Reset()
def _server_state_changed(self, state):
if state == avahi.SERVER_COLLISION:
log.warn("Server name collision")
self._remove_service()
elif state == avahi.SERVER_RUNNING:
self._add_service()
def _entry_group_state_changed(self, state, error):
log.debug("state change: %i", state)
if state == avahi.ENTRY_GROUP_ESTABLISHED:
log.info("Service established.")
elif state == avahi.ENTRY_GROUP_COLLISION:
self.rename_count -= 1
if self.rename_count > 0:
name = self.server.GetAlternativeServiceName(name)
log.warn("Service name collision, changing name to '%s' ...",
name)
self._remove_service()
add_service()
else:
log.error("No suitable service name found after %i
retries, exiting.", n_rename)
main_loop.quit()
elif state == avahi.ENTRY_GROUP_FAILURE:
log.error("Error in group state changed %s", error)
main_loop.quit()
return
def _check(self):
"""
If our parent process' id is 1, then our real parent has gone
away, and so should we.
"""
if os.getppid() == 1:
self.quit()
return True
def quit(self):
if not self.group is None:
self.group.Free()
log.info("Exiting...")
sys.exit(0)
def run(self):
# We have to fork here so that we have our own set of threads and
# signal handlers, etc. gobject's MainLoop doesn't seem to play nicely
# with Pylons' threading
if os.fork() != 0:
# Return immediately to the controlling process
return
DBusGMainLoop( set_as_default=True )
main_loop = gobject.MainLoop()
self.bus = dbus.SystemBus()
gobject.timeout_add(1000, self._check)
self.server = dbus.Interface(
self.bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
avahi.DBUS_INTERFACE_SERVER )
self.server.connect_to_signal( "StateChanged",
self._server_state_changed )
self._server_state_changed( self.server.GetState() )
try:
main_loop.run()
except KeyboardInterrupt:
pass
self.quit()
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"pylons-discuss" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en
-~----------~----~----~----~------~----~------~--~---