github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/pss/notify/notify.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 19:16:44</date> 10 //</624450116723412992> 11 12 package notify 13 14 import ( 15 "crypto/ecdsa" 16 "fmt" 17 "sync" 18 19 "github.com/ethereum/go-ethereum/common/hexutil" 20 "github.com/ethereum/go-ethereum/crypto" 21 "github.com/ethereum/go-ethereum/p2p" 22 "github.com/ethereum/go-ethereum/rlp" 23 "github.com/ethereum/go-ethereum/swarm/log" 24 "github.com/ethereum/go-ethereum/swarm/pss" 25 ) 26 27 const ( 28 //从请求者发送到更新者以请求开始通知 29 MsgCodeStart = iota 30 31 //从更新程序发送到请求程序,包含一个通知和一个新的符号键来替换旧的 32 MsgCodeNotifyWithKey 33 34 //从更新程序发送到请求程序,包含一个通知 35 MsgCodeNotify 36 37 //从请求程序发送到更新程序以请求停止通知(当前未使用) 38 MsgCodeStop 39 MsgCodeMax 40 ) 41 42 const ( 43 DefaultAddressLength = 1 44 symKeyLength = 32 //这应该从源头上得到 45 ) 46 47 var ( 48 //在对称密钥颁发完成之前使用控制主题 49 controlTopic = pss.Topic{0x00, 0x00, 0x00, 0x01} 50 ) 51 52 //当代码为msgcodestart时,有效负载为地址 53 //当代码为msgcodenotifywithkey时,有效负载为notification symkey 54 //当代码为msgcodenotify时,有效负载为notification 55 //当代码为msgcodestop时,有效负载为地址 56 type Msg struct { 57 Code byte 58 Name []byte 59 Payload []byte 60 namestring string 61 } 62 63 //newmsg创建新的通知消息对象 64 func NewMsg(code byte, name string, payload []byte) *Msg { 65 return &Msg{ 66 Code: code, 67 Name: []byte(name), 68 Payload: payload, 69 namestring: name, 70 } 71 } 72 73 //newmsgFromPayload将序列化消息负载解码为新的通知消息对象 74 func NewMsgFromPayload(payload []byte) (*Msg, error) { 75 msg := &Msg{} 76 err := rlp.DecodeBytes(payload, msg) 77 if err != nil { 78 return nil, err 79 } 80 msg.namestring = string(msg.Name) 81 return msg, nil 82 } 83 84 //通知程序在向其发送消息的每个地址空间中都有一个sendbin条目。 85 type sendBin struct { 86 address pss.PssAddress 87 symKeyId string 88 count int 89 } 90 91 //表示单个通知服务 92 //只有与通知客户端地址匹配的订阅地址箱才有条目。 93 type notifier struct { 94 bins map[string]*sendBin 95 topic pss.Topic //标识PSS接收器的资源 96 threshold int //箱中使用的地址字节数 97 updateC <-chan []byte 98 quitC chan struct{} 99 } 100 101 func (n *notifier) removeSubscription() { 102 n.quitC <- struct{}{} 103 } 104 105 //表示公钥在特定地址/邻居处进行的单个订阅 106 type subscription struct { 107 pubkeyId string 108 address pss.PssAddress 109 handler func(string, []byte) error 110 } 111 112 //控制器是控制、添加和删除通知服务和订阅的接口。 113 type Controller struct { 114 pss *pss.Pss 115 notifiers map[string]*notifier 116 subscriptions map[string]*subscription 117 mu sync.Mutex 118 } 119 120 //NewController创建新的控制器对象 121 func NewController(ps *pss.Pss) *Controller { 122 ctrl := &Controller{ 123 pss: ps, 124 notifiers: make(map[string]*notifier), 125 subscriptions: make(map[string]*subscription), 126 } 127 ctrl.pss.Register(&controlTopic, pss.NewHandler(ctrl.Handler)) 128 return ctrl 129 } 130 131 //IsActive用于检查是否存在指定ID字符串的通知服务 132 //如果存在则返回true,否则返回false 133 func (c *Controller) IsActive(name string) bool { 134 c.mu.Lock() 135 defer c.mu.Unlock() 136 return c.isActive(name) 137 } 138 139 func (c *Controller) isActive(name string) bool { 140 _, ok := c.notifiers[name] 141 return ok 142 } 143 144 //客户端使用订阅从通知服务提供程序请求通知 145 //它将创建一个msgcodestart消息,并使用其公钥和路由地址不对称地发送给提供程序。 146 //handler函数是一个回调函数,当收到通知时将调用该回调函数。 147 //如果无法发送请求PSS或无法序列化更新消息,则失败 148 func (c *Controller) Subscribe(name string, pubkey *ecdsa.PublicKey, address pss.PssAddress, handler func(string, []byte) error) error { 149 c.mu.Lock() 150 defer c.mu.Unlock() 151 msg := NewMsg(MsgCodeStart, name, c.pss.BaseAddr()) 152 c.pss.SetPeerPublicKey(pubkey, controlTopic, address) 153 pubkeyId := hexutil.Encode(crypto.FromECDSAPub(pubkey)) 154 smsg, err := rlp.EncodeToBytes(msg) 155 if err != nil { 156 return err 157 } 158 err = c.pss.SendAsym(pubkeyId, controlTopic, smsg) 159 if err != nil { 160 return err 161 } 162 c.subscriptions[name] = &subscription{ 163 pubkeyId: pubkeyId, 164 address: address, 165 handler: handler, 166 } 167 return nil 168 } 169 170 //取消订阅,也许不足为奇,会取消订阅的效果。 171 //如果订阅不存在、无法发送请求PSS或无法序列化更新消息,则失败 172 func (c *Controller) Unsubscribe(name string) error { 173 c.mu.Lock() 174 defer c.mu.Unlock() 175 sub, ok := c.subscriptions[name] 176 if !ok { 177 return fmt.Errorf("Unknown subscription '%s'", name) 178 } 179 msg := NewMsg(MsgCodeStop, name, sub.address) 180 smsg, err := rlp.EncodeToBytes(msg) 181 if err != nil { 182 return err 183 } 184 err = c.pss.SendAsym(sub.pubkeyId, controlTopic, smsg) 185 if err != nil { 186 return err 187 } 188 delete(c.subscriptions, name) 189 return nil 190 } 191 192 //通知服务提供程序使用NewNotifier创建新的通知服务 193 //它将名称作为资源的标识符,一个阈值指示订阅地址bin的粒度。 194 //然后,它启动一个事件循环,该循环监听所提供的更新通道,并在通道接收时执行通知。 195 //如果通知程序已在名称上注册,则失败 196 //func(c*controller)newnotifier(name string,threshold int,contentfunc func(string)([]byte,error))错误 197 func (c *Controller) NewNotifier(name string, threshold int, updateC <-chan []byte) (func(), error) { 198 c.mu.Lock() 199 if c.isActive(name) { 200 c.mu.Unlock() 201 return nil, fmt.Errorf("Notification service %s already exists in controller", name) 202 } 203 quitC := make(chan struct{}) 204 c.notifiers[name] = ¬ifier{ 205 bins: make(map[string]*sendBin), 206 topic: pss.BytesToTopic([]byte(name)), 207 threshold: threshold, 208 updateC: updateC, 209 quitC: quitC, 210 //contentfunc:contentfunc, 211 } 212 c.mu.Unlock() 213 go func() { 214 for { 215 select { 216 case <-quitC: 217 return 218 case data := <-updateC: 219 c.notify(name, data) 220 } 221 } 222 }() 223 224 return c.notifiers[name].removeSubscription, nil 225 } 226 227 //removenotifier用于停止通知服务。 228 //它取消了侦听通知提供程序的更新通道的事件循环 229 func (c *Controller) RemoveNotifier(name string) error { 230 c.mu.Lock() 231 defer c.mu.Unlock() 232 currentNotifier, ok := c.notifiers[name] 233 if !ok { 234 return fmt.Errorf("Unknown notification service %s", name) 235 } 236 currentNotifier.removeSubscription() 237 delete(c.notifiers, name) 238 return nil 239 } 240 241 //通知由通知服务提供程序调用以发出新通知 242 //它使用通知服务的名称和要发送的数据。 243 //如果不存在具有此名称的通知程序或无法序列化数据,则失败。 244 //请注意,发送消息失败时不会失败。 245 func (c *Controller) notify(name string, data []byte) error { 246 c.mu.Lock() 247 defer c.mu.Unlock() 248 if !c.isActive(name) { 249 return fmt.Errorf("Notification service %s doesn't exist", name) 250 } 251 msg := NewMsg(MsgCodeNotify, name, data) 252 smsg, err := rlp.EncodeToBytes(msg) 253 if err != nil { 254 return err 255 } 256 for _, m := range c.notifiers[name].bins { 257 log.Debug("sending pss notify", "name", name, "addr", fmt.Sprintf("%x", m.address), "topic", fmt.Sprintf("%x", c.notifiers[name].topic), "data", data) 258 go func(m *sendBin) { 259 err = c.pss.SendSym(m.symKeyId, c.notifiers[name].topic, smsg) 260 if err != nil { 261 log.Warn("Failed to send notify to addr %x: %v", m.address, err) 262 } 263 }(m) 264 } 265 return nil 266 } 267 268 //检查一下我们是否已经有箱子了 269 //如果这样做,从中检索symkey并增加计数 270 //如果我们不做一个新的symkey和一个新的bin条目 271 func (c *Controller) addToBin(ntfr *notifier, address []byte) (symKeyId string, pssAddress pss.PssAddress, err error) { 272 273 //解析消息中的地址,如果长度超过bin阈值,则截断。 274 if len(address) > ntfr.threshold { 275 address = address[:ntfr.threshold] 276 } 277 278 pssAddress = pss.PssAddress(address) 279 hexAddress := fmt.Sprintf("%x", address) 280 currentBin, ok := ntfr.bins[hexAddress] 281 if ok { 282 currentBin.count++ 283 symKeyId = currentBin.symKeyId 284 } else { 285 symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, pssAddress, false) 286 if err != nil { 287 return "", nil, err 288 } 289 ntfr.bins[hexAddress] = &sendBin{ 290 address: address, 291 symKeyId: symKeyId, 292 count: 1, 293 } 294 } 295 return symKeyId, pssAddress, nil 296 } 297 298 func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { 299 300 keyidbytes, err := hexutil.Decode(keyid) 301 if err != nil { 302 return err 303 } 304 pubkey, err := crypto.UnmarshalPubkey(keyidbytes) 305 if err != nil { 306 return err 307 } 308 309 //如果没有为通知注册名称,我们将不会响应 310 currentNotifier, ok := c.notifiers[msg.namestring] 311 if !ok { 312 return fmt.Errorf("Subscribe attempted on unknown resource '%s'", msg.namestring) 313 } 314 315 //添加或打开新肥料箱 316 symKeyId, pssAddress, err := c.addToBin(currentNotifier, msg.Payload) 317 if err != nil { 318 return err 319 } 320 321 //添加到通讯簿以发送初始通知 322 symkey, err := c.pss.GetSymmetricKey(symKeyId) 323 if err != nil { 324 return err 325 } 326 err = c.pss.SetPeerPublicKey(pubkey, controlTopic, pssAddress) 327 if err != nil { 328 return err 329 } 330 331 //TODO这被设置为零长度字节,等待初始消息的协议决定,是否应该包含消息,以及如何触发初始消息,以便在订阅时发送Swarm Feed的当前状态。 332 notify := []byte{} 333 replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength)) 334 copy(replyMsg.Payload, notify) 335 copy(replyMsg.Payload[len(notify):], symkey) 336 sReplyMsg, err := rlp.EncodeToBytes(replyMsg) 337 if err != nil { 338 return err 339 } 340 return c.pss.SendAsym(keyid, controlTopic, sReplyMsg) 341 } 342 343 func (c *Controller) handleNotifyWithKeyMsg(msg *Msg) error { 344 symkey := msg.Payload[len(msg.Payload)-symKeyLength:] 345 topic := pss.BytesToTopic(msg.Name) 346 347 //\t要跟踪并添加实际地址 348 updaterAddr := pss.PssAddress([]byte{}) 349 c.pss.SetSymmetricKey(symkey, topic, updaterAddr, true) 350 c.pss.Register(&topic, pss.NewHandler(c.Handler)) 351 return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload[:len(msg.Payload)-symKeyLength]) 352 } 353 354 func (c *Controller) handleStopMsg(msg *Msg) error { 355 //如果没有为通知注册名称,我们将不会响应 356 currentNotifier, ok := c.notifiers[msg.namestring] 357 if !ok { 358 return fmt.Errorf("Unsubscribe attempted on unknown resource '%s'", msg.namestring) 359 } 360 361 //解析消息中的地址,如果长度超过了bin的地址长度阈值,则截断。 362 address := msg.Payload 363 if len(msg.Payload) > currentNotifier.threshold { 364 address = address[:currentNotifier.threshold] 365 } 366 367 //从箱子中取出条目(如果存在),如果是最后一个剩余的,则取出箱子。 368 hexAddress := fmt.Sprintf("%x", address) 369 currentBin, ok := currentNotifier.bins[hexAddress] 370 if !ok { 371 return fmt.Errorf("found no active bin for address %s", hexAddress) 372 } 373 currentBin.count-- 374 if currentBin.count == 0 { //如果此bin中没有更多客户端,请将其删除 375 delete(currentNotifier.bins, hexAddress) 376 } 377 return nil 378 } 379 380 //handler是用于处理通知服务消息的PSS主题处理程序 381 //它应该在PSS中注册到任何提供的通知服务和使用该服务的客户机。 382 func (c *Controller) Handler(smsg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { 383 c.mu.Lock() 384 defer c.mu.Unlock() 385 log.Debug("notify controller handler", "keyid", keyid) 386 387 //查看消息是否有效 388 msg, err := NewMsgFromPayload(smsg) 389 if err != nil { 390 return err 391 } 392 393 switch msg.Code { 394 case MsgCodeStart: 395 return c.handleStartMsg(msg, keyid) 396 case MsgCodeNotifyWithKey: 397 return c.handleNotifyWithKeyMsg(msg) 398 case MsgCodeNotify: 399 return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload) 400 case MsgCodeStop: 401 return c.handleStopMsg(msg) 402 } 403 404 return fmt.Errorf("Invalid message code: %d", msg.Code) 405 } 406