Пример #1
0
 async def wrap_data(self, key) -> CachedDataWrapper:
     wrapper = await super().wrap_data(key)
     if wrapper and wrapper.data:
         # 对数据进行重新包装,将文件内容换成 json 对象
         wrapper.data = json.loads(wrapper.data)
         Cms4pyLog.get_instance().debug(f"Load json file {key}")
     return wrapper
Пример #2
0
    async def __call__(self, *args, **kwargs):
        # 获取数据管理器实例
        db_manager = await Db.get_instance()
        # 通过连接池建立一个连接
        conn = await db_manager.async_pydal.acquire()
        # 自动提交数据更改
        await conn.autocommit(True)
        # 获取数据库对象用于操作数据库
        self.db = await conn.cursor()

        # 无论在execute中发生了什么错误,总要执行释放连接的操作
        err = None
        try:
            await self.execute(*args, **kwargs)
        except BaseException as e:
            err = e
            Cms4pyLog.get_instance().error(e)

        # 关闭数据库对象
        await self.db.close()
        # 释放连接
        await db_manager.async_pydal.release(conn)

        if err:
            # 如果在执行 execute 过程中发生了错误,将此错误抛给ASGI
            raise err
Пример #3
0
async def application(scope, receive, send):
    # 获取请求类型
    request_type = scope['type']

    # 如果是 http 类型的请求,则由该程序段处理
    if request_type == 'http':
        # 如果路径以 /socket.io 开始,则使用 socket.io app 进行处理
        if scope['path'].startswith("/socket.io"):
            return await sio_asgi_app(scope, receive, send)

        data_sent = await dynamic_handler.handle_dynamic_request(
            scope, receive, send)

        # 如果经过动态请求处理程序后未发送数据,则尝试使用静态文件请求
        # 处理程序处理
        if not data_sent:
            data_sent = await static_file_handler.handle_static_file_request(
                scope, send)

        # 如果静态文件处理程序未发送数据,则意味着文件找不到,此时应该
        # 向浏览器发送404页面
        if not data_sent:
            # 对于未被处理的请求,均向浏览器发回 404 错误
            await error_pages.send_404_error(scope, receive, send)
    # 如果是 websocket,则使用 socket.io app 处理
    elif request_type == 'websocket':
        return await sio_asgi_app(scope, receive, send)
    # 如果是生命周期类型的请求,则由该程序段处理
    elif request_type == 'lifespan':
        await lifespan_handler.handle_lifespan(scope, receive, send)
    else:
        Cms4pyLog.get_instance().warning("Unsupported ASGI type")
Пример #4
0
            async def wrap_data_callback(cache_key) -> CachedDataWrapper:
                await target(*args)

                Cms4pyLog.get_instance().debug(f"Cache page {cache_key}")
                return CachedDataWrapper(
                    res.body,
                    # 记录缓存过期时间,便于对比
                    datetime.datetime.now().timestamp() + expire
                )
 async def wrap_data(self, key) -> CachedDataWrapper:
     m = None
     t = 0
     try:
         # 导入模块
         m = importlib.import_module(key)
         m_file = self.file_name_from_module_name(key)
         # 获取文件时间戳
         t = await aiofile.getmtime(m_file)
     except ModuleNotFoundError:
         Cms4pyLog.get_instance().warning(f"Module {key} not found")
     return CachedDataWrapper(m, t)
Пример #6
0
async def handle_lifespan(scope, receive, send):
    while True:
        # 不断读取数据
        message = await receive()
        # 如果读取消息类型为 lifespan.startup,则进行初始化操作
        if message['type'] == 'lifespan.startup':
            await load_sio_files()
            # 在初始化完成后,向 asgi 环境发送启动完成消息
            await send({'type': 'lifespan.startup.complete'})
            Cms4pyLog.get_instance().info("Server started")
        # 如果读取消息类型为 lifespan.shutdown,则进行收尾工作
        elif message['type'] == 'lifespan.shutdown':
            # 在收尾工作结束后,向 asgi 环境发送收尾完成消息
            await send({'type': 'lifespan.shutdown.complete'})
            Cms4pyLog.get_instance().info("Server stopped")
            break
Пример #7
0
    async def _parse_form(self):
        """
        解析表单,该函数由cms4py框架内部调用,应用层不应该调用此函数
        :return:
        """

        # TODO 目前实现仅支持GET方法与POST方法,需要逐步完善
        #  并支持所有的 HTTP 方法
        if self.query_string:
            # 尝试从 URL 中解析参数
            self._query_vars = url_helper.parse_url_pairs(
                self.query_string
            )
        if self.method == "POST":
            # 如果是 POST 方式,尝试读取消息体
            while True:
                message = await self._receive()
                # TODO 需要实现数据限制机制以防攻击
                self._body += message["body"] if 'body' in message else b''
                if "more_body" not in message or not message["more_body"]:
                    break
            if self.content_type:
                # 如果是 application/x-www-form-urlencoded 编码方式,
                # 则尝试以 URL 参数对的方式解析
                if self.content_type.startswith(
                        b'application/x-www-form-urlencoded'
                ):
                    self._body_vars = url_helper.parse_url_pairs(
                        self._body
                    )
                # 如果是 multipart/form-data 则当成表单数据解析,可用
                # 于处理文件上传请求
                elif self.content_type.startswith(b"multipart/form-data"):
                    # 该正则用于取出数据分割符
                    boundary_search_result = re.search(
                        b"multipart/form-data; boundary=(.+)",
                        self.content_type
                    )
                    if boundary_search_result:
                        # 取出分割符
                        boundary = boundary_search_result.group(1)
                        if self._body:
                            # 用分割符分割表单数据
                            body_results = self.body.split(
                                b'\r\n--' + boundary
                            )
                            if body_results:
                                for body_result in body_results:
                                    # 分割后的每一条数据都有头部和内容,
                                    # 头部和内容以 \r\n\r\n 分开,
                                    # 头部是字符串,描述该数据的信息
                                    # 内容部分是二进制数据
                                    split_index = body_result \
                                        .find(b'\r\n\r\n')
                                    if split_index != -1:
                                        # 获取头部信息字符串
                                        head = body_result[:split_index]
                                        # 获取内容
                                        content = body_result[
                                                  split_index + 4:]
                                        # 取出该字段的名称
                                        name_result = re.search(
                                            b'Content-Disposition: form-data; name="([^"]+)"',
                                            head, re.M
                                        )
                                        if name_result:
                                            name = name_result.group(1)
                                            if name not in self._body_vars:
                                                self._body_vars[name] = []
                                            # 如果是文件,则取出该字段的文件名
                                            file_name_result = re.search(
                                                b' filename="([^"]+)"',
                                                head, re.M
                                            )
                                            file_name = file_name_result \
                                                .group(1) if \
                                                file_name_result else None
                                            if not file_name:
                                                # 如果不是文件,值为普通字符串
                                                self._body_vars[name] \
                                                    .append(content)
                                            else:
                                                file_object = {
                                                    'name': name,
                                                    'filename': file_name,
                                                    'content': content
                                                }
                                                content_type_result = \
                                                    re.search(
                                                        b'Content-Type: (.*)',
                                                        head, re.M
                                                    )
                                                if content_type_result:
                                                    file_object[
                                                        'content-type'
                                                    ] = content_type_result.group(1)
                                                # 如果是文件,则值为文件对象
                                                self._body_vars[name].append(file_object)
                                        pass
                                    else:
                                        break
                else:
                    Cms4pyLog.get_instance().info(
                        f"Request content-type is {self.content_type}, we do not parse"
                    )
            else:
                Cms4pyLog.get_instance().warning("content-type is None")
            pass
        pass