changeset 2:669c531a857e

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
author Goffi <goffi@goffi.org>
date Tue, 08 Feb 2011 21:18:31 +0100
parents 0a7c685faa53
children 154d4caa57f4
files contact.py libervia.py libervia.tac
diffstat 3 files changed, 222 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- /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 <http://www.gnu.org/licenses/>.
+"""
+
+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")
--- 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")
--- 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)