Merge lp://qastaging/~cmiller/desktopcouch/kill-asyncore-use-twisted into lp://qastaging/desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Elliot Murphy
Approved revision: 3
Merged at revision: not available
Proposed branch: lp://qastaging/~cmiller/desktopcouch/kill-asyncore-use-twisted
Merge into: lp://qastaging/desktopcouch
Diff against target: None lines
To merge this branch: bzr merge lp://qastaging/~cmiller/desktopcouch/kill-asyncore-use-twisted
Reviewer Review Type Date Requested Status
Elliot Murphy (community) Approve
Review via email: mp+8597@code.qastaging.launchpad.net

Commit message

[r=statik] Change pairing tool to twisted instead of asyncore.

To post a comment you must log in.
Revision history for this message
Chad Miller (cmiller) wrote :

I, for one, welcome our new twisted overlords.

Revision history for this message
Elliot Murphy (statik) wrote :

Looks good! please file a bug for the couple of FIXME spots.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'desktopcouch/pair/couchdb_pairing/dbus_io.py'
--- desktopcouch/pair/couchdb_pairing/dbus_io.py 2009-07-08 17:48:11 +0000
+++ desktopcouch/pair/couchdb_pairing/dbus_io.py 2009-07-10 22:13:01 +0000
@@ -26,7 +26,7 @@
2626
2727
28def get_local_hostname():28def get_local_hostname():
29 """Get the name of this host, an ASCII-encoded string."""29 """Get the name of this host, as Unicode host and domain parts."""
30 bus, server = get_dbus_bus_server()30 bus, server = get_dbus_bus_server()
31 return server.GetHostName(), server.GetDomainName()31 return server.GetHostName(), server.GetDomainName()
3232
3333
=== modified file 'desktopcouch/pair/couchdb_pairing/network_io.py'
--- desktopcouch/pair/couchdb_pairing/network_io.py 2009-07-08 17:48:11 +0000
+++ desktopcouch/pair/couchdb_pairing/network_io.py 2009-07-10 22:13:01 +0000
@@ -15,11 +15,14 @@
15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
16"""All inter-tool communication."""16"""All inter-tool communication."""
1717
18import asyncore
19import socket
20import logging18import logging
21import hashlib19import hashlib
2220
21from twisted.internet import reactor
22from twisted.internet.protocol import ServerFactory, ReconnectingClientFactory
23from twisted.protocols import basic
24from twisted.internet import ssl
25
23import dbus26import dbus
2427
25try:28try:
@@ -29,132 +32,81 @@
29 get_remote_hostname = lambda addr: None32 get_remote_hostname = lambda addr: None
30 33
3134
32# asyncore is ancient. pylint: disable-msg=W0233
33# asyncore overridden. pylint: disable-msg=C0111
34
35message_terminator = "\n"
36hash = hashlib.sha51235hash = hashlib.sha512
3736
38def receive_up_to_char(s, buffer_list, sentinel=message_terminator):37
39 message = s.recv(4098)38class ListenForInvitations():
40 if len(message) == 0:
41 return None
42
43 buffer_list.append(message)
44 total_so_far = "".join(buffer_list)
45 if sentinel not in total_so_far:
46 return None
47
48 message, extra = total_so_far.split(sentinel, 1)
49 buffer_list[:] = [ extra ]
50
51 return message
52
53
54
55class ListenForInvitations(asyncore.dispatcher):
56 """Narrative "Alice".39 """Narrative "Alice".
5740
58 This is the first half of a TCP listening socket. We spawn off41 This is the first half of a TCP listening socket. We spawn off
59 processors when we accept invitation-connections."""42 processors when we accept invitation-connections."""
6043
61 def __init__(self, get_secret_from_user, on_close, local_map=False):44 def __init__(self, get_secret_from_user, on_close):
62 self.logging = logging.getLogger("ListenForInvitations")45 """Initialize."""
6346 self.logging = logging.getLogger(self.__class__.__name__)
64 if local_map:47
65 if not hasattr(local_map, "get"):48 self.factory = ProcessAnInvitationFactory(get_secret_from_user,
66 local_map = dict()49 on_close)
67 self.__map = local_map50 self.listening_port = reactor.listenTCP(0, self.factory)
68 asyncore.dispatcher.__init__(self, map=self.__map)
69 else:
70 self.__map = None
71 asyncore.dispatcher.__init__(self)
72
73 self.get_secret_from_user = get_secret_from_user
74 self.on_close = on_close
75
76 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
77 self.bind(("", 0))
78 self.listen(5)
79
80 def process(self):
81 """How we jump into asyncore processing. Call this occasionally."""
82 asyncore.loop(0.01, False, self.__map, 3)
83 return True
8451
85 def get_local_port(self):52 def get_local_port(self):
86 """We created a socket, and the caller needs to know what our port53 """We created a socket, and the caller needs to know what our port
87 number is, so it can advertise it."""54 number is, so it can advertise it."""
8855
89 bogus_address, port = self.getsockname()56 port = self.listening_port.getHost().port
90 self.logging.info("local port to receive invitations is %s", port)57 self.logging.info("local port to receive invitations is %s", port)
91 return port58 return port
9259
93 def handle_accept(self):60 def close(self):
94 s, remote_addr = self.accept()61 """Called from the UI when a window is destroyed and we do not need
95 self.logging.debug("accepted connection from %s", s)62 this connection any more."""
96 ProcessAnInvitation(self.get_secret_from_user, s, self.on_close,63 self.listening_port.stopListening()
97 local_map=self.__map)64
9865
9966class ProcessAnInvitationProtocol(basic.LineReceiver):
100class ProcessAnInvitation(asyncore.dispatcher_with_send):
101 """Narrative "Alice".67 """Narrative "Alice".
10268
103 Listen for messages, and when we receive one, call the display callback69 Listen for messages, and when we receive one, call the display callback
104 function with the inviter details plus a key."""70 function with the inviter details plus a key."""
10571
106 def __init__(self, get_secret_from_user, sock, on_close, local_map=False):72 def __init__(self):
107 self.logging = logging.getLogger("ProcessAnInvitation")73 """Initialize."""
108 74 self.logging = logging.getLogger(self.__class__.__name__)
109 if local_map:
110 assert hasattr(local_map, "get")
111 asyncore.dispatcher_with_send.__init__(self, sock, map=local_map)
112 else:
113 asyncore.dispatcher_with_send.__init__(self, sock)
114
115 self.expected_hash = None75 self.expected_hash = None
116 self.public_seed = None76 self.public_seed = None
11777
118 self.get_secret_from_user = get_secret_from_user78 def connectionMade(self):
119 self.on_close = on_close79 """Called when a connection is made. No obligation here."""
120 self.recv_buffers = []80 basic.LineReceiver.connectionMade(self)
121 self.logging.debug("initialized")81
12282 def connectionLost(self):
123 def handle_connect(self):83 """Called when a connection is lost."""
124 self.logging.debug("connecting")84 self.logging.debug("connection lost")
12585 basic.LineReceiver.connectionLost(self)
126 def handle_close(self):86
127 self.logging.debug("closing")87 def lineReceived(self, message):
128 self.on_close()88 """Handler for receipt of a message from the Bob end."""
129 self.close()
130
131 def handle_read(self):
132 message = receive_up_to_char(self, self.recv_buffers)
133 if message is None:
134 return
135
136 h = hash()89 h = hash()
137 digest_nybble_count = h.digest_size * 290 digest_nybble_count = h.digest_size * 2
138 self.expected_hash = message[0:digest_nybble_count]91 self.expected_hash = message[0:digest_nybble_count]
139 self.public_seed = message[digest_nybble_count:]92 self.public_seed = message[digest_nybble_count:]
140 self.get_secret_from_user(self.addr[0], self.check_secret_from_user,93 self.factory.get_secret_from_user(self.transport.getPeer().host,
94 self.check_secret_from_user,
141 self.send_secret_to_remote)95 self.send_secret_to_remote)
142 96
143 def send_secret_to_remote(self, secret_message):97 def send_secret_to_remote(self, secret_message):
144 """A callback for the invitation protocol to start a new phase 98 """A callback for the invitation protocol to start a new phase
145 involving the other end getting the hash-digest of the public 99 involving the other end getting the hash-digest of the public
146 seed and a secret we receive as a parameter."""100 seed and a secret we receive as a parameter."""
147
148 h = hash()101 h = hash()
149 h.update(self.public_seed)102 h.update(self.public_seed)
150 h.update(secret_message)103 h.update(secret_message)
151 self.send(h.hexdigest() + message_terminator)104 self.sendLine(h.hexdigest())
152 105
153 def check_secret_from_user(self, secret_message):106 def check_secret_from_user(self, secret_message):
154 """A callback for the invitation protocol to verify the secret107 """A callback for the invitation protocol to verify the secret
155 that the user gives, against the hash we received over the108 that the user gives, against the hash we received over the
156 network."""109 network."""
157
158 h = hash()110 h = hash()
159 h.update(secret_message)111 h.update(secret_message)
160 digest = h.hexdigest()112 digest = h.hexdigest()
@@ -163,89 +115,111 @@
163 h = hash()115 h = hash()
164 h.update(self.public_seed)116 h.update(self.public_seed)
165 h.update(secret_message)117 h.update(secret_message)
166 self.send(h.hexdigest() + message_terminator)118 self.sendLine(h.hexdigest())
167119
168 self.logging.debug("User knew secret!")120 self.logging.debug("User knew secret!")
121
122 self.transport.loseConnection()
169 return True123 return True
170124
171 self.logging.info("User secret %r is wrong.", secret_message)125 self.logging.info("User secret %r is wrong.", secret_message)
172 return False126 return False
173127
174# def handle_error(self, *args):128
175# self.logging.error("%s", args)129class ProcessAnInvitationFactory(ServerFactory):
176130 """Hold configuration values for all the connections, and fire off a
177131 protocol to handle the data sent and received."""
178class SendInvitation(asyncore.dispatcher_with_send):132
179 """Narrative "Bob".133 protocol = ProcessAnInvitationProtocol
180 """134
181135 def __init__(self, get_secret_from_user, on_close):
182 def __init__(self, host, port, auth_complete_cb, secret_message,136 self.logging = logging.getLogger(self.__class__.__name__)
183 public_seed, on_close, local_map=False):137 self.get_secret_from_user = get_secret_from_user
184 self.logging = logging.getLogger("SendInvitation")
185
186 if local_map:
187 if not hasattr(local_map, "get"):
188 local_map = dict()
189 self.__map = local_map
190 asyncore.dispatcher_with_send.__init__(self, map=self.__map)
191 else:
192 self.__map = None
193 asyncore.dispatcher_with_send.__init__(self)
194
195 self.auth_complete_cb = auth_complete_cb
196 self.on_close = on_close138 self.on_close = on_close
197 139
198 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)140
199 self.connect((host, port))141class SendInvitationProtocol(basic.LineReceiver):
200142 """Narrative "Bob"."""
201 self.recv_buffers = []143
202144 def __init__(self):
203 self.logging.debug("secret is %r", secret_message)145 """Initialize."""
204146 self.logging = logging.getLogger(self.__class__.__name__)
205 h = hash()147 self.logging.debug("initialized")
206 h.update(secret_message)148
207 self.send(h.hexdigest() + public_seed + message_terminator)149 def connectionMade(self):
208150 """Fire when a connection is made to the listener. No obligation
209 h = hash()151 here."""
210 h.update(public_seed)152 self.logging.debug("connection made")
211 h.update(secret_message)153
154 h = hash()
155 h.update(self.factory.secret_message)
156 self.sendLine(h.hexdigest() + self.factory.public_seed)
157
158 h = hash()
159 h.update(self.factory.public_seed)
160 h.update(self.factory.secret_message)
212 self.expected_hash_of_secret = h.hexdigest()161 self.expected_hash_of_secret = h.hexdigest()
213162
214 def process(self):163
215 """How we jump into asyncore processing. Call this occasionally."""164 def lineReceived(self, message):
216 asyncore.loop(0.01, False, self.__map, 3)165 """Handler for receipt of a message from the Alice end."""
217 return True
218
219 def handle_connect(self):
220 self.logging.debug("connecting")
221
222 def handle_read(self):
223 message = receive_up_to_char(self, self.recv_buffers)
224 if message is None:
225 return
226 self.logging.debug("received %r", message)
227 if message == self.expected_hash_of_secret:166 if message == self.expected_hash_of_secret:
228 remote_host = self.socket.getpeername()[0]167 remote_host = self.transport.getPeer().host
229 try:168 try:
230 remote_hostname = get_remote_hostname(remote_host)169 remote_hostname = get_remote_hostname(remote_host)
231 except dbus.exceptions.DBusException:170 except dbus.exceptions.DBusException:
232 remote_hostname = None171 remote_hostname = None
233 self.auth_complete_cb(remote_hostname, "(port)", "(info)")172 self.factory.auth_complete_cb(remote_hostname, "(port)", "(info)")
173 self.transport.loseConnection()
234 else:174 else:
235 self.logging.warn("Expected %r from invitation.",175 self.logging.warn("Expected %r from invitation.",
236 self.expected_hash_of_secret)176 self.expected_hash_of_secret)
237177
238 def handle_close(self):178 def connectionLost(self):
239 self.logging.debug("closing")179 """When a connected socked is broken, this is fired."""
240 self.on_close()180 self.logging.info("connection lost.")
241 self.close()181 basic.LineReceiver.connectionLost(self)
242182
243# def handle_error(self, *args):183
244# self.logging.error("%s", args)184class SendInvitationFactory(ReconnectingClientFactory):
245185 """Hold configuration values for all the connections, and fire off a
246186 protocol to handle the data sent and received."""
247187
248if __name__ == "__main__":188 protocol = SendInvitationProtocol
249 logging.basicConfig(level=logging.DEBUG, format=189
250 "%(asctime)s [%(process)d] %(levelname)s - %(name)s %(message)s") 190 def __init__(self, auth_complete_cb, secret_message, public_seed,
251191 on_close):
192 self.logging = logging.getLogger(self.__class__.__name__)
193 self.auth_complete_cb = auth_complete_cb
194 self.secret_message = secret_message
195 self.public_seed = public_seed
196 self.on_close = on_close
197 self.logging.debug("initialized")
198
199 def close(self):
200 """Called from the UI when a window is destroyed and we do not need
201 this connection any more."""
202 self.logging.warn("close not handled properly") # FIXME
203
204 def clientConnectionFailed(self, connector, reason):
205 """When we fail to connect to the listener, this is fired."""
206 self.logging.warn("connect failed. %s", reason)
207 ReconnectingClientFactory.clientConnectionFailed(self, connector,
208 reason)
209
210 def clientConnectionLost(self, connector, reason):
211 """When a connected socked is broken, this is fired."""
212 self.logging.info("connection lost. %s", reason)
213 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
214
215
216def start_send_invitation(host, port, auth_complete_cb, secret_message,
217 public_seed, on_close):
218 """Instantiate the factory to hold configuration data about sending an
219 invitation and let the reactor add it to its event-handling loop by way of
220 starting a TCP connection."""
221 factory = SendInvitationFactory(auth_complete_cb, secret_message,
222 public_seed, on_close)
223 reactor.connectTCP(host, port, factory)
224
225 return factory
252226
=== modified file 'desktopcouch/pair/pair.py'
--- desktopcouch/pair/pair.py 2009-07-08 17:48:11 +0000
+++ desktopcouch/pair/pair.py 2009-07-10 22:13:01 +0000
@@ -52,6 +52,11 @@
52import random52import random
53import cgi53import cgi
5454
55from twisted.internet import gtk2reactor
56gtk2reactor.install()
57from twisted.internet.reactor import run as run_program
58from twisted.internet.reactor import stop as stop_program
59
55import pygtk60import pygtk
56pygtk.require('2.0')61pygtk.require('2.0')
57import gtk62import gtk
@@ -64,7 +69,6 @@
64discovery_tool_version = "1"69discovery_tool_version = "1"
6570
6671
67
68def generate_secret(length=7):72def generate_secret(length=7):
69 """Create a secret that is easy to write and read. We hate ambiguity and73 """Create a secret that is easy to write and read. We hate ambiguity and
70 errors."""74 errors."""
@@ -124,7 +128,6 @@
124128
125 def destroy(self, widget, data=None):129 def destroy(self, widget, data=None):
126 """The window is destroyed."""130 """The window is destroyed."""
127 gobject.source_remove(self.inviter_loop)
128 self.inviter.close()131 self.inviter.close()
129132
130 def auth_completed(self, remote_host, remote_port, remote_info):133 def auth_completed(self, remote_host, remote_port, remote_info):
@@ -154,10 +157,9 @@
154 self.secret_message = secret_message157 self.secret_message = secret_message
155 self.public_seed = generate_secret()158 self.public_seed = generate_secret()
156159
157 self.inviter = network_io.SendInvitation(hostname, port, 160 self.inviter = network_io.start_send_invitation(hostname, port,
158 self.auth_completed, self.secret_message, self.public_seed,161 self.auth_completed, self.secret_message, self.public_seed,
159 self.on_close, local_map=False)162 self.on_close)
160 self.inviter_loop = gobject.idle_add(self.inviter.process)
161163
162 top_vbox = gtk.VBox()164 top_vbox = gtk.VBox()
163 self.window.add(top_vbox)165 self.window.add(top_vbox)
@@ -173,6 +175,12 @@
173 top_vbox.pack_start(text, False, False, 10)175 top_vbox.pack_start(text, False, False, 10)
174 text.show()176 text.show()
175177
178 cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL)
179 cancel_button.set_border_width(3)
180 cancel_button.connect("clicked", lambda widget: self.window.destroy())
181 top_vbox.pack_end(cancel_button, False, False, 10)
182 cancel_button.show()
183
176 self.window.show_all()184 self.window.show_all()
177185
178186
@@ -293,8 +301,6 @@
293 if self.advertisement is not None:301 if self.advertisement is not None:
294 self.advertisement.die()302 self.advertisement.die()
295 self.listener.close()303 self.listener.close()
296 if self.listener_loop is not None:
297 gobject.source_remove(self.listener_loop)
298304
299 def receive_invitation_challenge(self, remote_address, is_secret_valid,305 def receive_invitation_challenge(self, remote_address, is_secret_valid,
300 send_secret):306 send_secret):
@@ -317,9 +323,7 @@
317323
318 self.listener = network_io.ListenForInvitations(324 self.listener = network_io.ListenForInvitations(
319 self.receive_invitation_challenge, 325 self.receive_invitation_challenge,
320 lambda: self.window.destroy(),326 lambda: self.window.destroy())
321 local_map=False)
322 self.listener_loop = gobject.idle_add(self.listener.process)
323327
324 listen_port = self.listener.get_local_port()328 listen_port = self.listener.get_local_port()
325329
@@ -433,7 +437,7 @@
433437
434 def destroy(self, widget, data=None):438 def destroy(self, widget, data=None):
435 """The window was destroyed."""439 """The window was destroyed."""
436 gtk.main_quit()440 stop_program()
437441
438 def create_pick_pane(self, container):442 def create_pick_pane(self, container):
439 """Set up the pane that contains what's necessary to choose an443 """Set up the pane that contains what's necessary to choose an
@@ -633,6 +637,7 @@
633def main(args):637def main(args):
634 """Start execution."""638 """Start execution."""
635 global pick_or_listen # pylint: disable-msg=W0601639 global pick_or_listen # pylint: disable-msg=W0601
640
636 logging.basicConfig(level=logging.DEBUG, format=641 logging.basicConfig(level=logging.DEBUG, format=
637 "%(asctime)s [%(process)d] %(name)s:%(levelname)s: %(message)s")642 "%(asctime)s [%(process)d] %(name)s:%(levelname)s: %(message)s")
638643
@@ -641,7 +646,7 @@
641 try:646 try:
642 logging.debug("starting couchdb pairing tool")647 logging.debug("starting couchdb pairing tool")
643 pick_or_listen = PickOrListen()648 pick_or_listen = PickOrListen()
644 return gtk.main()649 return run_program()
645 finally:650 finally:
646 logging.debug("exiting couchdb pairing tool")651 logging.debug("exiting couchdb pairing tool")
647652
648653
=== modified file 'desktopcouch/pair/tests/test_network_io.py'
--- desktopcouch/pair/tests/test_network_io.py 2009-07-08 17:48:11 +0000
+++ desktopcouch/pair/tests/test_network_io.py 2009-07-10 22:13:01 +0000
@@ -14,15 +14,30 @@
14# You should have received a copy of the GNU Lesser General Public License14# You should have received a copy of the GNU Lesser General Public License
15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.15# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
1616
17
18import pygtk
19pygtk.require('2.0')
20import gtk
21
22from twisted.internet import gtk2reactor
23gtk2reactor.install()
24from twisted.internet import reactor, task
25
26
17if __name__ == "__main__":27if __name__ == "__main__":
18 import sys, os28 import sys, os
19 sys.path.append(os.pardir)29 sys.path.append(os.pardir)
20 from couchdb_pairing.network_io import SendInvitation, ListenForInvitations30 from couchdb_pairing.network_io import start_send_invitation, ListenForInvitations
31 from couchdb_pairing.dbus_io import get_local_hostname
21else:32else:
22 from ..couchdb_pairing.network_io import SendInvitation, ListenForInvitations33 from ..couchdb_pairing.network_io import start_send_invitation, ListenForInvitations
34 from ..couchdb_pairing.dbus_io import get_local_hostname
2335
24import unittest36import unittest
2537
38local_hostname = ".".join(get_local_hostname())
39
40
26class TestNetworkIO(unittest.TestCase):41class TestNetworkIO(unittest.TestCase):
2742
28 def setUp(self):43 def setUp(self):
@@ -47,11 +62,9 @@
47 listener_complete_auth()62 listener_complete_auth()
4863
49 def listener_close_socket():64 def listener_close_socket():
50 print "LISTNER!\n\n"
51 self._listener_socket_state = "closed"65 self._listener_socket_state = "closed"
5266
53 def inviter_close_socket():67 def inviter_close_socket():
54 print "INVITER!\n\n"
55 self._inviter_socket_state = "closed"68 self._inviter_socket_state = "closed"
5669
57 def inviter_complete_auth(a, b, c):70 def inviter_complete_auth(a, b, c):
@@ -67,16 +80,21 @@
6780
68 def inviter_display_message(*args):81 def inviter_display_message(*args):
69 """Show message to user."""82 """Show message to user."""
70 print "display message from inviter:", args83 logging.info("display message from inviter: %s", args)
7184
72 self.inviter = SendInvitation("localhost", listener_port,85 self.inviter = start_send_invitation(local_hostname, listener_port,
73 inviter_complete_auth, secret, "seed", inviter_close_socket)86 inviter_complete_auth, secret, "seed", inviter_close_socket)
7487
75 for i in xrange(50):88 def exit_on_success():
76 if self._listener_auth_completed and self._inviter_auth_completed:89 if self._listener_auth_completed and self._inviter_auth_completed:
77 break90 reactor.stop()
78 self.listener.process()91 task.LoopingCall(exit_on_success).start(1.0)
79 self.inviter.process()92
93 def exit_on_timeout():
94 reactor.stop()
95 reactor.callLater(30, exit_on_timeout)
96
97 reactor.run()
8098
81 self.assertTrue(self._listener_auth_completed)99 self.assertTrue(self._listener_auth_completed)
82 self.assertTrue(self._inviter_auth_completed)100 self.assertTrue(self._inviter_auth_completed)
@@ -117,14 +135,12 @@
117135
118 def inviter_display_message(*args):136 def inviter_display_message(*args):
119 """Show message to user."""137 """Show message to user."""
120 print "display message from inviter:", args138 logging.info("display message from inviter: %s", args)
121139
122 self.inviter = SendInvitation("localhost", listener_port,140 self.inviter = start_send_invitation(local_hostname, listener_port,
123 inviter_complete_auth, secret, "seed", inviter_close_socket)141 inviter_complete_auth, secret, "seed", inviter_close_socket)
124142
125 for i in xrange(50):143 # FIXME
126 self.listener.process()
127 self.inviter.process()
128144
129 self.assertFalse(self._listener_auth_completed)145 self.assertFalse(self._listener_auth_completed)
130 self.assertFalse(self._inviter_auth_completed)146 self.assertFalse(self._inviter_auth_completed)
@@ -147,11 +163,9 @@
147163
148164
149 def listener_close_socket():165 def listener_close_socket():
150 print "closed listener"
151 self._listener_socket_state = "closed"166 self._listener_socket_state = "closed"
152167
153 def inviter_close_socket():168 def inviter_close_socket():
154 print "closed inviter"
155 self._inviter_socket_state = "closed"169 self._inviter_socket_state = "closed"
156170
157 def inviter_complete_auth(a, b, c):171 def inviter_complete_auth(a, b, c):
@@ -167,16 +181,12 @@
167181
168 def inviter_display_message(*args):182 def inviter_display_message(*args):
169 """Show message to user."""183 """Show message to user."""
170 print "display message from inviter:", args184 logging.info("display message from inviter: %s", args)
171185
172 self.inviter = SendInvitation("localhost", listener_port,186 self.inviter = start_send_invitation(local_hostname, listener_port,
173 inviter_complete_auth, secret, "seed", inviter_close_socket)187 inviter_complete_auth, secret, "seed", inviter_close_socket)
174188
175 for i in xrange(500):189 # FIXME
176 if self._inviter_socket_state == "closed" and self._listener_socket_state == "closed":
177 break
178 self.listener.process()
179 self.inviter.process()
180190
181 self.assertFalse(self._listener_auth_completed)191 self.assertFalse(self._listener_auth_completed)
182 self.assertFalse(self._inviter_auth_completed)192 self.assertFalse(self._inviter_auth_completed)
@@ -185,8 +195,6 @@
185 self.assertEqual(self._inviter_socket_state, "closed")195 self.assertEqual(self._inviter_socket_state, "closed")
186196
187197
188
189
190if __name__ == "__main__":198if __name__ == "__main__":
191 import logging199 import logging
192 logging.basicConfig(level=logging.ERROR)200 logging.basicConfig(level=logging.ERROR)

Subscribers

People subscribed via source and target branches