Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update altcointip for newer dependencies and general bug fixes #47

Merged
merged 9 commits into from Jan 31, 2018
6 changes: 3 additions & 3 deletions src/_start.sh
Expand Up @@ -2,7 +2,7 @@

user=$1

if [ ! -f ./cointipbot.py ] ; then
if [ ! -f ./main.py ] ; then
# Output help message and exit
echo "Usage: $0 [username]"
echo "if [username] is specified, script will be started as user [username]"
Expand All @@ -12,8 +12,8 @@ fi

if [ -z "$user" ] ; then
# Run as current user
python -c 'import cointipbot; cb=cointipbot.CointipBot(); cb.main()'
python -c 'import main; main=main.Main(); main.main()'
else
# Run as $user
sudo su - $user -c "cd `pwd` && python -c 'import cointipbot; cb=cointipbot.CointipBot(); cb.main()'"
sudo su - $user -c "cd `pwd` && python -c 'import main; main=main.Main(); main.main()'"
fi
112 changes: 55 additions & 57 deletions src/cointipbot.py
Expand Up @@ -23,14 +23,13 @@
from jinja2 import Environment, PackageLoader

from requests.exceptions import HTTPError, ConnectionError, Timeout
from praw.errors import ExceptionList, APIException, InvalidCaptcha, InvalidUser, RateLimitExceeded
from praw.exceptions import APIException, ClientException
from socket import timeout

# Configure CointipBot logger
logging.basicConfig()
lg = logging.getLogger('cointipbot')


class CointipBot(object):
"""
Main class for cointip bot
Expand Down Expand Up @@ -87,7 +86,11 @@ def parse_config(self):
prefix='./conf/'
for i in ['coins', 'db', 'exchanges', 'fiat', 'keywords', 'logs', 'misc', 'reddit', 'regex']:
lg.debug("CointipBot::parse_config(): reading %s%s.yml", prefix, i)
conf[i] = yaml.load(open(prefix+i+'.yml'))

file = open(prefix + i + '.yml')
conf[i] = yaml.load(file)

file.close()
except yaml.YAMLError as e:
lg.error("CointipBot::parse_config(): error reading config file: %s", e)
if hasattr(e, 'problem_mark'):
Expand Down Expand Up @@ -121,8 +124,13 @@ def connect_reddit(self):
"""
lg.debug('CointipBot::connect_reddit(): connecting to Reddit...')

conn = praw.Reddit(user_agent = self.conf.reddit.auth.user)
conn.login(self.conf.reddit.auth.user, self.conf.reddit.auth.password)
conn = praw.Reddit(
user_agent = self.conf.reddit.auth.user,
client_id = self.conf.reddit.auth.client_id,
client_secret = self.conf.reddit.auth.client_secret,
username = self.conf.reddit.auth.user,
password = self.conf.reddit.auth.password
)

lg.info("CointipBot::connect_reddit(): logged in to Reddit as %s", self.conf.reddit.auth.user)
return conn
Expand Down Expand Up @@ -192,29 +200,29 @@ def check_inbox(self):
try:

# Try to fetch some messages
messages = list(ctb_misc.praw_call(self.reddit.get_unread, limit=self.conf.reddit.scan.batch_limit))
messages = list(ctb_misc.praw_call(self.reddit.inbox.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)
ctb_misc.praw_call(m.mark_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)
ctb_misc.praw_call(m.mark_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)
ctb_misc.praw_call(m.mark_read)
continue

# Ignore messages from banned users
Expand All @@ -223,7 +231,7 @@ def check_inbox(self):
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)
ctb_misc.praw_call(m.mark_read)
continue

action = None
Expand All @@ -249,17 +257,12 @@ def check_inbox(self):
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)
ctb_misc.praw_call(m.mark_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
Expand All @@ -285,7 +288,7 @@ def init_subreddits(self):

elif self.conf.reddit.scan.my_subreddits:
# Subreddits are subscribed to by bot user
my_reddits = ctb_misc.praw_call(self.reddit.get_my_subreddits, limit=None)
my_reddits = ctb_misc.praw_call(self.reddit.user.subreddits, limit=None)
my_reddits_list = []
for my_reddit in my_reddits:
my_reddits_list.append(my_reddit.display_name.lower())
Expand All @@ -301,7 +304,7 @@ def init_subreddits(self):

# Get multi-reddit PRAW object
lg.debug("CointipBot::check_subreddits(): multi-reddit string: %s", my_reddits_string)
self.conf.reddit.subreddits = ctb_misc.praw_call(self.reddit.get_subreddit, my_reddits_string)
self.conf.reddit.subreddits = ctb_misc.praw_call(self.reddit.subreddit, my_reddits_string)

except Exception as e:
lg.error("CointipBot::check_subreddits(): coudln't get subreddits: %s", e)
Expand Down Expand Up @@ -367,7 +370,7 @@ def check_subreddits(self):
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:
except (HTTPError, timeout) as e:
lg.warning("CointipBot::check_subreddits(): Reddit is down (%s), sleeping", e)
time.sleep(self.conf.misc.times.sleep_seconds)
pass
Expand All @@ -394,6 +397,32 @@ def refresh_ev(self):
lg.debug("< CointipBot::refresh_ev(): DONE (skipping)")
return

# For each enabled fiat...
for f in vars(self.conf.fiat):
if self.conf.fiat[f].enabled:

# Get fiat/BTC exchange rate
values = []
result = 0.0

# For each exchange that supports this fiat...
for e in self.exchanges:
if self.exchanges[e].supports_pair(_name1='btc', _name2=self.conf.fiat[f].unit):
# Get ticker value from exchange
value = self.exchanges[e].get_ticker_value(_name1='btc', _longname1='bitcoin', _name2=self.conf.fiat[f].unit)
if value and float(value) > 0.0:
values.append(float(value))

# Result is average of all responses
if len(values) > 0:
result = sum(values) / float(len(values))

# Assign result to self.runtime['ev']
if not self.runtime['ev'].has_key('btc'):
self.runtime['ev']['btc'] = {}

self.runtime['ev']['btc'][f] = result

# For each enabled coin...
for c in vars(self.conf.coins):
if self.conf.coins[c].enabled:
Expand All @@ -407,7 +436,7 @@ def refresh_ev(self):
for e in self.exchanges:
if self.exchanges[e].supports_pair(_name1=self.conf.coins[c].unit, _name2='btc'):
# Get ticker value from exchange
value = self.exchanges[e].get_ticker_value(_name1=self.conf.coins[c].unit, _name2='btc')
value = self.exchanges[e].get_ticker_value(_name1=self.conf.coins[c].unit, _longname1=self.conf.coins[c].name.lower(), _name2='btc')
if value and float(value) > 0.0:
values.append(float(value))

Expand All @@ -422,32 +451,13 @@ def refresh_ev(self):
# Assign result to self.runtime['ev']
if not self.runtime['ev'].has_key(c):
self.runtime['ev'][c] = {}
self.runtime['ev'][c]['btc'] = result

# For each enabled fiat...
for f in vars(self.conf.fiat):
if self.conf.fiat[f].enabled:

# Get fiat/BTC exchange rate
values = []
result = 0.0

# For each exchange that supports this fiat...
for e in self.exchanges:
if self.exchanges[e].supports_pair(_name1='btc', _name2=self.conf.fiat[f].unit):
# Get ticker value from exchange
value = self.exchanges[e].get_ticker_value(_name1='btc', _name2=self.conf.fiat[f].unit)
if value and float(value) > 0.0:
values.append(float(value))

# Result is average of all responses
if len(values) > 0:
result = sum(values) / float(len(values))
self.runtime['ev'][c]['btc'] = result

# Assign result to self.runtime['ev']
if not self.runtime['ev'].has_key('btc'):
self.runtime['ev']['btc'] = {}
self.runtime['ev']['btc'][f] = result
# For each enabled fiat...
for f in vars(self.conf.fiat):
if self.conf.fiat[f].enabled:
self.runtime['ev'][c][f] = self.runtime['ev']['btc'][f] * self.runtime['ev'][c]['btc']

lg.debug("CointipBot::refresh_ev(): %s", self.runtime['ev'])

Expand Down Expand Up @@ -573,16 +583,4 @@ def main(self):
# Send a notification, if enabled
if self.conf.misc.notify.enabled:
self.notify(_msg=tb)
sys.exit(1)

def secondary():
try:
while True:
main(self)
except:
traceback.print_exc()
print('Resuming in 30sec...')
time.sleep(30)
print('Resumed')
while True:
secondary()
sys.exit(1)
10 changes: 5 additions & 5 deletions src/conf-sample/db.yml
Expand Up @@ -11,17 +11,17 @@ sql:
name: "Total Accepted Tips (USD)"
desc: "Total value of all tips given and accepted in USD (default) fiat"
type: line
query: "SELECT SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat = 'usd'"
query: "SELECT SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat = 'usd' GROUP BY fiat"
01a_total_tipped_usd_by_coin:
name: "Total Accepted Tips (USD) By Coin"
desc: "Total value of all tips given and accepted in USD (default) fiat grouped by coin"
type: table
query: "SELECT coin, SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat = 'usd' GROUP BY coin ORDER BY coin"
query: "SELECT coin, SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat = 'usd' GROUP BY coin, fiat ORDER BY coin"
02_total_tips_expired_and_declined:
name: "Total Expired and Declined Tips (USD)"
desc: "Total value of all tips given that weren't accepted (expired or declined) in USD (default) fiat"
type: line
query: "SELECT SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND state = 'expired' OR state = 'declined' AND fiat = 'usd'"
query: "SELECT SUM(fiat_val) AS total_usd, fiat FROM t_action WHERE type = 'givetip' AND (state = 'expired' OR state = 'declined') AND fiat = 'usd' GROUP BY fiat"
03_total_users_registered:
name: "Total Users Registered"
desc: "Number of registered users"
Expand Down Expand Up @@ -51,7 +51,7 @@ sql:
name: "Top 10 Tippers"
desc: "Top 10 all-time tippers as determined by total USD/EUR (fiat) value of their tips."
type: table
query: "SELECT from_user, SUM(fiat_val) AS total_fiat, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat IN ('usd', 'eur') GROUP BY from_user ORDER BY total_fiat DESC LIMIT 10"
query: "SELECT from_user, SUM(fiat_val) AS total_fiat, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat IN ('usd', 'eur') GROUP BY from_user, fiat ORDER BY total_fiat DESC LIMIT 10"
07_top_10_tips:
name: "Top 10 Tips"
desc: "Top 10 all-time tips as determined by their USD/EUR (fiat) value."
Expand Down Expand Up @@ -91,7 +91,7 @@ sql:
name: "Top 10 Receivers"
desc: "Top 10 all-time tip receivers as determined by total USD/EUR (fiat) value of their received tips."
type: table
query: "SELECT to_user, SUM(fiat_val) AS total_fiat, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat IN ('usd', 'eur') AND to_user IS NOT NULL GROUP BY to_user ORDER BY total_fiat DESC LIMIT 10"
query: "SELECT to_user, SUM(fiat_val) AS total_fiat, fiat FROM t_action WHERE type = 'givetip' AND state = 'completed' AND fiat IN ('usd', 'eur') AND to_user IS NOT NULL GROUP BY to_user, fiat ORDER BY total_fiat DESC LIMIT 10"
userstats:
users: "SELECT username FROM t_users WHERE username IN (SELECT from_user FROM t_action WHERE type = 'givetip') OR username in (SELECT to_user FROM t_action WHERE type = 'givetip') ORDER BY username"
coins: 'SELECT DISTINCT coin FROM t_action WHERE coin IS NOT NULL ORDER BY coin'
Expand Down
22 changes: 22 additions & 0 deletions src/conf-sample/exchanges.yml
Expand Up @@ -7,6 +7,7 @@ blockchaininfo:
coinlist: ['btc']
fiatlist: ['usd','cny','jpy','sgd','hkd','cad','aud','nzd','gbp','dkk','sek','brl','chf','eur','rub','sll','pln','thb']
uppercase: true
longname: false

vircurex:
enabled: true
Expand All @@ -17,6 +18,7 @@ vircurex:
coinlist: ['anc','btc','dgc','dvc','frc','ftc','i0c','ixc','ltc','nmc','nvc','ppc','trc','xpm']
fiatlist: ['usd','eur']
uppercase: true
longname: false

btce:
enabled: true
Expand All @@ -27,6 +29,7 @@ btce:
coinlist: ['btc','ltc','nmc','nvc','trc','ppc','ftc','xpm']
fiatlist: ['usd','eur','rur']
uppercase: false
longname: false

bitstamp:
enabled: true
Expand All @@ -37,6 +40,7 @@ bitstamp:
coinlist: ['btc']
fiatlist: ['usd']
uppercase: false
longname: false

mtgox:
enabled: false
Expand All @@ -47,6 +51,7 @@ mtgox:
coinlist: ['btc']
fiatlist: ['usd','eur','jpy','gbp','rub']
uppercase: true
longname: false

campbx:
enabled: true
Expand All @@ -57,6 +62,7 @@ campbx:
coinlist: ['btc']
fiatlist: ['usd']
uppercase: false
longname: false

cryptsy:
enabled: true
Expand All @@ -67,6 +73,7 @@ cryptsy:
coinlist: ['btc','alf','amc','anc','arg','bqc','bte','btg','buk','cap','cgb','clr','cmc','crc','csc','dgc','dmd','elc','emd','frc','frk','fst','ftc','gdc','glc','glx','hbn','ixc','kgc','lk7','lky','ltc','mec','mnc','nbl','nec','nmc','nrb','nvc','phs','ppc','pts','pxc','pyc','qrk','sbc','spt','src','tag','tek','trc','wdc','xjo','xpm','yac','zet']
fiatlist: []
uppercase: true
longname: false

bter:
enabled: true
Expand All @@ -77,6 +84,7 @@ bter:
coinlist: ['btc','ltc','ppc','frc','ftc','cnc','bqc','btb','wdc','yac','xpm','pts','zcc','dtc','red','cent','zet','src','mec','qrk']
fiatlist: ['cny']
uppercase: false
longname: false

cryptotrade:
enabled: true
Expand All @@ -87,6 +95,7 @@ cryptotrade:
coinlist: ['btc','ltc','nmc','xpm','ppc','trc','ftc','dvc','wdc','dgc']
fiatlist: ['usd','eur']
uppercase: false
longname: false

coinse:
enabled: true
Expand All @@ -97,6 +106,7 @@ coinse:
coinlist: ['btc','alp','amc','anc','bet','bqc','cgb','cin','crc','dem','dtc','elc','elp','emd','frk','ftc','gdc','glc','kgc','ltc','mec','nan','net','nrb','nvc','orb','ppc','pts','qrk','rec','red','spt','tag','trc','uno','wdc','xnc','xpm','zet']
fiatlist: []
uppercase: true
longname: false

cryptocoincharts:
enabled: true
Expand All @@ -107,3 +117,15 @@ cryptocoincharts:
coinlist: ['btc','ltc','ppc','nmc','xmp','mec','bqc','dgc','ifc','ixc','mnc','qrk','sbc','zet','doge','nxt','msc','ftc','nvc','dvc','frc','trc']
fiatlist: ['usd','eur']
uppercase: false
longname: false

coinmarketcap:
enabled: true
domain: 'api.coinmarketcap.com'
https: true
urlpaths: ['/v1/ticker/{THING_FROM}/?convert={THING_TO}']
jsonpaths: ['0.price_{THING_TO}']
coinlist: ['dgb','btc']
fiatlist: ['usd','eur']
uppercase: false
longname: true
2 changes: 2 additions & 0 deletions src/conf-sample/reddit.yml
@@ -1,6 +1,8 @@
auth:
user: 'mybotuser'
password: 'mybotpass'
client_id: 'abcdefg'
client_secret: 'supersecretsecret'

scan:
batch_limit: 1000
Expand Down