feat: 添加 Python→Go 全双工回调支持(call_go)

- 新增 WithHandlers 选项,通过反射将 Go 结构体方法暴露给 Python
- 新增 callback/callback_result 消息类型,支持 Python 在处理中回调 Go
- client 侧新增 readResult,内联处理 callback,复用同一连接避免死锁
- Python 侧新增 call_go[T]() 泛型调用,支持 dataclass 自动构造
- 注入 GOBRIDGE_WORKER_ID/WORKER_COUNT 环境变量,支持多 worker 初始化分工
- 新增示例演示 Go→Python→Go→Python 四层全双工链路
- Python 包版本升至 0.1.1
This commit is contained in:
2026-04-14 13:06:50 +08:00
parent 07e9239ac5
commit b390effd8e
8 changed files with 490 additions and 54 deletions

View File

@@ -32,6 +32,12 @@ func main() {
ctx := context.Background()
demoPool(ctx, pool)
demoServer(ctx, script)
}
func demoPool(ctx context.Context, pool gobridge.Pool) {
// ── 普通调用 ──────────────────────────────────────────────────────────
sum, err := gobridge.Invoke[int](ctx, pool, "add", 3, 4)
if err != nil {
@@ -139,3 +145,78 @@ func main() {
fmt.Printf(" %+v\n", u)
}
}
// goService 实现 Handler 接口,公开方法自动暴露给 Python 通过 call_go() 调用
type goService struct {
pool gobridge.Pool // 用于 EnrichName 内部再调 Python
}
func (s *goService) Multiply(ctx context.Context, a, b int) (int, error) {
return a * b, nil
}
func (s *goService) Log(msg string) {
fmt.Println("[Go Log]", msg)
}
// EnrichName 内部通过 Invoke 调用 Python 的 to_upper演示 Go→Python→Go→Python 四层链路
func (s *goService) EnrichName(ctx context.Context, name string) (string, error) {
upper, err := gobridge.Invoke[string](ctx, s.pool, "to_upper", name)
if err != nil {
return "", err
}
return "Hello, " + upper + "!", nil
}
func (s *goService) MakeUser(ctx context.Context, uid int) (User, error) {
return User{ID: uid, Name: fmt.Sprintf("user_%d", uid), Score: float64(uid) * 1.5}, nil
}
func demoServer(ctx context.Context, script string) {
fmt.Println("\n── Server 全双工示例 ─────────────────────────────────────────────")
svc := &goService{}
serv, err := gobridge.NewPool(script,
gobridge.WithWorkers(1),
gobridge.WithHandlers(svc),
)
if err != nil {
log.Fatal(err)
}
defer serv.Close()
svc.pool = serv // 注入 pool 供 EnrichName 内部调用
// ── 示例1Python 调用 Go Multiply ───────────────────────────────────────
result, err := gobridge.Invoke[int](ctx, serv, "compute_with_go_mul", 6, 7)
if err != nil {
log.Fatal(err)
}
fmt.Println("compute_with_go_mul(6, 7) =", result) // 42
// ── 示例2流式输出 + Go Log 回调 ────────────────────────────────────────
ch, err := gobridge.Invoke[chan int](ctx, serv, "squared_with_log", 4)
if err != nil {
log.Fatal(err)
}
fmt.Print("squared_with_log(4) =")
for v := range ch {
fmt.Print(" ", v)
}
fmt.Println() // 1 4 9 16
// ── 示例3Go→Python→Go→Python 四层全双工链路 ───────────────────────────
// full_chain("world") → call_go[str]("EnrichName","world") → Invoke to_upper("world") → "WORLD"
// ← "Hello, WORLD!" ← "Hello, WORLD!"
greeting, err := gobridge.Invoke[string](ctx, serv, "full_chain", "world")
if err != nil {
log.Fatal(err)
}
fmt.Println("full_chain(world) =", greeting) // Hello, WORLD!
// ── 示例4call_go[User] 将 Go 返回的 dict 自动构造为 dataclass ──────────
enriched, err := gobridge.Invoke[User](ctx, serv, "get_user_via_go", 12)
if err != nil {
log.Fatal(err)
}
fmt.Printf("get_user_via_go(12) = %+v\n", enriched) // {ID:12 Name:user_12 Score:18 Level:gold}
}