[gnome-games/sudoku-tube] Ask receiver before open the network game



commit 5c658a45b785aefe88e6c1212e3667b98381f021
Author: Zhang Sen <zh jesse gmail com>
Date:   Fri Aug 14 17:54:45 2009 +0800

    Ask receiver before open the network game
    
    * Also ship the puzzle together with the tube offer, instead of querying
    afterwards.
    * Need to let the initiator be blocked until receiver has agreed.

 gnome-sudoku/src/lib/gnome_sudoku.py |    2 +-
 gnome-sudoku/src/lib/main.py         |  107 ++++++++++++++++++++++------------
 gnome-sudoku/src/lib/networking.py   |    5 --
 gnome-sudoku/src/lib/tp_tube.py      |    9 ++-
 gnome-sudoku/src/lib/tube_handler.py |   21 +++++--
 5 files changed, 91 insertions(+), 53 deletions(-)
---
diff --git a/gnome-sudoku/src/lib/gnome_sudoku.py b/gnome-sudoku/src/lib/gnome_sudoku.py
index 57d16fe..dbf4733 100644
--- a/gnome-sudoku/src/lib/gnome_sudoku.py
+++ b/gnome-sudoku/src/lib/gnome_sudoku.py
@@ -36,7 +36,7 @@ def start_game ():
     parser = optparse.OptionParser(
         version = defaults.VERSION,
         option_list = [
-            optparse.make_option("-v", const=True, action="store_const",
+            optparse.make_option("-d", const=True, action="store_const",
                 dest="debug", help="Print debug information",
                 default=False),
             optparse.make_option("-p", const=True, action="store_const",
diff --git a/gnome-sudoku/src/lib/main.py b/gnome-sudoku/src/lib/main.py
index 3abb0c6..09e23a4 100644
--- a/gnome-sudoku/src/lib/main.py
+++ b/gnome-sudoku/src/lib/main.py
@@ -79,7 +79,7 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
         self.setup_gui()
 
         self.tube_handler = tube_handler.TubeHandler(self._tube_service,
-                tube_received_cb=self._tube_received_cb)
+                tube_received_cb=self._tube_incoming_cb)
 
         self.timer = timer.ActiveTimer(self.w)
         self.won = False
@@ -121,17 +121,24 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
 
     def _auto_load_new(self):
         """Automatically open a new game"""
-        # TODO should use preconfigured level
-        level = self.gconf['game-level']
-        new_puzzle = self.sudoku_maker.get_puzzles(1, [level])
+        new_puzzle = self._generate_new_puzzle()
         if new_puzzle:
-            # new_puzzle is a list, with the form of (<puzzle>, <difficulty>)
-            logger.debug("%s game generated" % level)
-            return new_puzzle[0][0]
+            return new_puzzle
         else:
-            logger.warning("failed to genereate new puzzle")
+            logger.error("failed to genereate new puzzle")
             return None
 
+    def _generate_new_puzzle(self):
+        # TODO should use preconfigured or user-selected level
+        level = self.gconf['game-level']
+        # new_puzzle is a list, with the form of (<puzzle>, <difficulty>)
+        puzzles = self.sudoku_maker.get_puzzles(1, [level])
+        if puzzles:
+            puzzle = puzzles[0][0].replace(" ", "") # delete all spaces
+            logger.debug("%s game generated: %s" % (level, puzzle))
+            return puzzle
+        return None
+
     def _open_game(self, game_type, puzzle):
         """Finally enter the puzzle"""
         self._puzzle = puzzle
@@ -454,8 +461,15 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
             conn, handle, contact = choice
             logger.debug("selected: %s\n  connection: %s\n  handle: %d" % (
                     contact.alias, conn.service_name, handle))
-            self._tube_offer = tp_tube.TubeOffer(conn, handle,
-                    self._tube_service)
+
+            puzzle = self._generate_new_puzzle()
+            if not puzzle:
+                logger.error("failed to genereate new puzzle")
+                # should popup?
+                return
+
+            self._tube_offer = tp_tube.TubeOffer(
+                    conn, handle, self._tube_service, puzzle)
 
             _connecting_label = gtk.Label(_("Connecting..."))
             self._wait_dialog = gtk.Dialog("Sending request...",
@@ -466,7 +480,8 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
             self._wait_dialog.vbox.pack_start(_connecting_label)
             self._wait_dialog.connect("response", self._wait_dialog_response_cb)
 
-            self._tube_offer.connect("offer-succeeded", self._tube_offered_cb)
+            self._tube_offer.connect("offer-succeeded",
+                    self._tube_offered_cb, puzzle)
             self._tube_offer.connect("offer-failed", self._offer_fail_cb)
 
             self._tube_offer.execute()
@@ -501,15 +516,41 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
         self._wait_dialog.vbox.pack_start(fail_label)
         self._wait_dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
 
-    def _tube_received_cb(self, bus, tube):
+    def _tube_incoming_cb(self, bus, tube, params):
         """Called when we receive a tube"""
 
-        def error_cb(exception):
-            logger.error('get puzzle error: %s' % exception)
-            self.new_cb()
+        def reply_cb(dialog, response_id):
+            if response_id == gtk.RESPONSE_ACCEPT:
+                self._process_accepted_tube(bus, tube, puzzle)
+            else:
+                print 'do nothing; reply to initiator'
+
+        try:
+            puzzle = params['puzzle']
+        except KeyError:
+            logger.error("expected parameter missing from %s" % params)
+            return # do nothing
+
+        puzzle = str(puzzle)
+        logger.debug('got offer: %s' % puzzle)
+
+        dialog = gtk.Dialog("New game offer",
+                self.w,
+                gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
+                    gtk.STOCK_NO, gtk.RESPONSE_REJECT))
+        label = gtk.Label("<get-contact> wants to play with you")
+        label.show()
+        dialog.vbox.pack_start(label)
+        dialog.connect("response", reply_cb)
+        dialog.run()
+        dialog.destroy()
+
+    def _process_accepted_tube(self, bus, tube, puzzle):
+        """User has decided to accept the tube
+        """
 
         assert self._is_initiator is None
-        self._close_current_game()
         self._is_initiator = False
         self._bus = bus
         self._tube = tube
@@ -519,34 +560,24 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
         if not self._negotiate_peer_proxy(bus):
             return
 
-        self._peer.get_puzzle(
-                dbus_interface=networking.view_interface,
-                reply_handler=self._got_remote_puzzle_cb,
-                error_handler=error_cb)
-
-    def _got_remote_puzzle_cb(self, puzzle):
-        logger.debug("got puzzle: %s; type: %s" % (puzzle, type(puzzle)))
-        puzzle = str(puzzle)
-        assert len(puzzle) == 81
+        self.do_stop()
         self._open_game(game_selector.NewOrSavedGameSelector.NEW_GAME, puzzle)
-        self._init_side_view_display()
+        self._init_side_view_display(puzzle)
         self._negotiate_sideview_proxy(self._bus)
 
-    def _tube_offered_cb(self, offer, bus, tube):
+    def _tube_offered_cb(self, offer, bus, tube, puzzle):
         """Called when the peer accepts our tube"""
         self._wait_dialog.destroy()
-        self._close_current_game()
         self._tube = tube
         self._tube[tp_tube.CHANNEL_INTERFACE].connect_to_signal(
                 'Closed', self._tube_closed_cb)
-        # use this flag to ensure we are in a new game, and self._puzzle is a
-        # string. FIXME
-        self._auto_open_game(check_saved=False)
+        self.do_stop()
+        self._open_game(game_selector.NewOrSavedGameSelector.NEW_GAME, puzzle)
 
         if not self._negotiate_peer_proxy(bus):
             return
 
-        self._init_side_view_display()
+        self._init_side_view_display(puzzle)
         self._negotiate_sideview_proxy(bus)
 
     def _negotiate_peer_proxy(self, bus):
@@ -565,10 +596,9 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
         return True
 
     def get_puzzle(self):
-        return self._puzzle.replace(" ", "") # delete all spaces
+        return self._puzzle.replace(" ", "")
 
-    def _init_side_view_display(self):
-        puzzle = self.get_puzzle()
+    def _init_side_view_display(self, puzzle):
         for x in range(9):
             for y in range(9):
                 val = int(puzzle[9 * y + x])
@@ -598,7 +628,7 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
 
         self._side_grid_vew.show()
 
-    def _close_current_game (self):
+    def _close_current_game(self):
         """Close current running game
 
         Return True if game is closed, or else return False"""
@@ -642,7 +672,10 @@ class SudokuGame(gconf_wrapper.GConfWrapper):
 
     def _stop_network_game(self, *args):
         logger.debug("close tube-channel")
-        self._tube[tp_tube.CHANNEL_INTERFACE].Close()
+        try:
+            self._tube[tp_tube.CHANNEL_INTERFACE].Close()
+        except dbus.exceptions.DBusException as err:
+            logger.error("can't close tube: %s" % err)
         self._side_grid_vew.reset()
         self._side_grid_vew.hide()
         self._tube = None
diff --git a/gnome-sudoku/src/lib/networking.py b/gnome-sudoku/src/lib/networking.py
index ce3ad3a..958cab5 100644
--- a/gnome-sudoku/src/lib/networking.py
+++ b/gnome-sudoku/src/lib/networking.py
@@ -17,11 +17,6 @@ class Peer(dbus.service.Object):
         self._game = game
 
     @dbus.service.method(dbus_interface=view_interface,
-            in_signature="", out_signature="s")
-    def get_puzzle(self):
-        return self._game.get_puzzle()
-
-    @dbus.service.method(dbus_interface=view_interface,
             in_signature="", out_signature="b")
     def has_won(self):
         return self._game.won
diff --git a/gnome-sudoku/src/lib/tp_tube.py b/gnome-sudoku/src/lib/tp_tube.py
index c4bc295..edff6b4 100644
--- a/gnome-sudoku/src/lib/tp_tube.py
+++ b/gnome-sudoku/src/lib/tp_tube.py
@@ -30,7 +30,7 @@ class TubeOffer(gobject.GObject):
                 (str,)),
             }
 
-    def __init__(self, conn, handle, tube_service):
+    def __init__(self, conn, handle, tube_service, puzzle):
         logger.debug("create an offer")
         gobject.GObject.__init__(self)
         self._tube_state = None
@@ -41,6 +41,7 @@ class TubeOffer(gobject.GObject):
         self._conn = conn
         self._handle = handle
         self._tube_service = tube_service
+        self._puzzle = puzzle
 
     def _tube_state_changed_cb(self, state):
         self._tube_state = state
@@ -58,7 +59,7 @@ class TubeOffer(gobject.GObject):
         if self._tube_state == TUBE_CHANNEL_STATE_REMOTE_PENDING:
             # if tube is already open, it's not _offer_ failed (it's other
             # problems)
-            self.emit("offer-failed", _("Tube is closed by peer"))
+            self.emit("offer-failed", _("Connection closed by peer"))
 
     def cancel(self):
         if self._chan:
@@ -92,7 +93,9 @@ class TubeOffer(gobject.GObject):
 
         logger.debug("offering tube")
         try:
-            self._address = self._chan[CHANNEL_TYPE_DBUS_TUBE].Offer({},
+            data = {'puzzle': self._puzzle}
+            self._address = self._chan[CHANNEL_TYPE_DBUS_TUBE].Offer(
+                    data,
                     SOCKET_ACCESS_CONTROL_CREDENTIALS)
         except dbus.exceptions.DBusException as excep:
             error_busname = telepathy.errors.NotAvailable().get_dbus_name()
diff --git a/gnome-sudoku/src/lib/tube_handler.py b/gnome-sudoku/src/lib/tube_handler.py
index e2f1794..54683fb 100644
--- a/gnome-sudoku/src/lib/tube_handler.py
+++ b/gnome-sudoku/src/lib/tube_handler.py
@@ -4,6 +4,7 @@ import logging
 
 import dbus
 import dbus.service
+from dbus import PROPERTIES_IFACE
 from dbus.mainloop.glib import DBusGMainLoop
 
 from telepathy.client.conn import Connection
@@ -50,19 +51,25 @@ class TubeHandler(dbus.service.Object):
     def HandleTube(self, bus_name, connection, channel, handle_type, handle):
         """Called when we are offered a tube"""
         logger.debug("Tube received on %s" % channel)
-        conn = Connection(bus_name, connection)
-        self._tube_chan = Channel(bus_name, channel)
+        self._bus_name = bus_name
+        self._channel = channel
+        conn = Connection(bus_name, connection,
+                ready_handler=self._ready_handler)
 
-        self.address = self._tube_chan[CHANNEL_TYPE_DBUS_TUBE].Accept(
-                SOCKET_ACCESS_CONTROL_CREDENTIALS)
+    def _ready_handler(self, conn):
+        self._tube_chan = Channel(self._bus_name, self._channel)
         self._tube_chan[CHANNEL_INTERFACE_TUBE].connect_to_signal(
                 'TubeChannelStateChanged', self._tube_state_changed_cb)
 
+        self._address = self._tube_chan[CHANNEL_TYPE_DBUS_TUBE].Accept(
+                SOCKET_ACCESS_CONTROL_CREDENTIALS)
+
     def _tube_state_changed_cb(self, state):
         if state == TUBE_STATE_OPEN:
             logger.debug("Tube state changed ->open")
-            tube_conn = dbus.connection.Connection(self.address)
-
-            self._tube_received_cb(tube_conn, self._tube_chan)
+            bus = dbus.connection.Connection(self._address)
+            params = self._tube_chan[PROPERTIES_IFACE].Get(
+                    CHANNEL_INTERFACE_TUBE, 'Parameters')
+            self._tube_received_cb(bus, self._tube_chan, params)
         else:
             logger.debug("Tube state changed ->%s" % state)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]