Git Product home page Git Product logo

avilla's People

Contributors

blueglassblock avatar greyelaina avatar markyfsun avatar nullqwertyuiop avatar programripper avatar redlnn avatar rf-tar-railt avatar serinanya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

avilla's Issues

[Core] 选择器(Selector) 相关

mainline = create_selector("mainline")

mainline.channel # -> SelectorKey("mainline.channel")
r = mainline.channel[123] # -> <mainline>.channel[123]
r.to_dict() # -> {"channel": 123}

Metadata Core Support 的初步说明

已经完成.

group.name(mainline) -> str
group.description(mainline) -> str
group.member.max_count -> int
group.member.current_count -> int
member.name -> str
member.muted -> bool
member.join_time -> datetime
member.last_active -> datetime
member.mute_period -> timedelta
member.budget -> str
member.nickname -> str
self.name -> str
self.nickname -> str
self.budget -> str
self.muted -> bool
self.mute_period -> timedelta
self.join_time -> datetime

contextvars / Ctx 交互改进

Avilla, Protocol, Relationship 中, 后者的上下文可以承担前者.

Avilla.current(), get_current_protocol(), Relationship.current() (Relationship 似乎不需要变)

a huge change to service

BehaviourSession will be a param that bypass to a callback-like action(like websocket/http listen ), and if it's a multi-action, the "callback" can be a class.
and if it's a client-like but need to do some cleanning work, maybe we can use __del__ that push a callback to a task queue or positively call clean method.
B.S. must remove async-with, and to be a base class that can be expand some activities like WebsocketSession.

Issue about new abstraction "Subline" and "Notify"

        # 思考 -> 需要一个 MemberPoked 事件?(platform specific event)
        # answer: yes, but a more generic name
        # SpecialNotify?
        # 在其他平台,比如 Telegram, 似乎并没有这种特殊的触发方式或是消息类型。
        # 作为消息类型反而本末倒置:我删去了 user-space 的 reply/ source 就可以看出来这点。
        # Discord 似乎也没有。。。
        # 反倒是比如 Telegram 最近版本能给消息丢shit比心这样的。。这种又该怎么处理呢?
        #                                   ^^^^^^^^^^^^ MessageChanged?
        # 啊,一般来说,我认为这种应该不属于 “一条由特定个体发出的消息” 的范畴。。。
        # 虽然 Message 确实是 Mutable, 从 MessageEdit 就可以看出来。。。。
        # answer(you): 拓展一下 Message, 将 Poke type element 与 Poke action 放到一起, 作为...... metadata?
        # Message metadata 还可以存储些别的, 比如 reaction
        # GitHub discussion 为什么不能当作 message flow 呢
        # me: 或许将 Message 扩展一个 Notify, 不强调其 content 为 chain?
        # 那那种我认为叫 subline 比较好(单纯是设计用词)
        # well, the inputer of ubunti is shit, go to qq.
        # 结论: 可动态获取的(方式可以是 Operator)的附加信息。

Onebot Resource Provider(s)

Required:

  • OnebotGroupFileResourceProvider - OnebotGroupFileResourceOperator
  • OnebotVoiceResourceProvider - OnebotVoiceResourceOperator
  • and more multi-media element

[AEP-C031] Enhanced Resource API

当你看到本段文本时, 本提案仍处于草案阶段

已有实现

摘要

Avilla Resource 在写作该提案的当下, 已经实现了由 Protocol.fetch_resource 承担的, 并由 resource 选择器, ResourceAvailable 等事件的实现. 本提案提议了对于该部分的优化建议.

改进需求

对于资源文件的管理(包括远端服务器上的), Avilla 仍然不具备充分有效的能力去处理,
开发者可能用 tempfile 等库对该逻辑进行一个并不完备的实现, 而由此导致一系列的不可迁移性, 部署困难和不必要的耦合性.
本提案提出了基于 Service 特性的 FilehostInterface 实现, 并于 Core 模块内提供 aiofile ( LocalfileProvider ), aiofile+tempfile ( TempfileProvider ) 的本地文件管理实现.

分配的包/命名空间

  • avilla.core.service.common.file

  • avilla.core.service.localfile

建议的包名:

  • avillax.service.amazon_s3

  • avillax.service.onedrive

所引用/新增的命名空间:

  • avillax ~ avillax.service

阐述

对于 资源(Resource) , 我们的理解是: 具有一个在一定上下文中唯一的访问标识符; 以及通常都可以用 bytes 表示这两点.

操作(Activity)

由此来看, 资源与其说是文件, 不如说是 "类文件( file-like )",
且不说 QQ 等 IM 中的典型资源类型: 图片, 就没办法单纯的使用 create 操作先在服务器上注册,
然后再使用 write 方法进行数据写入/修改, 而只能使用 put 操作直接传达数据并获取资源的访问标识符 -- 何况是 remove 操作呢?

而当然的, 对于真正的存储在硬盘/对象存储里的真正的文件 -- 即使是 Amazon S3 或者是 Onedrive , 这些操作都是可用的, 我们需要一个较为通用的方案去处理这种情况.

本提案将对资源的操作, 先并称之为 "访问( access )".
如果要像是进行 create , write 这些操作, 我们得首先对一个资源或者是资源类型的上下文发起访问会话.

本提案目前所计划的访问方式:

  • create : 创建资源, 此时资源应该会是一个空值或者是上下文中的默认值(类似 DefaultDict );
  • write : 对资源进行写入, 默认不启用覆写;
  • put : 直接创建资源并写入, 如果成功将返回一个 resource 选择器实例;
  • read : 读取资源数据, 返回 Stream[bytes] ;
  • remove : 删除资源;
  • stats : 作为发起请求后的错误判断, 返回是 Status 对象.
  • rename : 更改资源的访问标识符;
  • ls : 对于类似 resource.dir[...] 的操作. 返回一个 List[resource_selector] ;
  • meta : 返回 MetaWrapper 的实例, 用于操作资源的元信息, 同样的也可以用 Generic 指定返回的是 CoreSupport 等(类似 Relationship)
  • etc... 大概后面还会想到一点?

以下是本提案目前否决了的访问类型, 同样的也简述了相应的动机:

  • exists : 使用 stats 操作即可;
  • is_dir / is_file / typeof : 资源的访问标识符基于 Selector , 你可以通过 Selector.last 方法获取资源的类型(以 str 表示);
  • chmod : 本提案认为实际情况过于复杂, 不应该简单的使用 POSIX 的方式进行权限判定;

这一设计将使用 BehaviourSession 作为基盘, 为了简单的复用已有的设计.

由于 Avilla 中的多账户支持等设计的相关因素, 本提案约定以下条规:

  • 对于 Protocol:
    • 强烈建议开发者在构造 resource 选择器时, 加入 mainlineprotocol 键.
    • 建议开发者在构造访问标识符时, 使用字符串作为标识, 并且在其中加入类似 tencent-qq:// 这样的前缀(对于用户来说也是如此.);
  • 对于 Service/Interface 等内部接口开发:
    • 在处理 resource 时, 无论什么时候都使用 Avilla.access_resource 或是其他的由 Avilla 实例提供的方法进行操作(即使有可能在获取上下文时发生 LookupError );
    • 在进行由 Protocol 负责的资源访问操作时, 先使用 get_status 方法初步确认能否进行, 避免不必要的代码健壮性问题.

对于资源的元信息, 本提案提议使用 Avilla.get_resource_meta 或者是 meta 操作获取 MetaWrapper 的实例,
并使用 pyi 的形式模仿/复用已有的 CoreSupport 以提供优秀的 type hint 体验.

附录: 本小节中 Avilla 的相关方法的签名:

@asynccontextmanager
async def access_resource(self, res: resource_selector) -> AsyncGenerator[BehaviourSession, None]:
    ...

async def fetch_resource(self, res: resource_selector) -> Stream[bytes]:
    ...

async def get_resource_meta(self, res: resource_selector) -> MetaWrapper:
    # 在实际中应该要用 typing.cast...
    # 基于 meta 
    ...

资源提供方(Resource Provider)

资源提供方( Resource Provider ) 是 Resource API 中使用到了 Service 的部分, 声明/扩展了以下参数:

  • supported_resource_types (Set[str]) : 支持的资源类型;
  • id_prefix (str) : 选择器中标识符的前缀.

对于 Service.supported_description_types ,
这个字段由 ResourceProvider 进行了值预置, 以便于开发(虽然大部分时候你都得重载);
ResourceProvider 中同样也能使用 status , 但这主要是为了在写 Protocol 时能把 ResourceProvider 直接混入进去.

当你要重载 supported_description_types 时, 记得把上面提到的所有的都给填上, 不管你到底有没有用到.

ResourceProvider 自然也是个抽象基类, 你需要实现 access_resource 方法, 签名和 Avilla.access_resource 大致一致,
或许你可以把 res 的 annotation 写成 Union[xxx] ?
这里如果出现 res.protocol 字段, 必定是将当前 ResourceProvider 作为 BaseProtocol.resource_provider (property)Protocol .

以下是一个简单的获取图片内容的示例:

class OnebotService(ResourceProvider, Service):
    ...
    _avilla: Optional[Avilla] = None

    @property
    def avilla(self) -> "Avilla":
        if self._avilla is None:
            raise TypeError("service is not ready!")
        return self._avilla

    @asynccontextmanager
    async def access_resource(self, res: resource_selector) -> AsyncGenerator[BehaviourSession, None]:
        if res.last() == "image":
            image_id = res.path['image'].partition("://")[2]
            http_interface: HttpClient = self.avilla.get_interface(HttpClient)
            async with http_interface.get(f"https://xxx.ooo.xxx/{image_id}") as session:
                status = await session.execute(get_status)
                content_stream = await session.execute(content_read)
                yield BehaviourSession(...)

    async def launch_prepare(self, avilla: Avilla):
        self._avilla = avilla

    @property
    def launch_component(self) -> LaunchComponent:
        return LaunchComponent(
            "protocol.onebot.service",
            {"http.universal_client"},
            prepare=self.launch_prepare
        )
                

关于详细的实现可以在代码库内找到.

以上就是一个 ResourceProvider 实现, 因为是 low level api 所以这么长, 但这也保证了其灵活性.

Avilla.access_resource 会自动做一个 map, 根据资源的类型和 protocol 中的值转接到相应的提供方.

具体的调用树就像这样:

+-----------------------------+      calls     +-------------------------------+
| Avilla.access_resource(...) | -------------> | Protocol.access_resource(...) |
+-----------------------------+                +-------------------------------+

大概就到这里.

[Refactoring] Landmark version `1.0.0-alpha.5`

概要

本次重构的 Landmark 版本被设定为 1.0.0-alpha.5.

本次主要对各种用名进行修改, 对 Relationship 模型进行重构, 以及分割 core 部件内的框架抽象到 avilla.core.abstract 处, 这将会不可避免的带来 API 的破坏性改动和用户体验的变化.

  • Rename Components
    • Context
    • Metadata
  • Context
    • #65
      • ContextClientSelector
      • ContextSceneSelector
      • ContextEndpointSelector
        • ContextRequestSelector
          • context.endpoint.expects_request() -> ContextRequestSelector
          • context.request (property)
    • #63
      • Context.wrap(bound: Selector) -> ContextSelector
      • Context.wrap(bound: MetadataOf) -> ContextWrappedMetadataOf
        • note: Generic omitted.
      • Context.wrap(bound: Selector, trait: type[T extends Trait]) -> T
      • Context.wrap(bound: MetadataOf, trait: type[T extends Trait]) -> T
      • ContextSelector.wrap(trait: type[T extends Trait]) -> T
      • ContextWrappedMetadata.wrap(trait: type[T extends Trait]) -> T
    • #64
      • ContextSelector.pull(metadata: type[T extends Metadata] | MetadataRoute[..._L, T]) -> T
      • ContextWrappedMetadataOf[T].pull() -> T
        • note: not required for otherwise arguments.
    • #66
      • Design Completed
  • #67
    • bound(...)
    • Modifies on record impl and others.
  • Event
    • Core

用名修改

以下更改同时会影响到 Filter 等内置组件上的方法命名, 请尤其是该提案的实现编写者注意.

Relationship => Context
Relationship.ctx => Context.client & Context.endpoint
Relationship.mainline => Context.scene
Relationship.via => Context.mediums (type: list[ContextMedium])
Relationship.cast =>
    | Context.wrap(bound: Selector, trait: type[T extends Trait]) -> T
    | Context.wrap(bound: Selector) -> ContextSelector

Cell => Metadata
CellOf => MetadataRoute

API 变动概览

ContextSelector

该 Selector 同时包装了一个 Context, 使得可以配合其完成更多的操作, 这也导致了一些代码风格上的变化.

Context.{client, endpoint, scene, mediums[number].selector} 的类型都为 ContextSelector.

await context.scene.send_message(...)
await context.scene.pull(...) # equals to context.pull(scene, ...)
await context.scene.wrap(trait) # equals to context.wrap(scene, trait)

目前正在考虑实现例如 ContextClientSelector, ContextSceneSelector 等派生类, 用于进一步的提供高效的 API 实现.

Selector 相关

新加入 Selector.expects 方法, 用于对 Selector 的内容进行断言. 在语法上使用 follows-style, 同时 follows-style 作为优雅的模式表达方式将得到进一步的推广.

selector = Selector().group("123").member("456")
selector.expects("group.member")  # pass
selector.expects("group(123).member")  # pass
selector.expects("friend") # error with ValueError

Metadata.of & MetadataRoute.of

需要注意的是, 这里的 MetadataOf 与先前版本中的 CellOf 完全不同.

MetadataOf 的声明:

@dataclass
class MetadataOf(Generic[T]):  # T bounds type[Metadata] | MetadataRoute
    target: Selector
    describe: T

可以这样创建:

Summary.of(context.scene)  # Metadata.of
(Privilege >> Summary).of(context.self)  # MetadataRoute.of

Context.wrap

该 API 不仅用于替代 Relationship.cast, 还用于简单的包装 Selector 为 ContextSelector.
该方法会自动运行 Context.complete, 且自动忽略 land 字段.

# 以下几种调用方法等价.
ctx.wrap(Selector().group(...)).wrap(MessageSend).send(...)
ctx.wrap(Selector().group(...), MessageSend).send(...)

对于 Metadata 上的 bound, 这里有一个简单的草案, 但未经验证:

x = ctx.wrap(bound=Metadata.of(selector))  # -> ContextWrappedMetadataOf
x.wrap(...) # -> Trait

Context.check

!> 该项仍然处于设计中(In-Design)阶段.

1.0.0rc4 中, Relationship.check 尚未被实现, 1.0.0rc5 将着手相关工程.

await ctx.check_existence(...) # 确认其存在, 因例如权限原因无法确认就抛出 CheckFailed (lint: 流程控制问题警告)
await ctx.check_accessible(...) # 确认其可操作性, 包括权限等
...

由于要确认的包括且不限于 Metadata, Selector, Trait 之类的交互形式, 所以该项仍然处于设计中阶段.

impl 相关

鉴于 bound 在 Context.wrap -> Trait 中的强制要求, 协议实现中 impl 的方式亦有所改变.

with bound("group.member"):
    @impl(MessageSend.send)
    ...

事件结构体变动

鉴于现在的自动从 AvillaEvent 生成 Context/Relationship 和注入 Metadata 的方式实在是不堪入目,
1.0.0-alpha.5 开始, 事件的实例化强制要求 Context 作为第一个参数的传入.
这不会影响事件本身描述的完整性, 也就是说, MessageReceived.scene 等不会被删除.

包组织结构改动

Trait, Fn 以及各式 recorder, AvillaEvent 事件基类, Resource 基类等部件将被移动至 avilla.core.abstract 处.
avilla-core 所提供的事件, 元信息类, 内建 Trait 等都被移动至 avilla.core.standards 下.

其他改动

  • Relationship.send_message 等缩写形式不再受到支持, 其职权将由 ContextSelector 及其派生完成, 而不需要实现默认求值 (default_target).
  • 鉴于上一条的影响, 实现记录器 default_target 不再提供.
  • 鉴于 bound 参数的强制要求, 追加声明方法 ImplRecorder.pin, 实现签名类型 OrientFnDirectFn 将不再提供.
  • 鉴于 bound 辅助型上下文管理器的出现, prefix 被标记为弃用.
  • MessageSend.send_message 等实现签名 Fn 的方法名现已被改为仅包含谓词的形式, 如 MessageSend.send, 这将减少语义杂糅.
  • Message 派生为多个消息类型, 如 ChatMessage, NoticeMessage, PlatformMessage 等.
  • MetadataModified.modifies 的表述方式现已如下呈现, 因为引入 Context.endpoint, 这一切都变得更简单了:
Modify(
    bound: Selector | MetadataOf,
    field: str,
    action: str,
    past: Any,
    present: Any # use generic ?
)

设计中事项

  • 考虑在下一个版本中重构 avilla.core.exceptions, 现阶段其大部分设计都来自于 OneBot 的错误类型.
  • 考虑将 BaseProtocol 使用单个 ProtocolManifest 实例表述, 并使用一套 Credential 机制或是 kayaku 描述账号及其鉴权信息.
    • 该项设计仍处于极度早期的阶段.
login = (
    MatrixLogin("elaina", "https://matrix.org")\
        .auth_with_credential_file("session_credential.json")\
        .auth_with_token(...)\
        .auth_with_password(...)\
        .auth_interactive()
)

[Repo Manage] 项目管理相关: 添加 Issue/PR Template

如题, 这样能让问题解决的流程更完善.

  • 使用中遇到的问题
  • 发生了奇怪的异常
  • 协议实现行为不符合预期
  • 文档问题
  • (PR)新的 Protocol/Tools/etc. 要加进 Ecosystem 里面
  • 其他周边的问题

这个 issue 暂时得开着

Refactor: Selena

Relationship 上的交互式重构,基于最小功能单元(Minimal Function Unit)设计。

Avilla Config - 配置文件规范

  • 只要能获取到 Avilla 实例就能用上
  • 使用 HOCON 作为配置文件格式, 不打算支持 yml / toml / json / ini.
  • 能够配合 pydantic.BaseSetting 生成样例文件
  • and more....

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.