예제 #1
0
파일: draft.py 프로젝트: guldfisk/cubeapp
class DraftInterface(ABC):
    pick_type: t.Type[Pick]
    passing_to: DraftInterface

    class ConnectionException(Exception):
        pass

    def __init__(self, drafter: Drafter, draft: Draft, draft_seat: DraftSeat):
        super().__init__()
        self._drafter = drafter
        self._draft = draft
        self._draft_seat = draft_seat

        self._pool = Cube()

        self._messages: t.List[t.Mapping[str, t.Any]] = []
        self._pick_counter = 0

        self._booster_queue = Queue()
        self._pick_queue = Queue()
        self._out_queue = Queue()

        self._current_booster: t.Optional[DraftBooster] = None

        self._terminating = threading.Event()

        self._booster_pusher = threading.Thread(target=self._draft_loop)

        self._connect_lock = threading.Lock()
        self._consumer: t.Optional[WebsocketConsumer] = None

    @property
    def messages(self) -> t.List[t.Mapping[str, t.Any]]:
        return self._messages

    @property
    def pool(self) -> Cube:
        return self._pool

    def connect(self, consumer: WebsocketConsumer) -> None:
        with self._connect_lock:
            if self._consumer is not None:
                raise self.ConnectionException('already connected')
            self._consumer = consumer

    def disconnect(self) -> None:
        with self._connect_lock:
            if self._consumer is None:
                raise self.ConnectionException('no consumer connected')
            self._consumer = None

    def send_message(self, message_type: str, **kwargs) -> None:
        self.out_queue.put({
            'type': message_type,
            **kwargs,
        })

    def send_error(self, error_type: str, **kwargs):
        self.send_message('error', error_type=error_type, **kwargs)

    @property
    def booster_queue(self) -> Queue[DraftBooster]:
        return self._booster_queue

    @property
    def booster_amount(self) -> int:
        return self._booster_queue.qsize() + (1
                                              if self._current_booster else 0)

    def give_booster(self, booster: DraftBooster) -> None:
        self._booster_queue.put(booster)
        self._draft.broadcast_message(
            'booster_amount_update',
            drafter=self._drafter.user.pk,
            queue_size=self.booster_amount,
        )

    @property
    def pick_queue(self) -> Queue[Cubeable]:
        return self._pick_queue

    @property
    def out_queue(self):
        return self._out_queue

    def receive_message(self, message: t.Any) -> None:
        message_type = message.get('type')

        if message_type == 'pick':
            pick = message.get('pick')
            if pick is None:
                self.send_error('empty_pick')
                return

            try:
                pick = RawStrategy(db).deserialize(self.pick_type, pick)
            except SerializationException:
                self.send_error('misconstrued_pick')
                return

            self._pick_queue.put(pick)

        else:
            self.send_error('unknown_message_type', message_type=message_type)

    def start(self) -> None:
        self.send_message(
            'started',
            **self._draft.serialize(),
        )
        self._booster_pusher.start()

    def stop(self) -> None:
        self._terminating.set()

    @abstractmethod
    def perform_pick(self, pick: Pick) -> bool:
        pass

    def _draft_loop(self) -> None:
        while not self._terminating.is_set():
            try:
                booster = self._booster_queue.get(timeout=2)
            except Empty:
                continue

            self._current_booster = booster

            self.send_message('booster',
                              booster=RawStrategy.serialize(
                                  self._current_booster))

            while not self._terminating.is_set():
                try:
                    pick = self._pick_queue.get(timeout=2)
                except Empty:
                    continue

                if not self.perform_pick(pick):
                    self.send_error(
                        'invalid_pick',
                        pick=pick.serialize(),
                    )
                    continue

                self._pick_counter += 1

                self.send_message(
                    'pick',
                    pick=pick.serialize(),
                    booster=RawStrategy.serialize(self._current_booster),
                    pick_number=self._pick_counter,
                )

                DraftPick.objects.create(
                    seat=self._draft_seat,
                    pack_number=self._draft.pack_counter,
                    pick_number=self._current_booster.pick_number,
                    global_pick_number=self._pick_counter - 1,
                    pack=self._current_booster,
                    pick=pick,
                )

                self._current_booster.pick_number += 1

                if self._current_booster.cubeables:
                    self.passing_to.give_booster(self._current_booster)
                else:
                    self._draft.booster_empty(self._current_booster)
                self._current_booster = None
                self._draft.broadcast_message(
                    'booster_amount_update',
                    drafter=self._drafter.user.pk,
                    queue_size=self.booster_amount,
                )
                break
예제 #2
0
class Nautilus:
    def __init__(self, url, max_depth):
        self.seed_url = url
        self.result_urls = []
        self.queue = Queue()
        self.max_depth = int(max_depth)
        self.cur_depth = 1
        self.db = DBHelper()
        self.logger = get_logger(__name__)

    def is_file_link(self, url):
        file_url_test = re.compile(r'^.*?\.(pdf|docx|doc|rtf|mobi|azw3|epub)$')
        if file_url_test.match(url.lower()):
            return True
        else:
            return False

    def insert_links(self, file_url, parent_url):
        with requests.get(parent_url, timeout=TIMEOUT) as html_response:
            response_parse = BeautifulSoup(html_response.text, 'html.parser')
            filename = unquote(file_url).split('/').pop()
            [s.extract() for s in response_parse('script')]
            [s.extract() for s in response_parse('style')]
            content = response_parse.body.get_text() \
                .replace(' ', '') \
                .replace('\n', '') \
                .replace('\r', '')
            timestamp = str(int(round(time.time()) * 1000))
            values = (file_url, filename, content, timestamp)
            self.db.insert_item(values)
            self.logger.info('GET: ' + filename + ' AT ' + file_url)

    def resolve_links(self, item, parent_url):
        link = item.get('href')
        url_resolver = Urls(link)
        if url_resolver.check_if_url() \
                and url_resolver.inner_url(self.seed_url):
            prefixed_url = url_resolver.prefix_url(self.seed_url, link)
            if prefixed_url not in self.result_urls:
                if self.is_file_link(prefixed_url):
                    self.insert_links(prefixed_url, parent_url)
                else:
                    self.result_urls.append(prefixed_url)
                    self.queue.enqueue(prefixed_url)
                    self.logger.info('FETCH: ' + prefixed_url)

    def get_url(self):
        for i in range(0, len(self.queue.get())):
            current_url = self.queue.dequeue()
            time.sleep(1.5)
            with requests.get(current_url, timeout=TIMEOUT) as html_response:
                soup = BeautifulSoup(html_response.text, 'html.parser')
                links = soup.find_all('a', {'href': True})
                for item in links:
                    time.sleep(1.5)
                    self.resolve_links(item, current_url)

    def bfs_traverse(self):
        self.queue.enqueue(self.seed_url)
        while self.cur_depth < self.max_depth:
            try:
                self.get_url()
                self.cur_depth += 1
            except Exception as e:
                self.logger.error(str(e))
                pass

    def run(self):
        self.logger.info('START BFS FROM: ' + self.seed_url)
        time.sleep(1)
        self.bfs_traverse()