Permalink
Browse files

MVP reached: msgs in campfire now go to xmpp and vice versa

  • Loading branch information...
1 parent e91df0c commit 98d4b0d49ec703784c7cfd9bb441c1fe97c28319 @bmuller committed Aug 21, 2011
Showing with 106 additions and 59 deletions.
  1. +74 −13 campfirer/campfire.py
  2. +20 −46 campfirer/muc.py
  3. +12 −0 test/client.py
View
87 campfirer/campfire.py
@@ -4,29 +4,72 @@
from twisted.python import log
from twisted.web import client
-from campfirer.DOMLight import createModel
+from campfirer.DOMLight import createModel, XMLMaker
class Message:
- def __init__(self, user, body, msgtype, tstamp):
+ def __init__(self, id, user, body, msgtype, tstamp):
+ self.id = id
self.user = user
self.body = body
self.msgtype = msgtype
self.tstamp = tstamp
+
+
+class ParticipantList:
+ def __init__(self):
+ self.participants = {}
+ self.recent = {}
+
+ def add(self, id, name):
+ self.participants[id] = name
+
+ def update(self, newpeople):
+ self.recent = {}
+ for uid, name in newpeople.items():
+ if not self.participants.has_key(uid):
+ self.recent[uid] = name
+ self.participants[uid] = name
+
+ def getName(self, id):
+ return self.participants.get(id, id)
+
+ def getJustJoined(self):
+ return self.recent
+
+ def __len__(self):
+ return len(self.participants)
class MessageList:
def __init__(self, maxsize=100):
self.maxsize = maxsize
self.msgs = []
self.last_msg_id = None
+ self.ignore = set()
+
+
+ def addIgnore(self, id):
+ self.ignore.add(id)
+
def append(self, msgs):
self.msgs = (self.msgs + msgs)[-self.maxsize:]
+
+ def reset(self, msgs):
+ self.msgs = []
+ for msg in msgs:
+ if msg.id in self.ignore:
+ self.ignore.discard(msg.id)
+ else:
+ self.msgs.append(msg)
+
+
def __iter__(self):
return self.msgs.__iter__()
+
def __len__(self):
return len(self.msgs)
@@ -52,11 +95,13 @@ def getPage(self, url, username=None, password=None):
return client.getPage(self.url(url), headers=headers)
- def postPage(self, url):
+ def postPage(self, url, data=None):
log.msg("POST %s" % url)
auth = "%s:X" % self.token
headers = {'Authorization': base64.b64encode(auth) }
- return client.getPage(self.url(url), method='POST', headers=headers)
+ if data is not None:
+ headers['Content-Type'] = 'application/xml'
+ return client.getPage(self.url(url), method='POST', headers=headers, postdata=data)
class CampfireRoom(CampfireClient):
@@ -65,7 +110,7 @@ def __init__(self, account, token, roomname, room_id, muc):
self.roomname = roomname
self.room_id = room_id
self.token = token
- self.participants = {}
+ self.participants = ParticipantList()
self.topic = ""
self.msgs = MessageList()
self.muc = muc
@@ -82,10 +127,15 @@ def setJIDs(self, source_jid, participant_jid):
def _updateRoom(self, response):
root = createModel(response)
- self.participants = {}
+
+ # update list of participants
+ participants = {}
for xmluser in root.users[0].user:
uid = xmluser.id[0].text[0]
- self.participants[uid] = xmluser.name[0].text[0]
+ name = xmluser.name[0].text[0]
+ participants[uid] = name
+ self.participants.update(participants)
+
self.topic = root.topic[0].text[0]
if self.msgs.last_msg_id is not None:
url = "room/%s/recent.xml?since_message_id=%s" % (self.room_id, self.msgs.last_msg_id)
@@ -100,15 +150,26 @@ def _updateMsgs(self, response):
for xmlmsg in root.message:
msgtype = xmlmsg.type[0].text[0]
if msgtype in ["TextMessage", "PasteMessage"]:
- user = self.participants.get(xmlmsg.children['user-id'][0].text[0], xmlmsg.children['user-id'][0].text[0])
+ user = self.participants.getName(xmlmsg.children['user-id'][0].text[0])
body = xmlmsg.body[0].text[0]
+ id = xmlmsg.id[0].text[0]
tstamp = xmlmsg.children["created-at"][0].text[0]
- msgs.append(Message(user, body, msgtype, tstamp))
+ msgs.append(Message(id, user, body, msgtype, tstamp))
self.msgs.last_msg_id = xmlmsg.children['id'][0].text[0]
- self.msgs.append(msgs)
+ self.msgs.reset(msgs)
return self
+ def say(self, msg):
+ xml = XMLMaker()
+ xmlmsg = xml.message({}, xml.body({}, msg))
+ # ignore this message next time we poll campfirenow.com
+ def addIgnore(result):
+ root = createModel(result)
+ self.msgs.addIgnore(root.id[0].text[0])
+ return self.postPage("room/%s/speak.xml" % self.room_id, data=str(xmlmsg)).addCallback(addIgnore)
+
+
def join(self):
return self.postPage("room/%s/join.xml" % self.room_id).addCallback(lambda _: self)
@@ -208,15 +269,15 @@ def key(self, account, user):
return "%s@%s" % (user, account)
- def getCampfire(self, account, user, password):
- key = self.key(account, user)
+ def getCampfire(self, account, jid, password=None):
+ key = self.key(account, jid.userhost())
if self.fires.has_key(key):
return defer.succeed(self.fires[key])
def save(result):
if result is not None:
self.fires[key] = result
return result
- return Campfire(account, self.muc).initialize(user, password).addCallback(save)
+ return Campfire(account, self.muc).initialize(jid.resource, password).addCallback(save)
def putCampfireOut(self, account, user):
View
66 campfirer/muc.py
@@ -52,6 +52,7 @@ def componentConnected(self, xmlstream):
self.xmlstream = xmlstream
self.xmlstream.addObserver(DISCO_INFO, self.onDiscoInfo)
self.xmlstream.addObserver(PRESENCE, self.onPresence)
+ self.xmlstream.addObserver(MESSAGE, self.onMessage)
log.msg("muc component connected")
@@ -66,13 +67,18 @@ def onDiscoInfo(self, iq):
response.send(iq['from'])
+ def parseCampfireName(self, jid):
+ room_parts = jid.user.split(".")
+ roomname = ".".join(room_parts[1:])
+ account = room_parts[0]
+ return (account, roomname)
+
+
# <presence from='bmuller@butterfat.net/hm-min' to='testthree@muc.campfirer.com/bmuller'>
# <x xmlns='http://jabber.org/protocol/muc'><password>password</password></x></presence>
def onPresence(self, pres):
to = jid.JID(pres['to'])
- room_parts = to.user.split(".")
- roomname = ".".join(room_parts[1:])
- account = room_parts[0]
+ account, roomname = self.parseCampfireName(to)
def handleAuth(campfire):
if campfire is None:
@@ -87,7 +93,7 @@ def handleAuth(campfire):
self.sendErrorPresence(pres, "not-authorized")
else:
log.msg("attempting to auth %s for room %s on account %s" % (to.resource, roomname, account))
- self.smokey.getCampfire(account, to.resource, password).addCallback(handleAuth)
+ self.smokey.getCampfire(account, to, password).addCallback(handleAuth)
def initializeRoom(self, campfire, roomname, participant_jid, source_jid):
@@ -101,7 +107,7 @@ def initParticipants(room):
def handleRoomUpdate(self, room):
- for username in room.participants.values():
+ for username in room.participants.getJustJoined().values():
mfrom = room.participant_jid.userhostJID()
mfrom.resource = username.replace(" ", "")
self.sendPresence(mfrom, room.source_jid)
@@ -139,45 +145,13 @@ def sendMessage(self, mfrom, msgBody, mto, tstamp):
self.xmlstream.send(m)
- ################## ################## ################## ################## ##################
- def presence(self, sendto):
- p = domish.Element((None, 'presence'))
- p['to'] = sendto
- p['from'] = self.jid
- return p
-
-
- def updateRoomList(self, roomlist):
- rooms = []
- for room in roomlist.firstChildElement().elements():
- rooms.append((room['jid'], room['name']))
-
- def setID(room):
- self.rooms[unicode(room.jid)] = (room.id, room.name)
-
- def addRooms(r):
- room = r.pop()
- d = Room.createIfNonexistant(room[0], room[1]).addCallback(setID)
- if len(r) > 0:
- return d.addCallback(lambda _: addRooms(r))
- return d
-
- addRooms(rooms).addCallback(lambda _: self.joinRooms())
-
-
- def joinRooms(self):
- for jid in self.rooms.keys():
- if len(self.config['rooms']) == 0 or self.config['rooms'].has_key(jid):
- p = self.presence("%s/%s" % (jid, 'gossipr'))
- p.addElement('x', 'http://jabber.org/protocol/muc')
- self.xmlstream.send(p)
-
-
def onMessage(self, msg):
- jidparts = jid.parse(msg['from'])
- userhost = "%s@%s" % (jidparts[0], jidparts[1])
-
- if self.rooms.has_key(userhost):
- room_id = self.rooms[userhost][0]
- body = xpath.queryForString("/message/body", msg)
- return Message(speaker=jidparts[2], message=body, room_id=room_id, created_at=datetime.datetime.now()).save()
+ to = jid.JID(msg['to'])
+ account, roomname = self.parseCampfireName(to)
+ def sendMsgRoom(room):
+ if room is not None:
+ room.say(xpath.queryForString("/message/body", msg))
+ def sendMsg(campfire):
+ if campfire is not None:
+ campfire.getRoom(roomname).addCallback(sendMsgRoom)
+ self.smokey.getCampfire(account, to).addCallback(sendMsg)
View
12 test/client.py
@@ -4,7 +4,9 @@
from twisted.names.srvconnect import SRVConnector
from twisted.internet import reactor
from twisted.python import log
+
import sys
+import time
from config import CONFIG
@@ -67,7 +69,17 @@ def authenticated(self, xs):
x = presence.addElement('x', 'http://jabber.org/protocol/muc')
x.addElement('password', content=CONFIG['roompasswd'])
xs.send(presence)
+ reactor.callLater(10, self.say, "hello there %i" % time.time())
+
+ def say(self, msgtxt):
+ msg = domish.Element((None, 'message'))
+ msg['from'] = CONFIG['jid']
+ msg['to'] = jid.JID(CONFIG['room']).userhost()
+ msg['type'] = "groupchat"
+ msg.addElement('body', content=msgtxt)
+ self.xmlstream.send(msg)
+
def init_failed(self, failure):
log.err("Initialization failed.")

0 comments on commit 98d4b0d

Please sign in to comment.