1
0
forked from bot/app
LiteyukiBot/docs/en/dev/api/comm/channel.md
2024-08-29 14:19:39 +08:00

556 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: liteyuki.comm.channel
---
### *func* `set_channel()`
**Description**: 设置通道实例
**Arguments**:
> - name: 通道名称
> - channel: 通道实例
<details>
<summary> <b>Source code</b> </summary>
```python
def set_channel(name: str, channel: Channel):
"""
设置通道实例
Args:
name: 通道名称
channel: 通道实例
"""
if not isinstance(channel, Channel):
raise TypeError(f'channel_ must be an instance of Channel, {type(channel)} found')
if IS_MAIN_PROCESS:
_channel[name] = channel
else:
channel_deliver_passive_channel.send(('set_channel', {'name': name, 'channel_': channel}))
```
</details>
### *func* `set_channels()`
**Description**: 设置通道实例
**Arguments**:
> - channels: 通道名称
<details>
<summary> <b>Source code</b> </summary>
```python
def set_channels(channels: dict[str, Channel]):
"""
设置通道实例
Args:
channels: 通道名称
"""
for name, channel in channels.items():
set_channel(name, channel)
```
</details>
### *func* `get_channel() -> Channel`
**Description**: 获取通道实例
**Arguments**:
> - name: 通道名称
<details>
<summary> <b>Source code</b> </summary>
```python
def get_channel(name: str) -> Channel:
"""
获取通道实例
Args:
name: 通道名称
Returns:
"""
if IS_MAIN_PROCESS:
return _channel[name]
else:
recv_chan = Channel[Channel[Any]]('recv_chan')
channel_deliver_passive_channel.send(('get_channel', {'name': name, 'recv_chan': recv_chan}))
return recv_chan.receive()
```
</details>
### *func* `get_channels() -> dict[str, Channel]`
**Description**: 获取通道实例
<details>
<summary> <b>Source code</b> </summary>
```python
def get_channels() -> dict[str, Channel]:
"""
获取通道实例
Returns:
"""
if IS_MAIN_PROCESS:
return _channel
else:
recv_chan = Channel[dict[str, Channel[Any]]]('recv_chan')
channel_deliver_passive_channel.send(('get_channels', {'recv_chan': recv_chan}))
return recv_chan.receive()
```
</details>
### `@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'set_channel')`
### *func* `on_set_channel()`
<details>
<summary> <b>Source code</b> </summary>
```python
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'set_channel')
def on_set_channel(data: tuple[str, dict[str, Any]]):
name, channel = (data[1]['name'], data[1]['channel_'])
set_channel(name, channel)
```
</details>
### `@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channel')`
### *func* `on_get_channel()`
<details>
<summary> <b>Source code</b> </summary>
```python
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channel')
def on_get_channel(data: tuple[str, dict[str, Any]]):
name, recv_chan = (data[1]['name'], data[1]['recv_chan'])
recv_chan.send(get_channel(name))
```
</details>
### `@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channels')`
### *func* `on_get_channels()`
<details>
<summary> <b>Source code</b> </summary>
```python
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channels')
def on_get_channels(data: tuple[str, dict[str, Any]]):
recv_chan = data[1]['recv_chan']
recv_chan.send(get_channels())
```
</details>
### **class** `Channel(Generic[T])`
### *method* `__init__(self, _id: str = '', type_check: Optional[bool] = None)`
**Description**: 初始化通道
**Arguments**:
> - _id: 通道ID
> - type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
<details>
<summary> <b>Source code</b> </summary>
```python
def __init__(self, _id: str='', type_check: Optional[bool]=None):
"""
初始化通道
Args:
_id: 通道ID
type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
"""
self.conn_send, self.conn_recv = Pipe()
self._closed = False
self._on_main_receive_funcs: list[int] = []
self._on_sub_receive_funcs: list[int] = []
self.name: str = _id
self.is_main_receive_loop_running = False
self.is_sub_receive_loop_running = False
if type_check is None:
type_check = self._get_generic_type() is not None
elif type_check:
if self._get_generic_type() is None:
raise TypeError('Type hint is required for enforcing type check.')
self.type_check = type_check
```
</details>
### *method* `_get_generic_type(self) -> Optional[type]`
**Description**: 获取通道传递泛型类型
**Return**: Optional[type]: 泛型类型
<details>
<summary> <b>Source code</b> </summary>
```python
def _get_generic_type(self) -> Optional[type]:
"""
获取通道传递泛型类型
Returns:
Optional[type]: 泛型类型
"""
if hasattr(self, '__orig_class__'):
return get_args(self.__orig_class__)[0]
return None
```
</details>
### *method* `_validate_structure(self, data: Any, structure: type) -> bool`
**Description**: 验证数据结构
**Arguments**:
> - data: 数据
> - structure: 结构
**Return**: bool: 是否通过验证
<details>
<summary> <b>Source code</b> </summary>
```python
def _validate_structure(self, data: Any, structure: type) -> bool:
"""
验证数据结构
Args:
data: 数据
structure: 结构
Returns:
bool: 是否通过验证
"""
if isinstance(structure, type):
return isinstance(data, structure)
elif isinstance(structure, tuple):
if not isinstance(data, tuple) or len(data) != len(structure):
return False
return all((self._validate_structure(d, s) for d, s in zip(data, structure)))
elif isinstance(structure, list):
if not isinstance(data, list):
return False
return all((self._validate_structure(d, structure[0]) for d in data))
elif isinstance(structure, dict):
if not isinstance(data, dict):
return False
return all((k in data and self._validate_structure(data[k], structure[k]) for k in structure))
return False
```
</details>
### *method* `send(self, data: T)`
**Description**: 发送数据
**Arguments**:
> - data: 数据
<details>
<summary> <b>Source code</b> </summary>
```python
def send(self, data: T):
"""
发送数据
Args:
data: 数据
"""
if self.type_check:
_type = self._get_generic_type()
if _type is not None and (not self._validate_structure(data, _type)):
raise TypeError(f'Data must be an instance of {_type}, {type(data)} found')
if self._closed:
raise RuntimeError('Cannot send to a closed channel_')
self.conn_send.send(data)
```
</details>
### *method* `receive(self) -> T`
**Description**: 接收数据
<details>
<summary> <b>Source code</b> </summary>
```python
def receive(self) -> T:
"""
接收数据
Args:
"""
if self._closed:
raise RuntimeError('Cannot receive from a closed channel_')
while True:
data = self.conn_recv.recv()
return data
```
</details>
### *method* `close(self)`
**Description**: 关闭通道
<details>
<summary> <b>Source code</b> </summary>
```python
def close(self):
"""
关闭通道
"""
self._closed = True
self.conn_send.close()
self.conn_recv.close()
```
</details>
### *method* `on_receive(self, filter_func: Optional[FILTER_FUNC] = None) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]`
**Description**: 接收数据并执行函数
**Arguments**:
> - filter_func: 过滤函数为None则不过滤
**Return**: 装饰器,装饰一个函数在接收到数据后执行
<details>
<summary> <b>Source code</b> </summary>
```python
def on_receive(self, filter_func: Optional[FILTER_FUNC]=None) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]:
"""
接收数据并执行函数
Args:
filter_func: 过滤函数为None则不过滤
Returns:
装饰器,装饰一个函数在接收到数据后执行
"""
if not self.is_sub_receive_loop_running and (not IS_MAIN_PROCESS):
threading.Thread(target=self._start_sub_receive_loop, daemon=True).start()
if not self.is_main_receive_loop_running and IS_MAIN_PROCESS:
threading.Thread(target=self._start_main_receive_loop, daemon=True).start()
def decorator(func: Callable[[T], Any]) -> Callable[[T], Any]:
global _func_id
async def wrapper(data: T) -> Any:
if filter_func is not None:
if is_coroutine_callable(filter_func):
if not await filter_func(data):
return
elif not filter_func(data):
return
if is_coroutine_callable(func):
return await func(data)
else:
return func(data)
_callback_funcs[_func_id] = wrapper
if IS_MAIN_PROCESS:
self._on_main_receive_funcs.append(_func_id)
else:
self._on_sub_receive_funcs.append(_func_id)
_func_id += 1
return func
return decorator
```
</details>
### *method* `_run_on_main_receive_funcs(self, data: Any)`
**Description**: 运行接收函数
**Arguments**:
> - data: 数据
<details>
<summary> <b>Source code</b> </summary>
```python
def _run_on_main_receive_funcs(self, data: Any):
"""
运行接收函数
Args:
data: 数据
"""
for func_id in self._on_main_receive_funcs:
func = _callback_funcs[func_id]
run_coroutine(func(data))
```
</details>
### *method* `_run_on_sub_receive_funcs(self, data: Any)`
**Description**: 运行接收函数
**Arguments**:
> - data: 数据
<details>
<summary> <b>Source code</b> </summary>
```python
def _run_on_sub_receive_funcs(self, data: Any):
"""
运行接收函数
Args:
data: 数据
"""
for func_id in self._on_sub_receive_funcs:
func = _callback_funcs[func_id]
run_coroutine(func(data))
```
</details>
### *method* `_start_main_receive_loop(self)`
**Description**: 开始接收数据
<details>
<summary> <b>Source code</b> </summary>
```python
def _start_main_receive_loop(self):
"""
开始接收数据
"""
self.is_main_receive_loop_running = True
while not self._closed:
data = self.conn_recv.recv()
self._run_on_main_receive_funcs(data)
```
</details>
### *method* `_start_sub_receive_loop(self)`
**Description**: 开始接收数据
<details>
<summary> <b>Source code</b> </summary>
```python
def _start_sub_receive_loop(self):
"""
开始接收数据
"""
self.is_sub_receive_loop_running = True
while not self._closed:
data = self.conn_recv.recv()
self._run_on_sub_receive_funcs(data)
```
</details>
### ***var*** `SYNC_ON_RECEIVE_FUNC = Callable[[T], Any]`
- **Type**: `TypeAlias`
### ***var*** `ASYNC_ON_RECEIVE_FUNC = Callable[[T], Coroutine[Any, Any, Any]]`
- **Type**: `TypeAlias`
### ***var*** `ON_RECEIVE_FUNC = SYNC_ON_RECEIVE_FUNC | ASYNC_ON_RECEIVE_FUNC`
- **Type**: `TypeAlias`
### ***var*** `SYNC_FILTER_FUNC = Callable[[T], bool]`
- **Type**: `TypeAlias`
### ***var*** `ASYNC_FILTER_FUNC = Callable[[T], Coroutine[Any, Any, bool]]`
- **Type**: `TypeAlias`
### ***var*** `FILTER_FUNC = SYNC_FILTER_FUNC | ASYNC_FILTER_FUNC`
- **Type**: `TypeAlias`
### ***var*** `_func_id = 0`
- **Type**: `int`
### ***var*** `_channel = {}`
- **Type**: `dict[str, 'Channel']`
### ***var*** `_callback_funcs = {}`
- **Type**: `dict[int, ON_RECEIVE_FUNC]`
### ***var*** `active_channel = None`
- **Type**: `Optional['Channel']`
- **Description**: 子进程可用的主动和被动通道
### ***var*** `passive_channel = None`
- **Type**: `Optional['Channel']`
### ***var*** `publish_channel = Channel(_id='publish_channel')`
- **Type**: `Channel[tuple[str, dict[str, Any]]]`
### ***var*** `channel_deliver_active_channel = NO_DEFAULT`
- **Type**: `Channel[Channel[Any]]`
- **Description**: 通道传递通道,主进程创建单例,子进程初始化时实例化
### ***var*** `channel_deliver_passive_channel = NO_DEFAULT`
- **Type**: `Channel[tuple[str, dict[str, Any]]]`