github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/subscription_test.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 "context" 29 "encoding/json" 30 "fmt" 31 "net" 32 "sync" 33 "testing" 34 "time" 35 ) 36 37 type NotificationTestService struct { 38 mu sync.Mutex 39 unsubscribed bool 40 41 gotHangSubscriptionReq chan struct{} 42 unblockHangSubscription chan struct{} 43 } 44 45 func (s *NotificationTestService) Echo(i int) int { 46 return i 47 } 48 49 func (s *NotificationTestService) wasUnsubCallbackCalled() bool { 50 s.mu.Lock() 51 defer s.mu.Unlock() 52 return s.unsubscribed 53 } 54 55 func (s *NotificationTestService) Unsubscribe(subid string) { 56 s.mu.Lock() 57 s.unsubscribed = true 58 s.mu.Unlock() 59 } 60 61 func (s *NotificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { 62 notifier, supported := NotifierFromContext(ctx) 63 if !supported { 64 return nil, ErrNotificationsUnsupported 65 } 66 67 //通过显式创建订阅,我们确保将订阅ID发送回客户端 68 //在第一次订阅之前。调用notify。否则,事件可能会在响应之前发送 69 //对于eth-subscribe方法。 70 subscription := notifier.CreateSubscription() 71 72 go func() { 73 //测试需要n个事件,如果我们立即开始发送事件,则某些事件 74 //可能会删除,因为订阅ID可能不会发送到 75 //客户。 76 time.Sleep(5 * time.Second) 77 for i := 0; i < n; i++ { 78 if err := notifier.Notify(subscription.ID, val+i); err != nil { 79 return 80 } 81 } 82 83 select { 84 case <-notifier.Closed(): 85 s.mu.Lock() 86 s.unsubscribed = true 87 s.mu.Unlock() 88 case <-subscription.Err(): 89 s.mu.Lock() 90 s.unsubscribed = true 91 s.mu.Unlock() 92 } 93 }() 94 95 return subscription, nil 96 } 97 98 //在s.unblockhangsubscription上挂起订阅块 99 //发送任何东西。 100 func (s *NotificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { 101 notifier, supported := NotifierFromContext(ctx) 102 if !supported { 103 return nil, ErrNotificationsUnsupported 104 } 105 106 s.gotHangSubscriptionReq <- struct{}{} 107 <-s.unblockHangSubscription 108 subscription := notifier.CreateSubscription() 109 110 go func() { 111 notifier.Notify(subscription.ID, val) 112 }() 113 return subscription, nil 114 } 115 116 func TestNotifications(t *testing.T) { 117 server := NewServer() 118 service := &NotificationTestService{} 119 120 if err := server.RegisterName("eth", service); err != nil { 121 t.Fatalf("unable to register test service %v", err) 122 } 123 124 clientConn, serverConn := net.Pipe() 125 126 go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) 127 128 out := json.NewEncoder(clientConn) 129 in := json.NewDecoder(clientConn) 130 131 n := 5 132 val := 12345 133 request := map[string]interface{}{ 134 "id": 1, 135 "method": "eth_subscribe", 136 "version": "2.0", 137 "params": []interface{}{"someSubscription", n, val}, 138 } 139 140 //创建订阅 141 if err := out.Encode(request); err != nil { 142 t.Fatal(err) 143 } 144 145 var subid string 146 response := jsonSuccessResponse{Result: subid} 147 if err := in.Decode(&response); err != nil { 148 t.Fatal(err) 149 } 150 151 var ok bool 152 if _, ok = response.Result.(string); !ok { 153 t.Fatalf("expected subscription id, got %T", response.Result) 154 } 155 156 for i := 0; i < n; i++ { 157 var notification jsonNotification 158 if err := in.Decode(¬ification); err != nil { 159 t.Fatalf("%v", err) 160 } 161 162 if int(notification.Params.Result.(float64)) != val+i { 163 t.Fatalf("expected %d, got %d", val+i, notification.Params.Result) 164 } 165 } 166 167 clientConn.Close() //导致调用通知取消订阅回调 168 time.Sleep(1 * time.Second) 169 170 if !service.wasUnsubCallbackCalled() { 171 t.Error("unsubscribe callback not called after closing connection") 172 } 173 } 174 175 func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSuccessResponse, 176 failures chan<- jsonErrResponse, notifications chan<- jsonNotification, errors chan<- error) { 177 178 //读取和分析服务器消息 179 for { 180 var rmsg json.RawMessage 181 if err := in.Decode(&rmsg); err != nil { 182 return 183 } 184 185 var responses []map[string]interface{} 186 if rmsg[0] == '[' { 187 if err := json.Unmarshal(rmsg, &responses); err != nil { 188 errors <- fmt.Errorf("Received invalid message: %s", rmsg) 189 return 190 } 191 } else { 192 var msg map[string]interface{} 193 if err := json.Unmarshal(rmsg, &msg); err != nil { 194 errors <- fmt.Errorf("Received invalid message: %s", rmsg) 195 return 196 } 197 responses = append(responses, msg) 198 } 199 200 for _, msg := range responses { 201 //确定接收和广播的消息类型 202 //通过相应的通道 203 if _, found := msg["result"]; found { 204 successes <- jsonSuccessResponse{ 205 Version: msg["jsonrpc"].(string), 206 Id: msg["id"], 207 Result: msg["result"], 208 } 209 continue 210 } 211 if _, found := msg["error"]; found { 212 params := msg["params"].(map[string]interface{}) 213 failures <- jsonErrResponse{ 214 Version: msg["jsonrpc"].(string), 215 Id: msg["id"], 216 Error: jsonError{int(params["subscription"].(float64)), params["message"].(string), params["data"]}, 217 } 218 continue 219 } 220 if _, found := msg["params"]; found { 221 params := msg["params"].(map[string]interface{}) 222 notifications <- jsonNotification{ 223 Version: msg["jsonrpc"].(string), 224 Method: msg["method"].(string), 225 Params: jsonSubscription{params["subscription"].(string), params["result"]}, 226 } 227 continue 228 } 229 errors <- fmt.Errorf("Received invalid message: %s", msg) 230 } 231 } 232 } 233 234 //testsubscriptionmultiplename空间确保订阅可以存在 235 //对于多个不同的命名空间。 236 func TestSubscriptionMultipleNamespaces(t *testing.T) { 237 var ( 238 namespaces = []string{"eth", "shh", "bzz"} 239 server = NewServer() 240 service = NotificationTestService{} 241 clientConn, serverConn = net.Pipe() 242 243 out = json.NewEncoder(clientConn) 244 in = json.NewDecoder(clientConn) 245 successes = make(chan jsonSuccessResponse) 246 failures = make(chan jsonErrResponse) 247 notifications = make(chan jsonNotification) 248 249 errors = make(chan error, 10) 250 ) 251 252 //安装并启动服务器 253 for _, namespace := range namespaces { 254 if err := server.RegisterName(namespace, &service); err != nil { 255 t.Fatalf("unable to register test service %v", err) 256 } 257 } 258 259 go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) 260 defer server.Stop() 261 262 //等待消息并将其写入给定的通道 263 go waitForMessages(t, in, successes, failures, notifications, errors) 264 265 //逐个创建订阅 266 n := 3 267 for i, namespace := range namespaces { 268 request := map[string]interface{}{ 269 "id": i, 270 "method": fmt.Sprintf("%s_subscribe", namespace), 271 "version": "2.0", 272 "params": []interface{}{"someSubscription", n, i}, 273 } 274 275 if err := out.Encode(&request); err != nil { 276 t.Fatalf("Could not create subscription: %v", err) 277 } 278 } 279 280 //在一批中创建所有订阅 281 var requests []interface{} 282 for i, namespace := range namespaces { 283 requests = append(requests, map[string]interface{}{ 284 "id": i, 285 "method": fmt.Sprintf("%s_subscribe", namespace), 286 "version": "2.0", 287 "params": []interface{}{"someSubscription", n, i}, 288 }) 289 } 290 291 if err := out.Encode(&requests); err != nil { 292 t.Fatalf("Could not create subscription in batch form: %v", err) 293 } 294 295 timeout := time.After(30 * time.Second) 296 subids := make(map[string]string, 2*len(namespaces)) 297 count := make(map[string]int, 2*len(namespaces)) 298 299 for { 300 done := true 301 for id := range count { 302 if count, found := count[id]; !found || count < (2*n) { 303 done = false 304 } 305 } 306 307 if done && len(count) == len(namespaces) { 308 break 309 } 310 311 select { 312 case err := <-errors: 313 t.Fatal(err) 314 case suc := <-successes: //已创建订阅 315 subids[namespaces[int(suc.Id.(float64))]] = suc.Result.(string) 316 case failure := <-failures: 317 t.Errorf("received error: %v", failure.Error) 318 case notification := <-notifications: 319 if cnt, found := count[notification.Params.Subscription]; found { 320 count[notification.Params.Subscription] = cnt + 1 321 } else { 322 count[notification.Params.Subscription] = 1 323 } 324 case <-timeout: 325 for _, namespace := range namespaces { 326 subid, found := subids[namespace] 327 if !found { 328 t.Errorf("Subscription for '%s' not created", namespace) 329 continue 330 } 331 if count, found := count[subid]; !found || count < n { 332 t.Errorf("Didn't receive all notifications (%d<%d) in time for namespace '%s'", count, n, namespace) 333 } 334 } 335 return 336 } 337 } 338 }