github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/rpc/client.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:45</date> 10 //</624342663759400960> 11 12 13 package rpc 14 15 import ( 16 "bytes" 17 "container/list" 18 "context" 19 "encoding/json" 20 "errors" 21 "fmt" 22 "net" 23 "net/url" 24 "os" 25 "reflect" 26 "strconv" 27 "strings" 28 "sync" 29 "sync/atomic" 30 "time" 31 32 "github.com/ethereum/go-ethereum/log" 33 ) 34 35 var ( 36 ErrClientQuit = errors.New("client is closed") 37 ErrNoResult = errors.New("no result in JSON-RPC response") 38 ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow") 39 ) 40 41 const ( 42 //超时 43 tcpKeepAliveInterval = 30 * time.Second 44 defaultDialTimeout = 10 * time.Second //如果上下文没有截止时间,则在拨号时使用 45 defaultWriteTimeout = 10 * time.Second //如果上下文没有截止时间,则用于调用 46 subscribeTimeout = 5 * time.Second //总超时eth_subscribe,rpc_模块调用 47 ) 48 49 const ( 50 //当订阅服务器无法跟上时,将删除订阅。 51 // 52 //这可以通过为通道提供足够大的缓冲区来解决, 53 //但这在文件中可能不方便也很难解释。另一个问题是 54 //缓冲通道是指即使不需要缓冲区,缓冲区也是静态的。 55 //大部分时间。 56 // 57 //这里采用的方法是维护每个订阅的链表缓冲区 58 //按需缩小。如果缓冲区达到以下大小,则订阅为 59 //下降。 60 maxClientSubscriptionBuffer = 20000 61 ) 62 63 //batchelem是批处理请求中的元素。 64 type BatchElem struct { 65 Method string 66 Args []interface{} 67 //结果未显示在此字段中。结果必须设置为 68 //所需类型的非零指针值,否则响应将为 69 //丢弃的。 70 Result interface{} 71 //如果服务器返回此请求的错误,或如果 72 //解组为结果失败。未设置I/O错误。 73 Error error 74 } 75 76 //此类型的值可以是JSON-RPC请求、通知、成功响应或 77 //错误响应。它是哪一个取决于田地。 78 type jsonrpcMessage struct { 79 Version string `json:"jsonrpc"` 80 ID json.RawMessage `json:"id,omitempty"` 81 Method string `json:"method,omitempty"` 82 Params json.RawMessage `json:"params,omitempty"` 83 Error *jsonError `json:"error,omitempty"` 84 Result json.RawMessage `json:"result,omitempty"` 85 } 86 87 func (msg *jsonrpcMessage) isNotification() bool { 88 return msg.ID == nil && msg.Method != "" 89 } 90 91 func (msg *jsonrpcMessage) isResponse() bool { 92 return msg.hasValidID() && msg.Method == "" && len(msg.Params) == 0 93 } 94 95 func (msg *jsonrpcMessage) hasValidID() bool { 96 return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' 97 } 98 99 func (msg *jsonrpcMessage) String() string { 100 b, _ := json.Marshal(msg) 101 return string(b) 102 } 103 104 //客户端表示到RPC服务器的连接。 105 type Client struct { 106 idCounter uint32 107 connectFunc func(ctx context.Context) (net.Conn, error) 108 isHTTP bool 109 110 //WRITECONN只能安全地访问外部调度,使用 111 //写入锁定保持。通过发送 112 //请求操作并通过发送发送完成释放。 113 writeConn net.Conn 114 115 //派遣 116 close chan struct{} 117 didQuit chan struct{} //客户端退出时关闭 118 reconnected chan net.Conn //写入/重新连接发送新连接的位置 119 readErr chan error //读取错误 120 readResp chan []*jsonrpcMessage //读取的有效消息 121 requestOp chan *requestOp //用于注册响应ID 122 sendDone chan error //信号写入完成,释放写入锁定 123 respWait map[string]*requestOp //主动请求 124 subs map[string]*ClientSubscription //活动订阅 125 } 126 127 type requestOp struct { 128 ids []json.RawMessage 129 err error 130 resp chan *jsonrpcMessage //接收最多len(id)响应 131 sub *ClientSubscription //仅为ethsubscribe请求设置 132 } 133 134 func (op *requestOp) wait(ctx context.Context) (*jsonrpcMessage, error) { 135 select { 136 case <-ctx.Done(): 137 return nil, ctx.Err() 138 case resp := <-op.resp: 139 return resp, op.err 140 } 141 } 142 143 //拨号为给定的URL创建新的客户端。 144 // 145 //当前支持的URL方案有“http”、“https”、“ws”和“wss”。如果RAWURL是 146 //没有URL方案的文件名,使用Unix建立本地套接字连接 147 //支持的平台上的域套接字和Windows上的命名管道。如果你想 148 //配置传输选项,使用dialHTTP、dialWebSocket或dialIPC。 149 // 150 //对于WebSocket连接,原点设置为本地主机名。 151 // 152 //如果连接丢失,客户端将自动重新连接。 153 func Dial(rawurl string) (*Client, error) { 154 return DialContext(context.Background(), rawurl) 155 } 156 157 //DialContext创建一个新的RPC客户端,就像Dial一样。 158 // 159 //上下文用于取消或超时初始连接建立。它确实 160 //不影响与客户的后续交互。 161 func DialContext(ctx context.Context, rawurl string) (*Client, error) { 162 u, err := url.Parse(rawurl) 163 if err != nil { 164 return nil, err 165 } 166 switch u.Scheme { 167 case "http", "https": 168 return DialHTTP(rawurl) 169 case "ws", "wss": 170 return DialWebsocket(ctx, rawurl, "") 171 case "stdio": 172 return DialStdIO(ctx) 173 case "": 174 return DialIPC(ctx, rawurl) 175 default: 176 return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme) 177 } 178 } 179 180 type StdIOConn struct{} 181 182 func (io StdIOConn) Read(b []byte) (n int, err error) { 183 return os.Stdin.Read(b) 184 } 185 186 func (io StdIOConn) Write(b []byte) (n int, err error) { 187 return os.Stdout.Write(b) 188 } 189 190 func (io StdIOConn) Close() error { 191 return nil 192 } 193 194 func (io StdIOConn) LocalAddr() net.Addr { 195 return &net.UnixAddr{Name: "stdio", Net: "stdio"} 196 } 197 198 func (io StdIOConn) RemoteAddr() net.Addr { 199 return &net.UnixAddr{Name: "stdio", Net: "stdio"} 200 } 201 202 func (io StdIOConn) SetDeadline(t time.Time) error { 203 return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} 204 } 205 206 func (io StdIOConn) SetReadDeadline(t time.Time) error { 207 return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} 208 } 209 210 func (io StdIOConn) SetWriteDeadline(t time.Time) error { 211 return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} 212 } 213 func DialStdIO(ctx context.Context) (*Client, error) { 214 return newClient(ctx, func(_ context.Context) (net.Conn, error) { 215 return StdIOConn{}, nil 216 }) 217 } 218 219 func newClient(initctx context.Context, connectFunc func(context.Context) (net.Conn, error)) (*Client, error) { 220 conn, err := connectFunc(initctx) 221 if err != nil { 222 return nil, err 223 } 224 _, isHTTP := conn.(*httpConn) 225 c := &Client{ 226 writeConn: conn, 227 isHTTP: isHTTP, 228 connectFunc: connectFunc, 229 close: make(chan struct{}), 230 didQuit: make(chan struct{}), 231 reconnected: make(chan net.Conn), 232 readErr: make(chan error), 233 readResp: make(chan []*jsonrpcMessage), 234 requestOp: make(chan *requestOp), 235 sendDone: make(chan error, 1), 236 respWait: make(map[string]*requestOp), 237 subs: make(map[string]*ClientSubscription), 238 } 239 if !isHTTP { 240 go c.dispatch(conn) 241 } 242 return c, nil 243 } 244 245 func (c *Client) nextID() json.RawMessage { 246 id := atomic.AddUint32(&c.idCounter, 1) 247 return []byte(strconv.FormatUint(uint64(id), 10)) 248 } 249 250 //supportedmodules调用rpc_modules方法,检索 251 //服务器上可用的API。 252 func (c *Client) SupportedModules() (map[string]string, error) { 253 var result map[string]string 254 ctx, cancel := context.WithTimeout(context.Background(), subscribeTimeout) 255 defer cancel() 256 err := c.CallContext(ctx, &result, "rpc_modules") 257 return result, err 258 } 259 260 //CLOSE关闭客户机,中止任何飞行中的请求。 261 func (c *Client) Close() { 262 if c.isHTTP { 263 return 264 } 265 select { 266 case c.close <- struct{}{}: 267 <-c.didQuit 268 case <-c.didQuit: 269 } 270 } 271 272 //调用使用给定的参数执行JSON-RPC调用,并将其解组为 273 //如果没有发生错误,则返回结果。 274 // 275 //结果必须是一个指针,以便包JSON可以解组到其中。你 276 //也可以传递nil,在这种情况下,结果将被忽略。 277 func (c *Client) Call(result interface{}, method string, args ...interface{}) error { 278 ctx := context.Background() 279 return c.CallContext(ctx, result, method, args...) 280 } 281 282 //callContext使用给定的参数执行JSON-RPC调用。如果上下文是 283 //在成功返回调用之前取消,callContext立即返回。 284 // 285 //结果必须是一个指针,以便包JSON可以解组到其中。你 286 //也可以传递nil,在这种情况下,结果将被忽略。 287 func (c *Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { 288 msg, err := c.newMessage(method, args...) 289 if err != nil { 290 return err 291 } 292 op := &requestOp{ids: []json.RawMessage{msg.ID}, resp: make(chan *jsonrpcMessage, 1)} 293 294 if c.isHTTP { 295 err = c.sendHTTP(ctx, op, msg) 296 } else { 297 err = c.send(ctx, op, msg) 298 } 299 if err != nil { 300 return err 301 } 302 303 //调度已接受请求,并将在退出时关闭通道。 304 switch resp, err := op.wait(ctx); { 305 case err != nil: 306 return err 307 case resp.Error != nil: 308 return resp.Error 309 case len(resp.Result) == 0: 310 return ErrNoResult 311 default: 312 return json.Unmarshal(resp.Result, &result) 313 } 314 } 315 316 //批处理调用将所有给定的请求作为单个批处理发送,并等待服务器 317 //为所有人返回响应。 318 // 319 //与调用不同,批调用只返回I/O错误。任何特定于的错误 320 //通过相应批处理元素的错误字段报告请求。 321 // 322 //注意,批处理调用不能在服务器端以原子方式执行。 323 func (c *Client) BatchCall(b []BatchElem) error { 324 ctx := context.Background() 325 return c.BatchCallContext(ctx, b) 326 } 327 328 //批处理调用将所有给定的请求作为单个批处理发送,并等待服务器 329 //为所有人返回响应。等待持续时间由 330 //上下文的最后期限。 331 // 332 //与callContext不同,batchcallContext只返回已发生的错误 333 //发送请求时。任何特定于请求的错误都会通过 334 //对应批处理元素的错误字段。 335 // 336 //注意,批处理调用不能在服务器端以原子方式执行。 337 func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { 338 msgs := make([]*jsonrpcMessage, len(b)) 339 op := &requestOp{ 340 ids: make([]json.RawMessage, len(b)), 341 resp: make(chan *jsonrpcMessage, len(b)), 342 } 343 for i, elem := range b { 344 msg, err := c.newMessage(elem.Method, elem.Args...) 345 if err != nil { 346 return err 347 } 348 msgs[i] = msg 349 op.ids[i] = msg.ID 350 } 351 352 var err error 353 if c.isHTTP { 354 err = c.sendBatchHTTP(ctx, op, msgs) 355 } else { 356 err = c.send(ctx, op, msgs) 357 } 358 359 //等待所有响应返回。 360 for n := 0; n < len(b) && err == nil; n++ { 361 var resp *jsonrpcMessage 362 resp, err = op.wait(ctx) 363 if err != nil { 364 break 365 } 366 //找到与此响应对应的元素。 367 //由于调度,元素被保证存在 368 //只向我们的频道发送有效的ID。 369 var elem *BatchElem 370 for i := range msgs { 371 if bytes.Equal(msgs[i].ID, resp.ID) { 372 elem = &b[i] 373 break 374 } 375 } 376 if resp.Error != nil { 377 elem.Error = resp.Error 378 continue 379 } 380 if len(resp.Result) == 0 { 381 elem.Error = ErrNoResult 382 continue 383 } 384 elem.Error = json.Unmarshal(resp.Result, elem.Result) 385 } 386 return err 387 } 388 389 //ethsubscribe在“eth”名称空间下注册一个订阅。 390 func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) { 391 return c.Subscribe(ctx, "eth", channel, args...) 392 } 393 394 //shhsubscribe在“shh”名称空间下注册一个订阅。 395 func (c *Client) ShhSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) { 396 return c.Subscribe(ctx, "shh", channel, args...) 397 } 398 399 //subscribe使用给定的参数调用“<namespace>\u subscribe”方法, 400 //注册订阅。订阅的服务器通知为 401 //发送到给定的频道。通道的元素类型必须与 402 //订阅返回的内容类型应为。 403 // 404 //context参数取消设置订阅但没有的RPC请求 405 //订阅返回后对订阅的影响。 406 // 407 //缓慢的订户最终将被删除。客户端缓冲区最多8000个通知 408 //在考虑用户死亡之前。订阅错误通道将接收 409 //errSubscriptionQueueOverflow。在通道上使用足够大的缓冲区或确保 410 //通道通常至少有一个读卡器来防止这个问题。 411 func (c *Client) Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*ClientSubscription, error) { 412 //首先检查通道类型。 413 chanVal := reflect.ValueOf(channel) 414 if chanVal.Kind() != reflect.Chan || chanVal.Type().ChanDir()&reflect.SendDir == 0 { 415 panic("first argument to Subscribe must be a writable channel") 416 } 417 if chanVal.IsNil() { 418 panic("channel given to Subscribe must not be nil") 419 } 420 if c.isHTTP { 421 return nil, ErrNotificationsUnsupported 422 } 423 424 msg, err := c.newMessage(namespace+subscribeMethodSuffix, args...) 425 if err != nil { 426 return nil, err 427 } 428 op := &requestOp{ 429 ids: []json.RawMessage{msg.ID}, 430 resp: make(chan *jsonrpcMessage), 431 sub: newClientSubscription(c, namespace, chanVal), 432 } 433 434 //发送订阅请求。 435 //响应的到达和有效性在Sub.Quit上发出信号。 436 if err := c.send(ctx, op, msg); err != nil { 437 return nil, err 438 } 439 if _, err := op.wait(ctx); err != nil { 440 return nil, err 441 } 442 return op.sub, nil 443 } 444 445 func (c *Client) newMessage(method string, paramsIn ...interface{}) (*jsonrpcMessage, error) { 446 params, err := json.Marshal(paramsIn) 447 if err != nil { 448 return nil, err 449 } 450 return &jsonrpcMessage{Version: "2.0", ID: c.nextID(), Method: method, Params: params}, nil 451 } 452 453 //发送寄存器op和调度循环,然后在连接上发送msg。 454 //如果发送失败,则注销OP。 455 func (c *Client) send(ctx context.Context, op *requestOp, msg interface{}) error { 456 select { 457 case c.requestOp <- op: 458 log.Trace("", "msg", log.Lazy{Fn: func() string { 459 return fmt.Sprint("sending ", msg) 460 }}) 461 err := c.write(ctx, msg) 462 c.sendDone <- err 463 return err 464 case <-ctx.Done(): 465 //如果客户端过载或无法跟上,就会发生这种情况。 466 //订阅通知。 467 return ctx.Err() 468 case <-c.didQuit: 469 return ErrClientQuit 470 } 471 } 472 473 func (c *Client) write(ctx context.Context, msg interface{}) error { 474 deadline, ok := ctx.Deadline() 475 if !ok { 476 deadline = time.Now().Add(defaultWriteTimeout) 477 } 478 //上一次写入失败。尝试建立新连接。 479 if c.writeConn == nil { 480 if err := c.reconnect(ctx); err != nil { 481 return err 482 } 483 } 484 c.writeConn.SetWriteDeadline(deadline) 485 err := json.NewEncoder(c.writeConn).Encode(msg) 486 if err != nil { 487 c.writeConn = nil 488 } 489 return err 490 } 491 492 func (c *Client) reconnect(ctx context.Context) error { 493 newconn, err := c.connectFunc(ctx) 494 if err != nil { 495 log.Trace(fmt.Sprintf("reconnect failed: %v", err)) 496 return err 497 } 498 select { 499 case c.reconnected <- newconn: 500 c.writeConn = newconn 501 return nil 502 case <-c.didQuit: 503 newconn.Close() 504 return ErrClientQuit 505 } 506 } 507 508 //调度是客户机的主循环。 509 //它向等待调用和批调用发送读取消息 510 //注册订阅的订阅通知。 511 func (c *Client) dispatch(conn net.Conn) { 512 //生成初始读取循环。 513 go c.read(conn) 514 515 var ( 516 lastOp *requestOp //跟踪上次发送操作 517 requestOpLock = c.requestOp //保持发送锁时为零 518 reading = true //如果为真,则运行读取循环 519 ) 520 defer close(c.didQuit) 521 defer func() { 522 c.closeRequestOps(ErrClientQuit) 523 conn.Close() 524 if reading { 525 //清空读取通道,直到读取结束。 526 for { 527 select { 528 case <-c.readResp: 529 case <-c.readErr: 530 return 531 } 532 } 533 } 534 }() 535 536 for { 537 select { 538 case <-c.close: 539 return 540 541 //读取路径。 542 case batch := <-c.readResp: 543 for _, msg := range batch { 544 switch { 545 case msg.isNotification(): 546 log.Trace("", "msg", log.Lazy{Fn: func() string { 547 return fmt.Sprint("<-readResp: notification ", msg) 548 }}) 549 c.handleNotification(msg) 550 case msg.isResponse(): 551 log.Trace("", "msg", log.Lazy{Fn: func() string { 552 return fmt.Sprint("<-readResp: response ", msg) 553 }}) 554 c.handleResponse(msg) 555 default: 556 log.Debug("", "msg", log.Lazy{Fn: func() string { 557 return fmt.Sprint("<-readResp: dropping weird message", msg) 558 }}) 559 //托多:也许接近 560 } 561 } 562 563 case err := <-c.readErr: 564 log.Debug("<-readErr", "err", err) 565 c.closeRequestOps(err) 566 conn.Close() 567 reading = false 568 569 case newconn := <-c.reconnected: 570 log.Debug("<-reconnected", "reading", reading, "remote", conn.RemoteAddr()) 571 if reading { 572 //等待上一个读取循环退出。这是一个罕见的病例。 573 conn.Close() 574 <-c.readErr 575 } 576 go c.read(newconn) 577 reading = true 578 conn = newconn 579 580 //发送路径。 581 case op := <-requestOpLock: 582 //停止侦听进一步的发送操作,直到当前操作完成。 583 requestOpLock = nil 584 lastOp = op 585 for _, id := range op.ids { 586 c.respWait[string(id)] = op 587 } 588 589 case err := <-c.sendDone: 590 if err != nil { 591 //删除上次发送的响应处理程序。我们把它们移到这里 592 //因为错误已经在call或batchcall中处理。当 593 //读取循环停止,它将发出所有其他当前操作的信号。 594 for _, id := range lastOp.ids { 595 delete(c.respWait, string(id)) 596 } 597 } 598 //再次收听发送操作。 599 requestOpLock = c.requestOp 600 lastOp = nil 601 } 602 } 603 } 604 605 //closerequestops取消阻止挂起的发送操作和活动订阅。 606 func (c *Client) closeRequestOps(err error) { 607 didClose := make(map[*requestOp]bool) 608 609 for id, op := range c.respWait { 610 //删除op,以便以后的调用不会再次关闭op.resp。 611 delete(c.respWait, id) 612 613 if !didClose[op] { 614 op.err = err 615 close(op.resp) 616 didClose[op] = true 617 } 618 } 619 for id, sub := range c.subs { 620 delete(c.subs, id) 621 sub.quitWithError(err, false) 622 } 623 } 624 625 func (c *Client) handleNotification(msg *jsonrpcMessage) { 626 if !strings.HasSuffix(msg.Method, notificationMethodSuffix) { 627 log.Debug("dropping non-subscription message", "msg", msg) 628 return 629 } 630 var subResult struct { 631 ID string `json:"subscription"` 632 Result json.RawMessage `json:"result"` 633 } 634 if err := json.Unmarshal(msg.Params, &subResult); err != nil { 635 log.Debug("dropping invalid subscription message", "msg", msg) 636 return 637 } 638 if c.subs[subResult.ID] != nil { 639 c.subs[subResult.ID].deliver(subResult.Result) 640 } 641 } 642 643 func (c *Client) handleResponse(msg *jsonrpcMessage) { 644 op := c.respWait[string(msg.ID)] 645 if op == nil { 646 log.Debug("unsolicited response", "msg", msg) 647 return 648 } 649 delete(c.respWait, string(msg.ID)) 650 //对于正常响应,只需将响应转发到call/batchcall。 651 if op.sub == nil { 652 op.resp <- msg 653 return 654 } 655 //对于订阅响应,如果服务器 656 //表示成功。ethsubscribe在任何情况下都可以通过 657 //Op.Resp频道。 658 defer close(op.resp) 659 if msg.Error != nil { 660 op.err = msg.Error 661 return 662 } 663 if op.err = json.Unmarshal(msg.Result, &op.sub.subid); op.err == nil { 664 go op.sub.start() 665 c.subs[op.sub.subid] = op.sub 666 } 667 } 668 669 //阅读发生在一个专门的Goroutine上。 670 671 func (c *Client) read(conn net.Conn) error { 672 var ( 673 buf json.RawMessage 674 dec = json.NewDecoder(conn) 675 ) 676 readMessage := func() (rs []*jsonrpcMessage, err error) { 677 buf = buf[:0] 678 if err = dec.Decode(&buf); err != nil { 679 return nil, err 680 } 681 if isBatch(buf) { 682 err = json.Unmarshal(buf, &rs) 683 } else { 684 rs = make([]*jsonrpcMessage, 1) 685 err = json.Unmarshal(buf, &rs[0]) 686 } 687 return rs, err 688 } 689 690 for { 691 resp, err := readMessage() 692 if err != nil { 693 c.readErr <- err 694 return err 695 } 696 c.readResp <- resp 697 } 698 } 699 700 //订阅。 701 702 //客户端订阅表示通过ethsubscribe建立的订阅。 703 type ClientSubscription struct { 704 client *Client 705 etype reflect.Type 706 channel reflect.Value 707 namespace string 708 subid string 709 in chan json.RawMessage 710 711 quitOnce sync.Once //确保退出关闭一次 712 quit chan struct{} //退出订阅时将关闭Quit 713 errOnce sync.Once //确保err关闭一次 714 err chan error 715 } 716 717 func newClientSubscription(c *Client, namespace string, channel reflect.Value) *ClientSubscription { 718 sub := &ClientSubscription{ 719 client: c, 720 namespace: namespace, 721 etype: channel.Type().Elem(), 722 channel: channel, 723 quit: make(chan struct{}), 724 err: make(chan error, 1), 725 in: make(chan json.RawMessage), 726 } 727 return sub 728 } 729 730 //err返回订阅错误通道。err的预期用途是 731 //客户端连接意外关闭时重新订阅。 732 // 733 //当订阅到期时,错误通道接收到一个值。 734 //出错。如果调用了close,则接收到的错误为nil。 735 //在基础客户端上,没有发生其他错误。 736 // 737 //当对订阅调用Unsubscribe时,错误通道将关闭。 738 func (sub *ClientSubscription) Err() <-chan error { 739 return sub.err 740 } 741 742 //取消订阅取消订阅通知并关闭错误通道。 743 //它可以安全地被多次调用。 744 func (sub *ClientSubscription) Unsubscribe() { 745 sub.quitWithError(nil, true) 746 sub.errOnce.Do(func() { close(sub.err) }) 747 } 748 749 func (sub *ClientSubscription) quitWithError(err error, unsubscribeServer bool) { 750 sub.quitOnce.Do(func() { 751 //调度循环将无法执行取消订阅调用 752 //如果交货时受阻。关闭Sub.Quit First,因为它 753 //解除锁定传递。 754 close(sub.quit) 755 if unsubscribeServer { 756 sub.requestUnsubscribe() 757 } 758 if err != nil { 759 if err == ErrClientQuit { 760 err = nil //遵循订阅语义。 761 } 762 sub.err <- err 763 } 764 }) 765 } 766 767 func (sub *ClientSubscription) deliver(result json.RawMessage) (ok bool) { 768 select { 769 case sub.in <- result: 770 return true 771 case <-sub.quit: 772 return false 773 } 774 } 775 776 func (sub *ClientSubscription) start() { 777 sub.quitWithError(sub.forward()) 778 } 779 780 func (sub *ClientSubscription) forward() (err error, unsubscribeServer bool) { 781 cases := []reflect.SelectCase{ 782 {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.quit)}, 783 {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.in)}, 784 {Dir: reflect.SelectSend, Chan: sub.channel}, 785 } 786 buffer := list.New() 787 defer buffer.Init() 788 for { 789 var chosen int 790 var recv reflect.Value 791 if buffer.Len() == 0 { 792 //空闲,省略发送案例。 793 chosen, recv, _ = reflect.Select(cases[:2]) 794 } else { 795 //非空缓冲区,发送第一个排队的项目。 796 cases[2].Send = reflect.ValueOf(buffer.Front().Value) 797 chosen, recv, _ = reflect.Select(cases) 798 } 799 800 switch chosen { 801 case 0: //<退出 802 return nil, false 803 case 1: //<-in in 804 val, err := sub.unmarshal(recv.Interface().(json.RawMessage)) 805 if err != nil { 806 return err, true 807 } 808 if buffer.Len() == maxClientSubscriptionBuffer { 809 return ErrSubscriptionQueueOverflow, true 810 } 811 buffer.PushBack(val) 812 case 2: //子通道< 813 cases[2].Send = reflect.Value{} //不要抓住价值。 814 buffer.Remove(buffer.Front()) 815 } 816 } 817 } 818 819 func (sub *ClientSubscription) unmarshal(result json.RawMessage) (interface{}, error) { 820 val := reflect.New(sub.etype) 821 err := json.Unmarshal(result, val.Interface()) 822 return val.Elem().Interface(), err 823 } 824 825 func (sub *ClientSubscription) requestUnsubscribe() error { 826 var result interface{} 827 return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid) 828 } 829