add first commit

This commit is contained in:
2026-07-21 15:43:39 +08:00
commit 482f8df508
19 changed files with 521 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
"""
Example Worker 插件 — 演示 @rpc_method + 显式模型绑定用法
本插件展示如何使用 chongming_worker 框架定义 RPC 端点。
核心工作流:
1. 编写 config/workers/example/*.toml 配置文件
2. 执行 uv run gen_models 生成 Pydantic 模型
3. 在 __init__.py 中用 @rpc_method 定义业务函数
4. 显式导入模型并绑定到对应端点(替代 auto_bind_models)
关键约定:
- 模型命名: <Operation><Method>{Request|Response}
(如 AddGetRequest, AddGetResponse 由 gen_models 自动生成)
- 装饰器 subject 中的操作名 → 模型前缀(驼峰)
example.add → Add, example.subtract → Subtract
"""
import modelvault
from pathlib import Path
from chongming_worker import auto_bind_models
from chongming_worker.runtime import create_workers as _create_workers
from .router import *
auto_bind_models("example")
# ============================================================
# 工厂函数 — 供 app lifespan 动态加载
# ============================================================
# 框架通过 __import__ + getattr 获取此函数,
# 然后调用 create_workers(session, config, count, worker_manager=worker_manager)。
# 详见 src/chongming/app/__init__.py 的 lifespan。
async def create_workers(session, config, count=1, worker_manager=None):
"""插件入口 — 委托给 chongming_worker 运行时创建 Worker 协程"""
from .global_var import set_global_var
db_path = Path(config.get("data_dir", "./data")) / "example.modelvault"
db_path.parent.mkdir(parents=True, exist_ok=True)
db = await modelvault.AsyncDatabase.open(str(db_path)) # type: ignore
set_global_var("db", db)
return _create_workers(session, config, count, worker_manager)
async def cleanup(worker_item: str):
print(f"{worker_item}关闭")
pass
+24
View File
@@ -0,0 +1,24 @@
import sys
from typing import Any, Callable, Awaitable, List
import modelvault
# 初始定义(可以保留 db 作为示例)
db: modelvault.AsyncDatabase | None = None # type: ignore
def set_global_var(name: str, value: Any) -> None:
"""
设置当前模块的全局变量。
Args:
name: 变量名(字符串)
value: 任意值
"""
globals()[name] = value
# 但这样会污染导出列表,不推荐自动添加。
__all__ = [
"db",
"set_global_var",
]
+32
View File
@@ -0,0 +1,32 @@
"""
模型导出 — example
自动生成,请勿手动修改
"""
from .pydantic import AddGetRequest
from .pydantic import AddGetResponse
from .pydantic import AddPostRequest
from .pydantic import AddPostResponse
from .pydantic import CountGetResponse
from .pydantic import DivideGetRequest
from .pydantic import DivideGetResponse
from .pydantic import ExampleResponse
from .pydantic import MultiplyGetRequest
from .pydantic import MultiplyGetResponse
from .pydantic import SubtractGetRequest
from .pydantic import SubtractGetResponse
__all__ = [
"AddGetRequest",
"AddGetResponse",
"AddPostRequest",
"AddPostResponse",
"CountGetResponse",
"DivideGetRequest",
"DivideGetResponse",
"ExampleResponse",
"MultiplyGetRequest",
"MultiplyGetResponse",
"SubtractGetRequest",
"SubtractGetResponse",
]
+14
View File
@@ -0,0 +1,14 @@
# src/plugins/example/models/counter.py
from pydantic import BaseModel
import modelvault
class Counter(BaseModel):
# 主键字段
__modelvault_primary_key__ = "name"
# 唯一索引
__modelvault_indexes__ = [
modelvault.models.unique("name"),
]
name: str # 计数器名称(例如 "visits")
value: int = 0
+74
View File
@@ -0,0 +1,74 @@
"""
自动生成的 Pydantic 模型 — example
来源: config/workers/example/
"""
from __future__ import annotations
from typing import Any, Optional
from pydantic import BaseModel, Field
class AddGetRequest(BaseModel):
"""Add two numbers — 请求体"""
a: float = Field(...)
b: float = Field(...)
class AddGetResponse(BaseModel):
"""Add two numbers — 响应体"""
result: float = Field(...)
operation: str = Field(default='add')
timestamp: Optional[float] = Field(default=0.0)
class AddPostRequest(BaseModel):
"""Add two numbers (POST) — 请求体"""
a: float = Field(...)
b: float = Field(...)
class AddPostResponse(BaseModel):
"""Add two numbers (POST) — 响应体"""
result: float = Field(...)
operation: str = Field(default='add')
timestamp: Optional[float] = Field(default=0.0)
class CountGetResponse(BaseModel):
"""Get visit count and increment — 响应体"""
name: str = Field(...)
value: int = Field(...)
class DivideGetRequest(BaseModel):
"""Divide two numbers — 请求体"""
a: float = Field(...)
b: float = Field(...)
class DivideGetResponse(BaseModel):
"""Divide two numbers — 响应体"""
result: Optional[float] = Field(default=0.0)
operation: str = Field(default='divide')
timestamp: Optional[float] = Field(default=0.0)
error: Optional[str] = Field(default='')
class MultiplyGetRequest(BaseModel):
"""Multiply two numbers — 请求体"""
a: float = Field(...)
b: float = Field(...)
class MultiplyGetResponse(BaseModel):
"""Multiply two numbers — 响应体"""
result: float = Field(...)
operation: str = Field(default='multiply')
timestamp: Optional[float] = Field(default=0.0)
class SubtractGetRequest(BaseModel):
"""Subtract two numbers — 请求体"""
a: float = Field(...)
b: float = Field(...)
class SubtractGetResponse(BaseModel):
"""Subtract two numbers — 响应体"""
result: float = Field(...)
operation: str = Field(default='subtract')
timestamp: Optional[float] = Field(default=0.0)
# 所有响应模型的联合类型
ExampleResponse = SubtractGetResponse | CountGetResponse | MultiplyGetResponse | AddPostResponse | AddGetResponse | DivideGetResponse
+14
View File
@@ -0,0 +1,14 @@
from .add import add, add_post
from .subtract import subtract
from .multiply import multiply
from .divide import divide
from .count import count_get
__all__ = [
"add",
"add_post",
"subtract",
"multiply",
"divide",
"count_get"
]
+52
View File
@@ -0,0 +1,52 @@
import time
import zenoh
from chongming_worker import rpc_method
from chongming_request import Client
from ..models.pydantic import (
AddGetRequest,
AddGetResponse,
AddPostRequest,
AddPostResponse
)
@rpc_method(
subject="example.add",
method="GET",
summary="Add two numbers via GET",
response_model=AddGetResponse,
)
async def add(add_get_request:AddGetRequest) -> AddGetResponse:
"""加法运算(GET)— 通过查询参数传入 a、b,返回它们的和"""
return AddGetResponse(
result=add_get_request.a + add_get_request.b,
operation="add",
timestamp=time.time()
)
@rpc_method(
subject="example.add",
method="POST",
summary="Add two numbers via POST",
response_model=AddPostResponse,
)
async def add_post(add_post_request: AddPostRequest, session: zenoh.Session) -> AddPostResponse:
"""加法运算(POST)— 通过 JSON Body 传入 a、b,返回它们的和"""
async with Client(session=session) as client:
add_result = await client.call(
worker_type="example",
subject="example.add",
payload={
"a":add_post_request.a,
"b":add_post_request.b
},
method="GET"
)
print(add_result)
return AddPostResponse(
result=add_post_request.a + add_post_request.b,
operation="add",
timestamp=time.time(),
)
+33
View File
@@ -0,0 +1,33 @@
import modelvault
from chongming_worker import rpc_method
from ..models.pydantic import CountGetResponse
from ..models.counter import Counter
@rpc_method(
subject="example.count",
method="GET",
summary="Increment and get counter value",
response_model=CountGetResponse, # 需要定义 CountResponse
)
async def count_get() -> CountGetResponse:
from ..global_var import db
# 确保数据库已初始化(如果未初始化,则同步初始化,但这里假设已就绪)
if db is None:
raise RuntimeError("Database not initialized")
counters = modelvault.models.async_collection(db, Counter) # type: ignore
async with db.transaction():
counter = await counters.get("visits")
if counter is None:
counter = Counter(name="visits", value=0)
await counters.insert(counter)
else:
new_value = counter.value + 1
await counters.update("visits", {"value": new_value})
counter.value = new_value # 更新本地对象以便返回
return CountGetResponse(name=counter.name, value=counter.value) # type: ignore
+29
View File
@@ -0,0 +1,29 @@
import time
from chongming_worker import rpc_method
from ..models.pydantic import (
DivideGetResponse,
DivideGetRequest,
)
@rpc_method(
subject="example.divide",
method="GET",
summary="Divide two numbers",
response_model=DivideGetResponse,
)
async def divide(divide_get_request: DivideGetRequest) -> DivideGetResponse:
"""除法运算:a / b(b 不能为 0)"""
if divide_get_request.b == 0:
return DivideGetResponse(
error="除数不能为零",
operation="divide",
result=0.0,
timestamp=time.time(),
)
return DivideGetResponse(
result=divide_get_request.a / divide_get_request.b,
operation="divide",
timestamp=time.time(),
)
+22
View File
@@ -0,0 +1,22 @@
import time
from chongming_worker import rpc_method
from ..models.pydantic import (
MultiplyGetRequest,
MultiplyGetResponse,
)
@rpc_method(
subject="example.multiply",
method="GET",
summary="Multiply two numbers",
response_model=MultiplyGetResponse,
)
async def multiply(multiply_get_request=MultiplyGetRequest) -> MultiplyGetResponse:
"""乘法运算:a * b"""
return MultiplyGetResponse(
result=multiply_get_request.a * multiply_get_request.b,
operation="multiply",
timestamp=time.time(),
)
+22
View File
@@ -0,0 +1,22 @@
import time
from chongming_worker import rpc_method
from ..models.pydantic import (
SubtractGetResponse,
SubtractGetRequest,
)
@rpc_method(
subject="example.subtract",
method="GET",
summary="Subtract two numbers",
response_model=SubtractGetResponse,
)
async def subtract(subtract_get_request: SubtractGetRequest) -> SubtractGetResponse:
"""减法运算:a - b"""
return SubtractGetResponse(
result=subtract_get_request.a - subtract_get_request.b,
operation="subtract",
timestamp=time.time(),
)