def _connect(self,host,port,login,password,delay): self.host=host self.port=port self.login=login self.password=password self.line_delay=delay log_info('Connecting to IRC at %s:%u' % (host, port)) self.last_send_time=0 self.last_ping_time = time.time() self.quitting = False self.buffered_data = "" self.userstable=dict() self.registered_users=set() try: self.irc = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) if self.use_ssl: try: raise RuntimeError('') self.irc_ssl_context = ssl.create_default_context() self.sslirc = self.irc_ssl_context.wrap_socket(self.irc, host) self.sslirc.connect ( ( host, port ) ) except Exception,e: log_warn('Failed to create SSL context, using fallback code: %s' % str(e)) self.irc.connect ( ( host, port ) ) self.sslirc = socket.ssl(self.irc) except Exception, e: log_error( 'Error initializing IRC: %s' % str(e)) return False
def GetTipbotBalance(link,cmd): log_info('%s wants to know the tipbot balance' % str(link)) try: balance, unlocked_balance = RetrieveTipbotBalance() except Exception,e: link.send("An error has occured") return
def GetTipbotBalance(link, cmd): log_info('%s wants to know the tipbot balance' % str(link)) try: balance, unlocked_balance = RetrieveTipbotBalance() except Exception, e: link.send("An error has occured") return
def _post_next_reply(self): data=redis_lindex('twitter:replies',0) if not data: return False parts=data.split(':',2) mtype=parts[0] data=parts[1] text=parts[2] try: if mtype == 'g': log_info('call: update_status(%s,%s)' % (str(text),str(data))) self.twitter.update_status(status=text,in_reply_to_status_id=data) elif mtype == 'u': log_info('call: send_direct_message(%s,%s)' % (str(data),str(text))) self.twitter.send_direct_message(user=data,text=text) else: log_error('Invalid reply type: %s' % str(mtype)) redis_lpop('twitter:replies') except Exception,e: log_error('Failed to send reply: %s' % str(e)) redis_lpop('twitter:replies') return True return False
def _connect(self, host, port, login, password, delay): self.host = host self.port = port self.login = login self.password = password self.line_delay = delay log_info('Connecting to IRC at %s:%u' % (host, port)) self.last_send_time = 0 self.last_ping_time = time.time() self.quitting = False self.buffered_data = "" self.userstable = dict() self.registered_users = set() try: self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.use_ssl: try: raise RuntimeError('') self.irc_ssl_context = ssl.create_default_context() self.sslirc = self.irc_ssl_context.wrap_socket( self.irc, host) self.sslirc.connect((host, port)) except Exception, e: log_warn( 'Failed to create SSL context, using fallback code: %s' % str(e)) self.irc.connect((host, port)) self.sslirc = socket.ssl(self.irc) except Exception, e: log_error('Error initializing IRC: %s' % str(e)) return False
def _parse_tweet(self,msg): if msg.user.screen_name.lower() == self.login.lower() and not force_parse_self: log_log('Ignoring tweet from self') return log_info('Twitter: parsing tweet from %s: %s' % (msg.user.screen_name,msg.text)) # twitter special: +x means tip the user mentioned with a @ for line in msg.text.split('\n'): line=line.lower() line=line.replace(self.keyword,'',1).strip() log_log('After removal: %s' % line) if re.match(username_regexp+"[ \t]*"+amount_regexp,line) or re.match(amount_regexp+"[ \t]*"+username_regexp,line): link=Link(self,User(self,msg.user.screen_name),None,msg) match=re.search(username_regexp,line) if not match: continue target=match.group(0) match=re.search(amount_regexp,line.replace(target,'').strip()) if not match: continue amount=match.group(0) if self.on_command: try: synthetic_cmd=['tip',target.replace('@','').strip(),amount.replace('+','').strip()] log_log('Running synthetic command: %s' % (str(synthetic_cmd))) self.on_command(link,synthetic_cmd) except Exception,e: log_error('Failed to tip %s: %s' % (target,str(e)))
def ValidateDNSSEC(address): log_info('Validating DNSSEC for %s' % address) try: resolver = dns.resolver.get_default_resolver() ns = resolver.nameservers[0] parts = address.split('.') for i in xrange(len(parts),0,-1): subpart = '.'.join(parts[i-1:]) query = dns.message.make_query(subpart,dns.rdatatype.NS) response = dns.query.udp(query,ns,1) if response.rcode() != dns.rcode.NOERROR: return False if len(response.authority) > 0: rrset = response.authority[0] else: rrset = response.answer[0] rr = rrset[0] if rr.rdtype == dns.rdatatype.SOA: continue query = dns.message.make_query(subpart,dns.rdatatype.DNSKEY,want_dnssec=True) response = dns.query.udp(query,ns,1) if response.rcode() != 0: return False answer = response.answer if len(answer) != 2: return False name = dns.name.from_text(subpart) dns.dnssec.validate(answer[0],answer[1],{name:answer[0]}) return True except Exception,e: log_error('Failed to validate DNSSEC for %s: %s' % (address, str(e))) return False
def PerformTip(link,whoid,units): identity=link.identity() try: account = GetAccount(identity) who_account = GetAccount(whoid) balance = redis_hget("balances",account) if balance == None: balance = 0 balance=long(balance) if units > balance: link.send("You only have %s" % (AmountToString(balance))) return log_info('Tip: %s tipping %s %u units, with balance %u' % (identity, whoid, units, balance)) try: p = redis_pipeline() p.incrby("tips_total_count",1); p.incrby("tips_total_amount",units); p.hincrby("tips_count",identity,1); p.hincrby("tips_amount",identity,units); p.hincrby("balances",account,-units); p.hincrby("balances",who_account,units) p.execute() if units < coinspecs.atomic_units: link.send("%s has tipped %s %s (%.16g %s)" % (NickFromIdentity(identity), NickFromIdentity(whoid), AmountToString(units), float(units) / coinspecs.atomic_units, coinspecs.name)) else: link.send("%s has tipped %s %s" % (NickFromIdentity(identity), NickFromIdentity(whoid), AmountToString(units))) except Exception, e: log_error("Tip: Error updating redis: %s" % str(e)) link.send("An error occured") return except Exception, e: log_error('Tip: exception: %s' % str(e)) link.send("An error has occured")
def Bookie(link, cmd): identity = link.identity() name = GetParam(cmd, 1) if not name: link.send( 'usage: !bookie <name> <outcome1> <outcome2> [<outcome3>...]') return outcomes = cmd[2:] if len(outcomes) < 2: link.send( 'usage: !bookie <name> <outcome1> <outcome2> [<outcome3>...]') return book_index = long(redis_get('bookie:last_book') or 0) book_index += 1 tname = "bookie:%d" % book_index log_info('%s opens book #%d for %s, with outcomes %s' % (identity, book_index, name, str(outcomes))) try: p = redis_pipeline() p.hset(tname, 'name', name) for o in outcomes: p.sadd(tname + ':outcomes', o) p.hset('bookie:active', book_index, name) redis_set('bookie:last_book', book_index) p.execute() except Exception, e: log_error( 'Bookie: Failed to register book for %s with outcomes %s: %s' % (name, str(outcomes), str(e))) link.send('Failed to create book') return
def Bookie(link,cmd): identity=link.identity() name = GetParam(cmd,1) if not name: link.send('usage: !bookie <name> <outcome1> <outcome2> [<outcome3>...]') return outcomes = cmd[2:] if len(outcomes) < 2: link.send('usage: !bookie <name> <outcome1> <outcome2> [<outcome3>...]') return book_index=long(redis_get('bookie:last_book') or 0) book_index += 1 tname = "bookie:%d" % book_index log_info('%s opens book #%d for %s, with outcomes %s' % (identity, book_index, name, str(outcomes))) try: p = redis_pipeline() p.hset(tname,'name',name) for o in outcomes: p.sadd(tname+':outcomes',o) p.hset('bookie:active',book_index,name) redis_set('bookie:last_book',book_index) p.execute() except Exception,e: log_error('Bookie: Failed to register book for %s with outcomes %s: %s' % (name, str(outcomes), str(e))) link.send('Failed to create book') return
def _post_next_reply(self): data = redis_lindex('twitter:replies', 0) if not data: return False parts = data.split(':', 2) mtype = parts[0] data = parts[1] text = parts[2] try: if mtype == 'g': log_info('call: update_status(%s,%s)' % (str(text), str(data))) self.twitter.update_status(status=text, in_reply_to_status_id=data) elif mtype == 'u': log_info('call: send_direct_message(%s,%s)' % (str(data), str(text))) self.twitter.send_direct_message(user=data, text=text) else: log_error('Invalid reply type: %s' % str(mtype)) redis_lpop('twitter:replies') except Exception, e: log_error('Failed to send reply: %s' % str(e)) redis_lpop('twitter:replies') return True return False
def ValidateDNSSEC(address): log_info('Validating DNSSEC for %s' % address) try: resolver = dns.resolver.get_default_resolver() ns = resolver.nameservers[0] parts = address.split('.') for i in xrange(len(parts), 0, -1): subpart = '.'.join(parts[i - 1:]) query = dns.message.make_query(subpart, dns.rdatatype.NS) response = dns.query.udp(query, ns, 1) if response.rcode() != dns.rcode.NOERROR: return False if len(response.authority) > 0: rrset = response.authority[0] else: rrset = response.answer[0] rr = rrset[0] if rr.rdtype == dns.rdatatype.SOA: continue query = dns.message.make_query(subpart, dns.rdatatype.DNSKEY, want_dnssec=True) response = dns.query.udp(query, ns, 1) if response.rcode() != 0: return False answer = response.answer if len(answer) != 2: return False name = dns.name.from_text(subpart) dns.dnssec.validate(answer[0], answer[1], {name: answer[0]}) return True except Exception, e: log_error('Failed to validate DNSSEC for %s: %s' % (address, str(e))) return False
def GetHeight(link, cmd): log_info('GetHeight: %s wants to know block height' % str(link)) try: j = SendDaemonHTMLCommand("getheight") except Exception, e: log_error('GetHeight: error: %s' % str(e)) link.send("An error has occured") return
def GetHeight(link,cmd): log_info('GetHeight: %s wants to know block height' % str(link)) try: j = SendDaemonHTMLCommand("getheight") except Exception,e: log_error('GetHeight: error: %s' % str(e)) link.send("An error has occured") return
def OnCommandProxy(link,cmd): if disabled: log_info('Ignoring command from %s while disabled: %s' % (str(link.identity()),str(cmd))) return link.batch_send_start() try: OnCommand(link,cmd,RunAdminCommand,RunRegisteredCommand) except Exception,e: log_error('Exception running command %s: %s' % (str(cmd),str(e)))
def Quit(link,cmd): global networks msg = "" for w in cmd[1:]: msg = msg + " " + w for network in networks: log_info('Quitting %s network' % network.name) network.quit() networks = []
def Quit(link, cmd): global networks msg = "" for w in cmd[1:]: msg = msg + " " + w for network in networks: log_info('Quitting %s network' % network.name) network.quit() networks = []
def connect_to_redis(host, port): log_info('Connecting to Redis at %s:%u' % (host, port)) try: global redisdb redisdb = redis.Redis(host=host, port=port) return redisdb except Exception, e: log_error('Error initializing redis: %s' % str(e)) exit()
def connect_to_redis(host,port): log_info('Connecting to Redis at %s:%u' % (host, port)) try: global redisdb redisdb = redis.Redis(host=host,port=port) return redisdb except Exception, e: log_error( 'Error initializing redis: %s' % str(e)) exit()
def disconnect(self): log_info('Reddit disconnect') if not self.thread: return log_info('Shutting down Reddit thread') self.stop = True self.thread.join() self.thread = None self.items_cache=None self.reddit = None
def OnCommandProxy(link, cmd): if disabled: log_info('Ignoring command from %s while disabled: %s' % (str(link.identity()), str(cmd))) return link.batch_send_start() try: OnCommand(link, cmd, RunAdminCommand, RunRegisteredCommand) except Exception, e: log_error('Exception running command %s: %s' % (str(cmd), str(e)))
def identify(self,link): nick = link.user.nick t = self.is_known(nick) if t < 60: log_info('%s is not known, or only time for %d seconds' % (nick, t)) if self.on_identified: self.on_identified(link,False) return log_info('Asking nickserv whether %s is identified' % nick) self.send_to('nickserv', "ACC " + nick)
def disconnect(self): log_info('Reddit disconnect') if not self.thread: return log_info('Shutting down Reddit thread') self.stop = True self.thread.join() self.thread = None self.items_cache = None self.reddit = None
def Result(link,cmd): identity=link.identity() SweepClosingTimes() res0, res1 = GetBookIndex(cmd,1) if res0 == None: link.send(res1) return book_index = res0 parm_offset = res1 tname = "bookie:%d" % book_index book_name=redis_hget(tname,'name') outcome = GetParam(cmd,1+parm_offset) if not outcome: link.send('usage: !result [<event name>] <outcome>') return outcomes = redis_smembers(tname+':outcomes') if not outcome in outcomes: link.send("%s is not a valid outcome for %s, try one of: %s" % (outcome, book_name, ", ".join(outcomes))) return log_info('%s calls %s on book %d' % (identity, outcome, book_index)) try: p = redis_pipeline() total_units_bet = long(redis_hget(tname,"bets") or 0) total_units_bet_by_winners = long(redis_hget(tname+":bets",outcome) or 0) resultmsg = [] bettors = redis_smembers(tname+':bettors') p.hincrby("earmarked","bookie",-total_units_bet) for bettor in bettors: o = redis_hget(tname,bettor+":outcome") ounits = long(redis_hget(tname,bettor+":units")) if o == outcome: a = GetAccount(bettor) owinunits = long(total_units_bet * (1-config.bookie_fee) * ounits / total_units_bet_by_winners) if owinunits<ounits: owinunits=ounits resultmsg.append("%s wins %s" % (NickFromIdentity(bettor), AmountToString(owinunits))) p.hincrby("balances",a,owinunits) else: resultmsg.append("%s loses %s" % (NickFromIdentity(bettor), AmountToString(ounits))) p.hdel('bookie:active',book_index) p.execute() if len(bettors) == 0: resultmsg = ["nobody had bet"] log_info('Book outcome is %s - %s' % (outcome, ", ".join(resultmsg))) link.send('Book #%d (%s) outcome is %s - %s' % (book_index, book_name, outcome, ", ".join(resultmsg))) except Exception,e: log_error('Result: Failed to process result: %s' % str(e)) link.send('An error occured') return
def disconnect(self): log_info('Twitter disconnect') if not self.thread: return log_info('Shutting down Twitter thread') self.stop = True self.thread.join() self.thread = None self.items_cache = None self.last_seen_tweet_id = None self.last_seen_dm_id = None self.twitter = None
def OnEventProxy(event,*args,**kwargs): log_info('Got event %s, args %s' % (event, str(kwargs))) if disabled: log_info('Ignoring event while disabled') return link=kwargs['link'] if 'link' in kwargs else None if link: link.batch_send_start() try: OnEvent(event,*args,**kwargs) except Exception,e: log_error('Exception handling event %s: %s' % (str(event),str(e)))
def OnEventProxy(event, *args, **kwargs): log_info('Got event %s, args %s' % (event, str(kwargs))) if disabled: log_info('Ignoring event while disabled') return link = kwargs['link'] if 'link' in kwargs else None if link: link.batch_send_start() try: OnEvent(event, *args, **kwargs) except Exception, e: log_error('Exception handling event %s: %s' % (str(event), str(e)))
def MuteUser(link): log_info('Muting %s (%s)' % (link.user.nick, link.user.ident)) if not link.group: return chan = link.group.name log_info("chan: " + chan) net = link.network try: cmd = "MODE " + chan + " +q " + link.user.ident net._irc_sendmsg(cmd) except: pass
def disconnect(self): log_info('Twitter disconnect') if not self.thread: return log_info('Shutting down Twitter thread') self.stop = True self.thread.join() self.thread = None self.items_cache=None self.last_seen_tweet_id=None self.last_seen_dm_id=None self.twitter = None
def RecordMove(link,actual): identity=link.identity() basic = GetBasicStrategyMove(link) log_info('%s %ss, basic strategy would %s' % (identity, actual, basic)) try: p = redis_pipeline() tname="blackjack:strategy:"+identity alltname="blackjack:strategy:" p.hincrby(tname,"moves",1) if actual == basic: p.hincrby(tname,"matching",1) p.execute() except Exception,e: log_error('Failed to record move for %s: %s' % (identity, str(e)))
def SweepClosingTimes(): books = GetActiveBooks() if not books: return now=time.time() for book_index in books.keys(): book_index = long(book_index) tname = "bookie:%d" % book_index if redis_hexists(tname,'closing_time'): closing_time=float(redis_hget(tname,'closing_time')) if closing_time<=now and not redis_hget(tname,'closed'): book_name=redis_hget(tname,'name') redis_hset(tname,'closed',1) log_info('Closing book #%d (%s) as scheduled, dt %s' % (book_index, book_name, TimeToString(now-closing_time)))
def _parse_dm(self,msg): if msg.sender.screen_name.lower() == self.login.lower() and not force_parse_self: log_log('Ignoring DM from self') return log_info('Twitter: parsing DM from %s: %s' % (msg.sender.screen_name,msg.text)) link=Link(self,User(self,msg.sender.screen_name),None,None) for line in msg.text.split('\n'): exidx=line.find('!') if exidx!=-1 and len(line)>exidx+1 and line[exidx+1] in string.ascii_letters and self.is_acceptable_command_prefix(line[:exidx]): cmd=line[exidx+1:].split(' ') cmd[0] = cmd[0].strip(' \t\n\r') log_info('Found command from %s: %s' % (link.identity(), str(cmd))) if self.on_command: self.on_command(link,cmd)
def _schedule_tweet(self,msg,reply_to_msg): try: log_info('Scheduling tweet in reply to %s: %s' % (str(reply_to_msg.id),msg)) if self.uri_base: name=self.canonicalize(reply_to_msg.user.screen_name) msg="%s: %s" % (name,msg) if self._can_be_sent_raw(msg): redis_sadd('twitter:message_hashes',hashlib.sha256(msg).hexdigest()) else: uri=self._make_uri(msg) msg="%s: %s%s" % (name,self.prefix_when_linked,uri) reply="g:"+str(reply_to_msg.id)+":"+msg redis_rpush('twitter:replies',reply) except Exception,e: log_error('Error scheduling tweet: %s' % str(e))
def _schedule_dm(self,msg,user): try: log_info('Scheduling DM to %s: %s' % (str(user.nick),msg)) if self.uri_base: nick=self.canonicalize(user.nick) msg="%s: %s" % (nick,uri) if self._can_be_sent_raw(msg): redis_sadd('twitter:message_hashes',hashlib.sha256(msg).hexdigest()) else: uri=self._make_uri(msg) msg="%s: %s%s" % (nick,self.prefix_when_linked,uri) reply="u:"+str(user.nick)+":"+msg redis_rpush('twitter:replies',reply) except Exception,e: log_error('Error scheduling DM: %s' % str(e))
def GetAccount(link_or_identity): if isinstance(link_or_identity,Link): identity=link_or_identity.identity() else: identity=link_or_identity account = redis_hget('accounts',identity) if account == None: log_info('No account found for %s, creating new one' % identity) next_account_id = long(redis_get('next_account_id') or 0) account = next_account_id if redis_hexists('accounts',account): raise RuntimeError('Next account ID already exists (%d)', account) redis_hset('accounts',identity,account) next_account_id += 1 redis_set('next_account_id',next_account_id) return account
def _schedule_dm(self, msg, user): try: log_info('Scheduling DM to %s: %s' % (str(user.nick), msg)) if self.uri_base: nick = self.canonicalize(user.nick) msg = "%s: %s" % (nick, uri) if self._can_be_sent_raw(msg): redis_sadd('twitter:message_hashes', hashlib.sha256(msg).hexdigest()) else: uri = self._make_uri(msg) msg = "%s: %s%s" % (nick, self.prefix_when_linked, uri) reply = "u:" + str(user.nick) + ":" + msg redis_rpush('twitter:replies', reply) except Exception, e: log_error('Error scheduling DM: %s' % str(e))
def GetAccount(link_or_identity): if isinstance(link_or_identity, Link): identity = link_or_identity.identity() else: identity = link_or_identity account = redis_hget('accounts', identity) if account == None: log_info('No account found for %s, creating new one' % identity) next_account_id = long(redis_get('next_account_id') or 0) account = next_account_id if redis_hexists('accounts', account): raise RuntimeError('Next account ID already exists (%d)', account) redis_hset('accounts', identity, account) next_account_id += 1 redis_set('next_account_id', next_account_id) return account
def SweepClosingTimes(): books = GetActiveBooks() if not books: return now = time.time() for book_index in books.keys(): book_index = long(book_index) tname = "bookie:%d" % book_index if redis_hexists(tname, 'closing_time'): closing_time = float(redis_hget(tname, 'closing_time')) if closing_time <= now and not redis_hget(tname, 'closed'): book_name = redis_hget(tname, 'name') redis_hset(tname, 'closed', 1) log_info( 'Closing book #%d (%s) as scheduled, dt %s' % (book_index, book_name, TimeToString(now - closing_time)))
def _schedule_tweet(self, msg, reply_to_msg): try: log_info('Scheduling tweet in reply to %s: %s' % (str(reply_to_msg.id), msg)) if self.uri_base: name = self.canonicalize(reply_to_msg.user.screen_name) msg = "%s: %s" % (name, msg) if self._can_be_sent_raw(msg): redis_sadd('twitter:message_hashes', hashlib.sha256(msg).hexdigest()) else: uri = self._make_uri(msg) msg = "%s: %s%s" % (name, self.prefix_when_linked, uri) reply = "g:" + str(reply_to_msg.id) + ":" + msg redis_rpush('twitter:replies', reply) except Exception, e: log_error('Error scheduling tweet: %s' % str(e))
def Load(link, cmd): modulename = GetParam(cmd, 1) if not modulename: link.send("Usage: load <modulename>") return if modulename == "builtin": link.send("Cannot load builtin module") return if modulename in sys.modules: link.send("There is already a %s module" % modulename) return log_info('Loading %s module' % modulename) try: __import__(modulename) link.send('%s loaded' % modulename) except Exception, e: log_error('Failed to load module "%s": %s' % (modulename, str(e))) link.send('An error occured')
def Load(link,cmd): modulename=GetParam(cmd,1) if not modulename: link.send("Usage: load <modulename>") return if modulename=="builtin": link.send("Cannot load builtin module") return if modulename in sys.modules: link.send("There is already a %s module" % modulename) return log_info('Loading %s module' % modulename) try: __import__(modulename) link.send('%s loaded' % modulename) except Exception,e: log_error('Failed to load module "%s": %s' % (modulename, str(e))) link.send('An error occured')
def Unload(link, cmd): modulename = GetParam(cmd, 1) if not modulename: link.send("Usage: unload <modulename>") return if modulename == "builtin": link.send("Cannot unload builtin module") return if not modulename in sys.modules: link.send("%s is not a dynamic module" % modulename) return log_info('Unloading %s module' % modulename) UnregisterModule(modulename) try: del sys.modules[modulename] link.send('%s unloaded' % modulename) except Exception, e: log_error('Failed to unload module "%s": %s' % (modulename, str(e))) link.send('An error occured')
def OnMessage(event, *args, **kwargs): line = kwargs['message'] if not line: return link = kwargs['link'] if IsAdmin(link): return if config.spammer_allowed and link.user.nick in config.spammer_allowed: return line = re.sub(r'\x03[0-9]?[0-9]?', '', line) line = re.sub(r'\x0f', '', line) line = line.lower().strip() log_info("Testing: " + line) for expr in triggers: if re.match(".*" + expr + ".*", line): MuteUser(link) return
def Unload(link,cmd): modulename=GetParam(cmd,1) if not modulename: link.send("Usage: unload <modulename>") return if modulename=="builtin": link.send("Cannot unload builtin module") return if not modulename in sys.modules: link.send("%s is not a dynamic module" % modulename) return log_info('Unloading %s module' % modulename) UnregisterModule(modulename) try: del sys.modules[modulename] link.send('%s unloaded' % modulename) except Exception,e: log_error('Failed to unload module "%s": %s' % (modulename, str(e))) link.send('An error occured')
def connect(self): if self.thread: return False try: cfg = config.network_config[self.name] self.login = cfg['login'] password = GetPassword(self.name + '/password') self.subreddits = cfg['subreddits'] user_agent = cfg['user_agent'] self.update_period = cfg['update_period'] self.load_limit = cfg['load_limit'] self.keyword = cfg['keyword'] self.use_unread_api = cfg['use_unread_api'] self.cache_timeout = cfg['cache_timeout'] client_id = GetPassword(self.name + '/client_id') client_secret = GetPassword(self.name + '/client_secret') username = GetPassword(self.name + '/username') if False: handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) logger = logging.getLogger('prawcore') logger.setLevel(logging.DEBUG) logger.addHandler(handler) self.reddit = praw.Reddit(client_id=client_id, client_secret=client_secret, password=password, user_agent=user_agent, username=username) log_info("Logged in reddit as " + str(self.reddit.user.me())) self.items_cache = dict() self.stop = False self.thread = threading.Thread(target=self.run) self.thread.start() self.logged_in = True except Exception, e: log_error('Failed to login to reddit: %s' % str(e)) return False
def ResolveCore(address,ctype): log_info('Resolving %s address for %s' % (ctype,address)) address=address.replace('@','.') if not '.' in address: return False,'invalid address' try: for attempt in range(3): resolver = dns.resolver.Resolver() resolver.timeout = 2 resolver.lifetime = 2 records = resolver.query(address,dns.rdatatype.TXT) for record in records: s = record.strings[0] if s.lower().startswith('oa1:%s' % ctype.lower()): a = re.sub('.*recipient_address[ \t]*=[ \t]*\"?([A-Za-z0-9]+)\"?.*','\\1',s) if IsValidAddress(a): log_info('Found %s address at %s: %s' % (ctype,address,a)) return True, [a,ValidateDNSSEC(address)] except Exception,e: log_error('Error resolving %s: %s' % (address,str(e)))
def _parse_dm(self, msg): if msg.sender.screen_name.lower() == self.login.lower( ) and not force_parse_self: log_log('Ignoring DM from self') return log_info('Twitter: parsing DM from %s: %s' % (msg.sender.screen_name, msg.text)) link = Link(self, User(self, msg.sender.screen_name), None, None) for line in msg.text.split('\n'): exidx = line.find('!') if exidx != -1 and len(line) > exidx + 1 and line[ exidx + 1] in string.ascii_letters and self.is_acceptable_command_prefix( line[:exidx]): cmd = line[exidx + 1:].split(' ') cmd[0] = cmd[0].strip(' \t\n\r') log_info('Found command from %s: %s' % (link.identity(), str(cmd))) if self.on_command: self.on_command(link, cmd)
def on_notice(self,who,text): if who == "NickServ!NickServ@services.": if text.find(' ACC ') != -1: stext = text.split(' ') ns_nick = stext[0] ns_acc = stext[1] ns_status = stext[2] if ns_acc == "ACC": ns_link=Link(self,User(self,ns_nick),None) if ns_status == "3": log_info('NickServ says %s is identified' % ns_nick) self.registered_users.add(ns_link.identity()) if self.on_identified: self.on_identified(ns_link,True) else: log_info('NickServ says %s is not identified' % ns_nick) self.registered_users.discard(ns_link.identity()) if self.on_identified: self.on_identified(ns_link,False) else: log_error('ACC line not as expected...') return True
def Close(link, cmd): identity = link.identity() SweepClosingTimes() res0, res1 = GetBookIndex(cmd, 0) if res0 == None: link.send(res1) return book_index = res0 parm_offset = res1 tname = "bookie:%d" % book_index book_name = redis_hget(tname, 'name') log_info('Closing book %d' % book_index) try: redis_hset(tname, 'closed', 1) except Exception, e: log_error('Failed to close book: %s' % str(e)) link.send('An error occured') return
def Close(link,cmd): identity=link.identity() SweepClosingTimes() res0, res1 = GetBookIndex(cmd,0) if res0 == None: link.send(res1) return book_index = res0 parm_offset = res1 tname = "bookie:%d" % book_index book_name=redis_hget(tname,'name') log_info('Closing book %d' % book_index) try: redis_hset(tname,'closed',1) except Exception,e: log_error('Failed to close book: %s' % str(e)) link.send('An error occured') return
def _parse_tweet(self, msg): if msg.user.screen_name.lower() == self.login.lower( ) and not force_parse_self: log_log('Ignoring tweet from self') return log_info('Twitter: parsing tweet from %s: %s' % (msg.user.screen_name, msg.text)) # twitter special: +x means tip the user mentioned with a @ for line in msg.text.split('\n'): line = line.lower() line = line.replace(self.keyword, '', 1).strip() log_log('After removal: %s' % line) if re.match(username_regexp + "[ \t]*" + amount_regexp, line) or re.match( amount_regexp + "[ \t]*" + username_regexp, line): link = Link(self, User(self, msg.user.screen_name), None, msg) match = re.search(username_regexp, line) if not match: continue target = match.group(0) match = re.search(amount_regexp, line.replace(target, '').strip()) if not match: continue amount = match.group(0) if self.on_command: try: synthetic_cmd = [ 'tip', target.replace('@', '').strip(), amount.replace('+', '').strip() ] log_log('Running synthetic command: %s' % (str(synthetic_cmd))) self.on_command(link, synthetic_cmd) except Exception, e: log_error('Failed to tip %s: %s' % (target, str(e)))
def PerformTip(link, whoid, units): identity = link.identity() try: account = GetAccount(identity) who_account = GetAccount(whoid) balance = redis_hget("balances", account) if balance == None: balance = 0 balance = long(balance) if units > balance: link.send("You only have %s" % (AmountToString(balance))) return log_info('Tip: %s tipping %s %u units, with balance %u' % (identity, whoid, units, balance)) try: p = redis_pipeline() p.incrby("tips_total_count", 1) p.incrby("tips_total_amount", units) p.hincrby("tips_count", identity, 1) p.hincrby("tips_amount", identity, units) p.hincrby("balances", account, -units) p.hincrby("balances", who_account, units) p.execute() if units < coinspecs.atomic_units: link.send("%s has tipped %s %s (%.16g %s)" % (NickFromIdentity(identity), NickFromIdentity(whoid), AmountToString(units), float(units) / coinspecs.atomic_units, coinspecs.name)) else: link.send("%s has tipped %s %s" % (NickFromIdentity(identity), NickFromIdentity(whoid), AmountToString(units))) except Exception, e: log_error("Tip: Error updating redis: %s" % str(e)) link.send("An error occured") return except Exception, e: log_error('Tip: exception: %s' % str(e)) link.send("An error has occured")
def Cancel(link, cmd): identity = link.identity() SweepClosingTimes() res0, res1 = GetBookIndex(cmd, 0) if res0 == None: link.send(res1) return book_index = res0 parm_offset = res1 tname = 'bookie:%d' % book_index book_name = redis_hget(tname, 'name') log_info('Cancelling book %d (%s)' % (book_index, book_name)) try: p = redis_pipeline() bettors = redis_smembers(tname + ':bettors') refundmsg = [] for bettor in bettors: units = long(redis_hget(tname, bettor + ":units")) log_info('Refunding %s to %s' % (AmountToString(units), bettor)) a = GetAccount(bettor) p.hincrby('balances', a, units) p.hincrby('earmarked', 'bookie', -units) refundmsg.append('%s to %s' % (AmountToString(units), NickFromIdentity(bettor))) p.hdel('bookie:active', book_index) p.execute() if len(refundmsg) == 0: link.send('Book %s cancelled, nobody had bet' % book_name) else: link.send('Book %s cancelled, refunding %s' % (book_name, ", ".join(refundmsg))) except Exception, e: log_error('Cancel: Failed to cancel book: %s' % str(e)) link.send('Failed to cancel book %s' % book_name) return
def Cancel(link,cmd): identity=link.identity() SweepClosingTimes() res0, res1 = GetBookIndex(cmd,0) if res0 == None: link.send(res1) return book_index = res0 parm_offset = res1 tname='bookie:%d' % book_index book_name=redis_hget(tname,'name') log_info('Cancelling book %d (%s)' % (book_index, book_name)) try: p = redis_pipeline() bettors = redis_smembers(tname+':bettors') refundmsg = [] for bettor in bettors: units = long(redis_hget(tname,bettor+":units")) log_info('Refunding %s to %s' % (AmountToString(units),bettor)) a = GetAccount(bettor) p.hincrby('balances',a,units) p.hincrby('earmarked','bookie',-units) refundmsg.append('%s to %s' % (AmountToString(units), NickFromIdentity(bettor))) p.hdel('bookie:active',book_index) p.execute() if len(refundmsg) == 0: link.send('Book %s cancelled, nobody had bet' % book_name) else: link.send('Book %s cancelled, refunding %s' % (book_name, ", ".join(refundmsg))) except Exception,e: log_error('Cancel: Failed to cancel book: %s' % str(e)) link.send('Failed to cancel book %s' % book_name) return
def ResolveCore(address, ctype): log_info('Resolving %s address for %s' % (ctype, address)) address = address.replace('@', '.') if not '.' in address: return False, 'invalid address' try: for attempt in range(3): resolver = dns.resolver.Resolver() resolver.timeout = 2 resolver.lifetime = 2 records = resolver.query(address, dns.rdatatype.TXT) for record in records: s = record.strings[0] if s.lower().startswith('oa1:%s' % ctype.lower()): a = re.sub( '.*recipient_address[ \t]*=[ \t]*\"?([A-Za-z0-9]+)\"?.*', '\\1', s) if IsValidAddress(a): log_info('Found %s address at %s: %s' % (ctype, address, a)) return True, [a, ValidateDNSSEC(address)] except Exception, e: log_error('Error resolving %s: %s' % (address, str(e)))
def _post_next_reply(self): data=redis_lindex('reddit:replies',0) if not data: return False parts=data.split(':',2) fullname=parts[0] recipient=parts[1] text=parts[2] text = text.replace('\n\n','\n\n \n\n').replace('\n',' \n') try: if recipient: # PM self.reddit.send_message(recipient,"Reply from %s"%self.login,text,raise_captcha_exception=True) log_info('Posted message to %s: %s' % (recipient,text)) else: # subreddit or reply to PM item = None log_info('looking for "%s" in %s' % (str(fullname),str(self.items_cache))) if fullname in self.items_cache: item=self.items_cache[fullname] if not item: item=self.reddit.get_info(thing_id=fullname) if not item: log_error('Failed to find item %s to post %s' % (fullname,text)) redis_lpop('reddit:replies') return True reply_item=item.reply(text) log_info('Posted reply to %s: %s' % (fullname,text)) if reply_item and hasattr(reply_item,'id'): redis_sadd('reddit:last_seen_ids',reply_item.id) redis_lpop('reddit:replies') except praw.errors.RateLimitExceeded,e: log_info('Rate limited trying to send %s, will retry: %s' % (data,str(e))) return False
def LinkCore(link,other_identity): try: identity=link.identity() if identity==other_identity: return True, "same-identity" links=redis_hget('links',identity) if links: if other_identity in links.split(chr(0)): return True, "already" links=links+chr(0)+other_identity else: links=other_identity redis_hset('links',identity,links) links=redis_hget('links',other_identity) if links: if identity in links.split(chr(0)): # we have both account=GetAccount(identity) other_account=GetAccount(other_identity) if account==other_account: log_info('%s and %s already have the same account: %s' % (identity,other_identity,account)) return True, "same-account" balance=long(redis_hget('balances',account)) log_info('Linking accounts %s (%s) and %s (%s)' % (account,identity,other_account,other_identity)) p=redis_pipeline() p.hincrby('balances',other_account,balance) p.hincrby('balances',account,-balance) accounts=redis_hgetall('accounts') for a in accounts: if accounts[a]==account: log_info('Changing %s\'s account from %s to %s' % (a,account,other_account)) p.hset('accounts',a,other_account) p.execute() return True, "linked" except Exception,e: log_error('Error linking %s and %s: %s' % (identity,other_identity,str(e))) return False, "error"
amount = GetParam(cmd,2+parm_offset) if not outcome or not amount: link.send('usage: !bet [<event name>] <outcome> <amount>') return try: units = StringToUnits(amount) except Exception,e: link.send('usage: !bet [<event name>] <outcome> <amount>') return if units <= 0: link.send("Invalid amount") return valid,reason = IsBetValid(link,amount,config.bookie_min_bet,config.bookie_max_bet,0,0,0) if not valid: log_info("Bookie: %s's bet refused: %s" % (identity, reason)) link.send("%s: %s" % (link.user.nick, reason)) return outcomes = redis_smembers(tname+':outcomes') if not outcome in outcomes: link.send("%s is not a valid outcome for %s, try one of: %s" % (outcome, book_name, ", ".join(outcomes))) return if redis_hexists(tname,identity+":outcome"): previous_outcome = redis_hget(tname,identity+":outcome") if previous_outcome != outcome: link.send("%s: you can only bet on one outcome per book, and you already bet on %s" % (NickFromIdentity(identity),previous_outcome)) return log_info('%s wants to bet %s on %s' % (identity, AmountToString(units), outcome)) try: