bridge: automatic bridge generator, first draft
This commit is contained in:
parent
9951b0b116
commit
f1dab02efa
2 changed files with 550 additions and 0 deletions
234
src/bridge/bridge_contructor.py
Executable file
234
src/bridge/bridge_contructor.py
Executable file
|
|
@ -0,0 +1,234 @@
|
|||
#!/usr/bin/python
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SAT: a jabber client
|
||||
Copyright (C) 2009, 2010, 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
#consts
|
||||
NAME = u"bridge_constructor"
|
||||
VERSION="0.1.0"
|
||||
ABOUT = NAME+u""" v%s (c) Jérôme Poisson (aka Goffi) 2011
|
||||
|
||||
---
|
||||
"""+NAME+u""" Copyright (C) 2011 Jérôme Poisson (aka Goffi)
|
||||
This program comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions.
|
||||
---
|
||||
|
||||
This script construct a SàT bridge using the given protocol
|
||||
"""
|
||||
MANAGED_PROTOCOLES=['dbus']
|
||||
DEFAULT_PROTOCOLE='dbus'
|
||||
|
||||
import sys
|
||||
import os
|
||||
from os import path
|
||||
from optparse import OptionParser
|
||||
from ConfigParser import RawConfigParser as Parser
|
||||
from ConfigParser import NoOptionError
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
#Used when the signature parsing is going wrong (invalid signature ?)
|
||||
pass
|
||||
|
||||
class Constructor:
|
||||
|
||||
def __init__(self, bridge_template, options):
|
||||
self.bridge_template = bridge_template
|
||||
self.options = options
|
||||
|
||||
def getValues(self, name):
|
||||
"""Return values of a function in a dict
|
||||
@param name: Name of the function to get
|
||||
@return: dict, each key has the config value or None if the value is not set"""
|
||||
function={}
|
||||
for option in ['type','category','sig_in','sig_out','doc']:
|
||||
try:
|
||||
value = self.bridge_template.get(name, option)
|
||||
except NoOptionError:
|
||||
value = None
|
||||
function[option] = value
|
||||
return function
|
||||
|
||||
def getArguments(self, signature):
|
||||
"""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")"""
|
||||
i=0
|
||||
idx=0
|
||||
attr_string=""
|
||||
while i<len(signature):
|
||||
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)
|
||||
idx+=1
|
||||
|
||||
if signature[i] == 'a':
|
||||
i+=1
|
||||
if signature[i]!='{' and signature[i]!='(': #FIXME: must manage tuples out of arrays
|
||||
i+=1
|
||||
continue #we have a simple type for the array
|
||||
opening_car = signature[i]
|
||||
closing_car = '}' if opening_car == '{' else ')'
|
||||
opening_count = 1
|
||||
while (True): #we have a dict or a list of tuples
|
||||
i+=1
|
||||
if i>=len(signature):
|
||||
raise ParseError("missing }")
|
||||
if signature[i] == opening_car:
|
||||
opening_count+=1
|
||||
if signature[i] == closing_car:
|
||||
opening_count-=1
|
||||
if opening_count == 0:
|
||||
break
|
||||
i+=1
|
||||
return attr_string
|
||||
|
||||
def generateCoreSide(self):
|
||||
"""create the constructor in SàT core side (backend)"""
|
||||
raise NotImplementedError
|
||||
|
||||
class DbusConstructor(Constructor):
|
||||
|
||||
def __init__(self, bridge_template, options):
|
||||
Constructor.__init__(self, bridge_template, options)
|
||||
self.core_template="dbus_core_template.py"
|
||||
self.core_dest="DBus.py"
|
||||
|
||||
def generateCoreSide(self):
|
||||
signals_part = []
|
||||
methods_part = []
|
||||
direct_calls = []
|
||||
sections = self.bridge_template.sections()
|
||||
sections.sort()
|
||||
for section in sections:
|
||||
function = self.getValues(section)
|
||||
print ("Adding %s %s" % (section, function["type"]))
|
||||
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'])
|
||||
}
|
||||
|
||||
if function["type"] == "signal":
|
||||
completion['body'] = "pass" if not self.options.debug else 'debug ("%s")' % section
|
||||
signals_part.append("""\
|
||||
@dbus.service.signal(const_INT_PREFIX+const_%(category)s_SUFFIX,
|
||||
signature='%(sig_in)s')
|
||||
def %(name)s(self, %(args)s):
|
||||
%(body)s
|
||||
""" % completion)
|
||||
direct_calls.append("""\
|
||||
def %(name)s(self, %(args)s):
|
||||
self.dbus_bridge.%(name)s(%(args)s)
|
||||
""" % completion)
|
||||
|
||||
elif function["type"] == "method":
|
||||
completion['debug'] = "" if not self.options.debug else 'debug ("%s")\n%s' % (section,8*' ')
|
||||
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)
|
||||
""" % completion)
|
||||
|
||||
#at this point, signals_part, methods_part and direct_calls should be filled,
|
||||
#we just have to place them in the right part of the template
|
||||
core_bridge = []
|
||||
try:
|
||||
with open(self.core_template) as core_template:
|
||||
for line in core_template:
|
||||
if line.startswith('##SIGNALS_PART##'):
|
||||
core_bridge.extend(signals_part)
|
||||
elif line.startswith('##METHODS_PART##'):
|
||||
core_bridge.extend(methods_part)
|
||||
elif line.startswith('##DIRECT_CALLS##'):
|
||||
core_bridge.extend(direct_calls)
|
||||
else:
|
||||
core_bridge.append(line.replace('\n',''))
|
||||
except IOError:
|
||||
print ("Can't open template file [%s]" % self.core_template)
|
||||
sys.exit(1)
|
||||
|
||||
#now we write to final file
|
||||
if os.path.exists(self.core_dest) and not self.options.force:
|
||||
print ("The destination file [%s] already exists ! Use --force to overwrite it" % self.core_dest)
|
||||
try:
|
||||
with open(self.core_dest,'w') as dest_file:
|
||||
dest_file.write('\n'.join(core_bridge))
|
||||
except IOError:
|
||||
print ("Can't open destination file [%s]" % self.dest_file)
|
||||
|
||||
class ConstructorError(Exception):
|
||||
pass
|
||||
|
||||
class ConstructorFactory:
|
||||
def create(self, bridge_template, options):
|
||||
if options.protocole=='dbus':
|
||||
return DbusConstructor(bridge_template, options)
|
||||
|
||||
raise ConstructorError('Unknown constructor type')
|
||||
|
||||
class BridgeConstructor:
|
||||
def __init__(self):
|
||||
self.options = None
|
||||
|
||||
def check_options(self):
|
||||
"""Check command line options"""
|
||||
_usage="""
|
||||
%prog [options]
|
||||
|
||||
%prog --help for options list
|
||||
"""
|
||||
parser = OptionParser(usage=_usage,version=ABOUT % VERSION)
|
||||
|
||||
parser.add_option("-p", "--protocole", action="store", type="string", default=DEFAULT_PROTOCOLE,
|
||||
help="Generate bridge using PROTOCOLE (default: %s, possible values: [%s])" % (DEFAULT_PROTOCOLE, ", ".join(MANAGED_PROTOCOLES)))
|
||||
parser.add_option("-s", "--side", action="store", type="string", default="core",
|
||||
help="Which side of the bridge do you want to make ? (default: %default, possible values: [core, frontend])")
|
||||
parser.add_option("-t", "--template", action="store", type="string", default='bridge_template.ini',
|
||||
help="Use TEMPLATE to generate bridge (default: %default)")
|
||||
parser.add_option("-f", "--force", action="store_true", default=False,
|
||||
help=("Force overwritting of existing files"))
|
||||
parser.add_option("-d", "--debug", action="store_true", default=False,
|
||||
help=("Add debug information printing"))
|
||||
|
||||
(self.options, args) = parser.parse_args()
|
||||
return args
|
||||
|
||||
def go(self):
|
||||
self.check_options()
|
||||
self.template = Parser()
|
||||
try:
|
||||
self.template.readfp(open(self.options.template))
|
||||
except IOError:
|
||||
print ("The template file doesn't exist or is not accessible")
|
||||
exit(1)
|
||||
constructor = ConstructorFactory().create(self.template, self.options)
|
||||
if self.options.side == "core":
|
||||
constructor.generateCoreSide()
|
||||
|
||||
if __name__ == "__main__":
|
||||
bc = BridgeConstructor()
|
||||
bc.go()
|
||||
316
src/bridge/bridge_template.ini
Normal file
316
src/bridge/bridge_template.ini
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
;signals
|
||||
|
||||
[connected]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=s
|
||||
doc=Connection is done
|
||||
|
||||
[disconnected]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=s
|
||||
doc=Connection is finished or lost
|
||||
|
||||
[connection_error]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=ss
|
||||
doc=Something went wront with the connection
|
||||
|
||||
[newContact]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=sa{ss}ass
|
||||
doc=New contact received in roster
|
||||
|
||||
[newMessage]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=sssss
|
||||
doc=A message has been received
|
||||
|
||||
[newAlert]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=ssss
|
||||
doc=A message has been received
|
||||
|
||||
[presenceUpdate]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=ssia{ss}s
|
||||
doc=Somebody changed his presence informations.
|
||||
|
||||
[subscribe]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=sss
|
||||
doc=Somebody wants to be added in roster list
|
||||
|
||||
[paramUpdate]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=ssss
|
||||
doc=A parameter has been changed
|
||||
|
||||
[contactDeleted]
|
||||
type=signal
|
||||
category=communication
|
||||
sig_in=ss
|
||||
doc=A contact has been supressed from roster list
|
||||
|
||||
[askConfirmation]
|
||||
type=signal
|
||||
category=request
|
||||
sig_in=ssa{ss}
|
||||
doc=A confirmation is needed for an action
|
||||
|
||||
[actionResult]
|
||||
type=signal
|
||||
category=request
|
||||
sig_in=ssa{ss}
|
||||
doc=Requested result of an action
|
||||
|
||||
[actionResultExt]
|
||||
type=signal
|
||||
category=request
|
||||
sig_in=ssa{sa{ss}}
|
||||
doc=Requested result of an action (Extended)
|
||||
|
||||
[updatedValue]
|
||||
type=signal
|
||||
category=request
|
||||
sig_in=sa{ss}
|
||||
doc=A value has been updated
|
||||
|
||||
;methods
|
||||
|
||||
[getVersion]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=
|
||||
sig_out=s
|
||||
doc=Get "Salut à Toi" version
|
||||
|
||||
[getProfileName]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=s
|
||||
sig_out=s
|
||||
doc=Get real profile name from profile key
|
||||
|
||||
[getProfilesList]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=
|
||||
sig_out=as
|
||||
doc=Get all profiles
|
||||
|
||||
[createProfile]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=s
|
||||
sig_out=i
|
||||
doc=Create a new profile
|
||||
|
||||
[deleteProfile]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=s
|
||||
sig_out=i
|
||||
doc=Delete a profile
|
||||
|
||||
[registerNewAccount]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=sssi
|
||||
sig_out=s
|
||||
doc=Register a new account on a given server
|
||||
|
||||
[connect]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Connect a profile
|
||||
|
||||
[disconnect]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Disconnect a profile
|
||||
|
||||
[isConnected]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=
|
||||
sig_out=b
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Tell if a profile is connected
|
||||
|
||||
[getContacts]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=a(sa{ss}as)
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Return informations about all contacts
|
||||
|
||||
[getPresenceStatus]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=a{sa{s(sia{ss})}}
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Return presence informations of all contacts
|
||||
|
||||
[getWaitingSub]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=a{ss}
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Get subscription requests in queue
|
||||
|
||||
[sendMessage]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=sssss
|
||||
sig_out=
|
||||
param_4_default="@DEFAULT@"
|
||||
doc=Send a message
|
||||
|
||||
[setPresence]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ssia{ss}s
|
||||
sig_out=
|
||||
param_4_default="@DEFAULT@"
|
||||
doc=Set presence information for the profile
|
||||
|
||||
[subscription]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=sss
|
||||
sig_out=
|
||||
param_2_default="@DEFAULT@"
|
||||
doc=Send subscription request/answer to a contact
|
||||
|
||||
[setParam]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ssss
|
||||
sig_out=
|
||||
param_3_default="@DEFAULT@"
|
||||
doc=Change a parameter
|
||||
|
||||
[getParamA]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=sss
|
||||
sig_out=s
|
||||
param_2_default="@DEFAULT@"
|
||||
doc=Helper method to get a parameter's attribute
|
||||
|
||||
[getParamsUI]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=s
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Return a SàT XMLUI for parameters
|
||||
|
||||
[getParams]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=s
|
||||
sig_out=s
|
||||
param_0_default="@DEFAULT@"
|
||||
doc=Return XML of parameters
|
||||
|
||||
[getParamsForCategory]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ss
|
||||
sig_out=s
|
||||
param_1_default="@DEFAULT@"
|
||||
doc=Return a xml of all params in a category
|
||||
|
||||
[getParamsCategories]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=
|
||||
sig_out=as
|
||||
doc=Get all categories currently existing in parameters
|
||||
|
||||
[getHistory]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ssi
|
||||
sig_out=a{i(ss)}
|
||||
doc=Get history of a communication between two entities
|
||||
|
||||
[addContact]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ss
|
||||
sig_out=
|
||||
param_1_default="@DEFAULT@"
|
||||
doc=Add a contact to profile's roster list
|
||||
|
||||
[delContact]
|
||||
type=method
|
||||
category=communication
|
||||
sig_in=ss
|
||||
sig_out=
|
||||
param_1_default="@DEFAULT@"
|
||||
doc=Remove a contact from profile's roster list
|
||||
|
||||
[launchAction]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=sa{ss}s
|
||||
sig_out=s
|
||||
param_2_default="@DEFAULT@"
|
||||
doc=Launch a specific action
|
||||
|
||||
[confirmationAnswer]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=sba{ss}
|
||||
sig_out=
|
||||
doc=Give answer to a confirmation request
|
||||
|
||||
[getProgress]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=s
|
||||
sig_out=a{ss}
|
||||
doc=Get progress information for an action
|
||||
|
||||
[getMenus]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=
|
||||
sig_out=a(sss)
|
||||
doc=Get all additional menus
|
||||
|
||||
[getMenuHelp]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=sss
|
||||
sig_out=s
|
||||
param_2="NORMAL"
|
||||
doc=Get help informationd for a menu
|
||||
|
||||
[callMenu]
|
||||
type=method
|
||||
category=request
|
||||
sig_in=ssss
|
||||
sig_out=s
|
||||
doc=Execute action associated with a menu
|
||||
|
||||
Loading…
Reference in a new issue