def AddLockFile( timeout=100 ): if os.path.isfile(LOCKFILE): if (time.time() - os.path.getmtime(LOCKFILE))>timeout: os.unlink(LOCKFILE) else: DBG.say( DBG.IMPORTANT, "LOCK FILE" ) exit() with open(LOCKFILE,'wb') as f: f.write('1')
def AddLockFile(timeout=100): if os.path.isfile(LOCKFILE): if (time.time() - os.path.getmtime(LOCKFILE)) > timeout: os.unlink(LOCKFILE) else: DBG.say(DBG.IMPORTANT, "LOCK FILE") exit() with open(LOCKFILE, 'wb') as f: f.write('1')
def SendMsg( vk_api, message, prefix = None, _replaceAlias = False ): DBG.trace(u"SendMsg( %s, msg='%s', prefix='%s', alias=%s\n%s", [vk_api,message,prefix,_replaceAlias,traceback.format_stack(5)] ) DBG.important(u'\nSENDMSG>>>\n%s\n<<<<', [message] ) if prefix is None: if not message.startswith(u'vk:'): prefix = u'vk:' else: prefix = '' if _replaceAlias: message = ReplaceAlias( message ) message = u"%s%s {rnd%x}" % ( prefix, message, random.randint(0,99999) ) vk_api.messages.send( user_id=COMMAND_USER, message=message )
def SendMsg(vk_api, message, prefix=None, _replaceAlias=False): DBG.trace( u"SendMsg( %s, msg='%s', prefix='%s', alias=%s\n%s", [vk_api, message, prefix, _replaceAlias, traceback.format_stack(5)]) DBG.important(u'\nSENDMSG>>>\n%s\n<<<<', [message]) if prefix is None: if not message.startswith(u'vk:'): prefix = u'vk:' else: prefix = '' if _replaceAlias: message = ReplaceAlias(message) message = u"%s%s {rnd%x}" % (prefix, message, random.randint(0, 99999)) vk_api.messages.send(user_id=COMMAND_USER, message=message)
def __init__( self, pool, fname, cmdl ): self.pool = pool self.cmd = CMD(cmdl) self.api = 1 if self.cmd.vk_api==vk_api1 else 2 self.me = me1 if self.api==1 else me2 self.Error = '' self.tmpFileName = os.path.join( DIR_TMP, '.'+'_'.join(cmdl[1:])) self.module = None if not self.cmd.isWatcher: self.Error = u"unknown watcher '%s'" % self.cmd.main_cmd DBG.important(self.Error) return self.default_module = WATCH_PROCESSORS[self.cmd.main_cmd] try: was = sys.dont_write_bytecode self.module = imp.load_source("module", getPath(fname) ) except Exception as e: self.Error = u"fail to load '%s':%s" % (fname,str(e)) DBG.important(self.Error) return finally: sys.dont_write_bytecode = was global_export = [ 'now', 'me1', 'me2', 'flags', 'USER_LOGIN', 'COMMAND_USER', 'DIR_MAIN', 'DIR_LOG','DIR_TMP', 'vk_utils', 'util', 'config', 'DBG', 'ReplaceAlias', 'ExecuteDownloadMSG', 'SendMsg' ] util.import_vars( self.module, self, ['cmd','me','tmpFileName','default_module'], isOverwrite=True ) util.import_vars( self.module, self.default_module, '*', isOverwrite=False ) util.import_vars( self.module, globals(), global_export, isOverwrite=True ) DBG.trace("Loaded '%s':\n%s" % (fname,util.debugDump(self.module,short=True)) )
def run( self, method, **kww ): defaultHandler = kww.pop('defaultHandler',False) handlerModule = self.default_module if ( defaultHandler or not hasattr(self.module,method) ) else self.module DBG.trace("%s.run('%s',%s)" % (self, self.method, kww) ) DBG.trace(" --> module=%s, default=%s, choosed=%s" % (self.module, self.default_module, handlerModule)) if not hasattr(handlerModule,method): raise SkipError("no '%s' method" % method) module = self.module ( module.vk_api1, module.vk_api2, module.vk_api ) = (pool.vk_api[0], pool.vk_api[1], pool.vk_api[self.api-1] ) module.vk_api = module.vk_api1 if self.api==1 else module.vk_api2 module.errorMessage = self.Error DBG.trace(" --> execute %s() with vk_api=%s/me=%s" % ( getattr( handlerModule, method ), module.vk_api, module.me)) rv = getattr( handlerModule, method )( module, *kww ) self.Error = module.errorMessage DBG.trace(" --> result=%s (err=%s)" % ( rv, self.Error) ) return rv
def run(self, method, **kww): defaultHandler = kww.pop('defaultHandler', False) handlerModule = self.default_module if ( defaultHandler or not hasattr(self.module, method)) else self.module DBG.trace("%s.run('%s',%s)" % (self, self.method, kww)) DBG.trace(" --> module=%s, default=%s, choosed=%s" % (self.module, self.default_module, handlerModule)) if not hasattr(handlerModule, method): raise SkipError("no '%s' method" % method) module = self.module (module.vk_api1, module.vk_api2, module.vk_api) = (pool.vk_api[0], pool.vk_api[1], pool.vk_api[self.api - 1]) module.vk_api = module.vk_api1 if self.api == 1 else module.vk_api2 module.errorMessage = self.Error DBG.trace(" --> execute %s() with vk_api=%s/me=%s" % (getattr(handlerModule, method), module.vk_api, module.me)) rv = getattr(handlerModule, method)(module, *kww) self.Error = module.errorMessage DBG.trace(" --> result=%s (err=%s)" % (rv, self.Error)) return rv
def __init__(self, pool, fname, cmdl): self.pool = pool self.cmd = CMD(cmdl) self.api = 1 if self.cmd.vk_api == vk_api1 else 2 self.me = me1 if self.api == 1 else me2 self.Error = '' self.tmpFileName = os.path.join(DIR_TMP, '.' + '_'.join(cmdl[1:])) self.module = None if not self.cmd.isWatcher: self.Error = u"unknown watcher '%s'" % self.cmd.main_cmd DBG.important(self.Error) return self.default_module = WATCH_PROCESSORS[self.cmd.main_cmd] try: was = sys.dont_write_bytecode self.module = imp.load_source("module", getPath(fname)) except Exception as e: self.Error = u"fail to load '%s':%s" % (fname, str(e)) DBG.important(self.Error) return finally: sys.dont_write_bytecode = was global_export = [ 'now', 'me1', 'me2', 'flags', 'USER_LOGIN', 'COMMAND_USER', 'DIR_MAIN', 'DIR_LOG', 'DIR_TMP', 'vk_utils', 'util', 'config', 'DBG', 'ReplaceAlias', 'ExecuteDownloadMSG', 'SendMsg' ] util.import_vars(self.module, self, ['cmd', 'me', 'tmpFileName', 'default_module'], isOverwrite=True) util.import_vars(self.module, self.default_module, '*', isOverwrite=False) util.import_vars(self.module, globals(), global_export, isOverwrite=True) DBG.trace("Loaded '%s':\n%s" % (fname, util.debugDump(self.module, short=True)))
def RunMainScript( cmd ): cmd = [ config.CONFIG['PYTHON_EXE'], config.CONFIG['VK_DOWNLOADER'] ] + cmd if len(cmd)<5: return '??', 'Too short cmd: %s'%str(cmd) cmd += ["--WAIT_AFTER=False", "--MACHINE=True"] DBG.info('RunMainScript(%s)',repr(cmd) ) #print ' '.join(map(lambda s: '"%s"'%s, cmd) ) try: fp = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr = subprocess.PIPE, shell = False ) stdout,stderr = fp.communicate() except Exception as e: stdout, stderr = '', u'FAIL TO RUN: %s' %str(e) if isinstance(stdout,str): stdout = stdout.decode('cp866') if isinstance(stderr,str): stderr = stderr.decode('cp866') print "--\n%s" % stdout DBG.trace(u"STDOUT:%s", stdout) if stderr: DBG.trace(u"STDERR:%s", stdout) return stdout, stderr
def RunMainScript(cmd): cmd = [config.CONFIG['PYTHON_EXE'], config.CONFIG['VK_DOWNLOADER']] + cmd if len(cmd) < 5: return '??', 'Too short cmd: %s' % str(cmd) cmd += ["--WAIT_AFTER=False", "--MACHINE=True"] DBG.info('RunMainScript(%s)', repr(cmd)) #print ' '.join(map(lambda s: '"%s"'%s, cmd) ) try: fp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) stdout, stderr = fp.communicate() except Exception as e: stdout, stderr = '', u'FAIL TO RUN: %s' % str(e) if isinstance(stdout, str): stdout = stdout.decode('cp866') if isinstance(stderr, str): stderr = stderr.decode('cp866') print "--\n%s" % stdout DBG.trace(u"STDOUT:%s", stdout) if stderr: DBG.trace(u"STDERR:%s", stdout) return stdout, stderr
def Notify(module, message): module.SendMsg(module.vk_api, message, prefix='') DBG.TODO('+ scan notifiers here') return False # True - if ask to make common notification too, False - use only this command
def addStatus(fname, cmdl): DBG.trace('addStatus(%s,%s)', [fname,cmdl]) if cmdl[0] not in ['on','off'] or len(cmdl)<3: return cmdl[2] = users.get( cmdl[2], cmdl[2] ) status[fname] = ' '.join(cmdl)
def main(): util.init_console() DBG.logfile_name='./LOG_WATCHER/vk_watch' DBG.level = DBG.TRACE DBG.important( u">>> RUN vk_watcher at %s" % os.getcwdu() ) if 'BASE_DIR' in globals() and BASE_DIR: os.chdir(BASE_DIR) LoadConfig() USER_LOGIN = config.CONFIG['USER_LOGIN'].strip() if not USER_LOGIN: raise util.FatalError('Unknown USER_LOGIN') DIR_MAIN = os.path.join( os.getcwdu(), '.vk_watcher-%s'%USER_LOGIN ) DIR_LOG = os.path.join( DIR_MAIN, 'log' ) DIR_TMP = os.path.join( DIR_MAIN, 'tmp' ) global LOCKFILE LOCKFILE = os.path.join(DIR_TMP,'lockfile.group_watch') AddLockFile( timeout=50 ) """" BASEDIR = os.path.join( os.getcwdu(),u"MSG-%s" % USER_LOGIN ) if not os.path.exists(BASEDIR): os.makedirs(BASEDIR) """ import vk.api vk.api.LOG_DIR = "./LOG_WATCHER" vk_api1, me1, USER_PASSWORD1 = vk_utils.VKSignIn( USER_LOGIN, False ) vk_api2, me2, USER_PASSWORD2 = vk_utils.VKSignInSecondary( False ) now = time.time() COMMAND_USER = config.CONFIG.get('COMMAND_USER','') if not COMMAND_USER: COMMAND_USER = me1 config.CONFIG['COMMAND_USER']=COMMAND_USER flags = {} # any kind of common flags (already done executed) commands = [] # [ [0CMD, 1msg, 2silence], ... ] logMessage = [] toDelMsgIds = set() #executedCmd = collections.OrderedDict() # ['cmd' = status] # IMPORTANT: set all local values to globals util.import_vars( globals(), locals(), '*', isOverwrite=True ) CMD_PREFIX = 'vk_' try: # Execute posponed commands ##CMDPool.ScanCommands( CMDPool.HandlerPostponed ) ##CMDPool.ScanCommands( CMDPool.HandlerCheck ) # Scan incoming messages to get commands res = vk_api.messages.getHistory( offset=0, count = 30, user_id = me, rev = 1 ) for item in res[u'items']: body = item.get(u'body','').strip().lower() if not body.startswith(CMD_PREFIX): continue delMsgId = item.get(u'id',0) lst = map(str.strip, body.split('\n') ) DBG.info( u"catch command(id=%s): %s", (delMsgId,lst) ) for cmd in lst: if not cmd.startswith(CMD_PREFIX): continue toDelMsgIds.add( delMsgId ) silence = cmd.endswith('@') if silence: cmd = cmd[:-1] try: command.append( [ CMD(cmd[len(CMD_PREFIX):].split()), None, silence ] ) except Exception as e: command.append( [ None, str(e), False ] ) # u"%s - FAIL(%s)" % (cmd,str(e)) dbg = "==COMMANDS:\n" for c in commands: dbg+= "=%s\n"%repr(c) if c[0] is not None: dbg+= util.debugDump(c[0],True) DBG.trace( dbg ) # Execute commands DBG.TODO('Execute commands') for frame in commands: try: if frame[0] is not None: DBG.trace("COMMAND: %s -> %s(%s)", [ frame[0].main_cmd, COMMAND_PROCESSORS.get(frame[0].main_cmd,None), frame ] ) COMMAND_PROCESSORS[frame[0].main_cmd]( frame[0], frame ) except Exception as e: frame[1] = str(e) # Observers: a) prepare the list DBG.TODO('Observers') pool = WatcherExecutor() pool.vk_api = [ vk_utils.BatchExecutor(vk_api1), vk_utils.BatchExecutor(vk_api2) ] CMDPool.ScanCommands( pool.collectWatchers ) # b) 1st pass (prepare cached queries) postponed = [] for c in pool.watchers: try: if c.Error: raise util.SkipError(c.Error) if not c.run('CheckWatcherStatus'): continue if c.run( 'Prepare', isDryRun = True ): c.run( 'DoAction', isDryRun = True ) postponed.append(c) except Exception as e: DBG.important(str(e)) c.Error = str(e) for c in postponed: try: c.run( 'Postprocess' ) except Exception as e: DBG.important(str(e)) c.Error = str(e) # c) 2nd pass (actually execute watchers) for idx in [0,1]: pool.vk_api[idx] = vk_utils.CachedVKAPI( pool.vk_api[idx].vk_api, pool.vk_api[idx] ) for c in pool.watchers: try: if c.Error: raise util.SkipError(c.Error) if not c.run('CheckWatcherStatus'): continue message = None if c.run( 'Prepare', isDryRun = False ): message = c.run( 'DoAction', isDryRun = False ) c.run( 'Postprocess', isDryRun = False ) #if message and not c.Error: if message and not c.Error: if c.run( 'Notify', message = message ): c.run( 'Notify', message = message, defaultHandler = True ) if not c.Error: # no need to include this into status continue except Exception as e: DBG.important(str(e)) c.Error = str(e) c.cmd.cmdl[0] = u"[auto]" + c.cmd.cmdl[0] commands.append( [ c.cmd, c.Error, True ] ) finally: # execute 'vk_status' command try: status = {} users = map( lambda i: [ i[1], str(i[0]) ], config.CONFIG.get('USERS',{}).iteritems() ) def addStatus(fname, cmdl): DBG.trace('addStatus(%s,%s)', [fname,cmdl]) if cmdl[0] not in ['on','off'] or len(cmdl)<3: return cmdl[2] = users.get( cmdl[2], cmdl[2] ) status[fname] = ' '.join(cmdl) if 'vk_status' in flags: CMDPool.ScanCommands(addStatus) DBG.trace(status) status = map( lambda k: status[k], sorted(status.keys()) ) if status: SendMsg( vk_api1, '\n'.join(status), prefix=u'vk: status\n' ) except Exception as e: DBG.TODO(str(e)) # send the commands status message if any non-silent or error try: if filter(lambda c: c[2] or c[1], commands ): aliases = map( lambda i: [ str(i[0]), repr(i[1])], config.CONFIG.get('ALIASES',{}).iteritems() ) logMessageCmd = [] for c in commands: if not c[0].cmdl: continue cmdl = ' '.join(c[0].cmdl) for a in aliases: cmdl = cmdl.replace(a[0],a[1]) logMessageCmd.append( u"%s%s" % (cmdl, u' - FAIL(%s)'%c[1] if c[1] is not None else '') ) logMessage = logMessageCmd + logMessage if logMessage: SendMsg( vk_api1, '\n'.join(logMessage), prefix=u'vk: ' ) except Exception as e: DBG.TODO(str(e)) # delete messages if toDelMsgIds: util.TODO('Maybe filter only that messages which were completely executed or failed??') DBG.trace("%s", [toDelMsgIds]) vk_api1.messages.delete( message_ids = ','.join(map(str,toDelMsgIds)) )
def addStatus(fname, cmdl): DBG.trace('addStatus(%s,%s)', [fname, cmdl]) if cmdl[0] not in ['on', 'off'] or len(cmdl) < 3: return cmdl[2] = users.get(cmdl[2], cmdl[2]) status[fname] = ' '.join(cmdl)
def main(): util.init_console() DBG.logfile_name = './LOG_WATCHER/vk_watch' DBG.level = DBG.TRACE DBG.important(u">>> RUN vk_watcher at %s" % os.getcwdu()) if 'BASE_DIR' in globals() and BASE_DIR: os.chdir(BASE_DIR) LoadConfig() USER_LOGIN = config.CONFIG['USER_LOGIN'].strip() if not USER_LOGIN: raise util.FatalError('Unknown USER_LOGIN') DIR_MAIN = os.path.join(os.getcwdu(), '.vk_watcher-%s' % USER_LOGIN) DIR_LOG = os.path.join(DIR_MAIN, 'log') DIR_TMP = os.path.join(DIR_MAIN, 'tmp') global LOCKFILE LOCKFILE = os.path.join(DIR_TMP, 'lockfile.group_watch') AddLockFile(timeout=50) """" BASEDIR = os.path.join( os.getcwdu(),u"MSG-%s" % USER_LOGIN ) if not os.path.exists(BASEDIR): os.makedirs(BASEDIR) """ import vk.api vk.api.LOG_DIR = "./LOG_WATCHER" vk_api1, me1, USER_PASSWORD1 = vk_utils.VKSignIn(USER_LOGIN, False) vk_api2, me2, USER_PASSWORD2 = vk_utils.VKSignInSecondary(False) now = time.time() COMMAND_USER = config.CONFIG.get('COMMAND_USER', '') if not COMMAND_USER: COMMAND_USER = me1 config.CONFIG['COMMAND_USER'] = COMMAND_USER flags = {} # any kind of common flags (already done executed) commands = [] # [ [0CMD, 1msg, 2silence], ... ] logMessage = [] toDelMsgIds = set() #executedCmd = collections.OrderedDict() # ['cmd' = status] # IMPORTANT: set all local values to globals util.import_vars(globals(), locals(), '*', isOverwrite=True) CMD_PREFIX = 'vk_' try: # Execute posponed commands ##CMDPool.ScanCommands( CMDPool.HandlerPostponed ) ##CMDPool.ScanCommands( CMDPool.HandlerCheck ) # Scan incoming messages to get commands res = vk_api.messages.getHistory(offset=0, count=30, user_id=me, rev=1) for item in res[u'items']: body = item.get(u'body', '').strip().lower() if not body.startswith(CMD_PREFIX): continue delMsgId = item.get(u'id', 0) lst = map(str.strip, body.split('\n')) DBG.info(u"catch command(id=%s): %s", (delMsgId, lst)) for cmd in lst: if not cmd.startswith(CMD_PREFIX): continue toDelMsgIds.add(delMsgId) silence = cmd.endswith('@') if silence: cmd = cmd[:-1] try: command.append( [CMD(cmd[len(CMD_PREFIX):].split()), None, silence]) except Exception as e: command.append([None, str(e), False]) # u"%s - FAIL(%s)" % (cmd,str(e)) dbg = "==COMMANDS:\n" for c in commands: dbg += "=%s\n" % repr(c) if c[0] is not None: dbg += util.debugDump(c[0], True) DBG.trace(dbg) # Execute commands DBG.TODO('Execute commands') for frame in commands: try: if frame[0] is not None: DBG.trace("COMMAND: %s -> %s(%s)", [ frame[0].main_cmd, COMMAND_PROCESSORS.get(frame[0].main_cmd, None), frame ]) COMMAND_PROCESSORS[frame[0].main_cmd](frame[0], frame) except Exception as e: frame[1] = str(e) # Observers: a) prepare the list DBG.TODO('Observers') pool = WatcherExecutor() pool.vk_api = [ vk_utils.BatchExecutor(vk_api1), vk_utils.BatchExecutor(vk_api2) ] CMDPool.ScanCommands(pool.collectWatchers) # b) 1st pass (prepare cached queries) postponed = [] for c in pool.watchers: try: if c.Error: raise util.SkipError(c.Error) if not c.run('CheckWatcherStatus'): continue if c.run('Prepare', isDryRun=True): c.run('DoAction', isDryRun=True) postponed.append(c) except Exception as e: DBG.important(str(e)) c.Error = str(e) for c in postponed: try: c.run('Postprocess') except Exception as e: DBG.important(str(e)) c.Error = str(e) # c) 2nd pass (actually execute watchers) for idx in [0, 1]: pool.vk_api[idx] = vk_utils.CachedVKAPI(pool.vk_api[idx].vk_api, pool.vk_api[idx]) for c in pool.watchers: try: if c.Error: raise util.SkipError(c.Error) if not c.run('CheckWatcherStatus'): continue message = None if c.run('Prepare', isDryRun=False): message = c.run('DoAction', isDryRun=False) c.run('Postprocess', isDryRun=False) #if message and not c.Error: if message and not c.Error: if c.run('Notify', message=message): c.run('Notify', message=message, defaultHandler=True) if not c.Error: # no need to include this into status continue except Exception as e: DBG.important(str(e)) c.Error = str(e) c.cmd.cmdl[0] = u"[auto]" + c.cmd.cmdl[0] commands.append([c.cmd, c.Error, True]) finally: # execute 'vk_status' command try: status = {} users = map(lambda i: [i[1], str(i[0])], config.CONFIG.get('USERS', {}).iteritems()) def addStatus(fname, cmdl): DBG.trace('addStatus(%s,%s)', [fname, cmdl]) if cmdl[0] not in ['on', 'off'] or len(cmdl) < 3: return cmdl[2] = users.get(cmdl[2], cmdl[2]) status[fname] = ' '.join(cmdl) if 'vk_status' in flags: CMDPool.ScanCommands(addStatus) DBG.trace(status) status = map(lambda k: status[k], sorted(status.keys())) if status: SendMsg(vk_api1, '\n'.join(status), prefix=u'vk: status\n') except Exception as e: DBG.TODO(str(e)) # send the commands status message if any non-silent or error try: if filter(lambda c: c[2] or c[1], commands): aliases = map(lambda i: [str(i[0]), repr(i[1])], config.CONFIG.get('ALIASES', {}).iteritems()) logMessageCmd = [] for c in commands: if not c[0].cmdl: continue cmdl = ' '.join(c[0].cmdl) for a in aliases: cmdl = cmdl.replace(a[0], a[1]) logMessageCmd.append(u"%s%s" % (cmdl, u' - FAIL(%s)' % c[1] if c[1] is not None else '')) logMessage = logMessageCmd + logMessage if logMessage: SendMsg(vk_api1, '\n'.join(logMessage), prefix=u'vk: ') except Exception as e: DBG.TODO(str(e)) # delete messages if toDelMsgIds: util.TODO( 'Maybe filter only that messages which were completely executed or failed??' ) DBG.trace("%s", [toDelMsgIds]) vk_api1.messages.delete( message_ids=','.join(map(str, toDelMsgIds)))