# Copyright (C) 2006, 2007, 2008 One Laptop Per Child
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import tempfile
from os import environ, chmod
from os.path import join, getsize, dirname, basename
from dbus.service import method, signal
from dbus.gobject_service import ExportedGObject
from sugar3.datastore import datastore
from gettext import gettext as _
SERVICE = 'org.laptop.Memorize'
IFACE = SERVICE
PATH = '/org/laptop/Memorize'
class Messenger(ExportedGObject):
def __init__(self, tube, is_initiator, get_buddy, game):
ExportedGObject.__init__(self, tube, PATH)
self._tube = tube
self.is_initiator = is_initiator
self._get_buddy = get_buddy
self.game = game
self.ordered_bus_names = []
self.entered = False
self._tube.watch_participants(self.participant_change_cb)
self.files = {}
def participant_change_cb(self, added, removed):
if not self.entered:
self._file_part_handler()
if self.is_initiator:
self._flip_handler()
self._change_game_handler()
self.player_id = self._tube.get_unique_name()
self.ordered_bus_names = [self.player_id]
self._hello_handler()
else:
self._hello_signal()
self.entered = True
# hello methods
@signal(IFACE, signature='')
def _hello_signal(self):
pass
def _hello_handler(self):
self._tube.add_signal_receiver(self._hello_receiver,
'_hello_signal',
IFACE,
path=PATH,
sender_keyword='sender')
def _hello_receiver(self, sender=None):
self.ordered_bus_names.append(sender)
data = self.game.model.data
path = data['game_file']
if self.game.model.data['mode'] == 'file':
title = data.get('title', 'Received game')
color = data.get('color', '#ff00ff,#00ff00')
self.file_sender(sender, path, title, color)
remote_object = self._tube.get_object(sender, PATH)
remote_object.load_game(
self.ordered_bus_names,
self.game.get_grid(), self.game.collect_data(),
self.game.players.index(self.game.current_player), path)
@method(dbus_interface=IFACE, in_signature='asaa{ss}a{ss}ns',
out_signature='', byte_arrays=True)
def load_game(self, bus_names, grid, data, current_player, path):
self.ordered_bus_names = bus_names
self.player_id = bus_names.index(self._tube.get_unique_name())
# self.game.load_waiting_list(list)
self._change_game_receiver(data['mode'], grid, data, path)
for i in range(len(self.game.players)):
self.game.increase_point(self.game.players[i],
int(data.get(str(i), '0')))
self.game.current_player = self.game.players[current_player]
self.game.update_turn()
self._flip_handler()
self._change_game_handler()
def change_game(self, sender, mode, grid, data, waiting_list, zip):
path = self.game.model.data['game_file']
if mode == 'file':
title = data.get('title', 'Received game')
color = data.get('color', '')
self.file_sender('all', path, title, color)
self._change_game_signal(mode, grid, data, path)
def _change_game_handler(self):
self._tube.add_signal_receiver(self._change_game_receiver,
'_change_game_signal',
IFACE, path=PATH,
sender_keyword='sender',
byte_arrays=True)
@signal(IFACE, signature='saa{ss}a{ss}s')
def _change_game_signal(self, mode, grid, data, path):
pass
def _change_game_receiver(self, mode, grid, data, path, sender=None):
# ignore my own signal
if sender == self._tube.get_unique_name():
return
if mode == 'demo':
game_name = basename(data.get('game_file', 'debug-demo'))
game_file = join(dirname(__file__), 'demos',
game_name).encode('ascii')
self.game.model.read(game_file)
if mode == 'art4apps':
game_file = data['game_file']
category = game_file[:game_file.find('_')]
language = data['language']
self.game.model.is_demo = True
self.game.model.read_art4apps(category, language)
if mode == 'file':
self.game.model.read(self.files[path])
if 'path' in self.game.model.data:
data['path'] = self.game.model.data['path']
data['pathimg'] = self.game.model.data['pathimg']
data['pathsnd'] = self.game.model.data['pathsnd']
self.game.load_remote(grid, data, mode, True)
# File transfer methods
def file_sender(self, target, filename, title, color):
size = getsize(filename)
f = open(filename, 'rb')
part_size = 8192
num_parts = (size / part_size) + 1
for part in range(num_parts):
bytes = f.read(part_size)
self._file_part_signal(target, filename, part + 1,
num_parts, bytes, title, color)
f.close()
@signal(dbus_interface=IFACE, signature='ssuuayss')
def _file_part_signal(self, target, filename, part, numparts,
bytes, title, color):
pass
def _file_part_handler(self):
self._tube.add_signal_receiver(self._file_part_receiver,
'_file_part_signal',
IFACE,
path=PATH,
sender_keyword='sender',
byte_arrays=True)
def _file_part_receiver(self, target, filename, part, numparts,
bytes, title=None, color=None, sender=None):
# ignore my own signal
if sender == self._tube.get_unique_name():
return
if target != self._tube.get_unique_name() and target != 'all':
return
# first chunk
if part == 1:
tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance')
temp_dir = tempfile.mkdtemp(dir=tmp_root)
chmod(temp_dir, 0777)
self.temp_file = join(temp_dir, 'game.zip')
self.files[filename] = self.temp_file
self.f = open(self.temp_file, 'a+b')
self.f.write(bytes)
percentage = int(float(part) / float(numparts) * 100.0)
self.game.set_load_mode(_('Receiving game') + ': '
+ str(percentage) + '% ' + _('done') + '.')
# last chunk
if part == numparts:
self.f.close()
# file = self.files[filename]
# Saves the zip in datastore
gameObject = datastore.create()
gameObject.metadata['title'] = title
gameObject.metadata['mime_type'] = 'application/x-memorize-project'
gameObject.metadata['icon-color'] = color
gameObject.file_path = self.temp_file
datastore.write(gameObject)
# gameObject.destroy()
# flip card methods
def flip_sender(self, widget, id):
self._flip_signal(id)
def _flip_handler(self):
self._tube.add_signal_receiver(self._flip_receiver,
'_flip_signal',
IFACE,
path=PATH,
sender_keyword='sender')
@signal(IFACE, signature='n')
def _flip_signal(self, card_number):
pass
def _flip_receiver(self, card_number, sender=None):
# ignore my own signal
if sender == self._tube.get_unique_name():
return
self.game.card_flipped(None, card_number, True)