# HG changeset patch # User Goffi # Date 1325719290 -3600 # Node ID afe9cfd2ddbb65cc45c49a3555973f6050a6bd42 # Parent 961543b208068642f83cd5e96db1398b7d583900 plugins: radio collective first draft diff -r 961543b20806 -r afe9cfd2ddbb frontends/src/bridge/DBus.py --- a/frontends/src/bridge/DBus.py Mon Dec 12 22:24:50 2011 +0100 +++ b/frontends/src/bridge/DBus.py Thu Jan 05 00:21:30 2012 +0100 @@ -205,6 +205,12 @@ def quizGameAnswer(self, player, referee, answer, profile_key): return self.db_plugin_iface.quizGameAnswer(player, referee, answer, profile_key) + def radiocolLaunch(self, players, profile_key): + return self.db_plugin_iface.radiocolLaunch(players, profile_key) + + def radiocolCreate(self, room_jid, profile_key): + return self.db_plugin_iface.radiocolCreate(room_jid, profile_key) + def sendFile(self, to, path, data, profile_key): return self.db_plugin_iface.sendFile(to, path, data, profile_key) diff -r 961543b20806 -r afe9cfd2ddbb src/bridge/bridge_constructor/dbus_frontend_template.py --- a/src/bridge/bridge_constructor/dbus_frontend_template.py Mon Dec 12 22:24:50 2011 +0100 +++ b/src/bridge/bridge_constructor/dbus_frontend_template.py Thu Jan 05 00:21:30 2012 +0100 @@ -98,6 +98,12 @@ def quizGameAnswer(self, player, referee, answer, profile_key): return self.db_plugin_iface.quizGameAnswer(player, referee, answer, profile_key) + def radiocolLaunch(self, players, profile_key): + return self.db_plugin_iface.radiocolLaunch(players, profile_key) + + def radiocolCreate(self, room_jid, profile_key): + return self.db_plugin_iface.radiocolCreate(room_jid, profile_key) + def sendFile(self, to, path, data, profile_key): return self.db_plugin_iface.sendFile(to, path, data, profile_key) diff -r 961543b20806 -r afe9cfd2ddbb src/plugins/plugin_misc_quiz.py --- a/src/plugins/plugin_misc_quiz.py Mon Dec 12 22:24:50 2011 +0100 +++ b/src/plugins/plugin_misc_quiz.py Thu Jan 05 00:21:30 2012 +0100 @@ -64,7 +64,7 @@ self.host = host self.games={} self.waiting_inv = {} #Invitation waiting for people to join to launch a game - host.bridge.addMethod("quizGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.quizGameLaunch) #args: room_jid, players, profile + host.bridge.addMethod("quizGameLaunch", ".plugin", in_sign='ass', out_sign='', method=self.quizGameLaunch) #args: players, profile host.bridge.addMethod("quizGameCreate", ".plugin", in_sign='sass', out_sign='', method=self.quizGameCreate) #args: room_jid, players, profile host.bridge.addMethod("quizGameReady", ".plugin", in_sign='sss', out_sign='', method=self.newPlayerReady) #args: player, referee, profile host.bridge.addMethod("quizGameAnswer", ".plugin", in_sign='ssss', out_sign='', method=self.playerAnswer) diff -r 961543b20806 -r afe9cfd2ddbb src/plugins/plugin_misc_radiocol.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/plugin_misc_radiocol.py Thu Jan 05 00:21:30 2012 +0100 @@ -0,0 +1,194 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +SAT plugin for managing Radiocol +Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) + +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 3 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, see . +""" + +from logging import debug, info, warning, error +from twisted.words.xish import domish +from twisted.internet import protocol, defer, threads, reactor +from twisted.words.protocols.jabber import client, jid, xmlstream +from twisted.words.protocols.jabber import error as jab_error +from twisted.words.protocols.jabber.xmlstream import IQ +import random + +from zope.interface import implements + +from wokkel import disco, iwokkel, data_form +from sat.tools.xml_tools import dataForm2xml +from sat.tools.games import TarotCard + +from time import time + +try: + from twisted.words.protocols.xmlstream import XMPPHandler +except ImportError: + from wokkel.subprotocols import XMPPHandler + +MESSAGE = '/message' +NC_RADIOCOL = 'http://www.goffi.org/protocol/radiocol' +RADIOC_TAG = 'radiocol' +RADIOC_REQUEST = MESSAGE + '/' + RADIOC_TAG + '[@xmlns="' + NC_RADIOCOL + '"]' + +PLUGIN_INFO = { +"name": "Radio collective plugin", +"import_name": "Radiocol", +"type": "Exp", +"protocols": [], +"dependencies": ["XEP-0045", "XEP-0249"], +"main": "Radiocol", +"handler": "yes", +"description": _("""Implementation of radio collective""") +} + + +class Radiocol(): + + def __init__(self, host): + info(_("Radio collective initialization")) + self.host = host + self.radios={} + host.bridge.addMethod("radiocolLaunch", ".plugin", in_sign='ass', out_sign='', method=self.radiocolLaunch) #args: occupants, profile + host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='ss', out_sign='', method=self.radiocolCreate) #args: room_jid, profile + host.bridge.addSignal("radiocolStarted", ".plugin", signature='ssass') #args: room_jid, referee, occupants, profile + host.trigger.add("MUC user joined", self.userJoinedTrigger) + + def createRadiocolElt(self, to_jid, type="normal"): + type = "normal" if to_jid.resource else "groupchat" + elt = domish.Element(('jabber:client','message')) + elt["to"] = to_jid.full() + elt["type"] = type + elt.addElement((NC_RADIOCOL, RADIOC_TAG)) + return elt + + def __create_started_elt(self): + """Create a game_started domish element""" + started_elt = domish.Element(('','started')) + return started_elt + + def userJoinedTrigger(self, room, user, profile): + """This trigger is used to check if we are waiting people in this room, + and to create a game if everybody is here""" + room_jid = room.occupantJID.userhostJID() + if self.radios.has_key(room_jid): + #we are in a radiocol room, let's start the party ! + mess = self.createRadiocolElt(jid.JID(room_jid.userhost()+'/'+occupant)) + mess.firstChildElement().addChild(self.__create_started_elt()) + self.host.profiles[profile].xmlstream.send(mess) + return True + + def radiocolLaunch(self, occupants, profile_key='@DEFAULT@'): + """Launch a game: helper method to create a room, invite occupants, and create the radiocol + @param occupants: list for occupants jid""" + debug(_('Launching radiocol')) + profile = self.host.memory.getProfileName(profile_key) + if not profile: + error(_("Unknown profile")) + return + + def radiocolRoomJoined(room): + print "radiocolRoomJoined" + _room_jid = room.occupantJID.userhostJID() + for occupant in occupants: + self.host.plugins["XEP-0249"].invite(jid.JID(occupant), room.occupantJID.userhostJID(), {"game":"Radiocol"}, profile) + self.radiocolCreate(_room_jid.userhost(), profile_key=profile) + + def after_init(ignore): + room_name = "sat_radiocol_%s" % self.host.plugins["XEP-0045"].getUniqueName(profile_key) + print "\n\n===> room_name:", room_name + muc_service = None + for service in self.host.memory.getServerServiceEntities("conference", "text", profile): + if not ".irc." in service.userhost(): + #FIXME: + #This awfull ugly hack is here to avoid an issue with openfire: the irc gateway + #use "conference/text" identity (instead of "conference/irc"), there is certainly a better way + #to manage this, but this hack fill do it for test purpose + muc_service = service + break + if not muc_service: + error(_("Can't find a MUC service")) + return + + _jid, xmlstream = self.host.getJidNStream(profile) + d = self.host.plugins["XEP-0045"].join(jid.JID("%s@%s" % (room_name, muc_service.userhost())), _jid.user, {}, profile) + d.addCallback(radiocolRoomJoined) + + client = self.host.getClient(profile) + if not client: + error(_('No client for this profile key: %s') % profile_key) + return + client.client_initialized.addCallback(after_init) + + def radiocolCreate(self, room_jid_param, profile_key='@DEFAULT@'): + """Create a new game + @param room_jid_param: jid of the room + @param profile_key: %(doc_profile_key)s""" + debug (_("Creating Radiocol")) + room_jid = jid.JID(room_jid_param) + profile = self.host.memory.getProfileName(profile_key) + if not profile: + error (_("profile %s is unknown") % profile_key) + return + if self.radios.has_key(room_jid): + warning (_("Radiocol already started in room %s") % room_jid.userhost()) + else: + room_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid.userhost(), profile) + if not room_nick: + error ('Internal error') + return + referee = room_jid.userhost() + '/' + room_nick + status = {} + occupants_data = {} + self.radios[room_jid.userhost()] = {'referee':referee, 'occupants_data':occupants_data} + mess = self.createRadiocolElt(jid.JID(room_jid.userhost())) + mess.firstChildElement().addChild(self.__create_started_elt()) + self.host.profiles[profile].xmlstream.send(mess) + + def radiocol_game_cmd(self, mess_elt, profile): + from_jid = jid.JID(mess_elt['from']) + room_jid = jid.JID(from_jid.userhost()) + radio_elt = mess_elt.firstChildElement() + radio_data = self.radios[room_jid.userhost()] + occupants_data = radio_data['occupants_data'] + + for elt in radio_elt.elements(): + + if elt.name == 'started': #new game created + self.host.bridge.radiocolStarted(room_jid.userhost(), from_jid.full(), [], profile) #FIXME: add occupants list here ? + else: + error (_('Unmanaged game element: %s') % elt.name) + + def getHandler(self, profile): + return RadiocolHandler(self) + +class RadiocolHandler (XMPPHandler): + implements(iwokkel.IDisco) + + def __init__(self, plugin_parent): + self.plugin_parent = plugin_parent + self.host = plugin_parent.host + + def connectionInitialized(self): + self.xmlstream.addObserver(RADIOC_REQUEST, self.plugin_parent.radiocol_game_cmd, profile = self.parent.profile) + + def getDiscoInfo(self, requestor, target, nodeIdentifier=''): + return [disco.DiscoFeature(NC_RADIOCOL)] + + def getDiscoItems(self, requestor, target, nodeIdentifier=''): + return [] + diff -r 961543b20806 -r afe9cfd2ddbb src/plugins/plugin_xep_0045.py --- a/src/plugins/plugin_xep_0045.py Mon Dec 12 22:24:50 2011 +0100 +++ b/src/plugins/plugin_xep_0045.py Thu Jan 05 00:21:30 2012 +0100 @@ -60,7 +60,7 @@ self.clients={} host.bridge.addMethod("joinMUC", ".plugin", in_sign='ssa{ss}s', out_sign='', method=self._join) host.bridge.addMethod("getRoomsJoined", ".plugin", in_sign='s', out_sign='a(sass)', method=self.getRoomsJoined) - host.bridge.addMethod("getRoomsSubjectss", ".plugin", in_sign='s', out_sign='a(ss)', method=self.getRoomsSubjectss) + host.bridge.addMethod("getRoomsSubjects", ".plugin", in_sign='s', out_sign='a(ss)', method=self.getRoomsSubjects) host.bridge.addMethod("getUniqueRoomName", ".plugin", in_sign='s', out_sign='s', method=self.getUniqueName) host.bridge.addSignal("roomJoined", ".plugin", signature='sasss') #args: room_jid, room_nicks, user_nick, profile host.bridge.addSignal("roomUserJoined", ".plugin", signature='ssa{ss}s') #args: room_jid, user_nick, user_data, profile @@ -101,6 +101,7 @@ mess = _("Error when joining the room") error (mess) self.host.bridge.newAlert(mess, _("Group chat error"), "ERROR", profile) + raise failure def getRoomsJoined(self, profile_key='@DEFAULT@'): """Return room where user is""" @@ -122,8 +123,7 @@ return '' return self.clients[profile].joined_rooms[room_jid].nick - - def getRoomsSubjectss(self, profile_key='@DEFAULT@'): + def getRoomsSubjects(self, profile_key='@DEFAULT@'): """Return received subjects of rooms""" profile = self.host.memory.getProfileName(profile_key) if not self.__check_profile(profile):