Skip to content

Commit d53e4e2

Browse files
committed
0.0.8
1 parent ecd5afe commit d53e4e2

19 files changed

Lines changed: 277 additions & 60 deletions

README.md

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,54 @@
1+
<div align="center">
2+
13
# Edoves
2-
A new abstract framework based on Cesloi
34

4-
## Example
5+
> _las su dres rin romilu, nann sune ri edar neru._
6+
7+
</div>
8+
9+
## 简介
10+
[![Licence](https://img.shields.io/github/license/ArcletProject/Edoves)](https://github.com/ArcletProject/Edoves/blob/main/LICENSE)
11+
[![PyPI](https://img.shields.io/pypi/v/arclet-edoves)](https://pypi.org/project/arclet-edoves)
12+
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/arclet-edoves)](https://www.python.org/)
13+
14+
Edoves 是 `Arclet Project` 基于同项目下的 `Cesloi`**第二代** 框架实现,
15+
16+
**该框架目前处于快速迭代状态, API 可能会发生 _剧烈_ 变化, 可能还不适合进行生产性的开发与运维**
17+
18+
## 特性
19+
+ 主要部分
20+
- [x] `InteractiveObject`: 对`Unity3d``GameObject`的简易模仿
21+
- [x] `Monomer`: 代表逻辑关系的IO
22+
- [x] `Module`: 负责处理事件的IO
23+
- [x] `ServerDocker`: 负责网络会话交互
24+
- [x] `Commander`: 基于 `Arclet Alconna` 的指令触发系统
25+
- [x] `Component`: IO的主要属性, 负责实际的数据管理与事件响应
26+
- [x] `Medium`: 传输事件信息的载体
27+
- [x] `Protocol`: 调度`Medium``IO`
28+
- [x] `Scene`: 对IO统一的生命周期管理
29+
30+
+ 实现支持
31+
- [x] `Edoves for mirai-api-http` : 对 [ `mirai-api-http` ](https://github.com/project-mirai/mirai-api-http) 的支持.
32+
- [ ] `Edoves for OneBot` : 对 [ `OneBot` ](https://github.com/botuniverse/onebot) 的协议实现.
33+
- [ ] `Edoves for go-cqhttp` : 对 [ `go-cqhttp` ](https://github.com/Mrs4s/go-cqhttp) 的扩展 API 支持.
34+
35+
## 样例
536

637
main.py:
738
```python
8-
from arclet.edoves.builtin.mah.messages import Source
39+
from arclet.edoves.builtin.mah.actions import Reply
940
from arclet.edoves.builtin.mah.module import MessageModule
10-
from arclet.edoves.builtin.commander import Commander
1141
from arclet.edoves.builtin.medium import Message
1242
from arclet.edoves.builtin.event.message import AllMessage
13-
from arclet.edoves.main import Edoves, Monomer
1443
from arclet.edoves.builtin.client import AioHttpClient
44+
from arclet.edoves.main import Edoves
45+
46+
47+
async def test_message_reaction(message: Message):
48+
if message.content.startswith("Hello World"):
49+
await Reply(message).execute()
50+
await message.set("I received 'Hello World'!").send()
51+
1552

1653
app = Edoves(
1754
debug=False,
@@ -23,26 +60,6 @@ app = Edoves(
2360
}
2461
)
2562
message_module = app.scene.activate_module(MessageModule)
26-
commander = app.scene.activate_module(Commander)
27-
28-
29-
@commander.command("print <content:str>")
30-
async def _(content: str, message: Message, sender: Monomer, bot: Edoves):
31-
await message.set("This is commander test").send()
32-
await message.set(f"I received content:{content} from {sender.metadata.name}").send()
33-
if content == "all_group":
34-
await message.set(f"{[k.metadata.name for k in bot.self.filter_parents('Group')]}").send()
35-
if content == "friend":
36-
await message.set(f"{[k.metadata.name for k in bot.self.filter_children('Friend')]}").send()
37-
38-
39-
async def test_message_reaction(message: Message):
40-
if message.content.startswith("Hello"):
41-
await message.purveyor.action("send_with")(
42-
message, reply=True, quote=message.content.find(Source).id, type=message.type)
43-
await message.set("I received 'Hello World!'").send()
44-
45-
4663
message_module.new_handler(AllMessage, test_message_reaction)
4764
app.run()
4865
```
@@ -61,3 +78,20 @@ class MessageModule(BaseModule):
6178

6279

6380
```
81+
82+
## 相关项目
83+
84+
> 这些项目都非常优秀, 我相信你听说过他们
85+
86+
+ [`Graia Framework`](https://github.com/GraiaProject)
87+
- [`Avilla`](https://github.com/GraiaProject/Avilla): `Graia Project` 的 "下一代" 框架实现
88+
- [ `Ariadne` ](https://github.com/GraiaProject/Ariadne): 继承了 `Graia Project``Application` 并进行了许多改进后产生的作品
89+
+ [ `Mamoe Technologies` ](https://github.com/mamoe):
90+
- [ `mirai` ](https://github.com/mamoe/mirai)
91+
- [ `mirai-api-http` ](https://github.com/project-mirai/mirai-api-http)
92+
93+
## 开源协议
94+
95+
Edoves 及其拓展 使用 MIT 作为开源协议.
96+
97+
但如果你若引用到了使用具有传染性开源协议(如 GPL/AGPL/LGPL 等)的项目, 请遵循相关规则.

arclet/edoves/builtin/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Edoves 内置组件"""

arclet/edoves/builtin/actions.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import inspect
2+
from typing import Optional
3+
from ..main.action import ExecutiveAction
4+
from .medium import Message
5+
6+
7+
class MessageAction(ExecutiveAction):
8+
data: Message
9+
action: str
10+
11+
def __init__(self, action: str, message: Message):
12+
super().__init__(message)
13+
self.action = action
14+
15+
async def execute(self):
16+
return await self.target.action(self.action)(
17+
self.data
18+
)
19+
20+
21+
class MessageSend(MessageAction):
22+
23+
def __init__(self, message: Optional[Message] = None):
24+
if not message:
25+
try:
26+
lcs = inspect.currentframe().f_back.f_back.f_locals
27+
for v in lcs.values():
28+
if isinstance(v, Message):
29+
message = v
30+
except AttributeError:
31+
raise ValueError
32+
else:
33+
if not message:
34+
raise ValueError
35+
super().__init__("send_with", message)
36+
37+
38+
class MessageSendDirectly(MessageSend):
39+
async def execute(self):
40+
return await self.target.action(self.action)(
41+
self.data, type=self.data.type
42+
)

arclet/edoves/builtin/client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class AioHttpClient(NetworkClient):
1313
def __init__(self):
1414
self.session = ClientSession()
1515

16+
async def close(self):
17+
await self.session.close()
18+
1619
@asynccontextmanager
1720
async def ensure_network(
1821
self,
@@ -22,11 +25,7 @@ async def ensure_network(
2225
timeout: float = 10.0,
2326
**kwargs: Any
2427
):
25-
# async with self.session.ws_connect(
26-
# url, timeout=timeout, **kwargs
27-
# ) as resp:
28-
# yield NetworkResponse(get_connection=lambda: resp)
29-
resp = await self.session.ws_connect(url, timeout=timeout, **kwargs).__aenter__()
28+
resp: ClientWebSocketResponse = await self.session.ws_connect(url, timeout=timeout, **kwargs).__aenter__()
3029
yield NetworkResponse(get_connection=lambda: resp)
3130

3231
@asynccontextmanager

arclet/edoves/builtin/combiner.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import TypeVar, Union, Type, Optional
2+
from inspect import isclass
3+
from ..main.behavior import BaseBehavior
4+
5+
TB = TypeVar("TB", bound=BaseBehavior)
6+
7+
8+
def combine_behaviors(*behavior: Union[Type[TB], TB]) -> Optional[Type[BaseBehavior]]:
9+
"""
10+
混合传入的行为器, 要求传入的所有行为器的父类与io属性类型一致
11+
12+
Behavior_B(BehaviorA){io: Monomer}, Behavior_C(BehaviorA){io: Monomer} # 通过
13+
14+
Behavior_B(BehaviorA){io: Monomer}, Behavior_C(BehaviorD){io: Monomer} # 不通过
15+
16+
Behavior_B(BehaviorA){io: Module}, Behavior_C(BehaviorA){io: Monomer} # 不通过
17+
18+
"""
19+
if not behavior:
20+
return
21+
base = behavior[0].__base__ if isclass(behavior[0]) else behavior[0].__class__.__base__
22+
io = behavior[0].__annotations__.get("io") if isclass(behavior[0]) else behavior[0].io.__class__
23+
for be in behavior:
24+
if isclass(be):
25+
if be.__base__ != base or be.__annotations__.get("io") != io:
26+
return
27+
else:
28+
if be.__class__.__base__ != base or be.io.__class__ != io:
29+
return
30+
31+
class CombineBehavior(*behavior):
32+
pass
33+
return CombineBehavior

arclet/edoves/builtin/commander.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ async def exec(self, params):
2525

2626
class CommanderData(ModuleMetaComponent):
2727
identifier = EDOVES_DEFAULT
28+
name = "Command of Edoves"
29+
description = "Based on Edoves and Arclet-Alconna"
2830

2931

3032
class CommandParsers(Component):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .message import AllMessage
2+
from .network import DockerOperate
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from ..actions import MessageSend
2+
from .chain import Source
3+
4+
MessageSend = MessageSend
5+
6+
7+
class Reply(MessageSend):
8+
async def execute(self):
9+
return await self.target.action(self.action)(
10+
self.data, reply=True, quote=self.data.content.find(Source).id
11+
)

arclet/edoves/builtin/mah/monomers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class MiraiMonoMetadata(MonoMetaComponent):
2828
joinTimestamp: Optional[int]
2929
lastSpeakTimestamp: Optional[int]
3030
mutetimeRemaining: Optional[int]
31-
group: Optional[str]
31+
group_id: Optional[str]
3232

3333
def update_data(self, name: str, value: Any):
3434
if not self.__dict__.get(name):
@@ -53,8 +53,8 @@ def __init__(
5353
self.get_component(MiraiMonoMetadata).update_data(k, v)
5454

5555
@property
56-
def group(self):
57-
return self.parents[self.metadata.group] if hasattr(self.metadata, "group") else None
56+
def current_group(self):
57+
return self.parents[self.metadata.group_id] if hasattr(self.metadata, "group_id") else None
5858

5959
def avatar(self):
6060
return f'https://q4.qlogo.cn/g?b=qq&nk={self.metadata.identifier}&s=140'

arclet/edoves/builtin/mah/protocol.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Dict, TYPE_CHECKING, List, Type
22

3+
from ...utilles import IOStatus
34
from .monomers import MiraiMonomer
45
from ..medium import Message
56
from .chain import MessageChain
@@ -17,6 +18,8 @@ class MAHProtocol(NetworkProtocol):
1718
async def medium_transport(self, action: str):
1819
server = list(self.storage.values())[-1]
1920
medium = await self.get_medium()
21+
if server.metadata.state in (IOStatus.CLOSED, IOStatus.CLOSE_WAIT):
22+
return
2023
if action.endswith("message"):
2124
rest = medium.get('rest')
2225
may_action = rest.get('type')
@@ -27,12 +30,12 @@ async def medium_transport(self, action: str):
2730
action = "sendFriendMessage"
2831
elif may_action.startswith("Group") and sender.compare("Member"):
2932
if sender.parents:
30-
target = sender.metadata.group
33+
target = sender.metadata.group_id
3134
action = "sendGroupMessage"
3235
else:
3336
if sender.prime_tag == "Member":
3437
if sender.parents:
35-
target = sender.metadata.group
38+
target = sender.metadata.group_id
3639
action = "sendGroupMessage"
3740
elif sender.prime_tag == "Friend":
3841
action = "sendFriendMessage"
@@ -111,19 +114,19 @@ async def parse_raw_data(self, data: Dict):
111114
group_data.get("name"),
112115
group_data.get("id"),
113116
**{
114-
"permission": sender_data.get("permission"),
117+
"permission": group_data.get("permission"),
115118
}
116119
)
117120
self.scene.monomers.setdefault(group.metadata.identifier, group)
118121
else:
119-
group.metadata.update_data("name", sender_data.get("name"))
120-
group.metadata.update_data("permission", sender_data.get("permission"))
122+
group.metadata.update_data("name", group_data.get("name"))
123+
group.metadata.update_data("permission", group_data.get("permission"))
121124

122125
group.set_child(self.scene.edoves.self)
123126
group.set_prime_tag("Group")
124127
if sender_id not in group.children:
125128
group.set_child(sender)
126-
sender.metadata.update_data("group", group.metadata.identifier)
129+
sender.metadata.update_data("group_id", group.metadata.identifier)
127130
else:
128131
if not (sender := self.scene.monomers.get(sender_id)):
129132
sender = MiraiMonomer(

0 commit comments

Comments
 (0)