github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/broker/http/http.go (about) 1 package http 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/tls" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "math/rand" 11 "net" 12 "net/http" 13 "net/url" 14 "runtime" 15 "sync" 16 "sync/atomic" 17 "time" 18 19 "github.com/volts-dev/volts/broker" 20 maddr "github.com/volts-dev/volts/internal/addr" 21 vnet "github.com/volts-dev/volts/internal/net" 22 "github.com/volts-dev/volts/logger" 23 "github.com/volts-dev/volts/router" 24 "github.com/volts-dev/volts/transport" 25 26 "github.com/google/uuid" 27 "github.com/volts-dev/volts/codec" 28 "github.com/volts-dev/volts/registry" 29 "github.com/volts-dev/volts/registry/cacher" 30 31 "golang.org/x/net/http2" 32 ) 33 34 var log = logger.New("broker") 35 36 type ( 37 httpBroker struct { 38 sync.RWMutex 39 id string 40 address string 41 subscribers map[string][]*httpSubscriber 42 running bool 43 exit chan chan error 44 45 config *broker.Config 46 router *router.TRouter 47 transport transport.ITransport 48 started atomic.Value // marks the serve as started 49 50 _mux *http.ServeMux 51 client *http.Client 52 registry registry.IRegistry 53 54 // offline message inbox 55 56 mtx sync.RWMutex 57 inbox map[string][][]byte 58 } 59 ) 60 61 var ( 62 DefaultSubPath = "/_sub" 63 serviceName = "volts.http.broker" 64 broadcastVersion = "volts.http.broadcast" 65 registerTTL = time.Minute 66 registerInterval = time.Second * 30 67 ) 68 69 func init() { 70 broker.Register("http", New) 71 } 72 73 func newTransport(config *tls.Config) *http.Transport { 74 if config == nil { 75 config = &tls.Config{ 76 InsecureSkipVerify: true, 77 } 78 } 79 80 dialTLS := func(network string, addr string) (net.Conn, error) { 81 return tls.Dial(network, addr, config) 82 } 83 84 t := &http.Transport{ 85 Proxy: http.ProxyFromEnvironment, 86 Dial: (&net.Dialer{ 87 Timeout: 30 * time.Second, 88 KeepAlive: 30 * time.Second, 89 }).Dial, 90 TLSHandshakeTimeout: 10 * time.Second, 91 DialTLS: dialTLS, 92 } 93 runtime.SetFinalizer(&t, func(tr **http.Transport) { 94 (*tr).CloseIdleConnections() 95 }) 96 97 // setup http2 98 http2.ConfigureTransport(t) 99 100 return t 101 } 102 103 func New(opts ...broker.Option) broker.IBroker { 104 var defaultOpts []broker.Option 105 defaultOpts = append(defaultOpts, 106 broker.WithName("http"), 107 broker.WithCodec(codec.JSON), 108 broker.WithRegistry(registry.Default()), 109 broker.WithContext(context.TODO()), 110 ) 111 112 cfg := broker.NewConfig(append(defaultOpts, opts...)...) 113 114 // set address 115 addr := broker.DefaultAddress 116 if len(cfg.Addrs) > 0 && len(cfg.Addrs[0]) > 0 { 117 addr = cfg.Addrs[0] 118 } 119 120 b := &httpBroker{ 121 id: uuid.New().String(), 122 config: cfg, 123 address: addr, 124 registry: cfg.Registry, 125 client: &http.Client{Transport: newTransport(cfg.TLSConfig)}, 126 subscribers: make(map[string][]*httpSubscriber), 127 exit: make(chan chan error), 128 //mux: http.NewServeMux(), 129 inbox: make(map[string][][]byte), 130 } 131 b.started.Store(false) 132 133 if b.transport == nil { 134 b.transport = transport.Default() 135 b.transport.Init( 136 transport.WithConfigPrefixName(cfg.String()), 137 ) 138 } 139 140 if b.router == nil { 141 b.router = router.New(router.WithConfigPrefixName(cfg.String())) 142 143 // 注册路由 144 b.router.Url("POST", DefaultSubPath, b.Handler) 145 } 146 147 // specify the message handler 148 //b.mux.Handle(DefaultSubPath, b) 149 150 // get optional handlers 151 if b.config.Context != nil { 152 handlers, ok := b.config.Context.Value("http_handlers").(map[string]http.Handler) 153 if ok { 154 for pattern, handler := range handlers { 155 b.router.Url("POST", pattern, handler) 156 } 157 } 158 } 159 160 return b 161 } 162 163 func (self *httpBroker) String() string { 164 return self.config.Name 165 } 166 167 func (self *httpBroker) Init(opts ...broker.Option) error { 168 for _, opt := range opts { 169 opt(self.config) 170 } 171 172 return nil 173 } 174 175 func (self *httpBroker) Config() *broker.Config { 176 return self.config 177 } 178 179 func (self *httpBroker) Address() string { 180 self.RLock() 181 defer self.RUnlock() 182 return self.address 183 } 184 185 func (self *httpBroker) Start() error { // 开始阻塞监听 186 if self.started.Load().(bool) { 187 return nil 188 } 189 190 self.Lock() 191 defer self.Unlock() 192 193 /* 194 var l net.Listener 195 var err error 196 197 if self.config.Secure || self.config.TLSConfig != nil { 198 config := self.config.TLSConfig 199 200 fn := func(addr string) (net.Listener, error) { 201 if config == nil { 202 hosts := []string{addr} 203 204 // check if its a valid host:port 205 if host, _, err := net.SplitHostPort(addr); err == nil { 206 if len(host) == 0 { 207 hosts = maddr.IPs() 208 } else { 209 hosts = []string{host} 210 } 211 } 212 213 // generate a certificate 214 cert, err := vtls.Certificate(hosts...) 215 if err != nil { 216 return nil, err 217 } 218 config = &tls.Config{Certificates: []tls.Certificate{cert}} 219 } 220 return tls.Listen("tcp", addr, config) 221 } 222 223 l, err = vnet.Listen(self.address, fn) 224 } else { 225 fn := func(addr string) (net.Listener, error) { 226 return net.Listen("tcp", addr) 227 } 228 229 l, err = vnet.Listen(self.address, fn) 230 } 231 232 if err != nil { 233 return err 234 } 235 236 addr := self.address 237 self.address = l.Addr().String() 238 239 go http.Serve(l, self.router) 240 go func() { 241 self.run(l) 242 self.Lock() 243 self.config.Addrs = []string{addr} 244 self.address = addr 245 self.Unlock() 246 }() 247 */ 248 // start listening on the transport 249 250 ts, err := self.transport.Listen(self.address) 251 if err != nil { 252 return err 253 } 254 255 addr := self.address 256 self.address = ts.Addr().String() 257 258 exit := make(chan bool) 259 260 // 监听链接 261 go func() { 262 for { 263 // listen for connections 264 err := ts.Serve(self.router) 265 266 // TODO: listen for messages 267 // msg := broker.Exchange(service).Consume() 268 269 select { 270 // check if we're supposed to exit 271 case <-exit: 272 return 273 // check the error and backoff 274 default: 275 if err != nil { 276 log.Errf("Accept error: %v", err) 277 278 time.Sleep(time.Second) 279 continue 280 } 281 } 282 283 // no error just exit 284 return 285 } 286 }() 287 288 // mark the server as started 289 self.started.Store(true) 290 291 log.Infof("Listening on %s - %s", ts.Addr(), self.transport.String()) 292 293 // 监听退出 294 go func() { 295 t := new(time.Ticker) 296 297 // only process if it exists 298 if self.config.RegisterInterval > time.Duration(0) { 299 // new ticker 300 t = time.NewTicker(self.config.RegisterInterval) 301 } 302 303 // return error chan 304 var ch chan error 305 306 Loop: 307 for { 308 select { 309 // register self on interval 310 case <-t.C: 311 self.RLock() 312 for _, subs := range self.subscribers { 313 for _, sub := range subs { 314 _ = self.registry.Register(sub.svc, registry.RegisterTTL(self.config.RegisterTTL)) 315 } 316 } 317 self.RUnlock() 318 // received exit signal 319 // wait for exit 320 case ch = <-self.exit: // 监听来自self.Stop()信号 321 self.RLock() 322 for _, subs := range self.subscribers { 323 for _, sub := range subs { 324 _ = self.registry.Deregister(sub.svc) 325 } 326 } 327 self.RUnlock() 328 329 t.Stop() 330 close(exit) 331 break Loop 332 } 333 } 334 335 //self.Lock() 336 //swg := self.wg 337 //self.Unlock() 338 339 // wait for requests to finish 340 //if swg != nil { 341 // swg.Wait() 342 //} 343 344 // close transport listener 345 ch <- ts.Close() 346 347 // swap back address 348 self.address = addr 349 }() 350 351 // set cache 352 //self.r = cache.New(self.config.Registry) 353 354 // set running 355 self.running = true 356 return nil 357 } 358 359 func (self *httpBroker) Close() error { 360 self.RLock() 361 if !self.running { 362 self.RUnlock() 363 return nil 364 } 365 self.RUnlock() 366 367 self.Lock() 368 defer self.Unlock() 369 370 // stop cache 371 rc, ok := self.registry.(cacher.ICacher) 372 if ok { 373 rc.Stop() 374 } 375 376 // exit and return err 377 ch := make(chan error) 378 self.exit <- ch 379 err := <-ch 380 381 // set not running 382 self.running = false 383 return err 384 } 385 386 func (self *httpBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error { 387 var cfg broker.PublishConfig 388 for _, opt := range opts { 389 opt(&cfg) 390 } 391 392 if cfg.Codec == nil { 393 // 验证解码器 394 cfg.Codec = codec.IdentifyCodec(cfg.SerializeType) 395 if cfg.Codec == nil { // no codec specified 396 cfg.Codec = codec.IdentifyCodec(codec.JSON) 397 //return fmt.Errorf("no codec specified") // errors.UnsupportedCodec("volts.client", cf) 398 } 399 } 400 401 // create the message first 402 m := &broker.Message{ 403 Header: make(map[string]string), 404 Body: message.Body, 405 } 406 407 for k, v := range message.Header { 408 m.Header[k] = v 409 } 410 411 m.Header["v-topic"] = topic 412 413 // encode the message 414 body, err := cfg.Codec.Encode(m) 415 if err != nil { 416 return err 417 } 418 419 // save the message 420 self.saveMessage(topic, body) 421 422 // now attempt to get the service 423 self.RLock() 424 s, err := self.registry.GetService(self.config.Name) 425 if err != nil { 426 self.RUnlock() 427 return err 428 } 429 self.RUnlock() 430 431 pub := func(node *registry.Node, t string, b []byte) error { 432 scheme := "http" 433 434 // check if secure is added in metadata 435 if node.Metadata["secure"] == "true" { 436 scheme = "https" 437 } 438 439 vals := url.Values{} 440 vals.Add("id", node.Id) 441 442 uri := fmt.Sprintf("%s://%s%s?%s", scheme, node.Address, DefaultSubPath, vals.Encode()) 443 r, err := self.client.Post(uri, "application/json", bytes.NewReader(b)) 444 if err != nil { 445 return err 446 } 447 448 // discard response body 449 io.Copy(ioutil.Discard, r.Body) 450 r.Body.Close() 451 return nil 452 } 453 454 srv := func(s []*registry.Service, b []byte) { 455 for _, service := range s { 456 var nodes []*registry.Node 457 458 for _, node := range service.Nodes { 459 // only use nodes tagged with broker http 460 if node.Metadata["broker"] != "http" { 461 continue 462 } 463 464 // look for nodes for the topic 465 if node.Metadata["topic"] != topic { 466 continue 467 } 468 469 nodes = append(nodes, node) 470 } 471 472 // only process if we have nodes 473 if len(nodes) == 0 { 474 continue 475 } 476 477 switch service.Version { 478 // broadcast version means broadcast to all nodes 479 case broadcastVersion: 480 var success bool 481 482 // publish to all nodes 483 for _, node := range nodes { 484 // publish async 485 if err := pub(node, topic, b); err == nil { 486 success = true 487 } 488 } 489 490 // save if it failed to publish at least once 491 if !success { 492 self.saveMessage(topic, b) 493 } 494 default: 495 // select node to publish to 496 node := nodes[rand.Int()%len(nodes)] 497 498 // publish async to one node 499 if err := pub(node, topic, b); err != nil { 500 // if failed save it 501 self.saveMessage(topic, b) 502 } 503 } 504 } 505 } 506 507 // do the rest async 508 go func() { 509 // get a third of the backlog 510 messages := self.getMessage(topic, 8) 511 delay := (len(messages) > 1) 512 513 // publish all the messages 514 for _, msg := range messages { 515 // serialize here 516 srv(s, msg) 517 518 // sending a backlog of messages 519 if delay { 520 time.Sleep(time.Millisecond * 100) 521 } 522 } 523 }() 524 525 return nil 526 } 527 528 func (self *httpBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.ISubscriber, error) { 529 var err error 530 var host, port string 531 scfg := broker.NewSubscribeOptions(opts...) 532 533 // parse address for host, port 534 host, port, err = net.SplitHostPort(self.Address()) 535 if err != nil { 536 return nil, err 537 } 538 539 addr, err := maddr.Extract(host) 540 if err != nil { 541 return nil, err 542 } 543 544 var secure bool 545 546 if self.config.Secure || self.config.TLSConfig != nil { 547 secure = true 548 } 549 550 // register service 551 node := ®istry.Node{ 552 Id: topic + "-" + self.id, 553 Address: vnet.HostPort(addr, port), 554 Metadata: map[string]string{ 555 "secure": fmt.Sprintf("%t", secure), 556 "broker": "http", 557 "topic": topic, 558 }, 559 } 560 561 // check for queue group or broadcast queue 562 version := scfg.Queue 563 if len(version) == 0 { 564 version = self.config.BroadcastVersion 565 } 566 567 service := ®istry.Service{ 568 Name: self.config.Name, 569 Version: version, 570 Nodes: []*registry.Node{node}, 571 } 572 573 // generate subscriber 574 subscriber := &httpSubscriber{ 575 opts: scfg, 576 hb: self, 577 id: node.Id, 578 topic: topic, 579 fn: handler, 580 svc: service, 581 } 582 583 // subscribe now 584 if err := self.subscribe(subscriber); err != nil { 585 return nil, err 586 } 587 588 // return the subscriber 589 return subscriber, nil 590 } 591 592 func (self *httpBroker) subscribe(s *httpSubscriber) error { 593 self.Lock() 594 defer self.Unlock() 595 596 if err := self.registry.Register(s.svc, registry.RegisterTTL(self.config.RegisterTTL)); err != nil { 597 return err 598 } 599 600 self.subscribers[s.topic] = append(self.subscribers[s.topic], s) 601 return nil 602 } 603 604 func (h *httpBroker) saveMessage(topic string, msg []byte) { 605 h.mtx.Lock() 606 defer h.mtx.Unlock() 607 608 // get messages 609 c := h.inbox[topic] 610 611 // save message 612 c = append(c, msg) 613 614 // max length 64 615 if len(c) > 64 { 616 c = c[:64] 617 } 618 619 // save inbox 620 h.inbox[topic] = c 621 } 622 623 func (h *httpBroker) getMessage(topic string, num int) [][]byte { 624 h.mtx.Lock() 625 defer h.mtx.Unlock() 626 627 // get messages 628 c, ok := h.inbox[topic] 629 if !ok { 630 return nil 631 } 632 633 // more message than requests 634 if len(c) >= num { 635 msg := c[:num] 636 h.inbox[topic] = c[num:] 637 return msg 638 } 639 640 // reset inbox 641 h.inbox[topic] = nil 642 643 // return all messages 644 return c 645 }