Move to new tubes API
[dtube-test.git] / dtube-test.py
blobae1c39520b2e7414ebc1c6927361fb9d1c7e557e
1 #!/usr/bin/python
2 # -*- coding:Utf-8 -*-
4 # Dtube test
5 # Copyright (C) 2009 Olivier Le Thanh Duong, Guillaume Desmottes
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import sys
21 import logging
22 logging.basicConfig(level=logging.DEBUG)
24 import dbus
25 from dbus.service import method, signal, Object
26 import gobject
28 from connection_watcher import ConnectionWatcher
30 from telepathy.interfaces import CHANNEL_TYPE_CONTACT_LIST, CONNECTION_INTERFACE_REQUESTS,\
31 CONNECTION_INTERFACE_SIMPLE_PRESENCE, CHANNEL_INTERFACE_GROUP, CHANNEL_INTERFACE
32 from telepathy.constants import HANDLE_TYPE_LIST, HANDLE_TYPE_CONTACT, CONNECTION_PRESENCE_TYPE_AVAILABLE,\
33 CONNECTION_PRESENCE_TYPE_AWAY, CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY, CONNECTION_PRESENCE_TYPE_BUSY,\
34 TUBE_STATE_OPEN
35 from telepathy.client.channel import Channel
36 from telepathy.client.conn import Connection
39 TUBE_SERVICE = "be.staz.DTubetest"
40 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
42 # TODO: import when tube API is stable
43 CHANNEL_INTERFACE_TUBE = CHANNEL_INTERFACE + ".Interface.Tube.DRAFT"
44 CHANNEL_TYPE_DBUS_TUBE = CHANNEL_INTERFACE + ".Type.DBusTube.DRAFT"
46 TUBE_CHANNEL_STATE_LOCAL_PENDING = 0
47 TUBE_CHANNEL_STATE_REMOTE_PENDING = 1
48 TUBE_CHANNEL_STATE_OPEN = 2
49 TUBE_CHANNEL_STATE_NOT_OFFERED = 3
51 # List of presences types we consider as online
52 ONLINE_TYPES = [CONNECTION_PRESENCE_TYPE_AVAILABLE,
53 CONNECTION_PRESENCE_TYPE_AWAY,
54 CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY,
55 CONNECTION_PRESENCE_TYPE_BUSY]
57 def search_contact_from_id(contact, conn):
58 """Return the handle that match the id in given connexion"""
60 if CONNECTION_INTERFACE_REQUESTS not in conn:
61 logging.warning("CONNECTION_INTERFACE_REQUESTS not implemented in %s" % (conn.service_name))
62 return None
64 # get contacts list
65 yours, path, props = conn[CONNECTION_INTERFACE_REQUESTS].EnsureChannel({
66 'org.freedesktop.Telepathy.Channel.ChannelType': CHANNEL_TYPE_CONTACT_LIST,
67 'org.freedesktop.Telepathy.Channel.TargetHandleType': HANDLE_TYPE_LIST,
68 'org.freedesktop.Telepathy.Channel.TargetID': 'subscribe'})
70 chan = Channel(conn.service_name, path)
71 contacts = chan[CHANNEL_INTERFACE_GROUP].GetMembers()
72 ids = conn.InspectHandles(HANDLE_TYPE_CONTACT, contacts)
74 for handle, id in zip(contacts, ids):
75 if id == contact:
76 return handle
78 def contact_is_online(handle, conn):
79 """Is contact online?"""
80 presences = conn[CONNECTION_INTERFACE_SIMPLE_PRESENCE].GetPresences([handle])
81 type, status, msg = presences[handle]
82 return type in ONLINE_TYPES
84 def offer_tube(conn, handle, tube_service):
85 """Offer a dtube to contact designed by @handle"""
86 # FIXME: check if contact supports our tube
87 yours, path, props = conn[CONNECTION_INTERFACE_REQUESTS].EnsureChannel({
88 'org.freedesktop.Telepathy.Channel.ChannelType': CHANNEL_TYPE_DBUS_TUBE,
89 'org.freedesktop.Telepathy.Channel.TargetHandleType': HANDLE_TYPE_CONTACT,
90 'org.freedesktop.Telepathy.Channel.TargetHandle': handle,
91 CHANNEL_TYPE_DBUS_TUBE + '.ServiceName': tube_service})
93 def tube_state_changed_cb(state):
94 if state == TUBE_STATE_OPEN:
95 print "Tube accepted "
97 tube_conn = dbus.connection.Connection(address)
98 # Create and export the object
99 obj = ExempleObject(tube_conn, "/Example")
101 elif state == TUBE_CHANNEL_STATE_REMOTE_PENDING:
102 print "Other player is invited, waiting for response..."
103 else:
104 print "Tube state changed", state
106 def tube_closed_cb():
107 print "Tube closed"
109 chan = Channel(conn.service_name, path)
110 chan[CHANNEL_INTERFACE_TUBE].connect_to_signal('TubeChannelStateChanged', tube_state_changed_cb)
111 chan[CHANNEL_INTERFACE].connect_to_signal('Closed', tube_closed_cb)
112 print "Invited contact on %s" % tube_service
113 address = chan[CHANNEL_TYPE_DBUS_TUBE].OfferDBusTube({})
115 def offer_tube_to_contact_cb(watcher, conn, contact, tube_service):
116 """When a new connection is added, check if @contact is present on and online on it, if found offer him a tube of @tube_service"""
117 #TODO : Remove itself when contact is found.
118 handle = search_contact_from_id(contact, conn)
119 if handle:
120 print "Contact %s found in %s" % (contact, conn.service_name)
121 if contact_is_online(handle, conn):
122 print "contact online"
123 offer_tube(conn, handle, tube_service)
124 else:
125 print "Contact %s not found in %s" % (contact, conn.service_name)
127 class Handler(Object):
128 """Create an Handler service which wait for a connection"""
129 @dbus.service.method("org.gnome.Empathy.TubeHandler",
130 in_signature='soouu', out_signature='')
131 def HandleTube(self, bus_name, connection, channel, handle_type, handle):
132 #We need a try here cause strangly it doesn't display exceptions
133 try:
134 logging.info("Handling a new tube!")
135 # TODO: ask to the user if he wants to accept or decline the tube
136 conn = Connection(bus_name, connection)
137 chan = Channel(bus_name, channel)
139 address = chan[CHANNEL_TYPE_DBUS_TUBE].AcceptDBusTube()
140 tube_conn = dbus.connection.Connection(address)
141 # FIXME This should be in a callback
142 # Get the object from the remote end of the tube
143 obj = tube_conn.get_object(object_path="/Example")
145 # Call a methode on it
146 ret = obj.HelloWorld("Hello world")
147 print ret
149 except Exception, e:
150 print e
151 raise
153 def create_handler(tube_service):
154 """create a D-Bus handler service,
155 which wait for someone to offer us a tube"""
156 logging.info("Creating the handler service")
157 # Open the local session bus
158 bus = dbus.SessionBus()
159 handler_name = "org.gnome.Empathy.DTubeHandler.%s" % tube_service
160 handler_path = "/org/gnome/Empathy/DTubeHandler/%s" % tube_service.replace('.','/')
161 logging.info("Bus name : %s" % handler_name)
162 logging.info("Bus path : %s" % handler_path)
163 name = dbus.service.BusName(handler_name, bus)
164 handler = Handler(bus, handler_path)
165 return name, handler
167 def invite_contact(contact, tube_service):
168 watcher = ConnectionWatcher()
169 print "Looking for contact..."
170 watcher.connect('connection-added', offer_tube_to_contact_cb, contact, tube_service)
172 class ExempleObject(dbus.service.Object):
173 @dbus.service.method("com.example.SampleInterface",
174 in_signature='s', out_signature='as')
175 def HelloWorld(self, hello_message):
176 print (str(hello_message))
177 return ["Hello", " from example-service.py"]
179 if __name__ == "__main__":
181 if sys.argv[1] == '--handler':
182 # We must keep a pointer on those otherwhise they get destroyed
183 name, handler = create_handler(TUBE_SERVICE)
184 else:
185 contact = sys.argv[1]
186 invite_contact(contact, TUBE_SERVICE)
188 loop = gobject.MainLoop()
189 loop.run()
191 # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: