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