def handle_throttle(driver, timeout_mins=10):
    alert('Throttled', 'Sosumi')
    # Dump source until we're sure we have correct locator for continue button
    dump_source(driver)
    try:
        click_when_enabled(driver,
                           wait_for_element(driver,
                                            config.Locators.THROTTLE_CONTINUE),
                           timeout=60)
    except Exception as e:
        log.error(e)
    t = datetime.now()
    while config.Patterns.THROTTLE_URL in remove_qs(driver.current_url):
        if int((datetime.now() - t).total_seconds()) > timeout_mins * 60:
            raise UnhandledRedirect(
                'Throttled and timed out waiting for user input')
        sleep(1)
def wait_for_auth(driver, timeout_mins=10):
    t = datetime.now()
    alerted = []
    if is_logged_in(driver):
        log.debug('Already logged in')
        return
    log.info('Waiting for user login...')
    while not is_logged_in(driver):
        elapsed = int((datetime.now() - t).total_seconds() / 60)
        if is_logged_in(driver):
            break
        elif elapsed > timeout_mins:
            raise RuntimeError(
                'Timed out waiting for login (>= {}min)'.format(timeout_mins))
        elif elapsed not in alerted:
            alerted.append(elapsed)
            alert('Log in to proceed')
        sleep(1)
    log.info('Logged in')
def handle_oos(driver, ignore_oos, timeout_mins=10):
    try:
        save_removed_items(driver)
    except Exception:
        log.error('Could not save removed items')
    if ignore_oos:
        log.warning('Attempting to proceed through OOS alert')
        click_when_enabled(
            driver, wait_for_element(driver, config.Locators.OOS_CONTINUE))
    else:
        t = datetime.now()
        alert(
            "An item is out of stock. Press continue if you'd like to proceed",
            'Sosumi')
        while config.Patterns.OOS_URL in remove_qs(driver.current_url):
            if int((datetime.now() - t).total_seconds()) > timeout_mins * 60:
                raise ItemOutOfStock(
                    'Encountered OOS alert and timed out waiting for user '
                    'input\n Use `ignore-oos` to bypass these alerts')
            sleep(1)
Exemple #4
0
def main_loop(driver, args):
    slot_prefs = get_prefs_from_conf()
    site_config = config.SiteConfig(args.service)
    wait_for_auth(driver)

    if args.save_cart:
        try:
            save_cart(driver, site_config)
        except Exception:
            log.error('Failed to save cart items')
    slot_route = build_route(site_config, 'SLOT_SELECT', args)
    slot_route.navigate(driver)
    slots = get_slots(driver, slot_prefs, slot_route)
    if slots:
        annoy()
        alert('Delivery slots available. What do you need me for?', 'Sosumi')
    else:
        executor = ThreadPoolExecutor()
    while not slots:
        log.info('No slots found :( waiting...')
        jitter(config.INTERVAL)
        driver.refresh()
        slots = get_slots(driver, slot_prefs, slot_route)
        if slots:
            alert('Delivery slots found')
            message_body = generate_message(slots, args.service, args.checkout)
            executor.submit(send_sms, message_body)
            executor.submit(send_telegram, message_body)
            if not args.checkout:
                break
            checked_out = False
            log.info('Attempting to select slot and checkout')
            while not checked_out:
                try:
                    log.info('Selecting slot: ' + slots[0].full_name)
                    slots[0].select()
                    build_route(site_config, 'CHECKOUT', args).navigate(driver)
                    checked_out = True
                    alert('Checkout complete', 'Hero')
                except RouteRedirect:
                    log.warning('Checkout failed: Redirected to slot select')
                    slots = get_slots(driver, slot_prefs, slot_route)
                    if not slots:
                        break
    try:
        executor.shutdown()
    except Exception as e:
        log.error(e)
 def main_loop(self):
     wait_for_auth(self)
     if self.args.save_cart:
         try:
             self.save_cart()
         except Exception:
             log.error('Failed to save cart items')
     self.navigate_route('SLOT_SELECT', retry=True)
     slots = self.get_slots()
     if slots:
         annoy()
         alert('Delivery slots available. What do you need me for?',
               'Sosumi')
     else:
         self.executor = ThreadPoolExecutor()
     while not slots:
         log.info('No slots found :( waiting...')
         jitter(INTERVAL)
         self.driver.refresh()
         slots = self.get_slots()
         if slots:
             alert('Delivery slots found')
             message_body = self.generate_message(slots)
             self.executor.submit(send_sms, message_body)
             self.executor.submit(send_telegram, message_body)
             if not self.args.checkout:
                 break
             checked_out = False
             log.info('Attempting to select slot and checkout')
             while not checked_out:
                 try:
                     log.info('Selecting slot: ' + slots[0].full_name)
                     slots[0].select()
                     self.navigate_route('CHECKOUT')
                     checked_out = True
                     alert('Checkout complete', 'Hero')
                 except RouteRedirect:
                     log.warning(
                         'Checkout failed: Redirected to slot select')
                     slots = self.get_slots()
                     if not slots:
                         break
     if self.executor:
         self.executor.shutdown()
Exemple #6
0
    logging.basicConfig(
        format='[%(asctime)s] {%(funcName)s} %(levelname)s: %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
        level=logging.INFO if not args.debug else logging.DEBUG)

    if not args.no_import:
        # Import appends ./env/lib/.../chromedriver to $PATH
        import chromedriver_binary

    log.info('Invoking Selenium Chrome webdriver')
    opts = Options()
    opts.add_argument("user-data-dir=" + config.USER_DATA_DIR)
    driver = webdriver.Chrome(options=opts)
    try:
        main_loop(driver, args)
    except WebDriverException:
        alert('Encountered an error', 'Basso')
        if args.debug:
            dump_source(driver)
        raise
    try:
        # allow time to check out manually
        min = 15
        log.info('Sleeping for {} minutes (press Ctrl+C to close)'.format(min))
        sleep(min * 60)
    except KeyboardInterrupt:
        log.warning('Slumber disturbed')
    log.info('Closing webdriver')
    driver.close()