读取Http GET响应的字节并打印它们,同时继续监听同一请求中的下一个字节

时间:2017-12-19 06:36:37

标签: python python-3.x http python-asyncio aiohttp

我有一个系统,我想打开一个套接字,执行基本身份验证,发送HTTP POST以注册自己并获取一个ID,然后将GET请求发送到特定的URL并开始收到通知。

问题是这个GET请求应该有一个无限制的超时,我应该在它们到达时获取并打印字节而不停止请求(意味着操作是不对称的,它不是请求 - 响应操作,而是请求和持续响应每个字节的位置,我应该立即做出反应,同时继续等待下一个字节。

例如:我会听取这样的联系,5分钟后我会得到" HELLO"在插座上,我打印它,并将继续等待完全相同的会话,再经过2分钟,我将得到"所有人都在同一个会议上,我想打印" HELLO"并且等待更多的输入,并在获得"在那里",也打印它并继续等待更多的数据。

您能指导我如何操作或提供示例代码吗?

10倍!

编辑:这是我已经拥有的代码,问题是我成功注册后没有收到任何通知,意味着没有调用回调...我已经添加了一个打印件验证我在通过标识符过滤之前确实得到了一些东西,但我不是......:

import asyncio
import json
import logging
import traceback
from http.client import HTTPResponse
from typing import Union, Awaitable
from urllib.parse import urljoin

from aiohttp import ClientSession, BasicAuth, TCPConnector


class HttpWrapper(object):
    def __init__(self, *, hostname: str, global_headers: dict, user: str, password: str):
    self._hostname = hostname
    auth = BasicAuth(login=user, password=password)
    connector = TCPConnector(verify_ssl=False)
    self._session = ClientSession(connector=connector,
                                  headers=global_headers,
                                  read_timeout=None,
                                  conn_timeout=None,
                                  auth=auth)

    def post_json(self, uri: str, data: Union['dict', 'list']) -> Awaitable[HTTPResponse]:
        return self._session.request('POST', urljoin(self._hostname, uri), json=data)

    def get(self, uri: 'str', extra_headers: 'dict' = None) -> Awaitable[HTTPResponse]:
        return self._session.request('GET', urljoin(self._hostname, uri), headers=extra_headers)

    def close(self):
        return self._session.close()


class NotificationsHandler:

    def __init__(self, hostname):
        self._http_client = HttpWrapper(hostname=hostname,
                                    global_headers={'Accept': 'application/json',
                                                    'Content-Type': 'application/json'},
                                    user='user',
                                    password='password')
        self._notifications_identifier = None
        self._keep_running = False
        self._loop = asyncio.get_event_loop()
        self._log = logging.getLogger("NotificationsHandler")

    async def register_for_notifications(self) -> bool:
        body = { "details": {"register-id": "123"} }
        try:
            async with self._http_client.post_json(uri='register-for-notifications',
                                               data=body) as resp:
                json_resp = await resp.json()
                self._notifications_identifier = json_resp['identifier']
                self._keep_running = True
        except Exception as error:
            self._log.error('Failed to register for notifications: {}'.format(error))
            self._log.debug(traceback.format_exc())
            self._notifications_identifier = None
            self._keep_running = False
        return self._keep_running

    async def handle_notifications(self, notifications_callback):
        """
        handle the notifications
        :param notifications_callback: coro which receives the notification as JSON
        :return: None
        """
        async with self._http_client.get(uri='get-notifications-json',
                                     extra_headers={'Cache-Control': 'no-cache',
                                                    'Accept': 'text/event-stream'}) as response:
            buffer = b""
            async for data, end_of_http_chunk in response.content.iter_chunks():
                buffer += data
                if end_of_http_chunk:
                    try:
                        update_json = json.loads(buffer)
                        if update_json['identifier'] == self._notifications_identifier:
                        self._loop.create_task(notifications_callback(update_json))
                except Exception as error:
                    self._log.exception("Failed to read update: {}".format(error))
                    self._log.debug(traceback.format_exc())
                buffer = b""
            if not self._keep_running:
                return

    def close(self):
        self._http_client.close()
        self.stop_handle_notifications()

    async def stop_handle_notifications(self):
        self._keep_running = False

0 个答案:

没有答案