def connect(self): if self.thread: return False try: cfg=config.network_config[self.name] self.login=cfg['login'] password=GetPassword(self.name) 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'] self.reddit=praw.Reddit(user_agent=user_agent,cache_timeout=self.cache_timeout) self.reddit.login(self.login,password) 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 _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 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 _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 _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 GetPaymentID(link): salt="2u3g55bkwrui32fi3g4bGR$j5g4ugnujb-"+coinspecs.name+"-"; p = hashlib.sha256(salt+link.identity()).hexdigest(); try: redis_hset("paymentid",p,link.identity()) except Exception,e: log_error('GetPaymentID: failed to set payment ID for %s to redis: %s' % (link.identity(),str(e)))
def run(self): while not self.stop: try: self._check() except Exception,e: log_error('Exception in TwitterNetwork:_check: %s' % str(e)) time.sleep(1)
def CompatibilityCheck(): try: r = redis.Redis() if not r.pipeline: raise RuntimeError('pipeline call not found') p = r.pipeline() if not p.exists: raise RuntimeError('exists call not found') if not p.get: raise RuntimeError('get call not found') if not p.set: raise RuntimeError('set call not found') if not p.hexists: raise RuntimeError('hexists call not found') if not p.hget: raise RuntimeError('hget call not found') if not p.hgetall: raise RuntimeError('hgetall call not found') if not p.hset: raise RuntimeError('hset call not found') if not p.hincrby: raise RuntimeError('hincrby call not found') if not p.hdel: raise RuntimeError('hdel call not found') if not p.incrby: raise RuntimeError('incrby call not found') if not p.sadd: raise RuntimeError('sadd call not found') if not p.smembers: raise RuntimeError('smembers call not found') if not p.sismember: raise RuntimeError('sismember call not found') if not p.rpush: raise RuntimeError('rpush call not found') if not p.lpop: raise RuntimeError('lpop call not found') if not p.llen: raise RuntimeError('llen call not found') if not p.lindex: raise RuntimeError('lindex call not found') if not p.lset: raise RuntimeError('lset call not found') if not p.zincrby: raise RuntimeError('zincrby call not found') if not p.zscore: raise RuntimeError('zscore call not found') if not p.zrangebylex: raise RuntimeError('zrangebylex call not found') if not p.keys: raise RuntimeError('keys call not found') if not p.execute: raise RuntimeError('execute call not found') if not p.delete: raise RuntimeError('delete call not found') except Exception,e: log_error('Error checking redis compatibility: %s' % str(e)) exit(1)
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 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 FairCheck(link,cmd): identity=link.identity() try: seed = GetServerSeed(link,'blackjack') except Exception,e: log_error('Failed to get server seed for %s: %s' % (identity,str(e))) link.send('An error has occured') return
def get_last_active_time(self,nick,chan): if not chan in self.userstable: log_error("IRCNetwork:get_last_active_time: channel %s not found in users table" % chan) return None if not nick in self.userstable[chan]: log_error("IRCNetwork:get_last_active_time: %s not found in channel %s's users table" % (nick, chan)) return None return self.userstable[chan][nick]
def InitScanBlockHeight(): try: scan_block_height = redis_get("scan_block_height") scan_block_height = long(scan_block_height) except Exception,e: try: redis_set("scan_block_height",0) except Exception,e: log_error('Failed to initialize scan_block_height: %s' % str(e))
def RetrieveBalance(link): try: account = GetAccount(link) balance = redis_hget("balances",account) or 0 confirming = redis_hget("confirming_payments",account) or 0 return long(balance), long(confirming) except Exception, e: log_error('RetrieveBalance: exception: %s' % str(e)) raise
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 _intern(self,contents): base=str(time.time())+":"+str(getrandbits(128))+":" for n in range(10000): filename=hashlib.sha256(base+str(n)).hexdigest()[:self.fs_hash_length] split_path=self._check_and_create(filename,contents) if split_path: return split_path log_error('Failed to intern contents') return None
def Seeds(link,cmd): identity=link.identity() try: sh = GetServerSeedHash(link,'dice') ps = GetPlayerSeed(link,'dice') except Exception,e: log_error('Failed to get server seed for %s: %s' % (identity,str(e))) link.send('An error has occured') return
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 update_last_active_time(self,chan,nick): if chan[0] != '#': return if not chan in self.userstable: log_error("IRCNetwork:update_last_active_time: %s spoke in %s, but %s not found in users table" % (nick, chan, chan)) self.userstable[chan] = dict() if not nick in self.userstable[chan]: log_error("IRCNetwork:update_last_active_time: %s spoke in %s, but was not found in that channel's users table" % (nick, chan)) self.userstable[chan][nick] = None self.userstable[chan][nick] = time.time()
def Roll(link): identity=link.identity() try: if redis_hexists('dice:rolls',identity): rolls = redis_hget('dice:rolls',identity) rolls = long(rolls) + 1 else: rolls = 1 except Exception,e: log_error('Failed to prepare roll for %s: %s' % (identity, str(e))) raise
def PlayerSeed(link,cmd): identity=link.identity() fair_string = GetParam(cmd,1) if not fair_string: link.send("Usage: !playerseed <string>") return try: SetPlayerSeed(link,'blackjack',fair_string) except Exception,e: log_error('Failed to save player seed for %s: %s' % (identity, str(e))) link.send('An error occured')
def GetNewShuffleSeed(link): identity=link.identity() try: if redis_hexists('blackjack:rolls',identity): rolls = redis_hget('blackjack:rolls',identity) rolls = long(rolls) + 1 else: rolls = 1 except Exception,e: log_error('Failed to prepare roll for %s: %s' % (identity, str(e))) raise
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 GetPassword(name): try: f = open('tipbot-password.txt', 'r') for p in f: p = p.strip("\r\n") parts=p.split(':') if parts[0]==name: return parts[1] except Exception,e: log_error('could not fetch password: %s' % str(e)) raise return "xxx"
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 IdentityFromString(link,s): if s.find(':') == -1: network = link.network nick=s else: parts=s.split(':') network_name=parts[0] network=GetNetworkByName(network_name) if not network: log_error('unknown network: %s' % network_name) raise RuntimeError('Unknown network: %s' % network_name) nick=parts[1] return network.name+':'+network.canonicalize(nick)
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 RetrieveTipbotBalance(force_refresh=False): global cached_tipbot_balance, cached_tipbot_unlocked_balance, cached_tipbot_balance_timestamp if not force_refresh and cached_tipbot_balance_timestamp and time.time()-cached_tipbot_balance_timestamp < config.tipbot_balance_cache_time: return cached_tipbot_balance, cached_tipbot_unlocked_balance j = SendWalletJSONRPCCommand("getbalance",None) if not "result" in j: log_error('RetrieveTipbotBalance: result not found in reply') raise RuntimeError("") return result = j["result"] if not "balance" in result: log_error('RetrieveTipbotBalance: balance not found in result') raise RuntimeError("") return if not "unlocked_balance" in result: log_error('RetrieveTipbotBalance: unlocked_balance not found in result') raise RuntimeError("") return balance = result["balance"] unlocked_balance = result["unlocked_balance"] log_log('RetrieveTipbotBalance: balance: %s' % str(balance)) log_log('RetrieveTipbotBalance: unlocked_balance: %s' % str(unlocked_balance)) pending = long(balance)-long(unlocked_balance) if pending < 0: log_error('RetrieveTipbotBalance: Negative pending balance! balance %s, unlocked %s' % (str(balance),str(unlocked_balance))) raise RuntimeError("") return cached_tipbot_balance_timestamp=time.time() cached_tipbot_balance=balance cached_tipbot_unlocked_balance=unlocked_balance return balance, unlocked_balance
def GetBlackjackStats(link,cmd): identity=link.identity() sidentity = GetParam(cmd,1) if sidentity: sidentity=IdentityFromString(link,sidentity) if sidentity and sidentity != identity: if not IsAdmin(link): log_error('%s is not admin, cannot see blackjack stats for %s' % (identity, sidentity)) link.send('Access denied') return else: sidentity=identity ShowBlackjackStats(link,sidentity,NickFromIdentity(sidentity)) ShowBlackjackStats(link,"reset:"+sidentity,'%s since reset' % NickFromIdentity(sidentity)) ShowBlackjackStats(link,'','overall')
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 AddBalance(link, cmd): nick = link.user.nick if GetParam(cmd, 2): anick = GetParam(cmd, 1) amount = GetParam(cmd, 2) else: anick = nick amount = GetParam(cmd, 1) if not amount: link.send('usage: !addbalance [<nick>] <amount>') return try: units = StringToUnits(amount) except Exception, e: log_error('AddBalance: error converting amount: %s' % str(e)) link.send('usage: !addbalance [<nick>] <amount>') return
def ResetKitsuneStats(link, cmd): identity = link.identity() sidentity = GetParam(cmd, 1) if sidentity: sidentity = IdentityFromString(link, sidentity) if sidentity and sidentity != identity: if not IsAdmin(link): log_error('%s is not admin, cannot see kitsune stats for %s' % (identity, sidentity)) link.send('Access denied') return else: sidentity = identity try: ResetGameStats(link, sidentity, "kitsune") except Exception, e: link.send("An error occured")
def GetKitsuneStats(link, cmd): identity = link.identity() sidentity = GetParam(cmd, 1) if sidentity: sidentity = IdentityFromString(link, sidentity) if sidentity and sidentity != identity: if not IsAdmin(link): log_error('%s is not admin, cannot see kitsune stats for %s' % (identity, sidentity)) link.send('Access denied') return else: sidentity = identity ShowKitsuneStats(link, sidentity, NickFromIdentity(sidentity)) ShowKitsuneStats(link, "reset:" + sidentity, '%s since reset' % NickFromIdentity(sidentity)) ShowKitsuneStats(link, '', 'overall')
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 get_active_users(self, seconds, chan): nicks = [] if not chan in self.userstable: return [] now = time.time() for nick in self.userstable[chan]: t = self.userstable[chan][nick] if t == None: continue dt = now - t if dt < 0: log_error( "IRCNetwork:get_active_users: %s active in %s in the future" % (nick, chan)) continue if dt < seconds: nicks.append(Link(self, User(self, nick), Group(self, chan))) return nicks
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"
def connect(self): try: cfg = config.network_config[self.name] host = cfg['host'] port = cfg['port'] login = cfg['login'] password = GetPassword(self.name) delay = cfg['delay'] self.use_ssl = cfg['ssl'] self.use_sasl = cfg['sasl'] self.welcome_line = cfg['welcome_line'] self.timeout_seconds = cfg['timeout_seconds'] self.channels = cfg['channels'] if self.use_sasl: self.sasl_name = cfg['sasl_name'] except Exception, e: log_error('Configuration not found for %s: %s' % (self.name, str(e))) return False
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'] ckey = GetPassword(self.name + "/ckey") csecret = GetPassword(self.name + "/csecret") atoken = GetPassword(self.name + "/atoken") atsecret = GetPassword(self.name + "/atsecret") self.update_period = cfg['update_period'] self.keyword = cfg['keyword'].lower() self.fs_location = cfg['fs_location'] self.fs_prefix_tree = cfg['fs_prefix_tree'] self.uri_base = cfg['uri_base'] self.prefix_when_linked = cfg['prefix_when_linked'] self.fs_hash_length = cfg['fs_hash_length'] if self.fs_location and not self._is_valid_location( self.fs_location): log_error('Invalid location: %s' % self.fs_location) return False self.items_cache = dict() self.last_seen_tweet_id = long( redis_get('twitter:last_seen_tweet_id') or 0) self.last_seen_dm_id = long( redis_get('twitter:last_seen_dm_id') or 0) log_log('loaded last seen id: tweet %s, dm %s' % (str(self.last_seen_tweet_id), str(self.last_seen_dm_id))) auth = tweepy.OAuthHandler(ckey, csecret) auth.set_access_token(atoken, atsecret) self.twitter = tweepy.API(auth) self.stop = False self.thread = threading.Thread(target=self.run) self.thread.start() except Exception, e: log_error('Failed to login to twitter: %s' % str(e)) return False
def Book(link, cmd): identity = link.identity() SweepClosingTimes() active_books = GetActiveBooks() if len(active_books) == 0: link.send('The book is empty') return for book_index in sorted(active_books.keys()): book_index = long(book_index) tname = 'bookie:%s' % book_index try: name = redis_hget(tname, 'name') outcomes = redis_smembers(tname + ':outcomes') outcome = redis_hget(tname, identity + ":outcome") units = redis_hget(tname, identity + ":units") except Exception, e: log_error('Book: Failed to retrieve book %d: %s' % (book_index, str(e))) link.send('An error occured') return outcomes = redis_smembers(tname + ':outcomes') outcomes_with_bets = [] for o in outcomes: ou = long(redis_hget(tname + ":bets", o) or 0) if ou > 0: outcomes_with_bets.append(o + " (%s)" % AmountToString(ou)) else: outcomes_with_bets.append(o) msg = 'Book #%d (%s): %s' % (book_index, name, ", ".join(outcomes_with_bets)) if redis_hget(tname, 'closed'): msg = msg + " - closed" elif redis_hexists(tname, 'closing_time'): try: closing_time = float(redis_hget(tname, 'closing_time')) msg = msg + ' - closing in %s' % (TimeToString(closing_time - time.time())) except Exception, e: log_error('Failed to get closing time: %s' % (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.message(fullname) if not item: gen=self.reddit.info([fullname]) item=next(gen, None) 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 Exception,e: log_error('Error sending %s, will retry: %s' % (data,str(e))) return False
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 ScheduleClose(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') try: minutes = float(GetParam(cmd, 1 + parm_offset)) except Exception, e: log_error('error getting minutes: %s' % str(e)) link.send('usage: schedule_close [<event name>] <minutes>') return
def _check_and_create(self, filename, contents): if len(filename) <= self.fs_prefix_tree: log_error('Filename %s too small for prefix tree %d' % (filename, self.fs_prefix_tree)) return None path = self.fs_location split_path = '' for p in range(self.fs_prefix_tree): path = os.path.join(path, filename[p]) split_path = '/'.join([split_path, filename[p]]) if os.path.exists(path): if not os.path.isdir(path): log_log('notadir') log_error('%s exists and is not a directory' % str(path)) return None else: os.mkdir(path) fpath = os.path.join(path, filename[self.fs_prefix_tree:]) split_path = '/'.join([split_path, filename[self.fs_prefix_tree:]]) if os.path.exists(fpath): log_error('%s exists' % str(fpath)) return None f = open(fpath, 'w') f.write(contents) f.close() return split_path
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 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 _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 UpdateCoin(data): global last_wallet_update_time if last_wallet_update_time == None: last_wallet_update_time = 0 t = time.time() dt = t - last_wallet_update_time if dt < config.wallet_update_time: return try: try: scan_block_height = redis_get("scan_block_height") scan_block_height = long(scan_block_height) except Exception, e: log_error('Failed to get scan_block_height: %s' % str(e)) last_wallet_update_time = time.time() return try: j = SendDaemonHTMLCommand("getheight") except Exception, e: log_error('UpdateCoin: error getting height: %s' % str(e)) return
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 _getline(self): idx = self.buffered_data.find("\n") if idx == -1: try: (r, w, x) = select.select([self.irc.fileno()], [], [], 1) if self.irc.fileno() in r: newdata = self._irc_recv(4096, socket.MSG_DONTWAIT) if len(newdata) == 0: raise RuntimeError('0 bytes received, EOF') else: newdata = None if self.irc.fileno() in x: log_error('getline: IRC socket in exception set') newdata = None except Exception, e: log_error('getline: Exception: %s' % str(e)) # Broken pipe when we get kicked for spam if str(e).find("Broken pipe") != -1: raise newdata = None if newdata == None: return None self.buffered_data += newdata
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 GetBalance(link, cmd): nick = link.user.nick if link.group and nick.startswith('blackbab'): link.send_private("Stop spamming the public channel") return try: balance, confirming = RetrieveBalance(link) sbalance = AmountToString(balance) if balance < coinspecs.atomic_units: if balance == 0: msg = "%s's balance is %s" % (nick, sbalance) else: msg = "%s's balance is %s (%.16g %s)" % ( nick, sbalance, float(balance) / coinspecs.atomic_units, coinspecs.name) else: msg = "%s's balance is %s" % (nick, sbalance) if confirming > 0: msg = msg + " (%s awaiting confirmation)" % ( AmountToString(confirming)) link.send(msg) except Exception, e: log_error('GetBalance: exception: %s' % str(e)) link.send("An error has occured")
def _is_valid_location(self, location): try: path = os.path.abspath(location) if not os.path.exists(path): log_error('Path %s does not exist' % str(path)) return False if not os.path.isdir(path): log_error('%s is not a directory' % str(path)) return False return True except Exception, e: log_error('Error checking path %s: %s' % (str(location), str(e))) return False
def GetTipbotAddress(): try: j = SendWalletJSONRPCCommand("getaddress", None) if not "result" in j: log_error('GetTipbotAddress: No result found in getaddress reply') return None result = j["result"] if not "address" in result: log_error('GetTipbotAddress: No address found in getaddress reply') return None return result["address"] except Exception, e: log_error("GetTipbotAddress: Error retrieving %s's address: %s" % (config.tipbot_name, str(e))) return None
def RetrieveTipbotBalance(force_refresh=False): global cached_tipbot_balance, cached_tipbot_unlocked_balance, cached_tipbot_balance_timestamp if not force_refresh and cached_tipbot_balance_timestamp and time.time( ) - cached_tipbot_balance_timestamp < config.tipbot_balance_cache_time: return cached_tipbot_balance, cached_tipbot_unlocked_balance j = SendWalletJSONRPCCommand("getbalance", None) if not "result" in j: log_error('RetrieveTipbotBalance: result not found in reply') raise RuntimeError("") return result = j["result"] if not "balance" in result: log_error('RetrieveTipbotBalance: balance not found in result') raise RuntimeError("") return if not "unlocked_balance" in result: log_error( 'RetrieveTipbotBalance: unlocked_balance not found in result') raise RuntimeError("") return balance = result["balance"] unlocked_balance = result["unlocked_balance"] log_log('RetrieveTipbotBalance: balance: %s' % str(balance)) log_log('RetrieveTipbotBalance: unlocked_balance: %s' % str(unlocked_balance)) pending = long(balance) - long(unlocked_balance) if pending < 0: log_error( 'RetrieveTipbotBalance: Negative pending balance! balance %s, unlocked %s' % (str(balance), str(unlocked_balance))) raise RuntimeError("") return cached_tipbot_balance_timestamp = time.time() cached_tipbot_balance = balance cached_tipbot_unlocked_balance = unlocked_balance return balance, unlocked_balance
pipe = redis_pipeline() pipe.hincrby("balances", account, -units) pipe.incrby("rain_total_count", 1) pipe.incrby("rain_total_amount", units) pipe.hincrby("rain_count", identity, 1) pipe.hincrby("rain_amount", identity, units) for user in userlist: a = GetAccount(user) pipe.hincrby("balances", a, user_units) if enumerate_users: msg = msg + " " + NickFromIdentity(user.identity()) pipe.execute() link.send("%s" % msg) except Exception, e: log_error('Rain: exception: %s' % str(e)) link.send("An error has occured") return def RainActive(link, cmd): identity = link.identity() amount = GetParam(cmd, 1) hours = GetParam(cmd, 2) minfrac = GetParam(cmd, 3) group = link.group if not group: link.send("Raining can only be done in a channel") return
from tipbot.utils import * from tipbot.redisdb import * from tipbot.command_manager import * disabled = False selected_coin = None modulenames = [] start_networks = [] argc = 1 while argc < len(sys.argv): arg = sys.argv[argc] if arg == "-c" or arg == "--coin": if argc + 1 == len(sys.argv): log_error( 'Usage: tipbot.py [-h|--help] [-m|--module modulename]* -c|--coin <coinname>' ) exit(1) argc = argc + 1 selected_coin = sys.argv[argc] try: log_info('Importing %s coin setup' % selected_coin) if not selected_coin in coinspecs.coinspecs: log_error('Unknown coin: %s' % selected_coin) exit(1) for field in coinspecs.coinspecs[selected_coin]: setattr(coinspecs, field, coinspecs.coinspecs[selected_coin][field]) except Exception, e: log_error('Failed to load coin setup for %s: %s' % (selected_coin, str(e)))
except Exception, e: link.send("Usage: !pinata <amount>") return if aim < min_target: link.send("The pinata can only be hit by at least %s" % AmountToString(min_target)) return if aim > max_target: link.send("The pinata can only be hit by at most %s" % AmountToString(max_target)) return try: target = long(redis_hget('pinata', 'target')) except Exception, e: log_error('Failed to get pinata target: %s' % str(e)) link.send('An error occured') return if target < min_target or target > max_target: log_error('Pinata target out of range: %s' % target) link.send('An error occured') return account = GetAccount(identity) log_info( "Pinata: %s wants to swing %s at the pinata, aim is %d, target is %d" % (identity, amount, aim, target)) valid, reason = IsBetValid(link, amount, None, None, 0, 0, 0) if not valid: log_info("Pinata: %s's bet refused: %s" % (identity, reason))