def test_get_torrent(self):
     handler = TorrentHandler(self.log)
     handler.download_torrent_file = test_component.download_torrent_file
     filename = yarss2.util.common.get_resource(
         "FreeBSD-9.0-RELEASE-amd64-dvd1.torrent", path="tests/data/")
     test_component.use_filedump = read_file(filename)
     torrent_info = {
         "link": "http://url.com/file.torrent",
         "site_cookies_dict": {
             "cookiekey": "cookievalue"
         },
         "user_agent": "test"
     }
     download = handler.get_torrent(torrent_info)
     self.assertEquals(download.headers, {'User-Agent': 'test'})
     self.assertEquals(download.cookies, {'cookiekey': 'cookievalue'})
     self.assertFalse(download.is_magnet)
 def test_get_torrent_magnet(self):
     handler = TorrentHandler(self.log)
     torrent_info = {"link": "magnet:hash"}
     download = handler.get_torrent(torrent_info)
     self.assertTrue(download.is_magnet)
class RSSFeedScheduler(object):
    """Handles scheduling the RSS Feed fetches."""

    def __init__(self, config, logger):
        self.yarss_config = config
        self.rssfeed_timers = {}
        self.run_queue = RSSFeedRunQueue()
        self.log = logger
        self.rssfeedhandler = RSSFeedHandler(logger)
        self.torrent_handler = TorrentHandler(logger)
        self.add_torrent_func = self.torrent_handler.add_torrents # To make it possible to disable adding torrents in testing

    def enable_timers(self):
        """Creates the LoopingCall timers, one for each RSS Feed"""
        config = self.yarss_config.get_config()
        for key in config["rssfeeds"]:
            self.set_timer(config["rssfeeds"][key]["key"], config["rssfeeds"][key]['update_interval'])
            self.log.info("Scheduled RSS Feed '%s' with interval %s" %
                     (config["rssfeeds"][key]["name"], config["rssfeeds"][key]["update_interval"]))

    def disable_timers(self):
        for key in self.rssfeed_timers.keys():
            self.rssfeed_timers[key]["timer"].stop()
            del self.rssfeed_timers[key]

    def set_timer(self, key, interval):
        """Schedule a timer for the specified interval."""
        try:
            interval = int(interval)
        except:
            self.log.error("Failed to convert interval '%s' to int!" % str(interval))
        # Already exists, so reschedule if interval has changed
        if self.rssfeed_timers.has_key(key):
            # Interval is the same, so return
            if self.rssfeed_timers[key]["update_interval"] == interval:
                return False
            self.rssfeed_timers[key]["timer"].stop()
            self.rssfeed_timers[key]["update_interval"] = interval
        else:
            # New timer
            # Second argument, the rssfeedkey is passed as argument in the callback method
            #timer = LoopingCall(self.rssfeed_update_handler, (key))
            timer = LoopingCall(self.queue_rssfeed_update, key)

            self.rssfeed_timers[key] = {"timer": timer, "update_interval": interval}
        self.rssfeed_timers[key]["timer"].start(interval * 60, now=False) # Multiply to get seconds
        return True

    def delete_timer(self, key):
        """Delete timer with the specified key."""
        if not self.rssfeed_timers.has_key(key):
            self.log.warn("Cannot delete timer. No timer with key %s" % key)
            return False
        self.rssfeed_timers[key]["timer"].stop()
        del self.rssfeed_timers[key]
        return True

    def rssfeed_update_handler(self, rssfeed_key=None, subscription_key=None):
        """Goes through all the feeds and runs the active ones.
        Multiple subscriptions on one RSS Feed will download the RSS feed page only once
        """
        if subscription_key:
            self.log.info("Manually running Subscription '%s'" %
                          (self.yarss_config.get_config()["subscriptions"][subscription_key]["name"]))
        elif rssfeed_key:
            if self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["active"] is False:
                return
            #self.log.info("Running RSS Feed '%s'" % (self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["name"]))
        fetch_result = self.rssfeedhandler.fetch_feed_torrents(self.yarss_config.get_config(), rssfeed_key,
                                                                       subscription_key=subscription_key)
        matching_torrents = fetch_result["matching_torrents"]
        # Fetching the torrent files. Do this slow task in non-main thread.
        for torrent in matching_torrents:
            torrent["torrent_download"] = self.torrent_handler.get_torrent(torrent)


        # Update TTL value?
        if fetch_result.has_key("ttl"):
            # Subscription is run directly. Get RSS Feed key
            if not rssfeed_key:
                rssfeed_key = self.yarss_config.get_config()["subscriptions"][subscription_key]["rssfeed_key"]
            self.log.info("Rescheduling RSS Feed '%s' with interval '%s' according to TTL." %
                     (self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["name"], fetch_result["ttl"]))
            self.set_timer(rssfeed_key, fetch_result["ttl"])
            # Set new interval in config
            self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["update_interval"] = fetch_result["ttl"]
        # Send YARSSConfigChangedEvent to GUI with updated config.
        try:
            # Tests throws KeyError for EventManager when running this method, so wrap this in try/except
            component.get("EventManager").emit(YARSSConfigChangedEvent(self.yarss_config.get_config()))
        except KeyError:
            pass

        def save_subscription_func(subscription_data):
            self.yarss_config.generic_save_config("subscriptions", data_dict=subscription_data)

        return (self.add_torrent_func, save_subscription_func,
                fetch_result["matching_torrents"], self.yarss_config.get_config())

    def add_torrents_callback(self, args):
        """This i called with the results from rssfeed_update_handler
        add_torrent_func must be called on the main thread
        """
        if args is None:
            return
        add_torrent_func, save_subscription_func, matching_torrents, config = args
        add_torrent_func(save_subscription_func, matching_torrents, config)

    def queue_rssfeed_update(self, *args, **kwargs):
        d = self.run_queue.push(self.rssfeed_update_handler, *args, **kwargs)
        d.addCallback(self.add_torrents_callback)
        return d