nolith / avahiserve

Avahi mercurial extension. Works only on Linux.

Clone this repository (size: 23.4 KB): HTTPS / SSH
$ hg clone http://code.l0g.in/avahiserve

Changed (Δ5.6 KB):

raw changeset »

aserve/__init__.py (26 lines added, 0 lines removed)

aserve/avahiserve.py (155 lines added, 0 lines removed)

avahiserve.py

Up to file-list aserve/__init__.py:

1
##   avahiserve - Mercurial serve command with avahi publishing
2
##   Copyright (C) 2008  Alessio Caiazza
3
##   
4
##   This program is free software: you can redistribute it and/or modify
5
##   it under the terms of the GNU General Public License as published by
6
##   the Free Software Foundation, either version 3 of the License, or
7
##   any later version.
8
##   
9
##   This program is distributed in the hope that it will be useful,
10
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
##   GNU General Public License for more details.
13
##   
14
##   You should have received a copy of the GNU General Public License
15
##   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17
18
from mercurial import hg
19
from avahiserve import *
20
21
cmdtable = {
22
	# cmd name        function call
23
	"aserve": (avahi_serve,
24
		commands.table['^serve'][1],
25
		"hg aserve [OPTION]...")
26
}

Up to file-list aserve/avahiserve.py:

1
##   avahiserve - Mercurial serve command with avahi publishing
2
##   Copyright (C) 2008  Alessio Caiazza
3
##   
4
##   This program is free software: you can redistribute it and/or modify
5
##   it under the terms of the GNU General Public License as published by
6
##   the Free Software Foundation, either version 3 of the License, or
7
##   any later version.
8
##   
9
##   This program is distributed in the hope that it will be useful,
10
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
##   GNU General Public License for more details.
13
##   
14
##   You should have received a copy of the GNU General Public License
15
##   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17
from mercurial import commands
18
19
import dbus
20
import gobject
21
import avahi
22
from dbus.mainloop.glib import DBusGMainLoop
23
24
VERSION='0.1.0'
25
26
class AvahiReg:
27
28
	def __init__(self, name, port):
29
		self.verbose = False
30
		self.serviceName = "Mercurial"
31
		if name != '':
32
			self.serviceName += ": " + name
33
		self.serviceType = "_http._tcp" # See http://www.dns-sd.org/ServiceTypes.html
34
		self.servicePort = port
35
		self.serviceTXT = ["extension's author=Alessio Caiazza"] #TXT record for the service
36
37
		self.domain = "" # Domain to publish on, default to .local
38
		self.host = "" # Host to publish records for, default to localhost
39
40
		self.group = None #our entry group
41
		self.rename_count = 12 # Counter so we only rename after collisions a sensible number of times
42
43
	def add_service(self):
44
		if self.group is None:
45
			self.group = dbus.Interface(
46
				self.bus.get_object( avahi.DBUS_NAME, self.server.EntryGroupNew()),
47
				avahi.DBUS_INTERFACE_ENTRY_GROUP)
48
			self.group.connect_to_signal('StateChanged', self.entry_group_state_changed)
49
		if self.verbose:
50
			print "Adding service '%s' of type '%s' ..." % (self.serviceName, self.serviceType)
51
		self.group.AddService(
52
			avahi.IF_UNSPEC,    #interface
53
			avahi.PROTO_UNSPEC, #protocol
54
			0,                  #flags
55
			self.serviceName, self.serviceType,
56
			self.domain, self.host,
57
			dbus.UInt16(self.servicePort),
58
			avahi.string_array_to_txt_array(self.serviceTXT))
59
		self.group.Commit()
60
61
	def remove_service(self):
62
		if not group is None:
63
			group.Reset()
64
65
	def server_state_changed(self, state):
66
		if state == avahi.SERVER_COLLISION:
67
			if self.verbose:
68
				print "WARNING: Server name collision"
69
			remove_service()
70
		elif state == avahi.SERVER_RUNNING:
71
			self.add_service()
72
73
	def entry_group_state_changed(self,state, error):
74
75
		if self.verbose:
76
			print "state change: %i" % state
77
78
		if state == avahi.ENTRY_GROUP_ESTABLISHED:
79
			print "Service established."
80
		elif state == avahi.ENTRY_GROUP_COLLISION:
81
82
			rename_count = rename_count - 1
83
			if rename_count > 0:
84
				name = server.GetAlternativeServiceName(name)
85
				if self.verbose:
86
					print "WARNING: Service name collision, changing name to '%s' ..." % name
87
				remove_service()
88
				add_service()
89
90
			else:
91
				if self.verbose:
92
					print "ERROR: No suitable service name found after %i retries, exiting." % n_rename
93
				main_loop.quit()
94
		elif state == avahi.ENTRY_GROUP_FAILURE:
95
			if self.verbose:
96
				print "Error in group state changed", error
97
			main_loop.quit()
98
			return
99
100
	def start(self):
101
		if self.verbose:
102
			print "Starting avahiserve version " + VERSION
103
		DBusGMainLoop( set_as_default=True )
104
		self.bus = dbus.SystemBus()
105
106
		self.server = dbus.Interface(
107
			self.bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
108
			avahi.DBUS_INTERFACE_SERVER )
109
110
		self.server.connect_to_signal( "StateChanged", self.server_state_changed )
111
		self.server_state_changed( self.server.GetState() )
112
	
113
	def stop(self):
114
		if self.verbose:
115
			print "Stopping avahi-publish-service"
116
		if not self.group is None:
117
			self.group.Free()
118
119
# every command must take a ui and and repo as arguments.
120
# opts is a dict where you can find other command line flags
121
#
122
# Other parameters are taken in order from items on the command line that
123
# don't start with a dash.  If no default value is given in the parameter list,
124
# they are required.
125
def avahi_serve(ui, repo, **opts):
126
	# The doc string below will show up in hg help
127
	"""Serve and publish on avahi zeroconf"""
128
129
	#print opts
130
	if opts['port'] != 0:
131
		port = int(opts['port'])
132
	else:
133
		port = 8000
134
	a = AvahiReg(opts['name'], port)
135
136
	if ui.cdata.has_option('web', 'description'):
137
		a.serviceTXT += ["description=" + ui.cdata.get('web','description')]
138
	if ui.cdata.has_option('ui', 'username'):
139
		#remove < and > cose make problems on Avahi Discovery
140
		a.serviceTXT += ["owner=" + 
141
				ui.cdata.get('ui','username')
142
				.replace('<','')
143
				.replace('>','')]
144
145
	a.verbose = ui.verbose
146
	a.start()
147
	try:
148
		commands.serve(ui,repo, **opts)
149
	except KeyboardInterrupt:
150
		pass
151
	
152
	a.stop()
153
154
155