runSession 建立一次连接,发 hello 帧,进入收发循环。任何错误(包括正常 EOF) 都返回 error,由上层 Run 触发重连。
(ctx context.Context, cfg Config)
| 14 | // runSession 建立一次连接,发 hello 帧,进入收发循环。任何错误(包括正常 EOF) |
| 15 | // 都返回 error,由上层 Run 触发重连。 |
| 16 | func runSession(ctx context.Context, cfg Config) error { |
| 17 | conn, err := cfg.Dialer(ctx) |
| 18 | if err != nil { |
| 19 | return fmt.Errorf("dial: %w", err) |
| 20 | } |
| 21 | defer conn.Close() |
| 22 | |
| 23 | // 整个 session 范围 ctx,stream 出错或 ctx 取消时统一收尾。 |
| 24 | sessionCtx, cancel := context.WithCancel(ctx) |
| 25 | defer cancel() |
| 26 | |
| 27 | client := nodev1.NewNodeAgentClient(conn) |
| 28 | stream, err := client.Session(sessionCtx) |
| 29 | if err != nil { |
| 30 | return fmt.Errorf("open session stream: %w", err) |
| 31 | } |
| 32 | |
| 33 | s := newSession(sessionCtx, cancel, cfg, stream) |
| 34 | |
| 35 | // 1) hello 帧 |
| 36 | helloBody, err := cfg.HelloProvider() |
| 37 | if err != nil { |
| 38 | return fmt.Errorf("HelloProvider: %w", err) |
| 39 | } |
| 40 | if err := s.sendRaw(&nodev1.NodeMessage{Event: "hello", Body: helloBody}); err != nil { |
| 41 | return fmt.Errorf("send hello: %w", err) |
| 42 | } |
| 43 | |
| 44 | if cfg.OnConnected != nil { |
| 45 | cfg.OnConnected(sessionCtx, s) |
| 46 | } |
| 47 | |
| 48 | // Dispatcher 选配 SetSender(Sender):用于流式 method 内部主动 push 帧。 |
| 49 | if setter, ok := cfg.Dispatcher.(interface{ SetSender(Sender) }); ok { |
| 50 | setter.SetSender(s) |
| 51 | } |
| 52 | |
| 53 | // 2) recv 循环(在当前 goroutine 跑),dispatch 派发到独立 goroutine。 |
| 54 | recvErr := s.recvLoop() |
| 55 | s.shutdown() |
| 56 | if recvErr != nil && !errors.Is(recvErr, io.EOF) && !errors.Is(recvErr, context.Canceled) { |
| 57 | return recvErr |
| 58 | } |
| 59 | if ctx.Err() != nil { |
| 60 | return ctx.Err() |
| 61 | } |
| 62 | if recvErr == nil { |
| 63 | // 不应发生(recvLoop 只在 Recv 出错或 ctx 取消时返回 nil 是 EOF 情形) |
| 64 | return errors.New("session ended") |
| 65 | } |
| 66 | return recvErr |
| 67 | } |
| 68 | |
| 69 | // session 是单次 Session 的状态: |
| 70 | // - inflight:reqID -> cancelFunc,用于响应 cancel_id; |
no test coverage detected