def handle_adminreloadconfig(bot, event): """ no arguments - reload bot config and mainconfig files. """ try: bot.cfg.reload() getmainconfig().reload() except Exception, ex: handle_exception()
def handle_rc(bot, event): """ arguments: <file>|<url> - execute a .jsb resource file with bot commands. """ if not event.rest: event.missing("<file>|<url>") return if not getmainconfig().allowrc: event.reply("rc mode is not enabled") return teller = 0 t = event.rest waiting = [] try: try: if getmainconfig().allowremoterc and t.startswith("http"): data = geturl2(t) else: data = open(t, 'r').read() except IOError, ex: event.reply("I/O error: %s" % str(ex)) return if not data: event.reply("can't get data from %s" % event.rest) return for d in data.split("\n"): i = d.strip() if not i: continue if i.startswith("#"): continue e = cpy(event) e.txt = "%s" % i.strip() e.direct = True bot.put(e) waiting.append(e) teller += 1 event.reply("%s commands executed" % teller)
def handle_adminreloadconfig(bot, event): """ no arguments - reload bot config and mainconfig files. """ try: bot.cfg.reload() getmainconfig().reload() except Exception, ex: handle_exception() event.done()
def handle_rc(bot, event): """ arguments: <file>|<url> - execute a .jsb resource file with bot commands. """ if not event.rest: event.missing("<file>|<url>") ; return if not getmainconfig().allowrc: event.reply("rc mode is not enabled") ; return teller = 0 t = event.rest waiting = [] try: try: if getmainconfig().allowremoterc and t.startswith("http"): data = geturl2(t) else: data = open(t, 'r').read() except IOError, ex: event.reply("I/O error: %s" % str(ex)) ; return if not data: event.reply("can't get data from %s" % event.rest) ; return for d in data.split("\n"): i = d.strip() if not i: continue if i.startswith("#"): continue e = cpy(event) e.txt = "%s" % i.strip() e.direct = True bot.put(e) waiting.append(e) teller += 1 event.reply("%s commands executed" % teller) except Exception, ex: event.reply("an error occured: %s" % str(ex)) ; handle_exception()
def handle_adminsave(bot, ievent): """ no arguments - boot the bot .. do some initialisation. """ ievent.reply("saving mainconfig") getmainconfig().save() ievent.reply("saving fleet bots") getfleet().save() ievent.reply("saving all plugins") plugs.save() ievent.done()
def bind(self): server = self.cfg.server elite = self.cfg['bindhost'] or getmainconfig()['bindhost'] if elite: logging.warn("trying to bind to %s" % elite) try: self.oldsock.bind((elite, 0)) except socket.gaierror: logging.debug("%s - can't bind to %s" % (self.cfg.name, elite)) if not server: try: socket.inet_pton(socket.AF_INET6, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: try: socket.inet_pton(socket.AF_INET, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: ips = [] try: for item in socket.getaddrinfo(self.cfg.server, None): if item[0] in [socket.AF_INET, socket.AF_INET6] and item[1] == socket.SOCK_STREAM: ip = item[4][0] if ip not in ips: ips.append(ip) except socket.error: pass else: server = random.choice(ips) return server
def getmc(): if not getmainconfig().memcached: logging.warn("memcached is disabled") ; return global mc if mc: return mc else: startmcdaemon() if mcboot(): return mc
def __init__(self, dbname=None, dbhost=None, dbuser=None, dbpasswd=None, dbtype=None, ddir=None, doconnect=True): self.datadir = ddir or getdatadir() self.datadir = self.datadir + os.sep + "db" + os.sep if hasattr(os, 'mkdir'): if not os.path.isdir(self.datadir): try: os.mkdir(self.datadir) except OSError: pass cfg = getmainconfig() self.dbname = dbname or cfg.dbname if not self.dbname: raise Exception("no db name") self.dbhost = dbhost or cfg.dbhost or "" self.dbuser = dbuser or cfg.dbuser or "" self.dbpasswd = dbpasswd or cfg.dbpasswd or "" self.connection = None self.timeout = 15 self.dbtype = dbtype or cfg.dbtype or 'sqlite' self.error = "" if doconnect: self.connect()
def getmc(): if not getmainconfig().memcached: return logging.warn("memcached is enabled") global mc if mc: return mc else: startmcdaemon() if mcboot(): return mc
def handle_loglevel(bot, event): """ arguments: <loglevel> - change loglevel of the bot. loglevel is on of debug, info, warn or error. """ if not event.rest: event.reply("loglevel is %s" % getloglevel()) ; return from jsb.lib.config import getmainconfig mainconfig = getmainconfig() mainconfig.loglevel = event.rest mainconfig.save() #mainhandler.put(4, setloglevel, event.rest) setloglevel(event.rest) event.done()
def handle_loglevel(bot, event): """ change loglevel of the bot. """ if not event.rest: event.missing("<loglevel> (string)") return setloglevel(event.rest) from jsb.lib.config import getmainconfig cfg = getmainconfig() if cfg.loglevel != event.rest: cfg.loglevel = event.rest ; cfg.save() event.done()
def options(self): if not getmainconfig().demo: self.response.set_status(404) ; return self.response.headers.add_header('Content-Type', 'application/x-www-form-urlencoded') self.response.headers.add_header("Server", getversion()) self.response.headers.add_header("Public", "*") self.response.headers.add_header('Accept', '*') self.response.headers.add_header('Access-Control-Allow-Origin', self.request.headers['Origin']) self.response.out.write("Allow: *") self.response.out.write('Access-Control-Allow-Origin: *') logging.warn("dispatch - options response send to %s - %s" % (self.request.remote_addr, str(self.request.headers)))
def getcc(self): if self.chan: cc = self.chan.data.cc else: cc = "" if not cc: cfg = getmainconfig() if cfg.globalcc and not cfg.globalcc in cc: cc += cfg.globalcc if not cc: cc = "!;" if not ";" in cc: cc += ";" logging.debug("cc is %s" % cc) return cc
def getcc(self): if self.chan: cc = self.chan.data.cc else: cc = "" if not cc: cfg = getmainconfig() if cfg.globalcc and not cfg.globalcc in cc: cc += cfg.globalcc if not cc: cc = "!;" if not ";" in cc: cc += ";" logging.info("cc is %s" % cc) return cc
def mcboot(): if not getmainconfig().memcached: logging.warn("memcached is disabled") ; return try: import jsb.contrib.memcache as memcache rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") global mc mc = memcache.Client(["unix:%s" % sock], debug=0) return isactive(sock) except ImportError, ex: logging.warn("using builtin cache - %s" % str(ex)) except Exception, ex: logging.warn("error starting memcached client: %s" % str(ex))
def mcboot(): if not getmainconfig().memcached: return logging.warn("memcached is enabled") try: import jsb.contrib.memcache as memcache rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") global mc mc = memcache.Client(["unix:%s" % sock], debug=0) return isactive(sock) except ImportError, ex: logging.warn("using builtin cache - %s" % str(ex)) except Exception, ex: logging.warn("error starting memcached client: %s" % str(ex))
def handle_loglevel(bot, event): """ arguments: <loglevel> - change loglevel of the bot. loglevel is on of debug, info, warn or error. """ if not event.rest: event.reply("loglevel is %s" % getloglevel()) return from jsb.lib.config import getmainconfig mainconfig = getmainconfig() mainconfig.loglevel = event.rest mainconfig.save() #mainhandler.put(4, setloglevel, event.rest) setloglevel(event.rest) event.done()
def handle_loglevel(bot, event): """ change loglevel of the bot. """ if not event.rest: event.missing("<loglevel> (string)") return setloglevel(event.rest) from jsb.lib.config import getmainconfig cfg = getmainconfig() if cfg.loglevel != event.rest: cfg.loglevel = event.rest cfg.save() event.done()
def __init__(self, cfg=None, users=None, plugs=None, name=None, domain=None, image_url='http://jsonbot.appspot.com/assets/favicon.png', profile_url='http://jsonbot.appspot.com/', *args, **kwargs): sname = 'jsb' BotBase.__init__(self, cfg, users, plugs, name, *args, **kwargs) assert self.cfg self.type = 'wave' if domain: self.cfg.domain = domain else: self.cfg.domain = getmainconfig().domain or "wave,google.com" self.cfg.nick = self.cfg.nick or name or "gae-wave" self.overload = True robot.Robot.__init__(self, name=getmainconfig().app_id or self.cfg.nick, image_url=image_url, profile_url=profile_url) credentials = _import_byfile("credentials", getdatadir() + os.sep + "config" + os.sep + "credentials.py") self.set_verification_token_info(credentials.verification_token[self.cfg.domain], credentials.verification_secret[self.cfg.domain]) self.setup_oauth(credentials.Consumer_Key[self.cfg.domain], credentials.Consumer_Secret[self.cfg.domain], server_rpc_base=credentials.RPC_BASE[self.cfg.domain]) self.register_handler(events.BlipSubmitted, self.OnBlipSubmitted) self.register_handler(events.WaveletSelfAdded, self.OnSelfAdded) self.register_handler(events.WaveletParticipantsChanged, self.OnParticipantsChanged) self.iswave = True self.isgae = True
def handle_cfgset(bot, event): if len(event.args) != 3: event.missing("<configname> <variable> <value>") ; return name, var, value = event.args if not var in allowset: event.reply("setting %s is not allowed" % var) ; return if name == "main": if not getusers().allowed(event.userhost, "OPER"): event.reply("you need to have OPER permissions to edit the mainconfig.") ; return mcfg = getmainconfig() try: mcfg[var] = int(value) except ValueError: mcfg[var] = value mcfg.save() event.done() else: event.reply('we current only support editing the "main" config.') ; return
def login(response, input={}): """ display start html so that bot output can follow. """ try: host = socket.gethostname() except AttributeError: if os.environ.get('HTTP_HOST'): host = os.environ['HTTP_HOST'] else: host = os.environ['SERVER_NAME'] if 'localhost' in host: url = 'http://%s/dispatch' % host else: url = 'https://%s/dispatch' % host template = LazyDict({'url': url, 'version': getversion(), 'host': host, 'color': getmainconfig().color or "#4b7cc6"}) if input: template.update(input) temp = os.path.join(os.getcwd(), 'templates/login.html') outstr = template.render(temp) response.out.write(outstr)
def get(self): """ show basic page. """ logging.warn("demo_handler - in") try: if not getmainconfig().demo: self.response.set_status(404) ; return logout = logouturl(self.request, self.response) user = "******" + "@" + self.request.remote_addr demo(self.response, {'appname': 'JSONBOT DEMO' , 'who': user, 'loginurl': 'logged in', 'logouturl': logout, 'onload': 'consoleinit();'}) except google.appengine.runtime.DeadlineExceededError: self.response.out.write("DeadLineExceededError .. this request took too long to finish.") except Exception, ex: handle_exception() self.response.set_status(500)
def handle_cfgset(bot, event): if len(event.args) != 3: event.missing("<configname> <variable> <value>") ; return name, var, value = event.args if not var in allowset: event.reply("setting %s is not allowed" % var) ; return if name == "main": if not getusers().allowed(event.userhost, "OPER"): event.reply("you need to have OPER permissions to edit the mainconfig.") ; return mcfg = getmainconfig() logging.info("using %s" % mcfg.cfile) try: mcfg[var] = int(value) except ValueError: mcfg[var] = value mcfg.save() event.done() else: event.reply('we current only support editing the "main" config.') ; return
def getmaindb(): try: from jsb.lib.config import getmainconfig cfg = getmainconfig() if cfg.dbenable: if "sqlite" in cfg.dbtype and not gotsqlite(): logging.error("sqlite is not found.") return global db if not db: from direct import Db db = Db() return db except Exception, ex: handle_exception()
def handle(self): """ send TICK events to callback. """ self.counter += 1 event = EventBase() event.nolog = True event.nobind = True event.channel = "usedefault" event.stop = True if self.counter % 60 == 0: event.type = event.cbtype = 'TICK60' callbacks.check(self.bot, event) maincfg = getmainconfig() t = maincfg.ticksleep or 1 if self.counter % t == 0: event.type = event.cbtype = 'TICK' callbacks.check(self.bot, event)
def handle_version(bot, ievent): """ no arguments - show bot's version. """ from jsb.version import getversion version = getversion(bot.type.upper()) cfg = getmainconfig() if cfg.dbenable: version += " " + cfg.dbtype.upper() if ievent.rest and ievent.rest == "repo": try: from mercurial import context, hg, node, repo, ui repository = hg.repository(ui.ui(), '.') ctx = context.changectx(repository) tip = str(ctx.rev()) except: tip = None if tip: version2 = version + " HG " + tip else: version2 = version ievent.reply(version2)
def post(self): """ this is where the command get disaptched. """ starttime = time.time() try: if not getmainconfig().demo: self.response.set_status(404) ; return logging.warn("DEMO incoming: %s - %s" % (self.request.get('content'), self.request.remote_addr)) event = WebEvent(bot=bot).parse(self.response, self.request) event.cbtype = "DISPATCH" event.type = "DISPATCH" bot.gatekeeper.allow(event.userhost) event.bind(bot) bot.doevent(event) except NoSuchCommand: self.response.out.write("no such command: %s" % event.usercmnd) except google.appengine.runtime.DeadlineExceededError, ex: self.response.out.write("the command took too long to finish: %s" % str(time.time()-starttime))
def killmcdaemon(): if not getmainconfig().memcached: logging.warn("memcached is disabled") ; return rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") pidfile = sock[:-7] + ".pid" try: pid = int(open(pidfile, "r").read().strip()) except Exception,ex : logging.warn("can't determine pid of memcached from %s - %s" % (pidfile,str(ex))) ; return False logging.warn("pid is %s" % pid) data = isactive(sock) if not data: logging.warn("memcached is not runniing") ; return False try: curr_connections = int(data[0][1]["curr_connections"]) except Exception, ex: logging.warn("can't determine current connections of memcached .. not killing - %s" % str(ex)) ; return False if curr_connections and curr_connections != 1: logging.warn("current connections of memcached is %s .. not killing" % curr_connections) ; return False try: os.kill(pid, 15) ; logging.warn("killed memcached with pid %s" % pid) except Exception, ex: logging.warn("failed to kill memcached (%s) - %s" % (pid, str(ex))) try: os.remove(pidfile) except: pass
def killmcdaemon(): if not getmainconfig().memcached: return logging.warn("killing memcached daemon") rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") pidfile = sock[:-7] + ".pid" try: pid = int(open(pidfile, "r").read().strip()) except Exception,ex : logging.warn("can't determine pid of memcached from %s - %s" % (pidfile,str(ex))) ; return False logging.warn("pid is %s" % pid) data = isactive(sock) if not data: logging.warn("memcached is not runniing") ; return False try: curr_connections = int(data[0][1]["curr_connections"]) except Exception, ex: logging.warn("can't determine current connections of memcached .. not killing - %s" % str(ex)) ; return False if curr_connections and curr_connections != 1: logging.warn("current connections of memcached is %s .. not killing" % curr_connections) ; return False try: os.kill(pid, 15) ; logging.warn("killed memcached with pid %s" % pid) except Exception, ex: logging.warn("failed to kill memcached (%s) - %s" % (pid, str(ex))) try: os.remove(pidfile) except: pass
def startmcdaemon(): if not getmainconfig().memcached: logging.warn("memcached is disabled") ; return try: from jsb.utils.popen import gozerpopen rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") logging.warn("using unix socket %s" % sock) pidfile = sock[:-7] + ".pid" if os.path.exists(sock) and isactive(sock): logging.warn("memcached daemon is already running") ; return args = [[]]*4 args[0] = "memcached" args[1] = "-s%s" % sock args[2] = "-P%s" % pidfile args[3] = "-d" logging.debug("running %s" % " ".join(args)) proces = gozerpopen(args) except Exception, ex: if "No such file" in str(ex): logging.warn("no memcached installed") else: logging.error('error running popen: %s' % str(ex)) return
def startmcdaemon(): if not getmainconfig().memcached: return logging.warn("starting memcached daemon") try: from jsb.utils.popen import gozerpopen rundir = getdatadir() + os.sep + 'run' sock = os.path.abspath(rundir + os.sep + "memcached.socket") logging.warn("using unix socket %s" % sock) pidfile = sock[:-7] + ".pid" if os.path.exists(sock) and isactive(sock): logging.warn("memcached daemon is already running") ; return args = [[]]*4 args[0] = "memcached" args[1] = "-s%s" % sock args[2] = "-P%s" % pidfile args[3] = "-d" logging.debug("running %s" % " ".join(args)) proces = gozerpopen(args) except Exception, ex: if "No such file" in str(ex): logging.warn("no memcached installed") else: logging.error('error running popen: %s' % str(ex)) return
def checkevent(self, event, dobind=True): if not event.iscommand: return False if getmainconfig().floodallow: return False if dobind: event.bind() if not event.user: got = False else: got = True t = got and event.user.data.floodtime or 60 if t < 60: t = 60 threshold = got and event.user.data.floodthreshold or 20 if threshold < 20: threshold = 20 wait = got and event.user.data.floodwait or 120 if wait < 120: wait = 120 floodrate = got and event.user.data.floodrate or 0.1 if floodrate < 0.1: floodrate = 0.1 if not self.check(event.userhost, t, threshold, wait, floodrate): return False if event.user and "OPER" in event.user.data.perms: return False logging.warn("floodcontrol block on %s" % event.userhost) if event.userhost not in self.warned: logging.warn("floodcontrol block on %s" % event.userhost) event.reply("floodcontrol enabled (%s seconds)" % wait) self.warned[event.userhost] = time.time() return True
def bind(self, bot=None, user=None, chan=None): """ bind event.bot event.user and event.chan to execute a command on it. """ if self.bonded: logging.debug("already bonded") ; return target = self.auth bot = bot or self.bot if not self.chan: if chan: self.chan = chan elif self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name) if self.chan: self.debug = self.chan.data.debug or False logging.debug("channel bonded - %s" % self.chan.data.tojson()) if not target: self.prepare(bot) ; self.bonded = True ; return if not self.user and target: cfg = getmainconfig() if cfg.auto_register: bot.users.addguest(target) self.user = user or bot.users.getuser(target) if self.user: logging.debug("user bonded - %s - from %s" % (self.user.data.tojson(), whichmodule())) if not self.user and target: logging.debug("no %s user found .. setting nodispatch" % target) ; self.nodispatch = True self.prepare(bot) self.bonded = True return self
def bind(self, bot=None, user=None, chan=None, force=False, dolog=None): """ bind event.bot event.user and event.chan to execute a command on it. """ #if self.nodispatch: logging.debug("nodispatch is set on event . .not binding"); return dolog = dolog or 'TICK' not in self.cbtype if dolog and not force and self.dontbind: logging.debug("dontbind is set on event . .not binding"); return if not force and self.bonded and (bot and not bot.isgae): logging.debug("already bonded") ; return dolog and logging.debug("starting bind on %s - %s" % (self.userhost, self.txt)) target = self.auth or self.userhost bot = bot or self.bot if not self.chan: if chan: self.chan = chan elif self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name) if self.chan: #self.debug = self.chan.data.debug or False dolog and logging.debug("channel bonded - %s" % self.chan.data.id) self.prepare(bot) if not target: self.bonded = True ; return if not self.user and target and not self.nodispatch: if user: u = user else: u = bot.users.getuser(target) if not u: cfg = getmainconfig() if cfg.auto_register and self.iscommand: u = bot.users.addguest(target, self.nick) if u: logging.warn("auto_register applied") else: logging.error("can't add %s to users database" % target) if u: msg = "!! %s -=- %s -=- %s -=- (%s) !!" % (u.data.name, self.usercmnd or "none", self.cbtype, self.bot.cfg.name) dolog and logging.warn(msg) self.user = u if self.user: dolog and logging.debug("user bonded from %s" % whichmodule()) if not self.user and target: dolog and self.iscommand and logging.warn("no %s user found" % target) ; self.nodispatch = True if self.bot: self.inchan = self.channel in self.bot.state.data.joinedchannels self.bonded = True return self
def bind(self): server = self.cfg.server elite = self.cfg['bindhost'] or getmainconfig()['bindhost'] if elite: logging.warn("trying to bind to %s" % elite) try: self.oldsock.bind((elite, 0)) except socket.gaierror: logging.debug("%s - can't bind to %s" % (self.cfg.name, elite)) if not server: try: socket.inet_pton(socket.AF_INET6, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: try: socket.inet_pton(socket.AF_INET, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: ips = [] try: for item in socket.getaddrinfo(self.cfg.server, None): if item[0] in [socket.AF_INET, socket.AF_INET6 ] and item[1] == socket.SOCK_STREAM: ip = item[4][0] if ip not in ips: ips.append(ip) except socket.error: pass else: server = random.choice(ips) return server
def boot(ddir=None, force=False, encoding="utf-8", umask=None, saveperms=True, fast=False, clear=False, loadall=False): """ initialize the bot. """ global plugin_packages try: if os.getuid() == 0: print "don't run the bot as root" os._exit(1) except AttributeError: pass from jsb.lib.datadir import getdatadir, setdatadir if ddir: setdatadir(ddir) origdir = ddir ddir = ddir or getdatadir() if not ddir: logging.error("can't determine datadir to boot from") raise Exception("can't determine datadir") if not ddir in sys.path: sys.path.append(ddir) makedirs(ddir) if os.path.isdir("/var/run/jsb") and botuser() == "jsb": rundir = "/var/run/jsb" else: rundir = ddir + os.sep + "run" try: k = open(rundir + os.sep + 'jsb.pid', 'w') k.write(str(os.getpid())) k.close() except IOError: pass try: reload(sys) sys.setdefaultencoding(encoding) except (AttributeError, IOError): handle_exception() try: if not umask: checkpermissions(getdatadir(), 0700) else: checkpermissions(getdatadir(), umask) except: handle_exception() from jsb.lib.plugins import plugs global loaded global cmndtable global retable global pluginlist global callbacktable global shorttable global cmndperms global timestamps global plugwhitelist global plugblacklist if not retable: retable = Persist(rundir + os.sep + 'retable') if clear: retable.data = {} if not cmndtable: cmndtable = Persist(rundir + os.sep + 'cmndtable') if clear: cmndtable.data = {} if not pluginlist: pluginlist = Persist(rundir + os.sep + 'pluginlist') if clear: pluginlist.data = [] if not callbacktable: callbacktable = Persist(rundir + os.sep + 'callbacktable') if clear: callbacktable.data = {} if not shorttable: shorttable = Persist(rundir + os.sep + 'shorttable') if clear: shorttable.data = {} if not timestamps: timestamps = Persist(rundir + os.sep + 'timestamps') if not plugwhitelist: plugwhitelist = Persist(rundir + os.sep + 'plugwhitelist') if not plugwhitelist.data: plugwhitelist.data = [] if not plugblacklist: plugblacklist = Persist(rundir + os.sep + 'plugblacklist') if not plugblacklist.data: plugblacklist.data = [] if not cmndperms: cmndperms = Config('cmndperms', ddir=ddir) changed = [] gotlocal = False dosave = clear or False maincfg = getmainconfig(ddir=ddir) logging.warn("mainconfig used is %s" % maincfg.cfile) if os.path.isdir('jsb'): gotlocal = True packages = find_packages("jsb" + os.sep + "plugs") pluglist = [x for x in packages if not 'db' in x] for p in pluglist: if p not in plugin_packages: plugin_packages.append(p) for plug in default_plugins: plugs.reload(plug, showerror=True, force=True) changed = scandir(getdatadir() + os.sep + 'myplugs', dbenable=maincfg.dbenable) if changed: logging.debug("myplugs has changed -=- %s" % str(changed)) for plugfile in changed: if "gae" in plugfile: continue try: plugs.reloadfile(plugfile, force=True) except Exception, ex: handle_exception() dosave = True
except Exception, ex: handle_exception() dosave = True if maincfg.dbenable: if not 'jsb.plugs.db' in plugin_packages: plugin_packages.append("jsb.plugs.db") try: from jsb.db import getmaindb from jsb.db.tables import tablestxt db = getmaindb() if db: db.define(tablestxt) except Exception, ex: logging.warn("could not initialize database %s" % str(ex)) else: logging.warn("db not enabled, set dbenable = 1 in %s to enable" % getmainconfig().cfile) try: plugin_packages.remove("jsb.plugs.db") except ValueError: pass if force or dosave or not cmndtable.data or len(cmndtable.data) < 100: logging.debug("using target %s" % str(plugin_packages)) plugs.loadall(plugin_packages, force=True) savecmndtable(saveperms=saveperms) savepluginlist() savecallbacktable() savealiases() ## filestamps stuff
def handle_datamain(bot, event): """ no arguments - dump bot as json dict. """ event.reply(getmainconfig().fordisplay())
class EventBase(LazyDict): """ basic event class. """ def __init__(self, input={}, bot=None): LazyDict.__init__(self) if bot: self.bot = bot self.threaded = False self.untildone = False self.ctime = time.time() self.speed = self.speed or 5 self.nrout = self.nrout or 0 if input: self.copyin(input) if not self.token: self.setup() def copyin(self, eventin): """ copy in an event. """ self.update(eventin) return self def setup(self): self.token = self.token or str(uuid.uuid4().hex) self.finished = threading.Condition() self.busy = deque() self.inqueue = deque() self.outqueue = deque() self.resqueue = deque() self.ok = threading.Event() return self def __deepcopy__(self, a): """ deepcopy an event. """ e = EventBase(self) return e def launched(self): logging.info(str(self)) self.ok.set() def startout(self): if not self.nodispatch and not self.token in self.busy: self.busy.append(self.token) def ready(self, what=None, force=False): """ signal the event as ready - push None to all queues. """ if self.threaded and self.untildone: return if self.nodispatch: return if not "TICK" in self.cbtype: logging.info(self.busy) try: self.busy.remove(self.token) except ValueError: pass if not self.busy or force: self.notify() def notify(self, p=None): self.finished.acquire() self.finished.notifyAll() self.finished.release() if not "TICK" in self.cbtype: logging.info("notified %s" % str(self)) def execwait(self, direct=False): from jsb.lib.commands import cmnds e = self.bot.put(self) if e: return e.wait() else: logging.info("no response for %s" % self.txt) ; return logging.info("%s wont dispatch" % self.txt) def wait(self, nr=1000): nr = int(nr) result = [] #if self.nodispatch: return if not self.busy: self.startout() self.finished.acquire() if self.threaded and self.untildone: logging.info("waiting until done") while 1: self.finished.wait(0.1) else: while nr > 0 and (self.busy and not self.dostop): self.finished.wait(0.1) ; nr -= 100 self.finished.release() if self.wait and self.thread: logging.warn("joining thread %s" % self.thread) ; self.thread.join(nr/1000) if not "TICK" in self.cbtype: logging.info(self.busy) if not self.resqueue: res = waitforqueue(self.resqueue, nr) else: res = self.resqueue return list(res) def waitandout(self, nr=1000): res = self.wait(nr) if res: for r in res: self.reply(r) def execute(self, direct=False, *args, **kwargs): """ dispatch event onto the cmnds object. this method needs both event.nodispatch = False amd event.iscommand = True set. """ logging.debug("execute %s" % self.cbtype) from jsb.lib.commands import cmnds res = self self.startout() self.bind(self.bot, force=True, dolog=True) if not self.pipelined and ' ! ' in self.txt: res = self.dopipe(direct, *args, **kwargs) else: try: res = cmnds.dispatch(self.bot, self, direct=direct, *args, **kwargs) except RequireError, ex: logging.error(str(ex)) except NoSuchCommand, ex: logging.error("we don't have a %s command" % str(ex)) ; self.ready() except NoSuchUser, ex: logging.error("we don't have user for %s" % str(ex)) except Exception , ex: handle_exception() return res def dopipe(self, direct=False, *args, **kwargs): """ split cmnds, create events for them, chain the queues and dispatch. """ direct = True logging.warn("starting pipeline") origout = self.outqueue events = [] self.pipelined = True splitted = self.txt.split(" ! ") counter = 1 for i in range(len(splitted)): t = splitted[i].strip() if not t: continue cc = self.getcc() if not t[0] in cc: t = cc[0] + t e = self.bot.make_event(self.userhost, self.channel, t, showall=self.showall) if self.sock: e.sock = self.sock e.nick = self.nick e.outqueue = deque() e.busy = deque() e.prev = None e.pipelined = True e.dontbind = False e.bind(self.bot) if not e.woulddispatch(): raise NoSuchCommand(e.txt) events.append(e) counter += 1 prev = None for i in range(len(events)): if i > 0: events[i].inqueue = events[i-1].outqueue events[i].prev = events[i-1] events[-1].pipelined = False events[-1].dontclose = False if self.sock and self.isdcc: events[-1].channel = self.sock for i in range(len(events)): if not direct: self.bot.put(events[i]) else: events[i].execute(direct) self.ready() return events[-1] def prepare(self, bot=None): """ prepare the event for dispatch. """ if bot: self.bot = bot or self.bot assert(self.bot) self.origin = self.channel self.bloh() self.makeargs() if not self.nolog: logging.debug("%s - prepared event - %s" % (self.auth, self.cbtype)) return self def bind(self, bot=None, user=None, chan=None, force=False, dolog=None, noraise=True): """ bind event.bot event.user and event.chan to execute a command on it. """ dolog = dolog or 'TICK' not in self.cbtype if self.cbtype == "PRESENCE" and not force: dolog and logging.info("presence from %s, not binding" % self.stripped or self.nick) ; return self if self.cbtype == "PING" and not force: logging.debug("not binding PING") ; return self if dolog and not force and self.dontbind: logging.debug("dontbind is set on event . .not binding"); return self if not force and self.bonded: logging.debug("already bonded") ; return self dolog and logging.debug("starting bind on %s - %s" % (self.userhost, self.txt)) if not self.options:self.makeoptions() target = self.auth or self.userhost bot = bot or self.bot dolog and target and logging.info("target is %s" % target) if not self.chan: if chan: self.chan = chan elif self.channelchanged: try: self.chan = ChannelBase(self.origchannel, bot.cfg.name, needexist=self.origchannel) except WrongFileName, ex: self.error = "no such channel %s" % self.channel logging.error(self.error) if not self.chan: if self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name) if self.chan: dolog and logging.debug("channel bonded - %s" % self.chan.data.id) self.chanid = self.chan.data.id self.prepare(bot) if not target: self.bonded = True ; return self if target.lower() in bot.state['ignore']: logging.warn("user %s is ignored .. not binding" % target) ; raise UserIgnored(target) if not self.user and target and not self.nodispatch: if user: u = user else: u = bot.users.getuser(target) if not u: cfg = getmainconfig() if cfg.auto_register and self.iscommand: u = bot.users.addguest(target, self.nick) if u: logging.warn("auto_register applied") else: logging.error("can't add %s to users database" % target) if u: msg = "!! %s -=- %s -=- %s -=- (%s) !!" % (u.data.name, self.usercmnd or "none", self.cbtype, self.bot.cfg.name) if self.cbtype in ["PING", ]: dolog and logging.info(msg) else: dolog and logging.warn(msg) self.user = u if self.user: dolog and logging.debug("user bonded from %s" % whichmodule()) if not self.user and target: dolog and self.iscommand and logging.warn("no %s user found" % target) ; self.nodispatch = True if self.bot: self.inchan = self.channel in self.bot.state.data.joinedchannels self.bonded = True return self
format_short_plain = "[!] %(asctime)-8s - %(module)+12s - %(message)s" format_plain = "[!] %(asctime)s.%(msecs)-13s - %(lineno)-5s%(module)+12s.%(funcName)-15s - %(message)s - %(levelname)s - <%(threadName)s>" datefmt = '%H:%M:%S' formatter_short = logging.Formatter(format_short, datefmt=datefmt) formatter = logging.Formatter(format, datefmt=datefmt) formatter_short_plain = logging.Formatter(format_short_plain, datefmt=datefmt) formatter_plain = logging.Formatter(format_plain, datefmt=datefmt) try: import waveapi except ImportError: try: filehandler = logging.handlers.TimedRotatingFileHandler(LOGDIR + os.sep + "jsb.log", 'midnight') except (IOError, AttributeError), ex: logging.error("can't create file loggger %s" % str(ex)) filehandler = None mainconfig = getmainconfig() docolors = colors or mainconfig.color level = LEVELS.get(str(level_name).lower(), logging.NOTSET) root = logging.getLogger() root.setLevel(level) if root and root.handlers: for handler in root.handlers: root.removeHandler(handler) ch = logging.StreamHandler() ch.setLevel(level) if level_name in ["debug", "info"]: if docolors: ch.setFormatter(formatter) else: ch.setFormatter(formatter_plain) if filehandler: filehandler.setFormatter(formatter_plain) else: if docolors: ch.setFormatter(formatter_short) else: ch.setFormatter(formatter_short_plain)
def boot(ddir=None, force=False, encoding="utf-8", umask=None, saveperms=True, fast=False, clear=False, loadall=False): """ initialize the bot. """ global plugin_packages try: if os.getuid() == 0: print "don't run the bot as root" os._exit(1) except AttributeError: pass logging.warn("starting!") from jsb.lib.datadir import getdatadir, setdatadir if ddir: setdatadir(ddir) origdir = ddir ddir = ddir or getdatadir() if not ddir: logging.error("can't determine datadir to boot from") ; raise Exception("can't determine datadir") if not ddir in sys.path: sys.path.append(ddir) makedirs(ddir) if os.path.isdir("/var/run/jsb") and botuser() == "jsb": rundir = "/var/run/jsb" else: rundir = ddir + os.sep + "run" try: k = open(rundir + os.sep + 'jsb.pid','w') k.write(str(os.getpid())) k.close() except IOError: pass try: reload(sys) sys.setdefaultencoding(encoding) except (AttributeError, IOError): handle_exception() try: if not umask: checkpermissions(getdatadir(), 0700) else: checkpermissions(getdatadir(), umask) except: handle_exception() from jsb.lib.plugins import plugs global loaded global cmndtable global retable global pluginlist global callbacktable global shorttable global cmndperms global timestamps global plugwhitelist global plugblacklist if not retable: retable = Persist(rundir + os.sep + 'retable') if clear: retable.data = {} if not cmndtable: cmndtable = Persist(rundir + os.sep + 'cmndtable') if clear: cmndtable.data = {} if not pluginlist: pluginlist = Persist(rundir + os.sep + 'pluginlist') if clear: pluginlist.data = [] if not callbacktable: callbacktable = Persist(rundir + os.sep + 'callbacktable') if clear: callbacktable.data = {} if not shorttable: shorttable = Persist(rundir + os.sep + 'shorttable') if clear: shorttable.data = {} if not timestamps: timestamps = Persist(rundir + os.sep + 'timestamps') #if clear: timestamps.data = {} if not plugwhitelist: plugwhitelist = Persist(rundir + os.sep + 'plugwhitelist') if not plugwhitelist.data: plugwhitelist.data = [] if not plugblacklist: plugblacklist = Persist(rundir + os.sep + 'plugblacklist') if not plugblacklist.data: plugblacklist.data = [] if not cmndperms: cmndperms = Config('cmndperms', ddir=ddir) changed = [] gotlocal = False dosave = clear or False maincfg = getmainconfig(ddir=ddir) logging.warn("mainconfig used is %s" % maincfg.cfile) if os.path.isdir('jsb'): gotlocal = True packages = find_packages("jsb" + os.sep + "plugs") pluglist = [x for x in packages if not 'db' in x] for p in pluglist: if p not in plugin_packages: plugin_packages.append(p) for plug in default_plugins: plugs.reload(plug, showerror=True, force=True) changed = scandir(getdatadir() + os.sep + 'myplugs', dbenable=maincfg.dbenable) if changed: logging.debug("myplugs has changed -=- %s" % str(changed)) for plugfile in changed: if "gae" in plugfile: continue try: plugs.reloadfile(plugfile, force=True) except Exception, ex: handle_exception() dosave = True configchanges = checkconfig() if configchanges: logging.info("there are configuration changes: %s" % str(configchanges)) for f in configchanges: if 'mainconfig' in f: force = True ; dosave = True if os.path.isdir('jsb'): corechanges = scandir("jsb" + os.sep + "plugs", dbenable=maincfg.dbenable) if corechanges: logging.debug("core changed -=- %s" % str(corechanges)) for plugfile in corechanges: if not maincfg.dbenable and "db" in plugfile: continue if "gae" in plugfile: continue try: plugs.reloadfile(plugfile, force=True) except Exception, ex: handle_exception() dosave = True if maincfg.dbenable: if not 'jsb.plugs.db' in plugin_packages: plugin_packages.append("jsb.plugs.db") try: from jsb.db import getmaindb from jsb.db.tables import tablestxt db = getmaindb() if db: db.define(tablestxt) except Exception, ex: logging.warn("could not initialize database %s" % str(ex)) else: logging.warn("db not enabled, set dbenable = 1 in %s to enable" % getmainconfig().cfile) try: plugin_packages.remove("jsb.plugs.db") except ValueError: pass if force or dosave or not cmndtable.data or len(cmndtable.data) < 100: logging.debug("using target %s" % str(plugin_packages)) plugs.loadall(plugin_packages, force=True) savecmndtable(saveperms=saveperms) savepluginlist() savecallbacktable() savealiases() logging.warn("ready")
def handle_cfg(bot, event): if len(event.args) != 1: event.missing("<configname>") ; return name = event.args[0] if name == "main": if not getusers().allowed(event.userhost, "OPER"): event.reply("you need to have OPER permissions to edit the mainconfig.") ; return event.reply(getmainconfig().fordisplay())