changeset 266:c4b84a2d2ad1

bridge: constructor and template improved, documentation added
author Goffi <goffi@goffi.org>
date Mon, 24 Jan 2011 17:47:45 +0100
parents b5f1f3dc9ac6
children bdcd535e179e
files frontends/src/quick_frontend/quick_app.py src/bridge/DBus.py src/bridge/bridge_contructor.py src/bridge/bridge_template.ini src/sat.tac
diffstat 5 files changed, 220 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_app.py	Mon Jan 24 01:22:00 2011 +0100
+++ b/frontends/src/quick_frontend/quick_app.py	Mon Jan 24 17:47:45 2011 +0100
@@ -188,7 +188,7 @@
         self.contactList.clear_contacts()
         self.setStatusOnline(False)
     
-    def connection_error(self, profile, error_type):
+    def connection_error(self, error_type, profile):
         """called when something goest wrong with the connection"""
         if not self.check_profile(profile):
             return
--- a/src/bridge/DBus.py	Mon Jan 24 01:22:00 2011 +0100
+++ b/src/bridge/DBus.py	Mon Jan 24 17:47:45 2011 +0100
@@ -24,7 +24,6 @@
 import dbus
 import dbus.service
 import dbus.mainloop.glib
-import pdb
 from logging import debug, info, error
 
 const_INT_PREFIX = "org.goffi.SAT"  #Interface prefix
@@ -55,7 +54,7 @@
     
     @dbus.service.signal(const_INT_PREFIX+const_COMM_SUFFIX,
                          signature='ss')
-    def connection_error(self, profile, error_type):
+    def connection_error(self, error_type, profile):
         debug("Connection_error signal")
     
     @dbus.service.signal(const_INT_PREFIX+const_COMM_SUFFIX,
@@ -142,7 +141,7 @@
                          in_signature='s', out_signature='i')
     def deleteProfile(self, name):
         info ('Profile deletion asked')
-        return self.cb["deleteProfile"](str(name))
+        return self.cb["deleteProfile"](unicode(name))
 
     @dbus.service.method(const_INT_PREFIX+const_COMM_SUFFIX,
                          in_signature='sssi', out_signature='s')
@@ -163,7 +162,7 @@
         return self.cb["disconnect"](profile_key)
     
     @dbus.service.method(const_INT_PREFIX+const_COMM_SUFFIX,
-                         in_signature='', out_signature='b')
+                         in_signature='s', out_signature='b')
     def isConnected(self, profile_key='@DEFAULT@'):
         info ("Connection status asked")
         return self.cb["isConnected"](profile_key)
--- a/src/bridge/bridge_contructor.py	Mon Jan 24 01:22:00 2011 +0100
+++ b/src/bridge/bridge_contructor.py	Mon Jan 24 17:47:45 2011 +0100
@@ -41,8 +41,9 @@
 import os
 from os import path
 from optparse import OptionParser
-from ConfigParser import RawConfigParser as Parser
+from ConfigParser import SafeConfigParser as Parser
 from ConfigParser import NoOptionError
+import re
 
 
 class ParseError(Exception):
@@ -67,8 +68,49 @@
                 value = None
             function[option] = value
         return function
+    
+    def getDefault(self, name):
+        """Return default values of a function in a dict
+        @param name: Name of the function to get
+        @return: dict, each key is the integer param number (no key if no default value)"""
+        default_dict={}
+        def_re = re.compile(r"param_(\d+)_default")
+        
+        for option in self.bridge_template.options(name):
+            if option == 'doc_return':
+                default_dict['return'] = self.bridge_template.get(name, option)
+                continue
+            match = def_re.match(option)
+            if match:
+                try:
+                    idx = int(match.group(1))
+                except ValueError:
+                    raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
+                default_dict[idx] = self.bridge_template.get(name, option)
+        
+        return default_dict
 
-    def getArguments(self, signature):
+    def getArgumentsDoc(self, name):
+        """Return documentation of arguments
+        @param name: Name of the function to get
+        @return: dict, each key is the integer param number (no key if no argument doc), value is a tuple (name, doc)"""
+        doc_dict={}
+        option_re = re.compile(r"doc_param_(\d+)")
+        value_re = re.compile(r"^(\w+): (.*)$", re.MULTILINE | re.DOTALL)
+        for option in self.bridge_template.options(name):
+            match = option_re.match(option)
+            if match:
+                try:
+                    idx = int(match.group(1))
+                except ValueError:
+                    raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
+                value_match = value_re.match(self.bridge_template.get(name, option))
+                if not value_match:
+                    raise ParseError("Invalid value for parameter doc [%i]" % idx)
+                doc_dict[idx]=(value_match.group(1),value_match.group(2))
+        return doc_dict
+    
+    def getArguments(self, signature, name=None, default=None):
         """Return arguments to user given a signature
         @param signature: signature in the short form (using s,a,i,b etc)
         @return: list of arguments that correspond to a signature (e.g.: "sss" return "arg1, arg2, arg3")""" 
@@ -79,7 +121,10 @@
             if signature[i] not in ['b','y','n','i','x','q','u','t','d','s','a']:
                 raise ParseError("Unmanaged attribute type [%c]" % signature[i])
 
-            attr_string += ("" if idx==0 else ", ") + ("arg_%i" % idx)
+            attr_string += ("" if idx==0 else ", ") + ("%(name)s%(default)s" % {
+                'name':name[idx][0] if (name and name.has_key(idx)) else "arg_%i" % idx,
+                'default':"="+default[idx] if (default and default.has_key(idx)) else ''
+                }) #give arg_1, arg2, etc or name1, name2=default, etc
             idx+=1
 
             if signature[i] == 'a':
@@ -88,6 +133,7 @@
                     i+=1
                     continue #we have a simple type for the array
                 opening_car = signature[i]
+                assert(opening_car in ['{','('])
                 closing_car = '}' if opening_car == '{' else ')'
                 opening_count = 1
                 while (True): #we have a dict or a list of tuples
@@ -123,12 +169,14 @@
         for section in sections:
             function = self.getValues(section)
             print ("Adding %s %s" % (section, function["type"]))
+            default = self.getDefault(section)
+            arg_doc = self.getArgumentsDoc(section)
             completion = {
         'sig_in':function['sig_in'] or '',
         'sig_out':function['sig_out'] or '',
         'category':'REQ' if function['category'] == 'request' else 'COMM',
         'name':section, 
-        'args':self.getArguments(function['sig_in'])
+        'args':self.getArguments(function['sig_in'], name=arg_doc, default=default, )
         }
 
             if function["type"] == "signal":
@@ -146,11 +194,12 @@
 
             elif function["type"] == "method":
                 completion['debug'] = "" if not self.options.debug else 'debug ("%s")\n%s' % (section,8*' ')
+                completion['args_nodefault'] = self.getArguments(function['sig_in'], name=arg_doc)
                 methods_part.append("""\
     @dbus.service.method(const_INT_PREFIX+const_%(category)s_SUFFIX,
                          in_signature='%(sig_in)s', out_signature='%(sig_out)s')
     def %(name)s(self, %(args)s):
-        %(debug)sreturn self.cb["%(name)s"](%(args)s)
+        %(debug)sreturn self.cb["%(name)s"](%(args_nodefault)s)
 """ % completion)
 
         #at this point, signals_part, methods_part and direct_calls should be filled,
--- a/src/bridge/bridge_template.ini	Mon Jan 24 01:22:00 2011 +0100
+++ b/src/bridge/bridge_template.ini	Mon Jan 24 17:47:45 2011 +0100
@@ -1,3 +1,7 @@
+[DEFAULT]
+doc_profile=profile: Name of the profile.
+doc_profile_key=profile_key: Profile key which can be either a magic (eg: @DEFAULT@) or the name of an existing profile.
+
 ;signals
 
 [connected]
@@ -5,84 +9,140 @@
 category=communication
 sig_in=s
 doc=Connection is done
+doc_param_0=%(doc_profile)s
 
 [disconnected]
 type=signal
 category=communication
 sig_in=s
 doc=Connection is finished or lost
+doc_param_0=%(doc_profile)s
 
 [connection_error]
 type=signal
 category=communication
 sig_in=ss
 doc=Something went wront with the connection
+doc_param_0=error_type: Why the connection got wrong, can be
+ - AUTH_ERROR: Authentification error
+doc_param_1=%(doc_profile)s
 
 [newContact]
 type=signal
 category=communication
 sig_in=sa{ss}ass
 doc=New contact received in roster
+doc_param_0=contact: JID from who the message is comming
+doc_param_1=attributes: Dictionary of attributes where keys are:
+ - name: name of the contact
+ - to: "True" if the contact give its presence information to us 
+ - from: "True" if contact is registred to our presence information
+ - ask: "True" is subscription is pending
+doc_param_2=groups: Roster's groups where the contact is
+doc_param_3=%(doc_profile)s
 
 [newMessage]
 type=signal
 category=communication
 sig_in=sssss
 doc=A message has been received
+doc_param_0=from_jid: JID where the message is comming from
+doc_param_1=message: Message itself
+doc_param_2=mess_type: Type of the message (cf RFC 3921 #2.1.1)
+doc_param_3=to_jid: JID where the message must be sent
+doc_param_4=%(doc_profile)s
 
 [newAlert]
 type=signal
 category=communication
 sig_in=ssss
-doc=A message has been received
+doc=A new alert happened
+doc_param_0=message: Body of the alert
+doc_param_1=title: Title of the alert
+doc_param_2=alert_type: Type of the alert, can be:
+ - INFO: Informative message
+ - ERROR: something went wrong
+doc_param_3=%(doc_profile)s
 
 [presenceUpdate]
 type=signal
 category=communication
 sig_in=ssia{ss}s
 doc=Somebody changed his presence informations.
+doc_param_0=entity: JID from which we have presence informations
+doc_param_1=show: availability status (see RFC 3921 #2.2.2.1)
+doc_param_2=priority: Priority level of the ressource (see RFC 3921 #2.2.2.3)
+doc_param_3=statuses: Natural language description of the availability status (see RFC 3921 #2.2.2.2)
+doc_param_4=%(doc_profile)s
 
 [subscribe]
 type=signal
 category=communication
 sig_in=sss
-doc=Somebody wants to be added in roster list
+doc=Somebody wants to be added in roster
+doc_param_0=sub_type: Subscription states (see RFC 3921 #9)
+doc_param_1=entity: JID from which the subscription is coming
+doc_param_2=%(doc_profile)s
 
 [paramUpdate]
 type=signal
 category=communication
 sig_in=ssss
 doc=A parameter has been changed
+doc_param_0=name: Name of the updated parameter
+doc_param_1=value: New value of the parameter
+doc_param_2=category: Category of the updated parameter
+doc_param_3=%(doc_profile)s
 
 [contactDeleted]
 type=signal
 category=communication
 sig_in=ss
-doc=A contact has been supressed from roster list
+doc=A contact has been supressed from roster
+doc_param_0=entity: JID of the contact removed from roster
+doc_param_1=%(doc_profile)s
 
 [askConfirmation]
 type=signal
 category=request
 sig_in=ssa{ss}
 doc=A confirmation is needed for an action
+doc_param_0=conf_type: Type of the confirmation, can be:
+ - YES/NO: A question which need a yes or no answer
+ - FILE_TRANSFERT: A confirmation is needed before transfering a file
+doc_param_1=id: Id of the confirmation query
+doc_param_2=data: conf_type dependent data
 
 [actionResult]
 type=signal
 category=request
 sig_in=ssa{ss}
 doc=Requested result of an action
+doc_param_0=answer_type: Type of the answer, can be:
+ - SUPPRESS: The action is managed, the id MUST be removed from queue
+ - XMLUI: A SàT XMLUI interface is sent
+ - ERROR: Something went wrong when doing the action
+ - RESULT: General result, interpretation depend of the action
+doc_param_1=id: Id of the action
+doc_param_2=data: answer_type specific data
 
 [actionResultExt]
 type=signal
 category=request
 sig_in=ssa{sa{ss}}
 doc=Requested result of an action (Extended)
+doc_param_0=answer_type: Same as for [actionResult] but with the following additional one:
+ - DICT_DICT: As RESULT, but returned as a dictionary of dictionary 
+doc_param_1=id: Id of the action
+doc_param_2=data: answer_type specific data
 
 [updatedValue]
 type=signal
 category=request
 sig_in=sa{ss}
 doc=A value has been updated
+doc_param_0=name: Name of the updated value
+doc_param_1=value: New value
 
 ;methods
 
@@ -99,6 +159,7 @@
 sig_in=s
 sig_out=s
 doc=Get real profile name from profile key
+doc_param_0=%(doc_profile_key)s
 
 [getProfilesList]
 type=method
@@ -113,6 +174,10 @@
 sig_in=s
 sig_out=i
 doc=Create a new profile
+doc_param_0=%(doc_profile)s
+doc_return=status of the creation:
+ - 0: Profile created
+ - 1: The profile name already exists
 
 [deleteProfile]
 type=method
@@ -120,13 +185,23 @@
 sig_in=s
 sig_out=i
 doc=Delete a profile
+doc_param_0=%(doc_profile)s
+doc_return=status of the deletion:
+ - 0: Profile deleted
+ - 1: The profile doesn't exists
 
 [registerNewAccount]
+deprecated=
 type=method
 category=communication
 sig_in=sssi
 sig_out=s
+param_3_default=5222
 doc=Register a new account on a given server
+doc_param_0=login: login of the account
+doc_param_1=password: password of the account
+doc_param_2=host: host of the server to register to
+doc_param_3=port: port of the server to register to
 
 [connect]
 type=method
@@ -135,6 +210,7 @@
 sig_out=
 param_0_default="@DEFAULT@"
 doc=Connect a profile
+doc_param_0=%(doc_profile_key)s
 
 [disconnect]
 type=method
@@ -143,14 +219,16 @@
 sig_out=
 param_0_default="@DEFAULT@"
 doc=Disconnect a profile
+doc_param_0=%(doc_profile_key)s
 
 [isConnected]
 type=method
 category=communication
-sig_in=
+sig_in=s
 sig_out=b
 param_0_default="@DEFAULT@"
 doc=Tell if a profile is connected
+doc_param_0=%(doc_profile_key)s
 
 [getContacts]
 type=method
@@ -159,6 +237,11 @@
 sig_out=a(sa{ss}as)
 param_0_default="@DEFAULT@"
 doc=Return informations about all contacts
+doc_param_0=%(doc_profile_key)s
+doc_return=array of tuples with the following values:
+ - JID of the contact
+ - list of attributes as in [newContact]
+ - groups where the contact is
 
 [getPresenceStatus]
 type=method
@@ -167,6 +250,9 @@
 sig_out=a{sa{s(sia{ss})}}
 param_0_default="@DEFAULT@"
 doc=Return presence informations of all contacts
+doc_param_0=%(doc_profile_key)s
+doc_return=Dict of presence with bare JID of contact as key, and value as follow:
+ A dict where key is the resource and the value is a tuple with (show, priority, statuses) as for [presenceUpdate] 
 
 [getWaitingSub]
 type=method
@@ -175,22 +261,40 @@
 sig_out=a{ss}
 param_0_default="@DEFAULT@"
 doc=Get subscription requests in queue
+doc_param_0=%(doc_profile_key)s
+doc_return=Dict where contact JID is the key, and value is the subscription type
 
 [sendMessage]
 type=method
 category=communication
 sig_in=sssss
 sig_out=
+param_2_default=""
+param_3_default="chat"
 param_4_default="@DEFAULT@"
 doc=Send a message
+doc_param_0=to_jid: JID of the recipient
+doc_param_1=message: body of the message
+doc_param_2=subject: Subject of the message ("" if no subject)
+doc_param_3=mess_type: Type of the message (cf RFC 3921 #2.1.1)
+doc_param_4=%(doc_profile_key)s
 
 [setPresence]
 type=method
 category=communication
 sig_in=ssia{ss}s
 sig_out=
+param_0_default=""
+param_1_default=""
+param_2_default=0
+param_3_default={}
 param_4_default="@DEFAULT@"
 doc=Set presence information for the profile
+doc_param_0=to_jid: the JID to who we send the presence data (emtpy string for broadcast)
+doc_param_1=show: as for [presenceUpdate]
+doc_param_2=priority: as for [presenceUpdate]
+doc_param_3=statuses: as for [presenceUpdate]
+doc_param_4=%(doc_profile_key)s
 
 [subscription]
 type=method
@@ -199,6 +303,9 @@
 sig_out=
 param_2_default="@DEFAULT@"
 doc=Send subscription request/answer to a contact
+doc_param_0=sub_type: as for [subscribe]
+doc_param_1=entity: as for [subscribe]
+doc_param_2=%(doc_profile_key)s
 
 [setParam]
 type=method
@@ -207,6 +314,10 @@
 sig_out=
 param_3_default="@DEFAULT@"
 doc=Change a parameter
+doc_param_0=name: Name of the parameter to change
+doc_param_1=value: New Value of the parameter
+doc_param_2=category: Category of the parameter to change
+doc_param_3=%(doc_profile_key)s
 
 [getParamA]
 type=method
@@ -215,6 +326,9 @@
 sig_out=s
 param_2_default="@DEFAULT@"
 doc=Helper method to get a parameter's attribute
+doc_param_0=name: as for [setParam]
+doc_param_1=category: as for [setParam]
+doc_param_2=%(doc_profile_key)s
 
 [getParamsUI]
 type=method
@@ -223,6 +337,7 @@
 sig_out=s
 param_0_default="@DEFAULT@"
 doc=Return a SàT XMLUI for parameters
+doc_param_0=%(doc_profile_key)s
 
 [getParams]
 type=method
@@ -231,6 +346,7 @@
 sig_out=s
 param_0_default="@DEFAULT@"
 doc=Return XML of parameters
+doc_param_0=%(doc_profile_key)s
 
 [getParamsForCategory]
 type=method
@@ -238,7 +354,9 @@
 sig_in=ss
 sig_out=s
 param_1_default="@DEFAULT@"
-doc=Return a xml of all params in a category 
+doc=Return a xml of all params in a category
+doc_param_0=category: Category to get
+doc_param_1=%(doc_profile_key)s
 
 [getParamsCategories]
 type=method
@@ -246,6 +364,7 @@
 sig_in=
 sig_out=as
 doc=Get all categories currently existing in parameters
+doc_return=list of categories
 
 [getHistory]
 type=method
@@ -253,6 +372,10 @@
 sig_in=ssi
 sig_out=a{i(ss)}
 doc=Get history of a communication between two entities
+doc_param_0=from_jid: source JID
+doc_param_1=to_jid: dest JID
+doc_param_2=size: size of the history (0 for the whole history)
+doc_return=Dict where key is timestamp (seconds this the Epoch), and value is a tuple (from_jid, to_jid)
 
 [addContact]
 type=method
@@ -260,7 +383,9 @@
 sig_in=ss
 sig_out=
 param_1_default="@DEFAULT@"
-doc=Add a contact to profile's roster list
+doc=Add a contact to profile's roster
+doc_param_0=entity: JID to add to roster
+doc_param_1=%(doc_profile_key)s
 
 [delContact]
 type=method
@@ -268,7 +393,9 @@
 sig_in=ss
 sig_out=
 param_1_default="@DEFAULT@"
-doc=Remove a contact from profile's roster list
+doc=Remove a contact from profile's roster
+doc_param_0=entity: JID to remove from roster
+doc_param_1=%(doc_profile_key)s
 
 [launchAction]
 type=method
@@ -277,6 +404,10 @@
 sig_out=s
 param_2_default="@DEFAULT@"
 doc=Launch a specific action
+doc_param_0=action_type: type of the action which can be:
+ - button: A button is pushed
+doc_param_1=data: action_type dependant data
+doc_param_2=%(doc_profile_key)s
 
 [confirmationAnswer]
 type=method
@@ -284,6 +415,9 @@
 sig_in=sba{ss}
 sig_out=
 doc=Give answer to a confirmation request
+doc_param_0=id: id of the confirmation request
+doc_param_1=accepted: True if the action is confirmed
+doc_param_2=data: action specific data
 
 [getProgress]
 type=method
@@ -291,6 +425,10 @@
 sig_in=s
 sig_out=a{ss}
 doc=Get progress information for an action
+doc_param_0=id: id of the progression status
+doc_return=dict with progress information:
+ - position: current position
+ - size: end position 
 
 [getMenus]
 type=method
@@ -298,6 +436,11 @@
 sig_in=
 sig_out=a(sss)
 doc=Get all additional menus
+doc_return=list of tuple with the following value:
+ - category: Category of the menu
+ - name: Name of the menu
+ - menu_type: Type which can be:
+    * NORMAL: Classical application menu 
 
 [getMenuHelp]
 type=method
@@ -305,7 +448,11 @@
 sig_in=sss
 sig_out=s
 param_2="NORMAL"
-doc=Get help informationd for a menu
+doc=Get help information for a menu
+doc_param_0=category: Category of the menu
+doc_param_1=name: Name of the menu
+doc_param_2=menu_type: Type of the menu as in [getMenus] return value
+doc_return=Help string
 
 [callMenu]
 type=method
@@ -313,4 +460,8 @@
 sig_in=ssss
 sig_out=s
 doc=Execute action associated with a menu
-
+doc_param_0=category: as in [getMenuHelp]
+doc_param_1=name: as in [getMenuHelp]
+doc_param_2=menu_type: as in [getMenuHelp]
+doc_param_3=%(doc_profile_key)s
+doc_return=return an actionId or the empty string if something went wrong
--- a/src/sat.tac	Mon Jan 24 01:22:00 2011 +0100
+++ b/src/sat.tac	Mon Jan 24 17:47:45 2011 +0100
@@ -108,7 +108,7 @@
 
     def initializationFailed(self, reason):
         print ("initializationFailed: %s" % reason)
-        self.host_app.bridge.connection_error(self.profile,"AUTH_ERROR")
+        self.host_app.bridge.connection_error("AUTH_ERROR", self.profile)
         try:
             client.XMPPClient.initializationFailed(self, reason)
         except:
@@ -793,7 +793,7 @@
             return ""
 
     def callMenu(self, category, name, type="NORMAL", profile_key='@DEFAULT@'):
-        """return the help string of the menu"""
+        """return the id of the action"""
         profile = self.memory.getProfileName(profile_key)
         if not profile_key:
             error (_('Non-exsitant profile'))