# HG changeset patch # User Goffi # Date 1297196311 -3600 # Node ID 669c531a857ef62482ecdc2516a18004ca3d4202 # Parent 0a7c685faa536c1a5e274e7718920fc66b842ee4 signals handling and first draft of microblogging - server side: signal handling throught json_signal_api page - browser side: - signal handling throught a json rpc call loop - first draft of microblog panel - ContactPanel put in a separate module diff -r 0a7c685faa53 -r 669c531a857e contact.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contact.py Tue Feb 08 21:18:31 2011 +0100 @@ -0,0 +1,127 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Libervia: a Salut à Toi frontend +Copyright (C) 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 Affero 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 Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +""" + +import pyjd # this is dummy in pyjs +from pyjamas.ui.SimplePanel import SimplePanel +from pyjamas.ui.VerticalPanel import VerticalPanel +from pyjamas.ui.HorizontalPanel import HorizontalPanel +from pyjamas.ui.Label import Label +from pyjamas import Window +from pyjamas import DOM + + +class GroupLabel(Label): + def __init__(self, group): + Label.__init__(self, group) + self.group = group + self.setStyleName('group') + +class ContactLabel(Label): + def __init__(self, jid, name=None): + if not name: + name=jid + Label.__init__(self, name) + self.jid=jid + self.setStyleName('contact') + +class GroupList(VerticalPanel): + + def __init__(self, parent): + VerticalPanel.__init__(self) + self._parent = parent + + def add(self, group): + _item = GroupLabel(group) + _item.addMouseListener(self._parent) + DOM.setStyleAttribute(_item.getElement(), "cursor", "pointer") + VerticalPanel.add(self, _item) + +class ContactList(VerticalPanel): + + def __init__(self): + VerticalPanel.__init__(self) + self.contacts=[] + + def __iter__(self): + return self.contacts.__iter__() + + def add(self, jid, name=None): + _item = ContactLabel(jid, name) + DOM.setStyleAttribute(_item.getElement(), "cursor", "pointer") + VerticalPanel.add(self, _item) + self.contacts.append(_item) + +class ContactPanel(SimplePanel): + """Manage the contacts and groups""" + + def __init__(self, host): + SimplePanel.__init__(self) + self.host = host + self.groups={} + + self.vPanel = VerticalPanel() + _title = Label('Contacts') + _title.setStyleName('contactTitle') + + self._contactList = ContactList() + self._contactList.setStyleName('contactList') + self._groupList = GroupList(self) + self._groupList.setStyleName('groupList') + + self.vPanel.add(_title) + self.vPanel.add(self._groupList) + self.vPanel.add(self._contactList) + self.add(self.vPanel) + self.setStyleName('contactBox') + + def addContact(self, jid, attributes, groups): + """Add a contact to the panel + @param jid: jid + @attributes: cf SàT Bridge API's newContact + @param groups: list of groups""" + for group in groups: + if not self.groups.has_key(group): + self.groups[group] = set() + self._groupList.add(group) + self.host.magicBox.addKey("@%s: " % group) + self.groups[group].add(jid) + self._contactList.add(jid) + + def onMouseMove(self, sender, x, y): + pass + + def onMouseDown(self, sender, x, y): + pass + + def onMouseUp(self, sender, x, y): + pass + + def onMouseEnter(self, sender): + if isinstance(sender, GroupLabel): + for contact in self._contactList: + if contact.jid in self.groups[sender.group]: + contact.addStyleName("selected") + + def onMouseLeave(self, sender): + if isinstance(sender, GroupLabel): + for contact in self._contactList: + if contact.jid in self.groups[sender.group]: + contact.removeStyleName("selected") diff -r 0a7c685faa53 -r 669c531a857e libervia.py --- a/libervia.py Mon Jan 31 20:31:25 2011 +0100 +++ b/libervia.py Tue Feb 08 21:18:31 2011 +0100 @@ -33,6 +33,7 @@ from pyjamas.JSONService import JSONProxy from register import RegisterPanel, RegisterBox from pyjamas import DOM +from contact import ContactPanel class LiberviaJsonProxy(JSONProxy): @@ -66,11 +67,16 @@ self.handler=self self.cb={} -class BrigeCall(LiberviaJsonProxy): +class BridgeCall(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/json_api", ["getContacts"]) +class BridgeSignals(LiberviaJsonProxy): + def __init__(self): + LiberviaJsonProxy.__init__(self, "/json_signal_api", + ["getSignals"]) + class MenuCmd: def __init__(self, object, handler): @@ -115,70 +121,6 @@ def addKey(self, key): self.getCompletionItems().completions.append(key) -class GroupLabel(Label): - def __init__(self, group): - Label.__init__(self, group) - self.group = group - self.setStyleName('group') - -class ContactLabel(Label): - def __init__(self, jid, name=None): - if not name: - name=jid - Label.__init__(self, name) - self.jid=jid - self.setStyleName('contact') - -class GroupList(VerticalPanel): - - def __init__(self, parent): - VerticalPanel.__init__(self) - self._parent = parent - - def add(self, group): - _item = GroupLabel(group) - _item.addMouseListener(self._parent) - DOM.setStyleAttribute(_item.getElement(), "cursor", "pointer") - VerticalPanel.add(self, _item) - -class ContactList(VerticalPanel): - - def __init__(self): - VerticalPanel.__init__(self) - self.contacts=[] - - def __iter__(self): - return self.contacts.__iter__() - - def add(self, jid, name=None): - _item = ContactLabel(jid, name) - DOM.setStyleAttribute(_item.getElement(), "cursor", "pointer") - VerticalPanel.add(self, _item) - self.contacts.append(_item) - -class ContactPanel(SimplePanel): - """Manage the contacts and groups""" - - def __init__(self, host): - SimplePanel.__init__(self) - self.host = host - self.groups={} - - self.vPanel = VerticalPanel() - _title = Label('Contacts') - _title.setStyleName('contactTitle') - - self._contactList = ContactList() - self._contactList.setStyleName('contactList') - self._groupList = GroupList(self) - self._groupList.setStyleName('groupList') - - self.vPanel.add(_title) - self.vPanel.add(self._groupList) - self.vPanel.add(self._contactList) - self.add(self.vPanel) - self.setStyleName('contactBox') - def addContact(self, jid, attributes, groups): """Add a contact to the panel @param jid: jid @@ -213,12 +155,48 @@ if contact.jid in self.groups[sender.group]: contact.removeStyleName("selected") +class MicroblogEntry(SimplePanel): + + def __init__(self, text): + SimplePanel.__init__(self) + self._vPanel = VerticalPanel() + self._vPanel.setStyleName('microblogEntry') + _label = Label(text) + self._vPanel.add(_label) + self.add(self._vPanel) + + + +class MicroblogPanel(VerticalPanel): + + def __init__(self): + VerticalPanel.__init__(self) + self.setStyleName('microblogPanel') + + def addEntry(self, text, author=None, date=None): + """Add an entry to the panel + @param text: main text of the entry + @param author: who wrote the entry + @param date: when the entry was written""" + _entry = MicroblogEntry(text) + self.add(_entry) + class MiddlePannel(HorizontalPanel): def __init__(self,host): self.host=host HorizontalPanel.__init__(self) - self.add(self.host.contactPanel) + self._left = self.host.contactPanel + self._right = HorizontalPanel() + self._right.setWidth('100%') + self._right.setHeight('100%') + test = MicroblogPanel() + self._right.add(test) + test.addEntry("test entry") + self.add(self._left) + self.setCellWidth(self._left, "15%") + self.add(self._right) + self.setCellWidth(self._right, "85%") class MainPanel(VerticalPanel): @@ -232,6 +210,7 @@ menu = Menu() magic_box = host.magicBox middle_panel = MiddlePannel(self.host) + middle_panel.setWidth('100%') self.add(menu) self.add(magic_box) @@ -242,6 +221,7 @@ self.setCellVerticalAlignment(magic_box, HasAlignment.ALIGN_CENTER) self.setCellHorizontalAlignment(magic_box, HasAlignment.ALIGN_CENTER) self.setCellHeight(middle_panel, "90%") + self.setCellWidth(middle_panel, "100%") self.setWidth("100%") self.setHeight("100%") @@ -275,14 +255,23 @@ del self._dialog # don't work if self._dialog is None #it's time to fill the page - bridge = BrigeCall() + bridge = BridgeCall() bridge.call('getContacts', self._getContactsCB) + bridge_signals = BridgeSignals() + bridge_signals.call('getSignals', self._getSignalsCB) + + def _getContactsCB(self, contacts_data): for contact in contacts_data: jid, attributes, groups = contact self.contactPanel.addContact(jid, attributes, groups) + def _getSignalsCB(self, signal_data): + bridge_signals = BridgeSignals() + bridge_signals.call('getSignals', self._getSignalsCB) + print('Got signal ==> name: %s, params: %s' % (signal_data[0],signal_data[1])) + if __name__ == '__main__': pyjd.setup("http://localhost:8080/libervia.html") diff -r 0a7c685faa53 -r 669c531a857e libervia.tac --- a/libervia.tac Mon Jan 31 20:31:25 2011 +0100 +++ b/libervia.tac Tue Feb 08 21:18:31 2011 +0100 @@ -182,13 +182,31 @@ Resource.__init__(self) self.register=None self.sat_host=sat_host - + self.signalDeferred = None + def plugRegister(self, register): self.register = register + + def jsonrpc_getSignals(self): + """Keep the connection alive until a signal is received, then send it + @return: (signal, *signal_args)""" + self.signalDeferred = defer.Deferred() + return self.signalDeferred + + def getGenericCb(self, function_name): + """Return a generic function which send all params to signalDeferred.callback""" + def genericCb(*args): + if self.signalDeferred: + self.signalDeferred.callback((function_name,args)) + else: + print("Warning: signal [%s] can't be sent" % function_name) + return genericCb + + def genericCallback(self, *args): + """"This method send all params to signalDeferred""" + if self.signalDeferred: + print ("Sending signals %s") - def presenceUpdate(self, entity, show, priority, statuses, profile): - print "update de",entity - def connected(self, profile): assert(self.register) #register must be plugged request = self.register.getWaitingRequest(profile) @@ -205,13 +223,27 @@ _error_t = "UNKNOWN" self.register._logginError(profile, request, _error_t) + def render(self, request): + """ + Render method wich reject access if user is not identified + """ + _session = request.getSession() + parsed = jsonrpclib.loads(request.content.read()) + try: + profile = _session.sat_profile + except AttributeError: + #user is not identified, we return a jsonrpc fault + fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia + return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) + self.request = request + return jsonrpc.JSONRPC.render(self, request) class Libervia(service.Service): def __init__(self): root = File("output/") self.signal_handler = SignalHandler(self) - root.putChild('test', self.signal_handler) + root.putChild('json_signal_api', self.signal_handler) _register = Register(self) self.signal_handler.plugRegister(_register) root.putChild('json_api', MethodHandler(self)) @@ -225,9 +257,10 @@ print(u"Can't connect to SàT backend, are you sure it's launched ?") import sys sys.exit(1) - self.bridge.register("presenceUpdate", self.signal_handler.presenceUpdate) self.bridge.register("connected", self.signal_handler.connected) self.bridge.register("connectionError", self.signal_handler.connectionError) + for signal_name in ['presenceUpdate']: + self.bridge.register(signal_name, self.signal_handler.getGenericCb(signal_name)) def startService(self): reactor.listenTCP(8080, self.site)