def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug('> CointipBot::check_inbox()') try: # Try to fetch some messages messages = list(ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info("CointipBot::check_inbox(): ignoring msg with no author") ctb_misc.praw_call(m.mark_as_read) continue lg.info("CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning("CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if m.author and m.author.name.lower() == self.conf.reddit.auth.user.lower(): lg.debug("CointipBot::check_inbox(): ignoring message from self") ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug("CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name = m.author.name, redditobj = m.author, ctb = self) if u.banned: lg.info("CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info("CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and not m.subject in ['post reply', 'comment reply']: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template('didnt-understand.tpl') msg = tpl.render(user_from=user.name, what='comment' if m.was_comment else 'message', source_link=m.permalink if hasattr(m, 'permalink') else None, ctb=self) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell(subj='What?', msg=msg, msgobj=m if not m.was_comment else None) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, timeout) as e: lg.warning("CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except RateLimitExceeded as e: lg.warning("CointipBot::check_inbox(): rate limit exceeded, sleeping for %s seconds", e.sleep_time) time.sleep(e.sleep_time) time.sleep(1) pass except Exception as e: lg.error("CointipBot::check_inbox(): %s", e) raise lg.debug("< CointipBot::check_inbox() DONE") return True
def check_subreddits(self): """ Evaluate new comments from configured subreddits """ lg.debug("> CointipBot::check_subreddits()") try: # Process comments until old comment reached # Get last_processed_comment_time if necessary if not hasattr(self.conf.reddit, 'last_processed_comment_time') or self.conf.reddit.last_processed_comment_time <= 0: self.conf.reddit.last_processed_comment_time = ctb_misc.get_value(conn=self.db, param0='last_processed_comment_time') updated_last_processed_time = 0 # Fetch comments from subreddits my_comments = ctb_misc.praw_call(self.conf.reddit.subreddits.get_comments, limit=self.conf.reddit.scan.batch_limit) # Match each comment against regex counter = 0 for c in my_comments: # Stop processing if old comment reached #lg.debug("check_subreddits(): c.id %s from %s, %s <= %s", c.id, c.subreddit.display_name, c.created_utc, self.conf.reddit.last_processed_comment_time) if c.created_utc <= self.conf.reddit.last_processed_comment_time: lg.debug("CointipBot::check_subreddits(): old comment reached") break counter += 1 if c.created_utc > updated_last_processed_time: updated_last_processed_time = c.created_utc # Ignore duplicate comments (may happen when bot is restarted) if ctb_action.check_action(msg_id=c.id, ctb=self): lg.warning("CointipBot::check_inbox(): duplicate action detected (comment.id %s), ignoring", c.id) continue # Ignore comments from banned users if c.author and self.conf.reddit.banned_users: lg.debug("CointipBot::check_subreddits(): checking whether user '%s' is banned..." % c.author) u = ctb_user.CtbUser(name = c.author.name, redditobj = c.author, ctb = self) if u.banned: lg.info("CointipBot::check_subreddits(): ignoring banned user '%s'" % c.author) continue # Attempt to evaluate comment action = ctb_action.eval_comment(c, self) # Perform action, if found if action: lg.info("CointipBot::check_subreddits(): %s from %s (%s)", action.type, action.u_from.name, c.id) lg.debug("CointipBot::check_subreddits(): comment body: <%s>", c.body) action.do() else: lg.info("CointipBot::check_subreddits(): no match") lg.debug("CointipBot::check_subreddits(): %s comments processed", counter) if counter >= self.conf.reddit.scan.batch_limit - 1: lg.warning("CointipBot::check_subreddits(): conf.reddit.scan.batch_limit (%s) was not large enough to process all comments", self.conf.reddit.scan.batch_limit) except (HTTPError, RateLimitExceeded, timeout) as e: lg.warning("CointipBot::check_subreddits(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error("CointipBot::check_subreddits(): coudln't fetch comments: %s", e) raise # Save updated last_processed_time value if updated_last_processed_time > 0: self.conf.reddit.last_processed_comment_time = updated_last_processed_time ctb_misc.set_value(conn=self.db, param0='last_processed_comment_time', value0=self.conf.reddit.last_processed_comment_time) lg.debug("< CointipBot::check_subreddits() DONE") return True
def check_subreddits(self): """ Evaluate new comments from configured subreddits """ lg.debug("> CointipBot::check_subreddits()") try: # Process comments until old comment reached # Get last_processed_comment_time if necessary if (not hasattr(self.conf.reddit, "last_processed_comment_time") or self.conf.reddit.last_processed_comment_time <= 0): self.conf.reddit.last_processed_comment_time = ctb_misc.get_value( conn=self.db, param0="last_processed_comment_time") updated_last_processed_time = 0 # Fetch comments from subreddits my_comments = ctb_misc.praw_call( self.conf.reddit.subreddits.get_comments, limit=self.conf.reddit.scan.batch_limit, ) # Match each comment against regex counter = 0 for c in my_comments: # Stop processing if old comment reached # lg.debug("check_subreddits(): c.id %s from %s, %s <= %s", c.id, c.subreddit.display_name, c.created_utc, self.conf.reddit.last_processed_comment_time) if c.created_utc <= self.conf.reddit.last_processed_comment_time: lg.debug( "CointipBot::check_subreddits(): old comment reached") break counter += 1 if c.created_utc > updated_last_processed_time: updated_last_processed_time = c.created_utc # Ignore duplicate comments (may happen when bot is restarted) if ctb_action.check_action(msg_id=c.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (comment.id %s), ignoring", c.id, ) continue # Ignore comments from banned users if c.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_subreddits(): checking whether user '%s' is banned..." % c.author) u = ctb_user.CtbUser(name=c.author.name, redditobj=c.author, ctb=self) if u.banned: lg.info( "CointipBot::check_subreddits(): ignoring banned user '%s'" % c.author) continue # Attempt to evaluate comment action = ctb_action.eval_comment(c, self) # Perform action, if found if action: lg.info( "CointipBot::check_subreddits(): %s from %s (%s)", action.type, action.u_from.name, c.id, ) lg.debug( "CointipBot::check_subreddits(): comment body: <%s>", c.body) action.do() else: lg.info("CointipBot::check_subreddits(): no match") lg.debug("CointipBot::check_subreddits(): %s comments processed", counter) if counter >= self.conf.reddit.scan.batch_limit - 1: lg.warning( "CointipBot::check_subreddits(): conf.reddit.scan.batch_limit (%s) was not large enough to process all comments", self.conf.reddit.scan.batch_limit, ) except (HTTPError, RateLimitExceeded, timeout) as e: lg.warning( "CointipBot::check_subreddits(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error( "CointipBot::check_subreddits(): coudln't fetch comments: %s", e) raise # Save updated last_processed_time value if updated_last_processed_time > 0: self.conf.reddit.last_processed_comment_time = updated_last_processed_time ctb_misc.set_value( conn=self.db, param0="last_processed_comment_time", value0=self.conf.reddit.last_processed_comment_time, ) lg.debug("< CointipBot::check_subreddits() DONE") return True
def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug("> CointipBot::check_inbox()") try: # Try to fetch some messages messages = list( ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info( "CointipBot::check_inbox(): ignoring msg with no author" ) ctb_misc.praw_call(m.mark_as_read) continue lg.info( "CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name, ) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id, ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if (m.author and m.author.name.lower() == self.conf.reddit.auth.user.lower()): lg.debug( "CointipBot::check_inbox(): ignoring message from self" ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) if u.banned: lg.info( "CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info( "CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id, ) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and m.subject not in [ "post reply", "comment reply", ]: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template("didnt-understand.tpl") msg = tpl.render( user_from=user.name, what="comment" if m.was_comment else "message", source_link=ctb_misc.permalink(m), ctb=self, ) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell( subj="What?", msg=msg, msgobj=m if not m.was_comment else None, ) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, RateLimitExceeded, timeout) as e: lg.warning( "CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.exception("CointipBot::check_inbox(): %s", e) # raise # ^ what do we say to death? # lg.error("^not today (^skipped raise)") # raise #not sure if right number of spaces; try to quit on error # for now, quitting on error because of dealing with on-going issues; switch # back when stable lg.debug("< CointipBot::check_inbox() DONE") return True
def process_transactions(self): lg.debug("< CointipBot::process_transactions() ") sql = "SELECT * FROM pending_action where state='pending' group by created_utc limit 50" for mysqlrow in self.db.execute(sql): such_fullname = mysqlrow['fullname'] #Check to see if message or comment check_fullname = such_fullname check_fullname = check_fullname.split('_') #process as a message if check_fullname[0] == 't4': #Set vars to pass into eval_db_message msg_body = mysqlrow['msg_body'] permalink = mysqlrow['msg_link'] fullname = such_fullname id = mysqlrow['msg_id'] verify = mysqlrow['verify'] fiat = mysqlrow['verify'] coin = mysqlrow['coin'] coin_val = mysqlrow['coin_val'] to_addr = mysqlrow['to_addr'] to_user = mysqlrow['to_user'] from_user = mysqlrow['from_user'] created_utc = mysqlrow['created_utc'] type = mysqlrow['type'] if not from_user: lg.warning('CointipBot::process_transactions(): no author') sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % such_fullname self.db.execute(sql2) continue if not msg_body: lg.warning( 'CointipBot::process_transactions(): message has no body dont process' ) sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % such_fullname self.db.execute(sql2) continue action = None action = ctb_action.eval_db_message(msg_body, permalink, fullname, id, verify, fiat, coin, coin_val, to_addr, to_user, from_user, created_utc, type, self) if action: lg.info( "CointipBot::processing transaction(): %s from %s (m.id %s)", action.type, action.u_from.name, action.deleted_msg_id) action.send_to_push_queue() sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % fullname self.db.execute(sql2) else: sql2 = "UPDATE pending_action SET state='failed' where fullname ='%s'" % fullname self.db.execute(sql2) #its a comment else: lg.debug( "< CointipBot::process_transactions() Processing %s " % such_fullname) m = ctb_misc.praw_call(self.reddit.get_info, thing_id=such_fullname) if not m: lg.warning( 'CointipBot::process_transactions(): message or post has been deleted' ) sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % such_fullname self.db.execute(sql2) continue if not m.author: lg.warning('CointipBot::process_transactions(): no author') sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % such_fullname self.db.execute(sql2) continue action = None if mysqlrow['msg_link']: action = ctb_action.eval_comment(m, self) if action: lg.info( "CointipBot::processing transaction(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) action.send_to_push_queue() sql2 = "UPDATE pending_action SET state='completed' where fullname ='%s'" % such_fullname self.db.execute(sql2) else: sql2 = "UPDATE pending_action SET state='failed' where fullname ='%s'" % such_fullname self.db.execute(sql2)
def check_inbox(self): """ Evaluate new messages until checkpoint is reached """ lg.debug('> CointipBot::check_inbox()') last_read = None running = True while running: try: # fetch all the messages since last read lg.debug("querying all messages since %s", last_read) my_params = {'after': last_read} messages = list( ctb_misc.praw_call(self.reddit.get_inbox, params=my_params)) # Process messages for m in messages: last_read = m.fullname lg.debug("Checking %s", last_read) #check for checkpoint if self.check_id(thingid=last_read): lg.debug("Hit checkpoint") running = False break # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info( "CointipBot::check_inbox(): ignoring msg with no author" ) self.mark_as_processed(thingid=m.fullname) continue lg.info("CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name) # Ignore self messages if m.author and m.author.name.lower( ) == self.conf.reddit.auth.user.lower(): lg.debug( "CointipBot::check_inbox(): ignoring message from self" ) self.mark_as_processed(thingid=m.fullname) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) if u.banned: lg.info( "CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) self.mark_as_processed(thingid=m.fullname) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # load into database if action: lg.info( "CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) lg.debug( "CointipBot::check_inbox(): message body: <%s>", m.body) action.save_pending(state="pending") else: lg.info( "CointipBot::check_inbox(): no match ... message body: <%s>", m.body) if self.conf.reddit.messages.sorry and not m.subject in [ 'post reply', 'comment reply' ]: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template( 'didnt-understand.tpl') msg = tpl.render( user_from=user.name, what='comment' if m.was_comment else 'message', source_link=m.permalink if hasattr( m, 'permalink') else None, ctb=self) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell(subj='What?', msg=msg, msgobj=m if not m.was_comment else None) # Mark message as read self.mark_as_processed(thingid=m.fullname) except (HTTPError, ConnectionError, Timeout, RateLimitExceeded, timeout) as e: lg.warning( "CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except Exception as e: lg.error("CointipBot::check_inbox(): %s", e) raise lg.debug("< CointipBot::check_inbox() DONE") return True
def check_inbox(self): """ Evaluate new messages in inbox """ lg.debug('> CointipBot::check_inbox()') try: # Try to fetch some messages messages = list( ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit)) messages.reverse() # Process messages for m in messages: # Sometimes messages don't have an author (such as 'you are banned from' message) if not m.author: lg.info( "CointipBot::check_inbox(): ignoring msg with no author" ) ctb_misc.praw_call(m.mark_as_read) continue lg.info("CointipBot::check_inbox(): %s from %s", "comment" if m.was_comment else "message", m.author.name) # Ignore duplicate messages (sometimes Reddit fails to mark messages as read) if ctb_action.check_action(msg_id=m.id, ctb=self): lg.warning( "CointipBot::check_inbox(): duplicate action detected (msg.id %s), ignoring", m.id) ctb_misc.praw_call(m.mark_as_read) continue # Ignore self messages if m.author and m.author.name.lower( ) == self.conf.reddit.auth.user.lower(): lg.debug( "CointipBot::check_inbox(): ignoring message from self" ) ctb_misc.praw_call(m.mark_as_read) continue # Ignore messages from banned users if m.author and self.conf.reddit.banned_users: lg.debug( "CointipBot::check_inbox(): checking whether user '%s' is banned..." % m.author) u = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) if u.banned: lg.info( "CointipBot::check_inbox(): ignoring banned user '%s'" % m.author) ctb_misc.praw_call(m.mark_as_read) continue action = None if m.was_comment: # Attempt to evaluate as comment / mention action = ctb_action.eval_comment(m, self) else: # Attempt to evaluate as inbox message action = ctb_action.eval_message(m, self) # Perform action, if found if action: lg.info("CointipBot::check_inbox(): %s from %s (m.id %s)", action.type, action.u_from.name, m.id) lg.debug("CointipBot::check_inbox(): message body: <%s>", m.body) action.do() else: lg.info("CointipBot::check_inbox(): no match") if self.conf.reddit.messages.sorry and not m.subject in [ 'post reply', 'comment reply' ]: user = ctb_user.CtbUser(name=m.author.name, redditobj=m.author, ctb=self) tpl = self.jenv.get_template('didnt-understand.tpl') msg = tpl.render( user_from=user.name, what='comment' if m.was_comment else 'message', source_link=m.permalink if hasattr(m, 'permalink') else None, ctb=self) lg.debug("CointipBot::check_inbox(): %s", msg) user.tell(subj='What?', msg=msg, msgobj=m if not m.was_comment else None) # Mark message as read ctb_misc.praw_call(m.mark_as_read) except (HTTPError, ConnectionError, Timeout, timeout) as e: lg.warning( "CointipBot::check_inbox(): Reddit is down (%s), sleeping", e) time.sleep(self.conf.misc.times.sleep_seconds) pass except RateLimitExceeded as e: lg.warning( "CointipBot::check_inbox(): rate limit exceeded, sleeping for %s seconds", e.sleep_time) time.sleep(e.sleep_time) time.sleep(1) pass except Exception as e: lg.error("CointipBot::check_inbox(): %s", e) raise lg.debug("< CointipBot::check_inbox() DONE") return True