comparison src/plugins/plugin_misc_radiocol.py @ 450:afe9cfd2ddbb

plugins: radio collective first draft
author Goffi <goffi@goffi.org>
date Thu, 05 Jan 2012 00:21:30 +0100
parents
children 5731b038fc7f
comparison
equal deleted inserted replaced
449:961543b20806 450:afe9cfd2ddbb
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 """
5 SAT plugin for managing Radiocol
6 Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org)
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """
21
22 from logging import debug, info, warning, error
23 from twisted.words.xish import domish
24 from twisted.internet import protocol, defer, threads, reactor
25 from twisted.words.protocols.jabber import client, jid, xmlstream
26 from twisted.words.protocols.jabber import error as jab_error
27 from twisted.words.protocols.jabber.xmlstream import IQ
28 import random
29
30 from zope.interface import implements
31
32 from wokkel import disco, iwokkel, data_form
33 from sat.tools.xml_tools import dataForm2xml
34 from sat.tools.games import TarotCard
35
36 from time import time
37
38 try:
39 from twisted.words.protocols.xmlstream import XMPPHandler
40 except ImportError:
41 from wokkel.subprotocols import XMPPHandler
42
43 MESSAGE = '/message'
44 NC_RADIOCOL = 'http://www.goffi.org/protocol/radiocol'
45 RADIOC_TAG = 'radiocol'
46 RADIOC_REQUEST = MESSAGE + '/' + RADIOC_TAG + '[@xmlns="' + NC_RADIOCOL + '"]'
47
48 PLUGIN_INFO = {
49 "name": "Radio collective plugin",
50 "import_name": "Radiocol",
51 "type": "Exp",
52 "protocols": [],
53 "dependencies": ["XEP-0045", "XEP-0249"],
54 "main": "Radiocol",
55 "handler": "yes",
56 "description": _("""Implementation of radio collective""")
57 }
58
59
60 class Radiocol():
61
62 def __init__(self, host):
63 info(_("Radio collective initialization"))
64 self.host = host
65 self.radios={}
66 host.bridge.addMethod("radiocolLaunch", ".plugin", in_sign='ass', out_sign='', method=self.radiocolLaunch) #args: occupants, profile
67 host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='ss', out_sign='', method=self.radiocolCreate) #args: room_jid, profile
68 host.bridge.addSignal("radiocolStarted", ".plugin", signature='ssass') #args: room_jid, referee, occupants, profile
69 host.trigger.add("MUC user joined", self.userJoinedTrigger)
70
71 def createRadiocolElt(self, to_jid, type="normal"):
72 type = "normal" if to_jid.resource else "groupchat"
73 elt = domish.Element(('jabber:client','message'))
74 elt["to"] = to_jid.full()
75 elt["type"] = type
76 elt.addElement((NC_RADIOCOL, RADIOC_TAG))
77 return elt
78
79 def __create_started_elt(self):
80 """Create a game_started domish element"""
81 started_elt = domish.Element(('','started'))
82 return started_elt
83
84 def userJoinedTrigger(self, room, user, profile):
85 """This trigger is used to check if we are waiting people in this room,
86 and to create a game if everybody is here"""
87 room_jid = room.occupantJID.userhostJID()
88 if self.radios.has_key(room_jid):
89 #we are in a radiocol room, let's start the party !
90 mess = self.createRadiocolElt(jid.JID(room_jid.userhost()+'/'+occupant))
91 mess.firstChildElement().addChild(self.__create_started_elt())
92 self.host.profiles[profile].xmlstream.send(mess)
93 return True
94
95 def radiocolLaunch(self, occupants, profile_key='@DEFAULT@'):
96 """Launch a game: helper method to create a room, invite occupants, and create the radiocol
97 @param occupants: list for occupants jid"""
98 debug(_('Launching radiocol'))
99 profile = self.host.memory.getProfileName(profile_key)
100 if not profile:
101 error(_("Unknown profile"))
102 return
103
104 def radiocolRoomJoined(room):
105 print "radiocolRoomJoined"
106 _room_jid = room.occupantJID.userhostJID()
107 for occupant in occupants:
108 self.host.plugins["XEP-0249"].invite(jid.JID(occupant), room.occupantJID.userhostJID(), {"game":"Radiocol"}, profile)
109 self.radiocolCreate(_room_jid.userhost(), profile_key=profile)
110
111 def after_init(ignore):
112 room_name = "sat_radiocol_%s" % self.host.plugins["XEP-0045"].getUniqueName(profile_key)
113 print "\n\n===> room_name:", room_name
114 muc_service = None
115 for service in self.host.memory.getServerServiceEntities("conference", "text", profile):
116 if not ".irc." in service.userhost():
117 #FIXME:
118 #This awfull ugly hack is here to avoid an issue with openfire: the irc gateway
119 #use "conference/text" identity (instead of "conference/irc"), there is certainly a better way
120 #to manage this, but this hack fill do it for test purpose
121 muc_service = service
122 break
123 if not muc_service:
124 error(_("Can't find a MUC service"))
125 return
126
127 _jid, xmlstream = self.host.getJidNStream(profile)
128 d = self.host.plugins["XEP-0045"].join(jid.JID("%s@%s" % (room_name, muc_service.userhost())), _jid.user, {}, profile)
129 d.addCallback(radiocolRoomJoined)
130
131 client = self.host.getClient(profile)
132 if not client:
133 error(_('No client for this profile key: %s') % profile_key)
134 return
135 client.client_initialized.addCallback(after_init)
136
137 def radiocolCreate(self, room_jid_param, profile_key='@DEFAULT@'):
138 """Create a new game
139 @param room_jid_param: jid of the room
140 @param profile_key: %(doc_profile_key)s"""
141 debug (_("Creating Radiocol"))
142 room_jid = jid.JID(room_jid_param)
143 profile = self.host.memory.getProfileName(profile_key)
144 if not profile:
145 error (_("profile %s is unknown") % profile_key)
146 return
147 if self.radios.has_key(room_jid):
148 warning (_("Radiocol already started in room %s") % room_jid.userhost())
149 else:
150 room_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid.userhost(), profile)
151 if not room_nick:
152 error ('Internal error')
153 return
154 referee = room_jid.userhost() + '/' + room_nick
155 status = {}
156 occupants_data = {}
157 self.radios[room_jid.userhost()] = {'referee':referee, 'occupants_data':occupants_data}
158 mess = self.createRadiocolElt(jid.JID(room_jid.userhost()))
159 mess.firstChildElement().addChild(self.__create_started_elt())
160 self.host.profiles[profile].xmlstream.send(mess)
161
162 def radiocol_game_cmd(self, mess_elt, profile):
163 from_jid = jid.JID(mess_elt['from'])
164 room_jid = jid.JID(from_jid.userhost())
165 radio_elt = mess_elt.firstChildElement()
166 radio_data = self.radios[room_jid.userhost()]
167 occupants_data = radio_data['occupants_data']
168
169 for elt in radio_elt.elements():
170
171 if elt.name == 'started': #new game created
172 self.host.bridge.radiocolStarted(room_jid.userhost(), from_jid.full(), [], profile) #FIXME: add occupants list here ?
173 else:
174 error (_('Unmanaged game element: %s') % elt.name)
175
176 def getHandler(self, profile):
177 return RadiocolHandler(self)
178
179 class RadiocolHandler (XMPPHandler):
180 implements(iwokkel.IDisco)
181
182 def __init__(self, plugin_parent):
183 self.plugin_parent = plugin_parent
184 self.host = plugin_parent.host
185
186 def connectionInitialized(self):
187 self.xmlstream.addObserver(RADIOC_REQUEST, self.plugin_parent.radiocol_game_cmd, profile = self.parent.profile)
188
189 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
190 return [disco.DiscoFeature(NC_RADIOCOL)]
191
192 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
193 return []
194