gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/tunnel/broker/broker.go (about) 1 // Package broker is a tunnel broker 2 package broker 3 4 import ( 5 "context" 6 7 "gitee.com/liuxuezhan/go-micro-v1.18.0/broker" 8 "gitee.com/liuxuezhan/go-micro-v1.18.0/transport" 9 "gitee.com/liuxuezhan/go-micro-v1.18.0/tunnel" 10 ) 11 12 type tunBroker struct { 13 opts broker.Options 14 tunnel tunnel.Tunnel 15 } 16 17 type tunSubscriber struct { 18 topic string 19 handler broker.Handler 20 opts broker.SubscribeOptions 21 22 closed chan bool 23 listener tunnel.Listener 24 } 25 26 type tunEvent struct { 27 topic string 28 message *broker.Message 29 } 30 31 // used to access tunnel from options context 32 type tunnelKey struct{} 33 type tunnelAddr struct{} 34 35 func (t *tunBroker) Init(opts ...broker.Option) error { 36 for _, o := range opts { 37 o(&t.opts) 38 } 39 return nil 40 } 41 42 func (t *tunBroker) Options() broker.Options { 43 return t.opts 44 } 45 46 func (t *tunBroker) Address() string { 47 return t.tunnel.Address() 48 } 49 50 func (t *tunBroker) Connect() error { 51 return t.tunnel.Connect() 52 } 53 54 func (t *tunBroker) Disconnect() error { 55 return t.tunnel.Close() 56 } 57 58 func (t *tunBroker) Publish(topic string, m *broker.Message, opts ...broker.PublishOption) error { 59 // TODO: this is probably inefficient, we might want to just maintain an open connection 60 // it may be easier to add broadcast to the tunnel 61 c, err := t.tunnel.Dial(topic, tunnel.DialMode(tunnel.Multicast)) 62 if err != nil { 63 return err 64 } 65 defer c.Close() 66 67 return c.Send(&transport.Message{ 68 Header: m.Header, 69 Body: m.Body, 70 }) 71 } 72 73 func (t *tunBroker) Subscribe(topic string, h broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { 74 l, err := t.tunnel.Listen(topic, tunnel.ListenMode(tunnel.Multicast)) 75 if err != nil { 76 return nil, err 77 } 78 79 var options broker.SubscribeOptions 80 for _, o := range opts { 81 o(&options) 82 } 83 84 tunSub := &tunSubscriber{ 85 topic: topic, 86 handler: h, 87 opts: options, 88 closed: make(chan bool), 89 listener: l, 90 } 91 92 // start processing 93 go tunSub.run() 94 95 return tunSub, nil 96 } 97 98 func (t *tunBroker) String() string { 99 return "tunnel" 100 } 101 102 func (t *tunSubscriber) run() { 103 for { 104 // accept a new connection 105 c, err := t.listener.Accept() 106 if err != nil { 107 select { 108 case <-t.closed: 109 return 110 default: 111 continue 112 } 113 } 114 115 // receive message 116 m := new(transport.Message) 117 if err := c.Recv(m); err != nil { 118 c.Close() 119 continue 120 } 121 122 // close the connection 123 c.Close() 124 125 // handle the message 126 go t.handler(&tunEvent{ 127 topic: t.topic, 128 message: &broker.Message{ 129 Header: m.Header, 130 Body: m.Body, 131 }, 132 }) 133 } 134 } 135 136 func (t *tunSubscriber) Options() broker.SubscribeOptions { 137 return t.opts 138 } 139 140 func (t *tunSubscriber) Topic() string { 141 return t.topic 142 } 143 144 func (t *tunSubscriber) Unsubscribe() error { 145 select { 146 case <-t.closed: 147 return nil 148 default: 149 close(t.closed) 150 return t.listener.Close() 151 } 152 } 153 154 func (t *tunEvent) Topic() string { 155 return t.topic 156 } 157 158 func (t *tunEvent) Message() *broker.Message { 159 return t.message 160 } 161 162 func (t *tunEvent) Ack() error { 163 return nil 164 } 165 166 func NewBroker(opts ...broker.Option) broker.Broker { 167 options := broker.Options{ 168 Context: context.Background(), 169 } 170 for _, o := range opts { 171 o(&options) 172 } 173 t, ok := options.Context.Value(tunnelKey{}).(tunnel.Tunnel) 174 if !ok { 175 t = tunnel.NewTunnel() 176 } 177 178 a, ok := options.Context.Value(tunnelAddr{}).(string) 179 if ok { 180 // initialise address 181 t.Init(tunnel.Address(a)) 182 } 183 184 if len(options.Addrs) > 0 { 185 // initialise nodes 186 t.Init(tunnel.Nodes(options.Addrs...)) 187 } 188 189 return &tunBroker{ 190 opts: options, 191 tunnel: t, 192 } 193 } 194 195 // WithAddress sets the tunnel address 196 func WithAddress(a string) broker.Option { 197 return func(o *broker.Options) { 198 if o.Context == nil { 199 o.Context = context.Background() 200 } 201 o.Context = context.WithValue(o.Context, tunnelAddr{}, a) 202 } 203 } 204 205 // WithTunnel sets the internal tunnel 206 func WithTunnel(t tunnel.Tunnel) broker.Option { 207 return func(o *broker.Options) { 208 if o.Context == nil { 209 o.Context = context.Background() 210 } 211 o.Context = context.WithValue(o.Context, tunnelKey{}, t) 212 } 213 }