Package emma
[hide private]
[frames] | no frames]

Source Code for Package emma

  1  """ 
  2  B{emma}: bot for digital assembly 
  3   
  4  The code is organice on three layers: 
  5      1. core controls event passing, config file, threads, mutex, storage, ... 
  6      2. L{interface} connect emma to the world (email, irc, wiki, microblog, 
  7      ...) 
  8      3. L{module} where the actual functionality happens. Easy to program, with 
  9      simple API of events to intercomunicate with the interfaces. 
 10   
 11  @copyright: (c) 2011 hackmeeting U{http://sindominio.net/hackmeeting} 
 12  @author: Ruben Pollan 
 13  @organization: hackmeeting U{http://sindominio.net/hackmeeting} 
 14  @contact: meskio@sindominio.net 
 15  @license: 
 16    This program is free software; you can redistribute it and/or 
 17    modify it under the terms of the Do What The Fuck You Want To 
 18    Public License, Version 2, as published by Sam Hocevar. See 
 19    U{http://sam.zoy.org/projects/COPYING.WTFPL} for more details. 
 20  """ 
 21   
 22  import os 
 23  import gettext 
 24  import thread 
 25  import ConfigParser 
 26  import re 
 27  import logging 
 28  from time import sleep 
 29  from cPickle import loads 
 30   
 31  from database import DB 
 32  from sched import at 
 33  from events import Event 
 34   
 35   
 36  __version__ = 0.2 
 37  """ Version of emma """ 
 38   
 39  confPaths = ( 
 40      '/usr/local/etc/emma.cfg', 
 41      '/etc/emma.cfg', 
 42      os.path.expanduser('~/.emma.cfg'), 
 43      'emma.cfg', 
 44  ) 
 45  """ Configuration file is searched in those locations. The latter files 
 46  have precedence when a configuration option is set in multiple files. 
 47  """ 
 48   
 49   
50 -def main(conf_paths=confPaths):
51 """ 52 Main function of the program 53 54 It loads all the interfaces and modules described on the config files. 55 """ 56 localedir = os.path.join(os.path.dirname(__file__), 'locale') 57 conf = ConfigParser.RawConfigParser() 58 conf.read(conf_paths) 59 _init_log(conf) 60 _init_i18n(conf, localedir) 61 db = DB() 62 db.connect(conf.get("core", "db_host"), 63 int(conf.get("core", "db_port")), 64 conf.get("core", "db_name")) 65 core = db.core() 66 _load_complements(conf) 67 _restore_sched(core) 68 69 while 1: 70 sleep(1000) # I didn't find any better wait method
71 72
73 -def _init_i18n(conf, localedir):
74 try: 75 language = conf.get("core", "language") 76 lang = gettext.translation('emma', localedir, 77 languages=language.split(',')) 78 lang.install() 79 except (ConfigParser.NoOptionError, IOError): 80 # If no config option of missing language catalog use system 81 # language 82 gettext.install('emma', localedir)
83 84
85 -def _init_log(conf):
86 fmt = "%(asctime)s (%(levelname).1s) %(message)s" 87 datefmt = "%b %d %H:%M:%S" 88 89 levels = {"debug": logging.DEBUG, 90 "info": logging.INFO, 91 "warning": logging.WARNING, 92 "error": logging.ERROR, 93 "critical": logging.CRITICAL} 94 try: 95 strlevel = conf.get("core", "log_level") 96 except ConfigParser.NoOptionError: 97 strlevel = "warning" 98 if strlevel in levels: 99 level = levels[strlevel] 100 else: 101 level = logging.WARNING 102 103 try: 104 log_file = conf.get("core", "log_file") 105 logging.basicConfig(format=fmt, datefmt=datefmt, level=level, \ 106 filename=log_file) 107 except ConfigParser.NoOptionError: 108 logging.basicConfig(format=fmt, datefmt=datefmt, level=level) 109 110 if strlevel not in levels: 111 logging.warning(_("[core] Not valid config value on log_level"))
112 113
114 -def _load_complements(conf):
115 logging.info(_("[core] preparing interfaces and modules")) 116 sectexp = re.compile(r"^[IM] ([^ ]*) (.*)$") 117 118 for section in conf.sections(): 119 options = dict(conf.items(section)) 120 m = sectexp.match(section) 121 if not m: 122 continue 123 name, identifier = m.groups() 124 if section[0] == 'M': 125 m = _init_complement('module', name, identifier, options) 126 thread.start_new_thread(m.run, ()) 127 if section[0] == 'I': 128 i = _init_complement('interface', name, identifier, options) 129 thread.start_new_thread(i.run, ())
130 131
132 -def _init_complement(tpe, name, identifier, options):
133 db = DB() 134 logging.debug(_("[core] load %(type)s %(name)s") % {'type': tpe, 135 'name': name}) 136 db_coll = db.collection("%s_%s_%s" % (tpe, name, identifier)) 137 imp = __import__("emma.%s.%s" % (tpe, name)) 138 complements = getattr(imp, tpe) 139 complement = getattr(complements, name) 140 clss = getattr(complement, name) 141 return clss(identifier, options, db_coll)
142 143
144 -def _restore_sched(db):
145 sched = db.find({'element': 'sched', 'type': 'at'}) 146 logging.info(_("[core] restore %s scheduled events") % sched.count()) 147 for s in sched: 148 elements = loads(str(s['event'])) 149 event = Event(*elements) 150 data = loads(str(s['data'])) 151 date = s['date'] 152 doc_id = s['_id'] 153 at(event, data, date, doc_id)
154