Esempio n. 1
0
def main():
    logging.info("Starting main")
    with open(os.path.join('..', 'cfg-tlgrm.json'), 'r',
              encoding='utf-8') as config_file:
        config_data = json.load(config_file)
        TOKEN = config_data['TOKEN']
        SUBREDDIT = config_data['SUBREDDIT']
        CHANNEL = config_data['CHANNEL']
        DBFILE = config_data['DBFILE']

    logging.info("Setting up Reddit connection")
    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         user_agent=config.USER_AGENT)
    reddit.read_only = True
    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()
    subreddit = reddit.subreddit(SUBREDDIT)

    killhandler = KillHandler()

    logging.info("Setting up database")
    conn = sqlite3.connect(DBFILE)
    conn.execute('CREATE TABLE IF NOT EXISTS posts (id)')
    conn.commit()

    logging.info("Setting up Telegram connection")
    tbot = telegram.Bot(token=TOKEN)
    try:
        tbot.get_me()
    except telegram.error.TelegramError as e_teleg:
        logging.error(e_teleg)
        logging.critical("Telegram error!")
        exit()

    for submission in subreddit.stream.submissions(pause_after=6):
        if submission:
            c = conn.cursor()
            c.execute('SELECT * FROM posts WHERE id=?', (submission.id, ))
            if not c.fetchone():
                link = 'https://redd.it/{id}'.format(id=submission.id)
                title = html.escape(submission.title or '')
                message_template = '<a href=\'{}\'>{}</a>'.format(link, title)
                logging.info('Posting %s', link)
                tbot.sendMessage(chat_id=CHANNEL,
                                 parse_mode=telegram.ParseMode.HTML,
                                 text=message_template)
                conn.execute('INSERT INTO posts (id) values (?)',
                             (submission.id, ))
                conn.commit()
            c.close()
        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
    conn.close()
Esempio n. 2
0
def main():
    killhandler = KillHandler()

    reddit = praw.Reddit(client_id=config.client_id,
                         client_secret=config.client_secret,
                         username=config.username,
                         password=config.password,
                         user_agent=config.user_agent)

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    while not killhandler.killed:
        try:
            for submission in reddit.subreddit('+'.join(
                    config.subreddits)).stream.submissions(skip_existing=True):
                duration = stopwatch.measure()

                logging.info(f"New submission: {submission}")
                logging.info(f" -- retrieved in {duration:5.2f}s")

                # We don't need to post a sticky on stickied posts
                if submission.stickied:
                    logging.info(f" -- skipping (stickied)")
                    continue

                # Post a comment to let people know where to invest
                bot_reply = submission.reply_wrap(message.invest_place_here)

                # Sticky the comment
                if config.is_moderator:
                    bot_reply.mod.distinguish(how='yes', sticky=True)

                # Measure how long processing took
                duration = stopwatch.measure()
                logging.info(f" -- processed in {duration:5.2f}s")

                if killhandler.killed:
                    logging.info("Termination signal received - exiting")
                    break

        except prawcore.exceptions.OAuthException as e_creds:
            traceback.print_exc()
            logging.error(e_creds)
            logging.critical("Invalid login credentials. Check your .env!")
            logging.critical(
                "Fatal error. Cannot continue or fix the problem. Bailing out..."
            )
            exit()

        except Exception as e:
            logging.error(e)
            traceback.print_exc()
            time.sleep(10)
Esempio n. 3
0
def main():
    logging.info("Starting leaderboard...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    while not killhandler.killed:
        sess = session_maker()

        top_users = sess.query(
                Investor.name,
                func.coalesce(Investor.balance+func.sum(Investment.amount), Investor.balance).label('networth')).\
                outerjoin(Investment, and_(Investor.name == Investment.name, Investment.done == 0)).\
            group_by(Investor.name).\
            order_by(desc('networth')).\
            limit(10).\
            all()

        top_firms = sess.query(Firm).\
            filter(Firm.size > 0).\
            order_by(Firm.balance.desc()).\
            limit(10).\
            all()

        top_users_text = "Rank|User|Net Worth\n"
        top_users_text += ":-:|:-:|:-:\n"
        for i, user in enumerate(top_users):
            top_users_text += f"{i + 1}|/u/{user.name}|{formatNumber(user.networth)} MC\n"

        top_firms_text = "Rank|Firm|Total Assets|Level|Tax Rate\n"
        top_firms_text += ":-:|:-:|:-:|:-:|:-:\n"
        for i, firm in enumerate(top_firms):
            is_private = '(**P**) ' if firm.private else ''
            top_firms_text += f"{i + 1}|{is_private}{firm.name}|{formatNumber(firm.balance)} MC|{firm.rank + 1}|{firm.tax}%\n"

        sidebar_text = sidebar_text_org.\
            replace("%TOP_USERS%", top_users_text).\
            replace("%TOP_FIRMS%", top_firms_text)

        logging.info(" -- Updating sidebar text to:")
        logging.info(sidebar_text)
        for subreddit in config.SUBREDDITS:
            reddit.subreddit(subreddit).mod.update(description=sidebar_text)

        sess.commit()

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits['remaining'])
        res = int(reddit.auth.limits['reset_timestamp'] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()

        time.sleep(config.LEADERBOARD_INTERVAL)
Esempio n. 4
0
def main():
    killhandler = KillHandler()

    engine = create_engine(config.db, pool_recycle=60)
    sm = scoped_session(sessionmaker(bind=engine))

    reddit = praw.Reddit(client_id=config.client_id,
                         client_secret=config.client_secret,
                         username=config.username,
                         password=config.password,
                         user_agent=config.user_agent)

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    while not killhandler.killed:
        
        try:
            sess = sm()
            submission_time = int(time.time())
            for submission in reddit.subreddit('+'.join(config.subreddits)).stream.submissions(skip_existing=True):
                duration = stopwatch.measure()

                logging.info(f"New submission: {submission}")
                logging.info(f" -- retrieved in {duration:5.2f}s")

                # We don't need to post a sticky on stickied posts
                if submission.stickied:
                    logging.info(f" -- skipping (stickied)")
                    continue

                # We are looking if the post is created in the past
                # so we won't double charge it
                if (submission.created_utc < submission_time):
                    logging.info(f" -- skipping (timeout)")
                    continue
                submission_time = int(submission.created_utc)
                logging.info(f" -- Submission timestamp: {time.asctime(time.gmtime(submission_time))}")
                
                bot_reply = 0
                delete_post = False
                
                # This is a bit of a controversial update, so im gonna make it
                # agile to switch between different modes
                if config.submission_fee:
                    # If a poster doesn't have an account, delete the post
                    # if he has, take 1000 MemeCoins and invest them
                    investor = sess.query(Investor).\
                        filter(Investor.name == submission.author.name).\
                        first()

                    if not investor:
                        bot_reply = submission.reply_wrap(message.no_account_post_org)
                        delete_post = True
                        logging.info(f" -- Not a registered investor!")
                    elif (investor.balance < 1000):
                        bot_reply = submission.reply_wrap(message.modify_pay_to_post(investor.balance))
                        delete_post = True
                        logging.info(f" -- Not enough funds!")
                    else:
                        # We will make it 6%
                        required_fee = int(investor.balance * 0.06)
                        if (required_fee < 250):
                            required_fee = 250
                        new_balance = investor.balance - required_fee
                        investor.balance = new_balance
                        bot_reply = submission.reply_wrap(message.modify_invest_place_here(required_fee))
                        
                    sess.commit()
                else:
                    # Post a comment to let people know where to invest
                    bot_reply = submission.reply_wrap(message.invest_place_here_no_fee)
                    
                # Sticky the comment
                if config.is_moderator:
                    bot_reply.mod.distinguish(how='yes', sticky=True)
                    if (delete_post):
                        logging.info(f" -- Deleting the post...")
                        #Should we hide or just delete the post?
                        submission.mod.remove()
                    
                # Measure how long processing took
                duration = stopwatch.measure()
                logging.info(f" -- processed in {duration:5.2f}s")

                if killhandler.killed:
                    logging.info("Termination signal received - exiting")
                    break

        except prawcore.exceptions.OAuthException as e_creds:
            traceback.print_exc()
            logging.error(e_creds)
            logging.critical("Invalid login credentials. Check your .env!")
            logging.critical("Fatal error. Cannot continue or fix the problem. Bailing out...")
            exit()
                
        except Exception as e:
            logging.error(e)
            traceback.print_exc()
            time.sleep(10)
Esempio n. 5
0
def main():
    """
    This is the main function that listens to new submissions
    and then posts the ATTENTION sticky comment.
    """
    logging.info("Starting submitter...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    sess_maker = scoped_session(sessionmaker(bind=engine))

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    sess = sess_maker()
    submission_time = int(time.time())

    minimum_fee = config.SUBMISSION_MIN_FEE

    for submission in reddit.subreddit('+'.join(config.SUBREDDITS)).\
        stream.submissions(skip_existing=True):

        duration = stopwatch.measure()

        logging.info("New submission: %s", submission)
        logging.info(" -- retrieved in %ss", duration)

        # We don't need to post a sticky on stickied posts
        if submission.stickied:
            logging.info(" -- skipping (stickied)")
            continue

        # We are looking if the post is created in the past
        # so we won't double charge it
        if submission.created_utc < submission_time:
            logging.info(" -- skipping (timeout)")
            continue

        submission_time = int(submission.created_utc)
        logging.info(" -- Submission timestamp: %s", \
                     time.asctime(time.gmtime(submission_time)))

        bot_reply = 0
        delete_post = False

        # This is a bit of a controversial update, so im gonna make it
        # agile to switch between different modes
        if not config.SUBMISSION_FEE:
            # Post a comment to let people know where to invest
            bot_reply = submission.reply_wrap(
                message.invest_no_fee(f"u/{submission.author.name}"))
        else:
            # If a poster doesn't have an account, delete the post
            # if he has, take 1000 MemeCoins and invest them
            investor = sess.query(Investor).\
                filter(Investor.name == submission.author.name).\
                first()

            if not investor:
                bot_reply = submission.reply_wrap(message.NO_ACCOUNT_POST_ORG)
                delete_post = True
                logging.info(" -- Not a registered investor!")
            elif investor.balance < minimum_fee:
                bot_reply = submission.reply_wrap(
                    message.modify_pay_to_post(investor.balance))
                delete_post = True
                logging.info(" -- Not enough funds!")
            else:
                # We will make it 6%
                required_fee = int(investor.balance *
                                   (config.SUBMISSION_FEE_PERCENT / 100))
                if required_fee < minimum_fee:
                    required_fee = minimum_fee
                new_balance = investor.balance - required_fee
                investor.balance = new_balance
                bot_reply = submission.\
                    reply_wrap(message.modify_invest_place_here(required_fee,
                                                                f"u/{submission.author.name}"))
                sess.commit()

        # Sticky the comment
        if config.IS_MODERATOR:
            bot_reply.mod.distinguish(how='yes', sticky=True)
            bot_reply.mod.approve()
            if delete_post:
                logging.info(" -- Deleting the post...")
                #Should we hide or just delete the post?
                submission.mod.remove()

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
Esempio n. 6
0
def main():
    logging.info("Starting payroll...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    while not killhandler.killed:
        # only process payouts 5pm - 6pm on Fridays EST (10pm - 11pm UTC)
        now_dt = datetime.datetime.now()
        if now_dt.hour != 22 or now_dt.weekday() != 4:
            time.sleep(10 * 60)
            continue

        sess = session_maker()
        now = time.time()

        # get firms which were not paid out to or created recently (last 3 days)
        firms = sess.query(Firm).\
            filter(now - Firm.last_payout >= (3 * 24 * 60 * 60)).\
            all()

        for firm in firms:
            # 10% of firm coins are burned as a tax
            firm.balance -= int(0.1 * firm.balance)

            payout_amount = int(0.4 * firm.balance)
            if payout_amount == 0:
                # handle broke firms
                firm.last_payout = now
                continue

            exec_amount = 0
            exec_total = 0
            if firm.execs > 0:
                exec_total = payout_amount * 0.4
                exec_amount = int(exec_total / firm.execs)

            trader_total = payout_amount - exec_total
            trader_amount = int(trader_total / (firm.size - firm.execs))

            logging.info(" -- firm '%s': paying out %s each to %s traders, and %s each to %s execs",\
                firm.name, trader_amount, firm.size - firm.execs, exec_amount, firm.execs)

            employees = sess.query(Investor).\
                filter(Investor.firm == firm.id).\
                all()
            for employee in employees:
                if employee.firm_role == "":
                    employee.balance += trader_amount
                elif employee.firm_role == "exec":
                    employee.balance += exec_amount

            firm.balance -= payout_amount
            firm.last_payout = now

        sess.commit()
        sess.close()

        time.sleep(10 * 60)
Esempio n. 7
0
def main():
    logging.info("Starting payroll...")
    logging.info("Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    while not killhandler.killed:
        # only process payouts 5pm - 6pm on Fridays EST (10pm - 11pm UTC)
        now_dt = datetime.datetime.now()
        if now_dt.hour != 22 or now_dt.weekday() != 4:
            time.sleep(10 * 60)
            continue

        sess = session_maker()
        now = time.time()

        # get firms which were not paid out to or created recently (last 3 days)
        firms = sess.query(Firm).\
            filter(now - Firm.last_payout >= (3 * 24 * 60 * 60)).\
            all()

        for firm in firms:
            # 10% of firm coins are burned as a tax
            firm.balance -= int(0.1 * firm.balance)

            # 50% of remaining firm coins are paid out
            payout_amount = int(0.5 * firm.balance)
            if payout_amount == 0:
                # handle broke firms
                firm.last_payout = now
                continue

            # 30% paid to board members (CEO, COO, CFO) (30% of total payroll)
            board_total = payout_amount * 0.3
            board_members = 1 + firm.coo + firm.cfo
            board_amount = int(board_total / board_members)

            remaining_amount = payout_amount - board_total

            # 40% of remaining paid to executives (28% of total payroll)
            exec_amount = 0
            exec_total = 0
            if firm.execs > 0:
                exec_total = remaining_amount * 0.4
                exec_amount = int(exec_total / firm.execs)
                remaining_amount -= exec_total

            # 50% of remaining paid to associates (21% of total payroll)
            assoc_amount = 0
            assoc_total = 0
            if firm.assocs > 0:
                assoc_total = remaining_amount * 0.5
                assoc_amount = int(assoc_total / firm.assocs)
                remaining_amount -= assoc_total

            # 100% of remaining paid to associates (21% of total payroll)
            trader_total = remaining_amount
            trader_amount = int(trader_total / max(firm.size - firm.execs, 1))

            logging.info(" -- firm '%s': paying out %s each to %s trader(s), %s each to %s associate(s), %s each to %s executive(s), and %s each to %s board member(s)",\
                firm.name, trader_amount, firm.size - firm.execs, assoc_amount, firm.assocs, exec_amount, firm.execs, board_amount, board_members)

            employees = sess.query(Investor).\
                filter(Investor.firm == firm.id).\
                all()
            for employee in employees:
                if employee.firm_role == "":
                    employee.balance += trader_amount
                elif employee.firm_role == "assoc":
                    employee.balance += assoc_amount
                elif employee.firm_role == "exec":
                    employee.balance += exec_amount
                elif employee.firm_role == "cfo":
                    employee.balance += board_amount
                elif employee.firm_role == "coo":
                    employee.balance += board_amount
                elif employee.firm_role == "ceo":
                    employee.balance += board_amount

            firm.balance -= payout_amount
            firm.last_payout = now

        sess.commit()
        sess.close()

        time.sleep(10 * 60)
Esempio n. 8
0
def main():
    logging.info("Starting main")

    if config.post_to_reddit:
        logging.info("Warning: Bot will actually post to Reddit!")

    logging.info("Setting up database")

    killhandler = KillHandler()
    engine = create_engine(config.db, pool_recycle=60)
    sm = scoped_session(sessionmaker(bind=engine))
    worker = CommentWorker(sm)

    while True:
        try:
            Base.metadata.create_all(engine)
            break
        except sqlalchemy.exc.OperationalError:
            logging.info("Database not available yet; retrying in 5s")
            time.sleep(5)

    logging.info("Setting up Reddit connection")

    reddit = praw.Reddit(client_id=config.client_id,
                         client_secret=config.client_secret,
                         username=config.username,
                         password=config.password,
                         user_agent=config.user_agent)

    stopwatch = Stopwatch()

    logging.info("Listening for inbox replies...")

    while not killhandler.killed:
        try:
            # Iterate over the latest comment replies in inbox
            reply_function = reddit.inbox.comment_replies

            if (config.maintenance):
                logging.info(
                    "ENTERING MAINTENANCE MODE. NO OPERATIONS WILL BE PROCESSED."
                )
                for comment in praw.models.util.stream_generator(
                        reply_function):
                    logging.info(f"New comment {comment}:")
                    if comment.new:
                        comment.reply_wrap(message.maintenance_org)
                        comment.mark_read()

            for comment in praw.models.util.stream_generator(reply_function):
                # Measure how long since we finished the last loop iteration
                duration = stopwatch.measure()
                logging.info(f"New comment {comment}:")
                logging.info(f" -- retrieved in {duration:5.2f}s")

                if comment.new:
                    # Process the comment
                    worker(comment)

                    # Mark the comment as processed
                    comment.mark_read()
                else:
                    logging.info(" -- skipping (already processed)")

                # Measure how long processing took
                duration = stopwatch.measure()
                logging.info(f" -- processed in {duration:5.2f}s")

                # Report the Reddit API call stats
                rem = int(reddit.auth.limits['remaining'])
                res = int(reddit.auth.limits['reset_timestamp'] - time.time())
                logging.info(
                    f" -- API calls remaining: {rem:3d}, resetting in {res:3d}s"
                )

                # Check for termination requests
                if killhandler.killed:
                    logging.info("Termination signal received - exiting")
                    break

                stopwatch.reset()

        except prawcore.exceptions.OAuthException as e_creds:
            traceback.print_exc()
            logging.error(e_creds)
            logging.critical("Invalid login credentials. Check your .env!")
            logging.critical(
                "Fatal error. Cannot continue or fix the problem. Bailing out..."
            )
            exit()

        except Exception as e:
            logging.error(e)
            traceback.print_exc()
            time.sleep(10)
Esempio n. 9
0
def main():
    logging.info("Starting calculator...")

    killhandler = KillHandler()

    engine = create_engine()
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        return ()

    praw.models.Comment.edit_wrap = edit_wrap
    stopwatch = Stopwatch()

    logging.info("Retrieving top ...")

    # query
    sess = session_maker()
    try:
        top_networth = (sess.query(
            Investor.name,
            func.coalesce(Investor.balance + func.sum(Investment.amount),
                          Investor.balance).label("networth"),
        ).outerjoin(
            Investment,
            and_(Investor.name == Investment.name,
                 Investment.done == 0)).group_by(Investor.name).order_by(
                     desc("networth")).limit(1).one())[1]
    except NoResultFound:
        top_networth = 0
    top_networth = max(top_networth,
                       config.STARTING_BALANCE * 10)  # al last starting * 10
    sess.close()
    logging.info("Top networth: %d", top_networth)

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        sess = session_maker()

        then = int(time.time()) - config.INVESTMENT_DURATION
        investment = (sess.query(Investment).filter(
            Investment.done == 0).filter(Investment.time < then).order_by(
                Investment.time.asc()).first())

        if not investment:
            # Nothing matured yet; wait a bit before trying again
            time.sleep(50)
            continue

        duration = stopwatch.measure()

        investor = sess.query(Investor).filter(
            Investor.name == investment.name).one()
        net_worth = investor.networth(sess)

        logging.info("New mature investment: %s", investment.comment)
        logging.info(" -- by %s", investor.name)

        # Retrieve the post the user invested in (lazily, no API call)
        post = reddit.submission(investment.post)

        # Retrieve the post's current upvote count (triggers an API call)
        upvotes_now = post.ups
        investment.final_upvotes = upvotes_now
        investment.op = (post.author and investor.name == post.author.name)
        investment.net_worth = net_worth
        investment.top_networth = top_networth

        # Updating the investor's balance
        factor = formula.calculate(upvotes_now, investment.upvotes, net_worth,
                                   top_networth)

        if factor > 1 and post.author and investor.name == post.author.name:
            # bonus per OP
            factor *= formula.OP_BONUS

        amount = investment.amount
        balance = investor.balance

        new_balance = int(balance + (amount * factor))
        change = new_balance - balance
        profit = change - amount

        # Updating the investor's variables
        investor.completed += 1

        # Retrieve the bot's original response (lazily, no API call)
        if investment.response != "0":
            response = reddit.comment(id=investment.response)
        else:
            response = EmptyResponse()

        if new_balance < BALANCE_CAP:
            # If investor is in a firm and he profits,
            # 15% goes to the firm
            investor.balance = new_balance

            # Edit the bot's response (triggers an API call)
            if profit > 0:
                logging.info(" -- profited %s", profit)
            elif profit == 0:
                logging.info(" -- broke even")
            else:
                logging.info(" -- lost %s", profit)

            edited_response = message.modify_invest_return(
                investment.amount,
                investment.upvotes,
                upvotes_now,
                change,
                profit,
                investor.balance,
            )

            response.edit_wrap(edited_response)
        else:
            # This investment pushed the investor's balance over the cap
            investor.balance = BALANCE_CAP

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %s but got capped", profit)
            response.edit_wrap(
                message.modify_invest_capped(
                    investment.amount,
                    investment.upvotes,
                    upvotes_now,
                    change,
                    profit,
                    investor.balance,
                ))

        investment.success = profit > 0
        investment.profit = profit
        investment.done = True

        sess.commit()

        if top_networth < investor.balance:
            top_networth = investor.balance
            logging.info("New Top networth: %d", top_networth)

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits["remaining"])
        res = int(reddit.auth.limits["reset_timestamp"] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()
Esempio n. 10
0
def main():
    logging.info("Starting calculator...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    praw.models.Comment.edit_wrap = edit_wrap

    stopwatch = Stopwatch()

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        sess = session_maker()

        then = int(time.time()) - config.INVESTMENT_DURATION
        investment = sess.query(Investment).\
            filter(Investment.done == 0).\
            filter(Investment.time < then).\
            order_by(Investment.time.asc()).\
            first()

        if not investment:
            # Nothing matured yet; wait a bit before trying again
            time.sleep(5)
            continue

        duration = stopwatch.measure()

        investor = sess.query(Investor).filter(
            Investor.name == investment.name).one()
        net_worth = sess.\
            query(func.sum(Investment.amount)).\
            filter(and_(Investment.name == investor.name, Investment.done == 0)).\
            scalar()\
            + investor.balance

        logging.info("New mature investment: %s", investment.comment)
        logging.info(" -- by %s", investor.name)

        # Retrieve the post the user invested in (lazily, no API call)
        post = reddit.submission(investment.post)

        # Retrieve the post's current upvote count (triggers an API call)
        upvotes_now = post.ups
        investment.final_upvotes = upvotes_now

        # Updating the investor's balance
        factor = formula.calculate(upvotes_now, investment.upvotes, net_worth)
        amount = investment.amount
        balance = investor.balance

        new_balance = int(balance + (amount * factor))
        change = new_balance - balance
        profit = change - amount
        percent_str = f"{int((profit/amount)*100)}%"

        # Updating the investor's variables
        investor.completed += 1

        # Retrieve the bot's original response (lazily, no API call)
        if investment.response != "0":
            response = reddit.comment(id=investment.response)
        else:
            response = EmptyResponse()

        firm_profit = 0
        if new_balance < BALANCE_CAP:
            # If investor is in a firm and he profits,
            # 15% goes to the firm
            firm_name = ''
            if investor.firm != 0 and profit >= 0:
                firm = sess.query(Firm).\
                    filter(Firm.id == investor.firm).\
                    first()
                firm_name = firm.name

                user_profit = int(profit * ((100 - firm.tax) / 100))
                investor.balance += user_profit + amount

                firm_profit = int(profit * (firm.tax / 100))
                firm.balance += firm_profit
            else:
                investor.balance = new_balance

            # Edit the bot's response (triggers an API call)
            if profit > 0:
                logging.info(" -- profited %s", profit)
            elif profit == 0:
                logging.info(" -- broke even")
            else:
                logging.info(" -- lost %s", profit)

            edited_response = message.modify_invest_return(
                investment.amount, investment.upvotes, upvotes_now, change,
                profit, percent_str, investor.balance)
            if investor.firm != 0:
                edited_response += message.modify_firm_tax(
                    firm_profit, firm_name)

            response.edit_wrap(edited_response)
        else:
            # This investment pushed the investor's balance over the cap
            investor.balance = BALANCE_CAP

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %s but got capped", profit)
            response.edit_wrap(
                message.modify_invest_capped(investment.amount,
                                             investment.upvotes, upvotes_now,
                                             change, profit, percent_str,
                                             investor.balance))

        investment.success = (profit > 0)
        investment.profit = profit
        investment.done = True

        sess.commit()

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits['remaining'])
        res = int(reddit.auth.limits['reset_timestamp'] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()
Esempio n. 11
0
def main():
    logging.info("Starting calculator")

    killhandler = KillHandler()

    engine = create_engine(config.db, pool_recycle=60)
    sm = sessionmaker(bind=engine)
    
    reddit = praw.Reddit(client_id=config.client_id,
                         client_secret=config.client_secret,
                         username=config.username,
                         password=config.password,
                         user_agent=config.user_agent)

    praw.models.Comment.edit_wrap = edit_wrap

    stopwatch = Stopwatch()

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        try:
            sess = sm()

            then = int(time.time()) - config.investment_duration
            investment = sess.query(Investment).\
                filter(Investment.done == 0).\
                filter(Investment.time < then).\
                order_by(Investment.time.asc()).\
                first()
            
            if not investment:
                # Nothing matured yet; wait a bit before trying again
                time.sleep(5)
                continue

            duration = stopwatch.measure()

            investor = sess.query(Investor).filter(Investor.name == investment.name).one()

            logging.info(f"New mature investment: {investment.comment}")
            logging.info(f" -- by {investor.name}")

            # Retrieve the post the user invested in (lazily, no API call)
            post = reddit.submission(investment.post)

            # Retrieve the post's current upvote count (triggers an API call)
            upvotes_now = post.ups
            investment.final_upvotes = upvotes_now

            # Updating the investor's balance
            factor = formula.calculate(upvotes_now, investment.upvotes)
            amount = investment.amount
            balance = investor.balance

            new_balance = int(balance + (amount * factor))
            change = new_balance - balance
            profit = change - amount
            percent_str = f"{int((profit/amount)*100)}%"

            # Updating the investor's variables
            investor.completed += 1

            # Retrieve the bot's original response (lazily, no API call)
            if investment.response != "0":
                response = reddit.comment(id=investment.response)
            else:
                response = EmptyResponse()

            if new_balance < BalanceCap:
                investor.balance = new_balance

                # Edit the bot's response (triggers an API call)
                if profit > 0:
                    logging.info(f" -- profited {profit}")
                elif profit == 0:
                    logging.info(f" -- broke even")
                else:
                    logging.info(f" -- lost {profit}")
                response.edit_wrap(message.modify_invest_return(investment.amount, investment.upvotes, upvotes_now, change, profit, percent_str, investor.balance))
            else:
                # This investment pushed the investor's balance over the cap
                investor.balance = BalanceCap

                # Edit the bot's response (triggers an API call)
                logging.info(f" -- profited {profit} but got capped")
                response.edit_wrap(message.modify_invest_capped(investment.amount, investment.upvotes, upvotes_now, change, profit, percent_str, investor.balance))

            investment.success = (profit > 0)
            investment.profit = profit
            investment.done = True

            sess.commit()

            # Measure how long processing took
            duration = stopwatch.measure()
            logging.info(f" -- processed in {duration:5.2f}s")

            # Report the Reddit API call stats
            rem = int(reddit.auth.limits['remaining'])
            res = int(reddit.auth.limits['reset_timestamp'] - time.time())
            logging.info(f" -- API calls remaining: {rem:3d}, resetting in {res:3d}s")

        except prawcore.exceptions.OAuthException as e_creds:
            traceback.print_exc()
            logging.error(e_creds)
            logging.critical("Invalid login credentials. Check your .env!")
            logging.critical("Fatal error. Cannot continue or fix the problem. Bailing out...")
            exit()
    
        except Exception as e:
            logging.error(e)
            traceback.print_exc()
            time.sleep(10)
        finally:
            sess.close()
Esempio n. 12
0
def main() -> None:
    """
    This is the main function that listens to new submissions
    and then posts the ATTENTION sticky comment.
    """
    logging.info("Starting submitter...")

    killhandler = KillHandler()

    engine = create_engine()
    sess_maker = scoped_session(sessionmaker(bind=engine))

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    logging.info("Setting up database")
    conn = sqlite3.connect(config.POST_DBFILE)
    conn.execute("CREATE TABLE IF NOT EXISTS posts (id)")
    conn.commit()

    logging.info("Setting up Telegram connection")
    tbot = telegram.Bot(token=config.TG_TOKEN)
    try:
        tbot.get_me()
    except telegram.error.TelegramError as e_teleg:
        logging.error(e_teleg)
        logging.critical("Telegram error!")
        return

    # We will test our reddit connection here
    if not test_reddit_connection(reddit):
        return

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    sess = sess_maker()

    subreddits = reddit.subreddit("+".join(config.SUBREDDITS))
    for submission in subreddits.stream.submissions(pause_after=6):
        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
        if not submission:
            # because of pause_after
            # to handle ctr+c above
            continue

        duration = stopwatch.measure()

        logging.info("New submission: %s", submission)
        logging.info(" -- retrieved in %ss", duration)

        c = conn.cursor()
        c.execute("SELECT * FROM posts WHERE id=?", (submission.id,))
        if c.fetchone():
            logging.info("Already processed")
            continue
        post_telegram(conn, submission, tbot)

        bot_reply = post_reply(submission)

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Create Buyable
        if bot_reply:
            sess.add(
                Buyable(post=submission.id, name=submission.author.name, response=bot_reply.id)
            )
        sess.commit()
Esempio n. 13
0
def main():
    """
    This is where the magic happens. This function listens
    to all new messages in the inbox and passes them to worker
    object that decides on what to do with them.
    """
    logging.info("Starting main")

    if config.POST_TO_REDDIT:
        logging.info("Warning: Bot will actually post to Reddit!")

    logging.info("Setting up database")

    killhandler = KillHandler()
    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = scoped_session(sessionmaker(bind=engine))
    worker = CommentWorker(session_maker)

    while True:
        try:
            Base.metadata.create_all(engine)
            break
        except sqlalchemy.exc.OperationalError:
            logging.info("Database not available yet; retrying in 5s")
            time.sleep(5)

    logging.info("Setting up Reddit connection")

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    stopwatch = Stopwatch()

    logging.info("Listening for inbox replies...")

    while not killhandler.killed:
        # Iterate over the latest comment replies in inbox
        reply_function = reddit.inbox.comment_replies

        if config.MAINTENANCE:
            logging.info(
                "ENTERING MAINTENANCE MODE. NO OPERATIONS WILL BE PROCESSED.")
            for comment in praw.models.util.stream_generator(reply_function):
                logging.info("New comment %s:", comment)
                if comment.new:
                    comment.reply_wrap(message.MAINTENANCE_ORG)
                    comment.mark_read()

        for comment in praw.models.util.stream_generator(reply_function):
            # Measure how long since we finished the last loop iteration
            duration = stopwatch.measure()
            logging.info("New comment %s (%s):", comment, type(comment))
            logging.info(" -- retrieved in %.2fs", duration)

            if comment.new:
                if comment.subreddit.display_name.lower() in config.SUBREDDITS:
                    # Process the comment only in allowed subreddits
                    worker(comment)
                else:
                    logging.info(" -- skipping (wrong subreddit)")

                # Mark the comment as processed
                comment.mark_read()
            else:
                logging.info(" -- skipping (already processed)")

            # Measure how long processing took
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)

            # Report the Reddit API call stats
            rem = int(reddit.auth.limits['remaining'])
            res = int(reddit.auth.limits['reset_timestamp'] - time.time())
            logging.info(" -- API calls remaining: %.2f, resetting in %.2fs",
                         rem, res)

            # Check for termination requests
            if killhandler.killed:
                logging.info("Termination signal received - exiting")
                break

            stopwatch.reset()
Esempio n. 14
0
def main():
    logging.info("Starting calculator")

    killhandler = KillHandler()

    engine = create_engine(config.db, pool_recycle=60)
    sm = sessionmaker(bind=engine)
    
    reddit = praw.Reddit(client_id=config.client_id,
                         client_secret=config.client_secret,
                         username=config.username,
                         password=config.password,
                         user_agent=config.user_agent)

    praw.models.Comment.edit_wrap = edit_wrap

    stopwatch = Stopwatch()

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        try:
            sess = sm()

            then = int(time.time()) - config.investment_duration
            investment = sess.query(Investment).\
                filter(Investment.done == 0).\
                filter(Investment.time < then).\
                order_by(Investment.time.asc()).\
                first()
            
            if not investment:
                # Nothing matured yet; wait a bit before trying again
                time.sleep(5)
                continue

            duration = stopwatch.measure()

            investor = sess.query(Investor).filter(Investor.name == investment.name).one()

            logging.info(f"New mature investment: {investment.comment}")
            logging.info(f" -- by {investor.name}")

            if investment.response != "0":
                response = reddit.comment(id=investment.response)
            else:
                response = EmptyResponse()

            post = reddit.submission(investment.post)
            upvotes_now = post.ups # <--- triggers a Reddit API call

            # Updating the investor's balance
            factor = formula.calculate(upvotes_now, investment.upvotes)
            amount = investment.amount
            balance = investor.balance

            new_balance = int(balance + (amount * factor))
            change = new_balance - balance
            profit = change - amount
            profit_str = f"{int((profit/amount)*100)}%"

            # Updating the investor's variables
            investor.completed += 1
            investor.balance = new_balance

            # Editing the comment as a confirmation
            text = response.body # <--- triggers a Reddit API call
            if profit > 0:
                logging.info(f" -- profited {profit}")
                response.edit_wrap(message.modify_invest_return(text, upvotes_now, change, profit_str, new_balance))
            elif profit == 0:
                logging.info(f" -- broke even")
                response.edit_wrap(message.modify_invest_break_even(text, upvotes_now, change, profit_str, new_balance))
            else:
                lost_memes = int( amount - change )
                logging.info(f" -- lost {profit}")
                response.edit_wrap(message.modify_invest_lose(text, upvotes_now, lost_memes, profit_str, new_balance))

            investment.success = (profit > 0)
            investment.profit = profit
            investment.done = True

            sess.commit()

            # Measure how long processing took
            duration = stopwatch.measure()
            logging.info(f" -- processed in {duration:5.2f}s")

            # Report the Reddit API call stats
            rem = int(reddit.auth.limits['remaining'])
            res = int(reddit.auth.limits['reset_timestamp'] - time.time())
            logging.info(f" -- API calls remaining: {rem:3d}, resetting in {res:3d}s")
        except Exception as e:
            logging.error(e)
            traceback.print_exc()
            time.sleep(10)
        finally:
            sess.close()