comparison src/tools/memory.py @ 412:62b17854254e

database integration: first draft - using SQLite as backend /!\ Not finished yet, break execution. SàT CAN'T LAUNCH PROPERLY IN THE CURRENT STATE
author Goffi <goffi@goffi.org>
date Sun, 30 Oct 2011 23:13:40 +0100
parents 3ed53803b3b3
children dd4caab17008
comparison
equal deleted inserted replaced
411:b109a79ac72f 412:62b17854254e
25 import time 25 import time
26 import cPickle as pickle 26 import cPickle as pickle
27 from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError 27 from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError
28 from xml.dom import minidom 28 from xml.dom import minidom
29 from logging import debug, info, warning, error 29 from logging import debug, info, warning, error
30 import pdb
31 from twisted.internet import defer 30 from twisted.internet import defer
32 from twisted.words.protocols.jabber import jid 31 from twisted.words.protocols.jabber import jid
33 from sat.tools.xml_tools import paramsXml2xmlUI 32 from sat.tools.xml_tools import paramsXml2xmlUI
34 from sat.core.default_config import default_config 33 from sat.core.default_config import default_config
34 from sat.tools.sqlite import SqliteStorage
35 35
36 SAVEFILE_PARAM_XML="/param" #xml parameters template 36 SAVEFILE_PARAM_XML="/param" #xml parameters template
37 SAVEFILE_PARAM_DATA="/param" #individual & general parameters; _ind and _gen suffixes will be added 37 SAVEFILE_PARAM_DATA="/param" #individual & general parameters; _ind and _gen suffixes will be added
38 SAVEFILE_HISTORY="/history" 38 SAVEFILE_HISTORY="/history"
39 SAVEFILE_PRIVATE="/private" #file used to store misc values (mainly for plugins) 39 SAVEFILE_PRIVATE="/private" #file used to store misc values (mainly for plugins)
40 SAVEFILE_DATABASE="/sat.db"
40 41
41 class Param(): 42 class Param():
42 """This class manage parameters with xml""" 43 """This class manage parameters with xml"""
43 ### TODO: add desciption in params 44 ### TODO: add desciption in params
44 45
73 74
74 def load_xml(self, file): 75 def load_xml(self, file):
75 """Load parameters template from file""" 76 """Load parameters template from file"""
76 self.dom = minidom.parse(file) 77 self.dom = minidom.parse(file)
77 78
78 def load_data(self, file): 79 def loadGenData(self, storage):
79 """Load parameters data from file""" 80 """Load general parameters data from storage
80 file_ind = file + '_ind' 81 @param storage: xxxStorage object instance
81 file_gen = file + '_gen' 82 @return: deferred triggered once params are loaded"""
82 83 return storage.loadGenParams(self.params_gen)
83 if os.path.exists(file_gen): 84
84 try: 85 def loadIndData(self, storage, profile):
85 with open(file_gen, 'r') as file_gen_pickle: 86 """Load individual parameters
86 self.params_gen=pickle.load(file_gen_pickle) 87 set self.params cache
87 debug(_("general params data loaded")) 88 @param storage: xxxStorage object instance
88 except: 89 @param profile: profile to load (*must exist*)
89 error (_("Can't load general params data !")) 90 @return: deferred triggered once params are loaded"""
90 91 self.params[profile] = {}
91 if os.path.exists(file_ind): 92 return storage.loadIndParams(self.params, profile)
92 try:
93 with open(file_ind, 'r') as file_ind_pickle:
94 self.params=pickle.load(file_ind_pickle)
95 debug(_("individual params data loaded"))
96 except:
97 error (_("Can't load individual params data !"))
98 93
99 def save_xml(self, file): 94 def save_xml(self, file):
100 """Save parameters template to xml file""" 95 """Save parameters template to xml file"""
101 with open(file, 'wb') as xml_file: 96 with open(file, 'wb') as xml_file:
102 xml_file.write(self.dom.toxml('utf-8')) 97 xml_file.write(self.dom.toxml('utf-8'))
122 self.params_gen = {} 117 self.params_gen = {}
123 host.set_const('savefile_param_xml', SAVEFILE_PARAM_XML) 118 host.set_const('savefile_param_xml', SAVEFILE_PARAM_XML)
124 host.set_const('savefile_param_data', SAVEFILE_PARAM_DATA) 119 host.set_const('savefile_param_data', SAVEFILE_PARAM_DATA)
125 host.registerGeneralCB("registerNewAccount", host.registerNewAccountCB) 120 host.registerGeneralCB("registerNewAccount", host.registerNewAccountCB)
126 121
127 def getProfilesList(self):
128 return self.params.keys()
129
130 def createProfile(self, name): 122 def createProfile(self, name):
131 """Create a new profile 123 """Create a new profile
132 @param name: Name of the profile""" 124 @param name: Name of the profile"""
133 if self.params.has_key(name): 125 if self.storage.hasProfile(name):
134 info (_('The profile name already exists')) 126 info (_('The profile name already exists'))
135 return 1 127 return True
136 if not self.host.trigger.point("ProfileCreation", name): 128 if not self.host.trigger.point("ProfileCreation", name):
137 return 0 129 return False
138 self.params[name]={} 130 self.params[name]={}
139 return 0 131 return False
140 132
141 def deleteProfile(self, name): 133 def deleteProfile(self, name):
142 """Delete an existing profile 134 """Delete an existing profile
143 @param name: Name of the profile""" 135 @param name: Name of the profile"""
144 if not self.params.has_key(name): 136 if not self.storage.hasProfile(name):
145 error (_('Trying to delete an unknown profile')) 137 error (_('Trying to delete an unknown profile'))
146 return 1 138 return True
147 del self.params[name] 139 del self.params[name]
148 return 0 140 return False
149 141
150 def getProfileName(self, profile_key): 142 def getProfileName(self, profile_key):
151 """return profile according to profile_key 143 """return profile according to profile_key
152 @param profile_key: profile name or key which can be 144 @param profile_key: profile name or key which can be
153 @ALL@ for all profiles 145 @ALL@ for all profiles
157 if not self.params: 149 if not self.params:
158 return "" 150 return ""
159 default = self.host.memory.getPrivate('Profile_default') 151 default = self.host.memory.getPrivate('Profile_default')
160 if not default or not default in self.params: 152 if not default or not default in self.params:
161 info(_('No default profile, returning first one')) #TODO: manage real default profile 153 info(_('No default profile, returning first one')) #TODO: manage real default profile
162 default = self.params.keys()[0] 154 default = self.getProfilesList()[0]
163 self.host.memory.setPrivate('Profile_default', default) 155 self.host.memory.setPrivate('Profile_default', default)
164 return default #FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists 156 return default #FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists
165 if not self.params.has_key(profile_key): 157 if not self.storage.hasProfile(profile_key):
166 info (_('Trying to access an unknown profile')) 158 info (_('Trying to access an unknown profile'))
167 return "" 159 return ""
168 return profile_key 160 return profile_key
169 161
170 def __get_unique_node(self, parent, tag, name): 162 def __get_unique_node(self, parent, tag, name):
394 error(_('Requesting an unknown parameter (%(category)s/%(name)s)') % {'category':category, 'name':name}) 386 error(_('Requesting an unknown parameter (%(category)s/%(name)s)') % {'category':category, 'name':name})
395 return 387 return
396 388
397 if node[0] == 'general': 389 if node[0] == 'general':
398 self.params_gen[(category, name)] = value 390 self.params_gen[(category, name)] = value
391 self.storage.setGenParam(category, name, value)
399 for profile in self.getProfilesList(): 392 for profile in self.getProfilesList():
400 if self.host.isConnected(profile): 393 if self.host.isConnected(profile):
401 self.host.bridge.paramUpdate(name, value, category, profile) 394 self.host.bridge.paramUpdate(name, value, category, profile)
402 return 395 return
403 396
406 399
407 type = node[1].getAttribute("type") 400 type = node[1].getAttribute("type")
408 if type=="button": 401 if type=="button":
409 print "clique",node.toxml() 402 print "clique",node.toxml()
410 else: 403 else:
411 self.params[profile][(category, name)] = value 404 if self.host.isConnected(profile): #key can not exists if profile is not connected
412 self.host.bridge.paramUpdate(name, value, category, profile) #TODO: add profile in signal 405 self.params[profile][(category, name)] = value
406 self.host.bridge.paramUpdate(name, value, category, profile)
407 self.storage.setIndParam(category, name, value, profile)
413 408
414 class Memory: 409 class Memory:
415 """This class manage all persistent informations""" 410 """This class manage all persistent informations"""
416 411
417 def __init__(self, host): 412 def __init__(self, host):
418 info (_("Memory manager init")) 413 info (_("Memory manager init"))
414 self.initialized = defer.Deferred()
415 init_defers = [] #list of deferred to wait before initialization is finished
419 self.host = host 416 self.host = host
420 self.contacts={} 417 self.contacts={}
421 self.presenceStatus={} 418 self.presenceStatus={}
422 self.lastResource={} #tmp, will be refactored with bdd integration 419 self.lastResource={} #tmp, will be refactored with bdd integration
423 self.subscriptions={} 420 self.subscriptions={}
427 self.server_features={} #used to store discovery's informations 424 self.server_features={} #used to store discovery's informations
428 self.server_identities={} 425 self.server_identities={}
429 self.config = self.parseMainConf() 426 self.config = self.parseMainConf()
430 host.set_const('savefile_history', SAVEFILE_HISTORY) 427 host.set_const('savefile_history', SAVEFILE_HISTORY)
431 host.set_const('savefile_private', SAVEFILE_PRIVATE) 428 host.set_const('savefile_private', SAVEFILE_PRIVATE)
432 self.load() 429 host.set_const('savefile_database', SAVEFILE_DATABASE)
430 database_file = os.path.expanduser(self.getConfig('','local_dir')+
431 self.host.get_const('savefile_database'))
432 self.loadFiles()
433 self.storage = SqliteStorage(database_file)
434 self.storage.initialized.addCallback(lambda ignore: self.load(init_defers))
435
436 defer.DeferredList(init_defers).chainDeferred(self.initialized)
433 437
434 def parseMainConf(self): 438 def parseMainConf(self):
435 """look for main .ini configuration file, and parse it""" 439 """look for main .ini configuration file, and parse it"""
436 _config = SafeConfigParser(defaults=default_config) 440 _config = SafeConfigParser(defaults=default_config)
437 try: 441 try:
453 except NoOptionError, NoSectionError: 457 except NoOptionError, NoSectionError:
454 _value = '' 458 _value = ''
455 459
456 return os.path.expanduser(_value) if name.endswith('_path') or name.endswith('_dir') else _value 460 return os.path.expanduser(_value) if name.endswith('_path') or name.endswith('_dir') else _value
457 461
458 def load(self): 462
463 def loadFiles(self):
459 """Load parameters and all memory things from file/db""" 464 """Load parameters and all memory things from file/db"""
460 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+ 465 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+
461 self.host.get_const('savefile_param_xml')) 466 self.host.get_const('savefile_param_xml'))
462 param_file_data = os.path.expanduser(self.getConfig('','local_dir')+ 467 param_file_data = os.path.expanduser(self.getConfig('','local_dir')+
463 self.host.get_const('savefile_param_data')) 468 self.host.get_const('savefile_param_data'))
464 history_file = os.path.expanduser(self.getConfig('','local_dir')+ 469 history_file = os.path.expanduser(self.getConfig('','local_dir')+
465 self.host.get_const('savefile_history')) 470 self.host.get_const('savefile_history'))
466 private_file = os.path.expanduser(self.getConfig('','local_dir')+ 471 private_file = os.path.expanduser(self.getConfig('','local_dir')+
467 self.host.get_const('savefile_private')) 472 self.host.get_const('savefile_private'))
468 473
469 #parameters 474 #parameters template
470 if os.path.exists(param_file_xml): 475 if os.path.exists(param_file_xml):
471 try: 476 try:
472 self.params.load_xml(param_file_xml) 477 self.params.load_xml(param_file_xml)
473 debug(_("params template loaded")) 478 debug(_("params template loaded"))
474 except: 479 except:
476 self.params.load_default_params() 481 self.params.load_default_params()
477 else: 482 else:
478 info (_("No params template, using default template")) 483 info (_("No params template, using default template"))
479 self.params.load_default_params() 484 self.params.load_default_params()
480 485
481 try: 486
482 self.params.load_data(param_file_data)
483 debug(_("params loaded"))
484 except:
485 error (_("Can't load params !"))
486
487 #history 487 #history
488 if os.path.exists(history_file): 488 if os.path.exists(history_file):
489 try: 489 try:
490 with open(history_file, 'r') as history_pickle: 490 with open(history_file, 'r') as history_pickle:
491 self.history=pickle.load(history_pickle) 491 self.history=pickle.load(history_pickle)
499 with open(private_file, 'r') as private_pickle: 499 with open(private_file, 'r') as private_pickle:
500 self.private=pickle.load(private_pickle) 500 self.private=pickle.load(private_pickle)
501 debug(_("private values loaded")) 501 debug(_("private values loaded"))
502 except: 502 except:
503 error (_("Can't load private values !")) 503 error (_("Can't load private values !"))
504
505 def load(self, init_defers):
506 """Load parameters and all memory things from db
507 @param init_defers: list of deferred to wait before parameters are loaded"""
508 #parameters data
509 init_defers.append(self.params.loadGenData(self.storage))
510
511 def loadIndividualParams(self, profile_key):
512 """Load individual parameters for a profile
513 @param profile_key: %(doc_profile_key)s"""
514 profile = self.getProfileName(profile_key)
515 if not profile:
516 error (_('Trying to load parameters for a non-existant profile'))
517 raise Exception("Profile doesn't exist")
518 return self.params.loadIndParams(profile)
519
504 520
505 def save(self): 521 def save(self):
506 """Save parameters and all memory things to file/db""" 522 """Save parameters and all memory things to file/db"""
507 #TODO: need to encrypt files (at least passwords !) and set permissions 523 #TODO: need to encrypt files (at least passwords !) and set permissions
508 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+ 524 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+
523 with open(private_file, 'w') as private_pickle: 539 with open(private_file, 'w') as private_pickle:
524 pickle.dump(self.private, private_pickle) 540 pickle.dump(self.private, private_pickle)
525 debug(_("private values saved")) 541 debug(_("private values saved"))
526 542
527 def getProfilesList(self): 543 def getProfilesList(self):
528 return self.params.getProfilesList() 544 return self.storage.getProfilesList()
529 545
530 546
531 def getProfileName(self, profile_key): 547 def getProfileName(self, profile_key):
532 """Return name of profile from keyword 548 """Return name of profile from keyword
533 @param profile_key: can be the profile name or a keywork (like @DEFAULT@) 549 @param profile_key: can be the profile name or a keywork (like @DEFAULT@)