Add pub/sub to client/server and make broker more low level
This commit is contained in:
@@ -1,24 +1,19 @@
|
||||
package broker
|
||||
|
||||
import (
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Broker interface {
|
||||
Address() string
|
||||
Connect() error
|
||||
Disconnect() error
|
||||
Init() error
|
||||
Publish(context.Context, string, []byte) error
|
||||
Subscribe(string, func(context.Context, *Message)) (Subscriber, error)
|
||||
Publish(string, *Message) error
|
||||
Subscribe(string, Handler) (Subscriber, error)
|
||||
}
|
||||
|
||||
type Handler func(*Message)
|
||||
|
||||
type Message struct {
|
||||
Id string
|
||||
Timestamp int64
|
||||
Topic string
|
||||
Body []byte
|
||||
Header map[string]string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
type Subscriber interface {
|
||||
@@ -31,24 +26,14 @@ type options struct{}
|
||||
type Option func(*options)
|
||||
|
||||
var (
|
||||
Address string
|
||||
Id string
|
||||
DefaultBroker Broker
|
||||
DefaultBroker Broker = newHttpBroker([]string{})
|
||||
)
|
||||
|
||||
func NewBroker(addrs []string, opt ...Option) Broker {
|
||||
return newHttpBroker([]string{Address}, opt...)
|
||||
return newHttpBroker(addrs, opt...)
|
||||
}
|
||||
|
||||
func Init() error {
|
||||
if len(Id) == 0 {
|
||||
Id = "broker-" + uuid.NewUUID().String()
|
||||
}
|
||||
|
||||
if DefaultBroker == nil {
|
||||
DefaultBroker = newHttpBroker([]string{Address})
|
||||
}
|
||||
|
||||
return DefaultBroker.Init()
|
||||
}
|
||||
|
||||
@@ -60,10 +45,10 @@ func Disconnect() error {
|
||||
return DefaultBroker.Disconnect()
|
||||
}
|
||||
|
||||
func Publish(ctx context.Context, topic string, body []byte) error {
|
||||
return DefaultBroker.Publish(ctx, topic, body)
|
||||
func Publish(topic string, msg *Message) error {
|
||||
return DefaultBroker.Publish(topic, msg)
|
||||
}
|
||||
|
||||
func Subscribe(topic string, function func(context.Context, *Message)) (Subscriber, error) {
|
||||
return DefaultBroker.Subscribe(topic, function)
|
||||
func Subscribe(topic string, handler Handler) (Subscriber, error) {
|
||||
return DefaultBroker.Subscribe(topic, handler)
|
||||
}
|
||||
|
@@ -7,21 +7,14 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
log "github.com/golang/glog"
|
||||
c "github.com/myodc/go-micro/context"
|
||||
"github.com/myodc/go-micro/errors"
|
||||
"github.com/myodc/go-micro/registry"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type httpBroker struct {
|
||||
@@ -39,28 +32,22 @@ type httpSubscriber struct {
|
||||
id string
|
||||
topic string
|
||||
ch chan *httpSubscriber
|
||||
fn func(context.Context, *Message)
|
||||
fn Handler
|
||||
svc *registry.Service
|
||||
}
|
||||
|
||||
// used in brokers where there is no support for headers
|
||||
type envelope struct {
|
||||
Header map[string]string
|
||||
Message *Message
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultSubPath = "/_sub"
|
||||
)
|
||||
|
||||
func newHttpBroker(addrs []string, opt ...Option) Broker {
|
||||
addr := ":0"
|
||||
if len(addrs) > 0 {
|
||||
if len(addrs) > 0 && len(addrs[0]) > 0 {
|
||||
addr = addrs[0]
|
||||
}
|
||||
|
||||
return &httpBroker{
|
||||
id: Id,
|
||||
id: "broker-" + uuid.NewUUID().String(),
|
||||
address: addr,
|
||||
subscribers: make(map[string][]*httpSubscriber),
|
||||
unsubscribe: make(chan *httpSubscriber),
|
||||
@@ -96,9 +83,6 @@ func (h *httpBroker) start() error {
|
||||
go http.Serve(l, h)
|
||||
|
||||
go func() {
|
||||
ce := make(chan os.Signal, 1)
|
||||
signal.Notify(ce, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
|
||||
|
||||
for {
|
||||
select {
|
||||
case ch := <-h.exit:
|
||||
@@ -107,8 +91,6 @@ func (h *httpBroker) start() error {
|
||||
h.running = false
|
||||
h.Unlock()
|
||||
return
|
||||
case <-ce:
|
||||
h.stop()
|
||||
case subscriber := <-h.unsubscribe:
|
||||
h.Lock()
|
||||
var subscribers []*httpSubscriber
|
||||
@@ -150,26 +132,27 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var e *envelope
|
||||
if err = json.Unmarshal(b, &e); err != nil {
|
||||
var m *Message
|
||||
if err = json.Unmarshal(b, &m); err != nil {
|
||||
errr := errors.InternalServerError("go.micro.broker", fmt.Sprintf("Error parsing request body: %v", err))
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(errr.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(e.Message.Topic) == 0 {
|
||||
topic := m.Header[":topic"]
|
||||
delete(m.Header, ":topic")
|
||||
|
||||
if len(topic) == 0 {
|
||||
errr := errors.InternalServerError("go.micro.broker", "Topic not found")
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(errr.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
ctx := c.WithMetadata(context.Background(), e.Header)
|
||||
|
||||
h.RLock()
|
||||
for _, subscriber := range h.subscribers[e.Message.Topic] {
|
||||
subscriber.fn(ctx, e.Message)
|
||||
for _, subscriber := range h.subscribers[topic] {
|
||||
subscriber.fn(m)
|
||||
}
|
||||
h.RUnlock()
|
||||
}
|
||||
@@ -195,26 +178,14 @@ func (h *httpBroker) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpBroker) Publish(ctx context.Context, topic string, body []byte) error {
|
||||
func (h *httpBroker) Publish(topic string, msg *Message) error {
|
||||
s, err := registry.GetService("topic:" + topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message := &Message{
|
||||
Id: uuid.NewUUID().String(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Topic: topic,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
header, _ := c.GetMetadata(ctx)
|
||||
|
||||
b, err := json.Marshal(&envelope{
|
||||
header,
|
||||
message,
|
||||
})
|
||||
|
||||
msg.Header[":topic"] = topic
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -229,7 +200,7 @@ func (h *httpBroker) Publish(ctx context.Context, topic string, body []byte) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpBroker) Subscribe(topic string, function func(context.Context, *Message)) (Subscriber, error) {
|
||||
func (h *httpBroker) Subscribe(topic string, handler Handler) (Subscriber, error) {
|
||||
// parse address for host, port
|
||||
parts := strings.Split(h.Address(), ":")
|
||||
host := strings.Join(parts[:len(parts)-1], ":")
|
||||
@@ -251,11 +222,10 @@ func (h *httpBroker) Subscribe(topic string, function func(context.Context, *Mes
|
||||
id: uuid.NewUUID().String(),
|
||||
topic: topic,
|
||||
ch: h.unsubscribe,
|
||||
fn: function,
|
||||
fn: handler,
|
||||
svc: service,
|
||||
}
|
||||
|
||||
log.Infof("Registering subscriber %s", node.Id)
|
||||
if err := registry.Register(service); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -3,14 +3,9 @@ package nats
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/apcera/nats"
|
||||
"github.com/myodc/go-micro/broker"
|
||||
c "github.com/myodc/go-micro/context"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type nbroker struct {
|
||||
@@ -22,12 +17,6 @@ type subscriber struct {
|
||||
s *nats.Subscription
|
||||
}
|
||||
|
||||
// used in brokers where there is no support for headers
|
||||
type envelope struct {
|
||||
Header map[string]string
|
||||
Message *broker.Message
|
||||
}
|
||||
|
||||
func (n *subscriber) Topic() string {
|
||||
return n.s.Subject
|
||||
}
|
||||
@@ -67,34 +56,21 @@ func (n *nbroker) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *nbroker) Publish(ctx context.Context, topic string, body []byte) error {
|
||||
header, _ := c.GetMetadata(ctx)
|
||||
|
||||
message := &broker.Message{
|
||||
Id: uuid.NewUUID().String(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Topic: topic,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(&envelope{
|
||||
header,
|
||||
message,
|
||||
})
|
||||
func (n *nbroker) Publish(topic string, msg *broker.Message) error {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.conn.Publish(topic, b)
|
||||
}
|
||||
|
||||
func (n *nbroker) Subscribe(topic string, function func(context.Context, *broker.Message)) (broker.Subscriber, error) {
|
||||
func (n *nbroker) Subscribe(topic string, handler broker.Handler) (broker.Subscriber, error) {
|
||||
sub, err := n.conn.Subscribe(topic, func(msg *nats.Msg) {
|
||||
var e *envelope
|
||||
if err := json.Unmarshal(msg.Data, &e); err != nil {
|
||||
var m *broker.Message
|
||||
if err := json.Unmarshal(msg.Data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
ctx := c.WithMetadata(context.Background(), e.Header)
|
||||
function(ctx, e.Message)
|
||||
handler(m)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -1,13 +1,8 @@
|
||||
package rabbitmq
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/myodc/go-micro/broker"
|
||||
c "github.com/myodc/go-micro/context"
|
||||
"github.com/streadway/amqp"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type rbroker struct {
|
||||
@@ -28,24 +23,20 @@ func (s *subscriber) Unsubscribe() error {
|
||||
return s.ch.Close()
|
||||
}
|
||||
|
||||
func (r *rbroker) Publish(ctx context.Context, topic string, body []byte) error {
|
||||
header, _ := c.GetMetadata(ctx)
|
||||
|
||||
msg := amqp.Publishing{
|
||||
MessageId: uuid.NewUUID().String(),
|
||||
Timestamp: time.Now().UTC(),
|
||||
Body: body,
|
||||
Headers: amqp.Table{},
|
||||
func (r *rbroker) Publish(topic string, msg *broker.Message) error {
|
||||
m := amqp.Publishing{
|
||||
Body: msg.Body,
|
||||
Headers: amqp.Table{},
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
msg.Headers[k] = v
|
||||
for k, v := range msg.Header {
|
||||
m.Headers[k] = v
|
||||
}
|
||||
|
||||
return r.conn.Publish("", topic, msg)
|
||||
return r.conn.Publish("", topic, m)
|
||||
}
|
||||
|
||||
func (r *rbroker) Subscribe(topic string, function func(context.Context, *broker.Message)) (broker.Subscriber, error) {
|
||||
func (r *rbroker) Subscribe(topic string, handler broker.Handler) (broker.Subscriber, error) {
|
||||
ch, sub, err := r.conn.Consume(topic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -56,12 +47,9 @@ func (r *rbroker) Subscribe(topic string, function func(context.Context, *broker
|
||||
for k, v := range msg.Headers {
|
||||
header[k], _ = v.(string)
|
||||
}
|
||||
ctx := c.WithMetadata(context.Background(), header)
|
||||
function(ctx, &broker.Message{
|
||||
Id: msg.MessageId,
|
||||
Timestamp: msg.Timestamp.Unix(),
|
||||
Topic: topic,
|
||||
Body: msg.Body,
|
||||
handler(&broker.Message{
|
||||
Header: header,
|
||||
Body: msg.Body,
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user