예제 #1
0
 def navigate_route(self, route, retry=False, timeout=NAV_TIMEOUT):
     if isinstance(route, str):
         route = self.routes.get(route)
     log.info('Navigating ' + str(route))
     route.waypoints_reached = 0
     if self.current_url != route.route_start:
         log.info('Navigating to route start: {}'.format(route.route_start))
         jitter(.4)
         self.driver.get(route.route_start)
     for waypoint in route.waypoints:
         try:
             valid_dest = []
             for w in route.waypoints[route.waypoints.index(waypoint):]:
                 valid_dest.extend(w.dest)
             if waypoint.check_current(self.current_url):
                 log.warning("Already at dest: '{}'".format(
                     waypoint.check_current(self.current_url)))
             else:
                 self.navigate_waypoint(waypoint, timeout, valid_dest)
         except NavigationException:
             try:
                 handle_redirect(self,
                                 valid_dest=valid_dest,
                                 timeout=timeout,
                                 route=route)
             except RouteRedirect:
                 if retry:
                     log.warning('Retrying route')
                     self.navigate_route(route, timeout=timeout)
                     return
                 else:
                     raise
         route.waypoints_reached += 1
     log.info('Route complete')
예제 #2
0
 def save_cart(self):
     jitter(.4)
     self.driver.get(self.site_config.BASE_URL +
                     self.site_config.cart_endpoint)
     cart = []
     for element in wait_for_elements(self.driver,
                                      self.Locators.CART_ITEMS):
         try:
             cart.append(CartItem(element).data)
         except Exception:
             log.warning('Failed to parse a cart item')
     if cart:
         dump_toml(
             {'cart_item': sorted(cart, key=lambda k: k['product_id'])},
             self.site_config.service.replace(' ', '') + '_cart')
예제 #3
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)
예제 #4
0
def save_cart(driver, site_config):
    filepath = '{}_cart_{}.toml'.format(site_config.service.replace(' ', ''),
                                        timestamp())
    driver.get(config.BASE_URL + site_config.cart_endpoint)
    jitter(.4)
    cart = []
    for element in wait_for_elements(driver, config.Locators.CART_ITEMS):
        try:
            cart.append(CartItem(element).data)
        except Exception:
            log.warning('Failed to parse a cart item')
    if cart:
        cart = sorted(cart, key=lambda k: k['product_id'])
        log.info('Writing {} cart items to: {}'.format(len(cart), filepath))
        with open(filepath, 'w', encoding='utf-8') as f:
            toml.dump({'cart_item': cart}, f)  # :)
예제 #5
0
 def navigate_waypoint(self, driver, waypoint, timeout, valid_dest):
     log.info('Navigating ' + str(waypoint))
     elem = wait_for_element(driver, waypoint.locator, timeout=timeout)
     jitter(.4)
     click_when_enabled(driver, elem)
     try:
         WebDriverWait(driver, timeout).until(EC.staleness_of(elem))
     except TimeoutException:
         pass
     current = remove_qs(driver.current_url)
     if current == BASE_URL + waypoint.dest:
         log.info("Navigated to '{}'".format(waypoint.dest))
     elif valid_dest and any(d in current for d in valid_dest):
         log.info("Navigated to valid dest '{}'".format(current))
     else:
         raise NavigationException("Navigation to '{}' failed".format(
             waypoint.dest))
예제 #6
0
 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()
예제 #7
0
 def navigate_waypoint(self, waypoint, timeout, valid_dest):
     if callable(waypoint.callable):
         log.info('Executing {}() before navigation'.format(
             waypoint.callable.__name__))
         waypoint.callable(browser=self)
     log.info('Navigating ' + str(waypoint))
     elem = wait_for_element(self.driver, waypoint.locator, timeout=timeout)
     jitter(.4)
     click_when_enabled(self.driver, elem)
     try:
         WebDriverWait(self.driver, timeout).until(EC.staleness_of(elem))
     except TimeoutException:
         pass
     if waypoint.check_current(self.current_url):
         log.info("Navigated to '{}'".format(
             waypoint.check_current(self.current_url)))
     elif valid_dest and any(d in self.current_url for d in valid_dest):
         log.info("Navigated to valid dest '{}'".format(self.current_url))
     else:
         raise NavigationException("Navigation to '{}' failed".format(
             waypoint.dest))