Move plugins to go-plugins
This commit is contained in:
parent
469b12ecea
commit
04e07f4b39
@ -1,11 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
// This is a hack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/micro/go-micro/broker"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewBroker(addrs []string, opt ...broker.Option) broker.Broker {
|
|
||||||
return broker.NewBroker(addrs, opt...)
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
package nats
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/apcera/nats"
|
|
||||||
"github.com/micro/go-micro/broker"
|
|
||||||
)
|
|
||||||
|
|
||||||
type nbroker struct {
|
|
||||||
addrs []string
|
|
||||||
conn *nats.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
type subscriber struct {
|
|
||||||
s *nats.Subscription
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *subscriber) Topic() string {
|
|
||||||
return n.s.Subject
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *subscriber) Unsubscribe() error {
|
|
||||||
return n.s.Unsubscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *nbroker) Address() string {
|
|
||||||
if len(n.addrs) > 0 {
|
|
||||||
return n.addrs[0]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *nbroker) Connect() error {
|
|
||||||
if n.conn != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := nats.DefaultOptions
|
|
||||||
opts.Servers = n.addrs
|
|
||||||
c, err := opts.Connect()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
n.conn = c
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *nbroker) Disconnect() error {
|
|
||||||
n.conn.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *nbroker) Init() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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, handler broker.Handler) (broker.Subscriber, error) {
|
|
||||||
sub, err := n.conn.Subscribe(topic, func(msg *nats.Msg) {
|
|
||||||
var m *broker.Message
|
|
||||||
if err := json.Unmarshal(msg.Data, &m); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
handler(m)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &subscriber{s: sub}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBroker(addrs []string, opt ...broker.Option) broker.Broker {
|
|
||||||
var cAddrs []string
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if len(addr) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(addr, "nats://") {
|
|
||||||
addr = "nats://" + addr
|
|
||||||
}
|
|
||||||
cAddrs = append(cAddrs, addr)
|
|
||||||
}
|
|
||||||
if len(cAddrs) == 0 {
|
|
||||||
cAddrs = []string{nats.DefaultURL}
|
|
||||||
}
|
|
||||||
return &nbroker{
|
|
||||||
addrs: cAddrs,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
//
|
|
||||||
// All credit to Mondo
|
|
||||||
//
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nu7hatch/gouuid"
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rabbitMQChannel struct {
|
|
||||||
uuid string
|
|
||||||
connection *amqp.Connection
|
|
||||||
channel *amqp.Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRabbitChannel(conn *amqp.Connection) (*rabbitMQChannel, error) {
|
|
||||||
id, err := uuid.NewV4()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rabbitCh := &rabbitMQChannel{
|
|
||||||
uuid: id.String(),
|
|
||||||
connection: conn,
|
|
||||||
}
|
|
||||||
if err := rabbitCh.Connect(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return rabbitCh, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Connect() error {
|
|
||||||
var err error
|
|
||||||
r.channel, err = r.connection.Channel()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Close() error {
|
|
||||||
if r.channel == nil {
|
|
||||||
return errors.New("Channel is nil")
|
|
||||||
}
|
|
||||||
return r.channel.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Publish(exchange, key string, message amqp.Publishing) error {
|
|
||||||
if r.channel == nil {
|
|
||||||
return errors.New("Channel is nil")
|
|
||||||
}
|
|
||||||
return r.channel.Publish(exchange, key, false, false, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareExchange(exchange string) error {
|
|
||||||
return r.channel.ExchangeDeclare(
|
|
||||||
exchange, // name
|
|
||||||
"topic", // kind
|
|
||||||
false, // durable
|
|
||||||
false, // autoDelete
|
|
||||||
false, // internal
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
false, // durable
|
|
||||||
true, // autoDelete
|
|
||||||
false, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareDurableQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
true, // durable
|
|
||||||
false, // autoDelete
|
|
||||||
false, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareReplyQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
false, // durable
|
|
||||||
true, // autoDelete
|
|
||||||
true, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) ConsumeQueue(queue string) (<-chan amqp.Delivery, error) {
|
|
||||||
return r.channel.Consume(
|
|
||||||
queue, // queue
|
|
||||||
r.uuid, // consumer
|
|
||||||
true, // autoAck
|
|
||||||
false, // exclusive
|
|
||||||
false, // nolocal
|
|
||||||
false, // nowait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) BindQueue(queue, exchange string) error {
|
|
||||||
return r.channel.QueueBind(
|
|
||||||
queue, // name
|
|
||||||
queue, // key
|
|
||||||
exchange, // exchange
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
//
|
|
||||||
// All credit to Mondo
|
|
||||||
//
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultExchange = "micro"
|
|
||||||
DefaultRabbitURL = "amqp://guest:guest@127.0.0.1:5672"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rabbitMQConn struct {
|
|
||||||
Connection *amqp.Connection
|
|
||||||
Channel *rabbitMQChannel
|
|
||||||
ExchangeChannel *rabbitMQChannel
|
|
||||||
notify chan bool
|
|
||||||
exchange string
|
|
||||||
url string
|
|
||||||
|
|
||||||
connected bool
|
|
||||||
|
|
||||||
mtx sync.Mutex
|
|
||||||
close chan bool
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRabbitMQConn(exchange string, urls []string) *rabbitMQConn {
|
|
||||||
var url string
|
|
||||||
|
|
||||||
if len(urls) > 0 && strings.HasPrefix(urls[0], "amqp://") {
|
|
||||||
url = urls[0]
|
|
||||||
} else {
|
|
||||||
url = DefaultRabbitURL
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(exchange) == 0 {
|
|
||||||
exchange = DefaultExchange
|
|
||||||
}
|
|
||||||
|
|
||||||
return &rabbitMQConn{
|
|
||||||
exchange: exchange,
|
|
||||||
url: url,
|
|
||||||
notify: make(chan bool, 1),
|
|
||||||
close: make(chan bool),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Init() chan bool {
|
|
||||||
go r.Connect(r.notify)
|
|
||||||
return r.notify
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Connect(connected chan bool) {
|
|
||||||
for {
|
|
||||||
if err := r.tryToConnect(); err != nil {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
connected <- true
|
|
||||||
r.connected = true
|
|
||||||
notifyClose := make(chan *amqp.Error)
|
|
||||||
r.Connection.NotifyClose(notifyClose)
|
|
||||||
|
|
||||||
// Block until we get disconnected, or shut down
|
|
||||||
select {
|
|
||||||
case <-notifyClose:
|
|
||||||
// Spin around and reconnect
|
|
||||||
r.connected = false
|
|
||||||
case <-r.close:
|
|
||||||
// Shut down connection
|
|
||||||
if err := r.Connection.Close(); err != nil {
|
|
||||||
}
|
|
||||||
r.connected = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) IsConnected() bool {
|
|
||||||
return r.connected
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Close() {
|
|
||||||
r.mtx.Lock()
|
|
||||||
defer r.mtx.Unlock()
|
|
||||||
|
|
||||||
if r.closed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
close(r.close)
|
|
||||||
r.closed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) tryToConnect() error {
|
|
||||||
var err error
|
|
||||||
r.Connection, err = amqp.Dial(r.url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Channel, err = newRabbitChannel(r.Connection)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Channel.DeclareExchange(r.exchange)
|
|
||||||
r.ExchangeChannel, err = newRabbitChannel(r.Connection)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Consume(queue string) (*rabbitMQChannel, <-chan amqp.Delivery, error) {
|
|
||||||
consumerChannel, err := newRabbitChannel(r.Connection)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = consumerChannel.DeclareQueue(queue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
deliveries, err := consumerChannel.ConsumeQueue(queue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = consumerChannel.BindQueue(queue, r.exchange)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumerChannel, deliveries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Publish(exchange, key string, msg amqp.Publishing) error {
|
|
||||||
return r.ExchangeChannel.Publish(exchange, key, msg)
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/micro/go-micro/broker"
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rbroker struct {
|
|
||||||
conn *rabbitMQConn
|
|
||||||
addrs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type subscriber struct {
|
|
||||||
topic string
|
|
||||||
ch *rabbitMQChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *subscriber) Topic() string {
|
|
||||||
return s.topic
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *subscriber) Unsubscribe() error {
|
|
||||||
return s.ch.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rbroker) Publish(topic string, msg *broker.Message) error {
|
|
||||||
m := amqp.Publishing{
|
|
||||||
Body: msg.Body,
|
|
||||||
Headers: amqp.Table{},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range msg.Header {
|
|
||||||
m.Headers[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.conn.Publish("", topic, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := func(msg amqp.Delivery) {
|
|
||||||
header := make(map[string]string)
|
|
||||||
for k, v := range msg.Headers {
|
|
||||||
header[k], _ = v.(string)
|
|
||||||
}
|
|
||||||
handler(&broker.Message{
|
|
||||||
Header: header,
|
|
||||||
Body: msg.Body,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for d := range sub {
|
|
||||||
go fn(d)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &subscriber{ch: ch, topic: topic}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rbroker) Address() string {
|
|
||||||
if len(r.addrs) > 0 {
|
|
||||||
return r.addrs[0]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rbroker) Init() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rbroker) Connect() error {
|
|
||||||
<-r.conn.Init()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rbroker) Disconnect() error {
|
|
||||||
r.conn.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBroker(addrs []string, opt ...broker.Option) broker.Broker {
|
|
||||||
return &rbroker{
|
|
||||||
conn: newRabbitMQConn("", addrs),
|
|
||||||
addrs: addrs,
|
|
||||||
}
|
|
||||||
}
|
|
27
cmd/cmd.go
27
cmd/cmd.go
@ -15,21 +15,6 @@ import (
|
|||||||
"github.com/micro/go-micro/registry"
|
"github.com/micro/go-micro/registry"
|
||||||
"github.com/micro/go-micro/server"
|
"github.com/micro/go-micro/server"
|
||||||
"github.com/micro/go-micro/transport"
|
"github.com/micro/go-micro/transport"
|
||||||
|
|
||||||
// brokers
|
|
||||||
"github.com/micro/go-micro/broker/http"
|
|
||||||
"github.com/micro/go-micro/broker/nats"
|
|
||||||
"github.com/micro/go-micro/broker/rabbitmq"
|
|
||||||
|
|
||||||
// registries
|
|
||||||
"github.com/micro/go-micro/registry/consul"
|
|
||||||
"github.com/micro/go-micro/registry/etcd"
|
|
||||||
"github.com/micro/go-micro/registry/memory"
|
|
||||||
|
|
||||||
// transport
|
|
||||||
thttp "github.com/micro/go-micro/transport/http"
|
|
||||||
tnats "github.com/micro/go-micro/transport/nats"
|
|
||||||
trmq "github.com/micro/go-micro/transport/rabbitmq"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -132,21 +117,15 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
Brokers = map[string]func([]string, ...broker.Option) broker.Broker{
|
Brokers = map[string]func([]string, ...broker.Option) broker.Broker{
|
||||||
"http": http.NewBroker,
|
"http": broker.NewBroker,
|
||||||
"nats": nats.NewBroker,
|
|
||||||
"rabbitmq": rabbitmq.NewBroker,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Registries = map[string]func([]string, ...registry.Option) registry.Registry{
|
Registries = map[string]func([]string, ...registry.Option) registry.Registry{
|
||||||
"consul": consul.NewRegistry,
|
"consul": registry.NewRegistry,
|
||||||
"etcd": etcd.NewRegistry,
|
|
||||||
"memory": memory.NewRegistry,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transports = map[string]func([]string, ...transport.Option) transport.Transport{
|
Transports = map[string]func([]string, ...transport.Option) transport.Transport{
|
||||||
"http": thttp.NewTransport,
|
"http": transport.NewTransport,
|
||||||
"rabbitmq": trmq.NewTransport,
|
|
||||||
"nats": tnats.NewTransport,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package consul
|
|
||||||
|
|
||||||
// This is a hack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/micro/go-micro/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewRegistry(addrs []string, opt ...registry.Option) registry.Registry {
|
|
||||||
return registry.NewRegistry(addrs, opt...)
|
|
||||||
}
|
|
@ -1,193 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
etcd "github.com/coreos/etcd/client"
|
|
||||||
"github.com/micro/go-micro/registry"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
prefix = "/micro-registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
type etcdRegistry struct {
|
|
||||||
client etcd.KeysAPI
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
services map[string][]*registry.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func encode(s *registry.Service) string {
|
|
||||||
b, _ := json.Marshal(s)
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func decode(ds string) *registry.Service {
|
|
||||||
var s *registry.Service
|
|
||||||
json.Unmarshal([]byte(ds), &s)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func nodePath(s, id string) string {
|
|
||||||
service := strings.Replace(s, "/", "-", -1)
|
|
||||||
node := strings.Replace(id, "/", "-", -1)
|
|
||||||
return filepath.Join(prefix, service, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func servicePath(s string) string {
|
|
||||||
return filepath.Join(prefix, strings.Replace(s, "/", "-", -1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdRegistry) Deregister(s *registry.Service) error {
|
|
||||||
if len(s.Nodes) == 0 {
|
|
||||||
return errors.New("Require at least one node")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, node := range s.Nodes {
|
|
||||||
_, err := e.client.Delete(context.Background(), nodePath(s.Name, node.Id), &etcd.DeleteOptions{Recursive: false})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.client.Delete(context.Background(), servicePath(s.Name), &etcd.DeleteOptions{Dir: true})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdRegistry) Register(s *registry.Service) error {
|
|
||||||
if len(s.Nodes) == 0 {
|
|
||||||
return errors.New("Require at least one node")
|
|
||||||
}
|
|
||||||
|
|
||||||
service := ®istry.Service{
|
|
||||||
Name: s.Name,
|
|
||||||
Version: s.Version,
|
|
||||||
Metadata: s.Metadata,
|
|
||||||
Endpoints: s.Endpoints,
|
|
||||||
}
|
|
||||||
|
|
||||||
e.client.Set(context.Background(), servicePath(s.Name), "", &etcd.SetOptions{Dir: true})
|
|
||||||
|
|
||||||
for _, node := range s.Nodes {
|
|
||||||
service.Nodes = []*registry.Node{node}
|
|
||||||
_, err := e.client.Set(context.Background(), nodePath(service.Name, node.Id), encode(service), &etcd.SetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdRegistry) GetService(name string) ([]*registry.Service, error) {
|
|
||||||
e.RLock()
|
|
||||||
service, ok := e.services[name]
|
|
||||||
e.RUnlock()
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rsp, err := e.client.Get(context.Background(), servicePath(name), &etcd.GetOptions{})
|
|
||||||
if err != nil && !strings.HasPrefix(err.Error(), "100: Key not found") {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceMap := map[string]*registry.Service{}
|
|
||||||
|
|
||||||
for _, n := range rsp.Node.Nodes {
|
|
||||||
if n.Dir {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sn := decode(n.Value)
|
|
||||||
|
|
||||||
s, ok := serviceMap[sn.Version]
|
|
||||||
if !ok {
|
|
||||||
s = ®istry.Service{
|
|
||||||
Name: sn.Name,
|
|
||||||
Version: sn.Version,
|
|
||||||
Metadata: sn.Metadata,
|
|
||||||
Endpoints: sn.Endpoints,
|
|
||||||
}
|
|
||||||
serviceMap[s.Version] = s
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, node := range sn.Nodes {
|
|
||||||
s.Nodes = append(s.Nodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var services []*registry.Service
|
|
||||||
for _, service := range serviceMap {
|
|
||||||
services = append(services, service)
|
|
||||||
}
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdRegistry) ListServices() ([]*registry.Service, error) {
|
|
||||||
e.RLock()
|
|
||||||
serviceMap := e.services
|
|
||||||
e.RUnlock()
|
|
||||||
|
|
||||||
var services []*registry.Service
|
|
||||||
|
|
||||||
if len(serviceMap) > 0 {
|
|
||||||
for _, service := range serviceMap {
|
|
||||||
services = append(services, service...)
|
|
||||||
}
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rsp, err := e.client.Get(context.Background(), prefix, &etcd.GetOptions{Recursive: true, Sort: true})
|
|
||||||
if err != nil && !strings.HasPrefix(err.Error(), "100: Key not found") {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, node := range rsp.Node.Nodes {
|
|
||||||
service := ®istry.Service{}
|
|
||||||
for _, n := range node.Nodes {
|
|
||||||
i := decode(n.Value)
|
|
||||||
service.Name = i.Name
|
|
||||||
}
|
|
||||||
services = append(services, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdRegistry) Watch() (registry.Watcher, error) {
|
|
||||||
// todo: fix watcher
|
|
||||||
return newEtcdWatcher(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRegistry(addrs []string, opt ...registry.Option) registry.Registry {
|
|
||||||
var cAddrs []string
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if len(addr) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cAddrs = append(cAddrs, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cAddrs) == 0 {
|
|
||||||
cAddrs = []string{"http://127.0.0.1:2379"}
|
|
||||||
}
|
|
||||||
|
|
||||||
c, _ := etcd.New(etcd.Config{
|
|
||||||
Endpoints: cAddrs,
|
|
||||||
})
|
|
||||||
|
|
||||||
e := &etcdRegistry{
|
|
||||||
client: etcd.NewKeysAPI(c),
|
|
||||||
services: make(map[string][]*registry.Service),
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
etcd "github.com/coreos/etcd/client"
|
|
||||||
"github.com/micro/go-micro/registry"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type etcdWatcher struct {
|
|
||||||
registry *etcdRegistry
|
|
||||||
stop chan bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func addNodes(old, neu []*registry.Node) []*registry.Node {
|
|
||||||
for _, n := range neu {
|
|
||||||
var seen bool
|
|
||||||
for i, o := range old {
|
|
||||||
if o.Id == n.Id {
|
|
||||||
seen = true
|
|
||||||
old[i] = n
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !seen {
|
|
||||||
old = append(old, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
func addServices(old, neu []*registry.Service) []*registry.Service {
|
|
||||||
for _, s := range neu {
|
|
||||||
var seen bool
|
|
||||||
for i, o := range old {
|
|
||||||
if o.Version == s.Version {
|
|
||||||
s.Nodes = addNodes(o.Nodes, s.Nodes)
|
|
||||||
seen = true
|
|
||||||
old[i] = s
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !seen {
|
|
||||||
old = append(old, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
func delNodes(old, del []*registry.Node) []*registry.Node {
|
|
||||||
var nodes []*registry.Node
|
|
||||||
for _, o := range old {
|
|
||||||
var rem bool
|
|
||||||
for _, n := range del {
|
|
||||||
if o.Id == n.Id {
|
|
||||||
rem = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !rem {
|
|
||||||
nodes = append(nodes, o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
func delServices(old, del []*registry.Service) []*registry.Service {
|
|
||||||
var services []*registry.Service
|
|
||||||
for i, o := range old {
|
|
||||||
var rem bool
|
|
||||||
for _, s := range del {
|
|
||||||
if o.Version == s.Version {
|
|
||||||
old[i].Nodes = delNodes(o.Nodes, s.Nodes)
|
|
||||||
if len(old[i].Nodes) == 0 {
|
|
||||||
rem = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !rem {
|
|
||||||
services = append(services, o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return services
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEtcdWatcher(r *etcdRegistry) (registry.Watcher, error) {
|
|
||||||
ew := &etcdWatcher{
|
|
||||||
registry: r,
|
|
||||||
stop: make(chan bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
w := r.client.Watcher(prefix, &etcd.WatcherOptions{AfterIndex: 0, Recursive: true})
|
|
||||||
|
|
||||||
c := context.Background()
|
|
||||||
ctx, cancel := context.WithCancel(c)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
<-ew.stop
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
|
|
||||||
go ew.watch(ctx, w)
|
|
||||||
|
|
||||||
return ew, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *etcdWatcher) watch(ctx context.Context, w etcd.Watcher) {
|
|
||||||
for {
|
|
||||||
rsp, err := w.Next(ctx)
|
|
||||||
if err != nil && ctx.Err() != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if rsp.Node.Dir {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s := decode(rsp.Node.Value)
|
|
||||||
if s == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
e.registry.Lock()
|
|
||||||
|
|
||||||
service, ok := e.registry.services[s.Name]
|
|
||||||
if !ok {
|
|
||||||
if rsp.Action == "create" {
|
|
||||||
e.registry.services[s.Name] = []*registry.Service{s}
|
|
||||||
}
|
|
||||||
e.registry.Unlock()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch rsp.Action {
|
|
||||||
case "delete":
|
|
||||||
services := delServices(service, []*registry.Service{s})
|
|
||||||
if len(services) > 0 {
|
|
||||||
e.registry.services[s.Name] = services
|
|
||||||
} else {
|
|
||||||
delete(e.registry.services, s.Name)
|
|
||||||
}
|
|
||||||
case "create":
|
|
||||||
e.registry.services[s.Name] = addServices(service, []*registry.Service{s})
|
|
||||||
}
|
|
||||||
|
|
||||||
e.registry.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ew *etcdWatcher) Stop() {
|
|
||||||
ew.stop <- true
|
|
||||||
}
|
|
@ -1,372 +0,0 @@
|
|||||||
package memory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
log "github.com/golang/glog"
|
|
||||||
"github.com/hashicorp/memberlist"
|
|
||||||
"github.com/micro/go-micro/registry"
|
|
||||||
"github.com/pborman/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
type action int
|
|
||||||
|
|
||||||
const (
|
|
||||||
addAction action = iota
|
|
||||||
delAction
|
|
||||||
syncAction
|
|
||||||
)
|
|
||||||
|
|
||||||
type broadcast struct {
|
|
||||||
msg []byte
|
|
||||||
notify chan<- struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type delegate struct {
|
|
||||||
broadcasts *memberlist.TransmitLimitedQueue
|
|
||||||
updates chan *update
|
|
||||||
}
|
|
||||||
|
|
||||||
type memoryRegistry struct {
|
|
||||||
broadcasts *memberlist.TransmitLimitedQueue
|
|
||||||
updates chan *update
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
services map[string][]*registry.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
type update struct {
|
|
||||||
Action action
|
|
||||||
Service *registry.Service
|
|
||||||
sync chan *registry.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
type watcher struct{}
|
|
||||||
|
|
||||||
func (b *broadcast) Invalidates(other memberlist.Broadcast) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *broadcast) Message() []byte {
|
|
||||||
return b.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *broadcast) Finished() {
|
|
||||||
if b.notify != nil {
|
|
||||||
close(b.notify)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegate) NodeMeta(limit int) []byte {
|
|
||||||
return []byte{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegate) NotifyMsg(b []byte) {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, len(b))
|
|
||||||
copy(buf, b)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
switch buf[0] {
|
|
||||||
case 'd': // data
|
|
||||||
var updates []*update
|
|
||||||
if err := json.Unmarshal(buf[1:], &updates); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, u := range updates {
|
|
||||||
d.updates <- u
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte {
|
|
||||||
return d.broadcasts.GetBroadcasts(overhead, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegate) LocalState(join bool) []byte {
|
|
||||||
if !join {
|
|
||||||
return []byte{}
|
|
||||||
}
|
|
||||||
|
|
||||||
syncCh := make(chan *registry.Service, 1)
|
|
||||||
m := map[string][]*registry.Service{}
|
|
||||||
|
|
||||||
d.updates <- &update{
|
|
||||||
Action: syncAction,
|
|
||||||
sync: syncCh,
|
|
||||||
}
|
|
||||||
|
|
||||||
for s := range syncCh {
|
|
||||||
m[s.Name] = append(m[s.Name], s)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, _ := json.Marshal(m)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegate) MergeRemoteState(buf []byte, join bool) {
|
|
||||||
if len(buf) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !join {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var m map[string][]*registry.Service
|
|
||||||
if err := json.Unmarshal(buf, &m); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, services := range m {
|
|
||||||
for _, service := range services {
|
|
||||||
d.updates <- &update{
|
|
||||||
Action: addAction,
|
|
||||||
Service: service,
|
|
||||||
sync: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) run() {
|
|
||||||
for u := range m.updates {
|
|
||||||
switch u.Action {
|
|
||||||
case addAction:
|
|
||||||
m.Lock()
|
|
||||||
if service, ok := m.services[u.Service.Name]; !ok {
|
|
||||||
m.services[u.Service.Name] = []*registry.Service{u.Service}
|
|
||||||
} else {
|
|
||||||
m.services[u.Service.Name] = addServices(service, []*registry.Service{u.Service})
|
|
||||||
}
|
|
||||||
m.Unlock()
|
|
||||||
case delAction:
|
|
||||||
m.Lock()
|
|
||||||
if service, ok := m.services[u.Service.Name]; ok {
|
|
||||||
if services := delServices(service, []*registry.Service{u.Service}); len(services) == 0 {
|
|
||||||
delete(m.services, u.Service.Name)
|
|
||||||
} else {
|
|
||||||
m.services[u.Service.Name] = services
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Unlock()
|
|
||||||
case syncAction:
|
|
||||||
if u.sync == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m.RLock()
|
|
||||||
for _, services := range m.services {
|
|
||||||
for _, service := range services {
|
|
||||||
u.sync <- service
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.RUnlock()
|
|
||||||
close(u.sync)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) Register(s *registry.Service) error {
|
|
||||||
m.Lock()
|
|
||||||
if service, ok := m.services[s.Name]; !ok {
|
|
||||||
m.services[s.Name] = []*registry.Service{s}
|
|
||||||
} else {
|
|
||||||
m.services[s.Name] = addServices(service, []*registry.Service{s})
|
|
||||||
}
|
|
||||||
m.Unlock()
|
|
||||||
|
|
||||||
b, _ := json.Marshal([]*update{
|
|
||||||
&update{
|
|
||||||
Action: addAction,
|
|
||||||
Service: s,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
m.broadcasts.QueueBroadcast(&broadcast{
|
|
||||||
msg: append([]byte("d"), b...),
|
|
||||||
notify: nil,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) Deregister(s *registry.Service) error {
|
|
||||||
m.Lock()
|
|
||||||
if service, ok := m.services[s.Name]; ok {
|
|
||||||
if services := delServices(service, []*registry.Service{s}); len(services) == 0 {
|
|
||||||
delete(m.services, s.Name)
|
|
||||||
} else {
|
|
||||||
m.services[s.Name] = services
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Unlock()
|
|
||||||
|
|
||||||
b, _ := json.Marshal([]*update{
|
|
||||||
&update{
|
|
||||||
Action: delAction,
|
|
||||||
Service: s,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
m.broadcasts.QueueBroadcast(&broadcast{
|
|
||||||
msg: append([]byte("d"), b...),
|
|
||||||
notify: nil,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) GetService(name string) ([]*registry.Service, error) {
|
|
||||||
m.RLock()
|
|
||||||
service, ok := m.services[name]
|
|
||||||
m.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("Service %s not found", name)
|
|
||||||
}
|
|
||||||
return service, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) ListServices() ([]*registry.Service, error) {
|
|
||||||
var services []*registry.Service
|
|
||||||
m.RLock()
|
|
||||||
for _, service := range m.services {
|
|
||||||
services = append(services, service...)
|
|
||||||
}
|
|
||||||
m.RUnlock()
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memoryRegistry) Watch() (registry.Watcher, error) {
|
|
||||||
return &watcher{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watcher) Stop() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func addNodes(old, neu []*registry.Node) []*registry.Node {
|
|
||||||
for _, n := range neu {
|
|
||||||
var seen bool
|
|
||||||
for i, o := range old {
|
|
||||||
if o.Id == n.Id {
|
|
||||||
seen = true
|
|
||||||
old[i] = n
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !seen {
|
|
||||||
old = append(old, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
func addServices(old, neu []*registry.Service) []*registry.Service {
|
|
||||||
for _, s := range neu {
|
|
||||||
var seen bool
|
|
||||||
for i, o := range old {
|
|
||||||
if o.Version == s.Version {
|
|
||||||
s.Nodes = addNodes(o.Nodes, s.Nodes)
|
|
||||||
seen = true
|
|
||||||
old[i] = s
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !seen {
|
|
||||||
old = append(old, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
func delNodes(old, del []*registry.Node) []*registry.Node {
|
|
||||||
var nodes []*registry.Node
|
|
||||||
for _, o := range old {
|
|
||||||
var rem bool
|
|
||||||
for _, n := range del {
|
|
||||||
if o.Id == n.Id {
|
|
||||||
rem = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !rem {
|
|
||||||
nodes = append(nodes, o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
func delServices(old, del []*registry.Service) []*registry.Service {
|
|
||||||
var services []*registry.Service
|
|
||||||
for i, o := range old {
|
|
||||||
var rem bool
|
|
||||||
for _, s := range del {
|
|
||||||
if o.Version == s.Version {
|
|
||||||
old[i].Nodes = delNodes(o.Nodes, s.Nodes)
|
|
||||||
if len(old[i].Nodes) == 0 {
|
|
||||||
rem = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !rem {
|
|
||||||
services = append(services, o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return services
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRegistry(addrs []string, opt ...registry.Option) registry.Registry {
|
|
||||||
cAddrs := []string{}
|
|
||||||
hostname, _ := os.Hostname()
|
|
||||||
updates := make(chan *update, 100)
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if len(addr) > 0 {
|
|
||||||
cAddrs = append(cAddrs, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcasts := &memberlist.TransmitLimitedQueue{
|
|
||||||
NumNodes: func() int {
|
|
||||||
return len(cAddrs)
|
|
||||||
},
|
|
||||||
RetransmitMult: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
mr := &memoryRegistry{
|
|
||||||
broadcasts: broadcasts,
|
|
||||||
services: make(map[string][]*registry.Service),
|
|
||||||
updates: updates,
|
|
||||||
}
|
|
||||||
|
|
||||||
go mr.run()
|
|
||||||
|
|
||||||
c := memberlist.DefaultLocalConfig()
|
|
||||||
c.BindPort = 0
|
|
||||||
c.Name = hostname + "-" + uuid.NewUUID().String()
|
|
||||||
c.Delegate = &delegate{
|
|
||||||
updates: updates,
|
|
||||||
broadcasts: broadcasts,
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := memberlist.Create(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error creating memberlist: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cAddrs) > 0 {
|
|
||||||
_, err := m.Join(cAddrs)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error joining members: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Local memberlist node %s:%d\n", m.LocalNode().Addr, m.LocalNode().Port)
|
|
||||||
return mr
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package memory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDelServices(t *testing.T) {
|
|
||||||
services := []*registry.Service{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Version: "1.0.0",
|
|
||||||
Nodes: []*registry.Node{
|
|
||||||
{
|
|
||||||
Id: "foo-123",
|
|
||||||
Address: "localhost",
|
|
||||||
Port: 9999,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Version: "1.0.0",
|
|
||||||
Nodes: []*registry.Node{
|
|
||||||
{
|
|
||||||
Id: "foo-123",
|
|
||||||
Address: "localhost",
|
|
||||||
Port: 6666,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servs := delServices([]*registry.Service{services[0]}, []*registry.Service{services[1]})
|
|
||||||
if i := len(servs); i > 0 {
|
|
||||||
t.Errorf("Expected 0 nodes, got %d: %+v", i, servs)
|
|
||||||
}
|
|
||||||
t.Logf("Services %+v", servs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDelNodes(t *testing.T) {
|
|
||||||
services := []*registry.Service{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Version: "1.0.0",
|
|
||||||
Nodes: []*registry.Node{
|
|
||||||
{
|
|
||||||
Id: "foo-123",
|
|
||||||
Address: "localhost",
|
|
||||||
Port: 9999,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "foo-321",
|
|
||||||
Address: "localhost",
|
|
||||||
Port: 6666,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Version: "1.0.0",
|
|
||||||
Nodes: []*registry.Node{
|
|
||||||
{
|
|
||||||
Id: "foo-123",
|
|
||||||
Address: "localhost",
|
|
||||||
Port: 6666,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes := delNodes(services[0].Nodes, services[1].Nodes)
|
|
||||||
if i := len(nodes); i != 1 {
|
|
||||||
t.Errorf("Expected only 1 node, got %d: %+v", i, nodes)
|
|
||||||
}
|
|
||||||
t.Logf("Nodes %+v", nodes)
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type buffer struct {
|
|
||||||
io.ReadWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *buffer) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
// This is a hack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/micro/go-micro/transport"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTransport(addrs []string, opt ...transport.Option) transport.Transport {
|
|
||||||
return transport.NewTransport(addrs, opt...)
|
|
||||||
}
|
|
@ -12,6 +12,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type buffer struct {
|
||||||
|
io.ReadWriter
|
||||||
|
}
|
||||||
|
|
||||||
type httpTransport struct{}
|
type httpTransport struct{}
|
||||||
|
|
||||||
type httpTransportClient struct {
|
type httpTransportClient struct {
|
||||||
@ -33,6 +37,10 @@ type httpTransportListener struct {
|
|||||||
listener net.Listener
|
listener net.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *buffer) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *httpTransportClient) Send(m *Message) error {
|
func (h *httpTransportClient) Send(m *Message) error {
|
||||||
header := make(http.Header)
|
header := make(http.Header)
|
||||||
|
|
||||||
|
@ -1,162 +0,0 @@
|
|||||||
package nats
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/apcera/nats"
|
|
||||||
"github.com/micro/go-micro/transport"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ntport struct {
|
|
||||||
addrs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ntportClient struct {
|
|
||||||
conn *nats.Conn
|
|
||||||
addr string
|
|
||||||
id string
|
|
||||||
sub *nats.Subscription
|
|
||||||
}
|
|
||||||
|
|
||||||
type ntportSocket struct {
|
|
||||||
conn *nats.Conn
|
|
||||||
m *nats.Msg
|
|
||||||
}
|
|
||||||
|
|
||||||
type ntportListener struct {
|
|
||||||
conn *nats.Conn
|
|
||||||
addr string
|
|
||||||
exit chan bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportClient) Send(m *transport.Message) error {
|
|
||||||
b, err := json.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.conn.PublishRequest(n.addr, n.id, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportClient) Recv(m *transport.Message) error {
|
|
||||||
rsp, err := n.sub.NextMsg(time.Second * 10)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mr *transport.Message
|
|
||||||
if err := json.Unmarshal(rsp.Data, &mr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*m = *mr
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportClient) Close() error {
|
|
||||||
n.sub.Unsubscribe()
|
|
||||||
n.conn.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportSocket) Recv(m *transport.Message) error {
|
|
||||||
if m == nil {
|
|
||||||
return errors.New("message passed in is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(n.m.Data, &m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportSocket) Send(m *transport.Message) error {
|
|
||||||
b, err := json.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return n.conn.Publish(n.m.Reply, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportSocket) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportListener) Addr() string {
|
|
||||||
return n.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportListener) Close() error {
|
|
||||||
n.exit <- true
|
|
||||||
n.conn.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntportListener) Accept(fn func(transport.Socket)) error {
|
|
||||||
s, err := n.conn.Subscribe(n.addr, func(m *nats.Msg) {
|
|
||||||
fn(&ntportSocket{
|
|
||||||
conn: n.conn,
|
|
||||||
m: m,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
<-n.exit
|
|
||||||
return s.Unsubscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
|
|
||||||
cAddr := nats.DefaultURL
|
|
||||||
|
|
||||||
if len(n.addrs) > 0 && strings.HasPrefix(n.addrs[0], "nats://") {
|
|
||||||
cAddr = n.addrs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := nats.Connect(cAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
id := nats.NewInbox()
|
|
||||||
sub, err := c.SubscribeSync(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ntportClient{
|
|
||||||
conn: c,
|
|
||||||
addr: addr,
|
|
||||||
id: id,
|
|
||||||
sub: sub,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *ntport) Listen(addr string) (transport.Listener, error) {
|
|
||||||
cAddr := nats.DefaultURL
|
|
||||||
|
|
||||||
if len(n.addrs) > 0 && strings.HasPrefix(n.addrs[0], "nats://") {
|
|
||||||
cAddr = n.addrs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := nats.Connect(cAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ntportListener{
|
|
||||||
addr: nats.NewInbox(),
|
|
||||||
conn: c,
|
|
||||||
exit: make(chan bool, 1),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTransport(addrs []string, opt ...transport.Option) transport.Transport {
|
|
||||||
return &ntport{
|
|
||||||
addrs: addrs,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
//
|
|
||||||
// All credit to Mondo
|
|
||||||
//
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nu7hatch/gouuid"
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rabbitMQChannel struct {
|
|
||||||
uuid string
|
|
||||||
connection *amqp.Connection
|
|
||||||
channel *amqp.Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRabbitChannel(conn *amqp.Connection) (*rabbitMQChannel, error) {
|
|
||||||
id, err := uuid.NewV4()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rabbitCh := &rabbitMQChannel{
|
|
||||||
uuid: id.String(),
|
|
||||||
connection: conn,
|
|
||||||
}
|
|
||||||
if err := rabbitCh.Connect(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return rabbitCh, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Connect() error {
|
|
||||||
var err error
|
|
||||||
r.channel, err = r.connection.Channel()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Close() error {
|
|
||||||
if r.channel == nil {
|
|
||||||
return errors.New("Channel is nil")
|
|
||||||
}
|
|
||||||
return r.channel.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) Publish(exchange, key string, message amqp.Publishing) error {
|
|
||||||
if r.channel == nil {
|
|
||||||
return errors.New("Channel is nil")
|
|
||||||
}
|
|
||||||
return r.channel.Publish(exchange, key, false, false, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareExchange(exchange string) error {
|
|
||||||
return r.channel.ExchangeDeclare(
|
|
||||||
exchange, // name
|
|
||||||
"topic", // kind
|
|
||||||
false, // durable
|
|
||||||
false, // autoDelete
|
|
||||||
false, // internal
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
false, // durable
|
|
||||||
true, // autoDelete
|
|
||||||
false, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareDurableQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
true, // durable
|
|
||||||
false, // autoDelete
|
|
||||||
false, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) DeclareReplyQueue(queue string) error {
|
|
||||||
_, err := r.channel.QueueDeclare(
|
|
||||||
queue, // name
|
|
||||||
false, // durable
|
|
||||||
true, // autoDelete
|
|
||||||
true, // exclusive
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) ConsumeQueue(queue string) (<-chan amqp.Delivery, error) {
|
|
||||||
return r.channel.Consume(
|
|
||||||
queue, // queue
|
|
||||||
r.uuid, // consumer
|
|
||||||
true, // autoAck
|
|
||||||
false, // exclusive
|
|
||||||
false, // nolocal
|
|
||||||
false, // nowait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQChannel) BindQueue(queue, exchange string) error {
|
|
||||||
return r.channel.QueueBind(
|
|
||||||
queue, // name
|
|
||||||
queue, // key
|
|
||||||
exchange, // exchange
|
|
||||||
false, // noWait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
//
|
|
||||||
// All credit to Mondo
|
|
||||||
//
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultExchange = "micro"
|
|
||||||
DefaultRabbitURL = "amqp://guest:guest@127.0.0.1:5672"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rabbitMQConn struct {
|
|
||||||
Connection *amqp.Connection
|
|
||||||
Channel *rabbitMQChannel
|
|
||||||
notify chan bool
|
|
||||||
exchange string
|
|
||||||
url string
|
|
||||||
|
|
||||||
connected bool
|
|
||||||
|
|
||||||
mtx sync.Mutex
|
|
||||||
close chan bool
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRabbitMQConn(exchange string, urls []string) *rabbitMQConn {
|
|
||||||
var url string
|
|
||||||
|
|
||||||
if len(urls) > 0 && strings.HasPrefix(urls[0], "amqp://") {
|
|
||||||
url = urls[0]
|
|
||||||
} else {
|
|
||||||
url = DefaultRabbitURL
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(exchange) == 0 {
|
|
||||||
exchange = DefaultExchange
|
|
||||||
}
|
|
||||||
|
|
||||||
return &rabbitMQConn{
|
|
||||||
exchange: exchange,
|
|
||||||
url: url,
|
|
||||||
notify: make(chan bool, 1),
|
|
||||||
close: make(chan bool),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Init() chan bool {
|
|
||||||
go r.Connect(r.notify)
|
|
||||||
return r.notify
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Connect(connected chan bool) {
|
|
||||||
for {
|
|
||||||
if err := r.tryToConnect(); err != nil {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
connected <- true
|
|
||||||
r.connected = true
|
|
||||||
notifyClose := make(chan *amqp.Error)
|
|
||||||
r.Connection.NotifyClose(notifyClose)
|
|
||||||
|
|
||||||
// Block until we get disconnected, or shut down
|
|
||||||
select {
|
|
||||||
case <-notifyClose:
|
|
||||||
// Spin around and reconnect
|
|
||||||
r.connected = false
|
|
||||||
case <-r.close:
|
|
||||||
// Shut down connection
|
|
||||||
if err := r.Connection.Close(); err != nil {
|
|
||||||
}
|
|
||||||
r.connected = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) IsConnected() bool {
|
|
||||||
return r.connected
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Close() {
|
|
||||||
r.mtx.Lock()
|
|
||||||
defer r.mtx.Unlock()
|
|
||||||
|
|
||||||
if r.closed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
close(r.close)
|
|
||||||
r.closed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) tryToConnect() error {
|
|
||||||
var err error
|
|
||||||
r.Connection, err = amqp.Dial(r.url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Channel, err = newRabbitChannel(r.Connection)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Channel.DeclareExchange(r.exchange)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Consume(queue string) (<-chan amqp.Delivery, error) {
|
|
||||||
consumerChannel, err := newRabbitChannel(r.Connection)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = consumerChannel.DeclareQueue(queue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
deliveries, err := consumerChannel.ConsumeQueue(queue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = consumerChannel.BindQueue(queue, r.exchange)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return deliveries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rabbitMQConn) Publish(exchange, key string, msg amqp.Publishing) error {
|
|
||||||
return r.Channel.Publish(exchange, key, msg)
|
|
||||||
}
|
|
@ -1,249 +0,0 @@
|
|||||||
package rabbitmq
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"errors"
|
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
|
||||||
"github.com/streadway/amqp"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/transport"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
directReplyQueue = "amq.rabbitmq.reply-to"
|
|
||||||
)
|
|
||||||
|
|
||||||
type rmqtport struct {
|
|
||||||
conn *rabbitMQConn
|
|
||||||
addrs []string
|
|
||||||
|
|
||||||
once sync.Once
|
|
||||||
replyTo string
|
|
||||||
|
|
||||||
sync.Mutex
|
|
||||||
inflight map[string]chan amqp.Delivery
|
|
||||||
}
|
|
||||||
|
|
||||||
type rmqtportClient struct {
|
|
||||||
rt *rmqtport
|
|
||||||
addr string
|
|
||||||
corId string
|
|
||||||
reply chan amqp.Delivery
|
|
||||||
}
|
|
||||||
|
|
||||||
type rmqtportSocket struct {
|
|
||||||
conn *rabbitMQConn
|
|
||||||
d *amqp.Delivery
|
|
||||||
}
|
|
||||||
|
|
||||||
type rmqtportListener struct {
|
|
||||||
conn *rabbitMQConn
|
|
||||||
addr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportClient) Send(m *transport.Message) error {
|
|
||||||
if !r.rt.conn.IsConnected() {
|
|
||||||
return errors.New("Not connected to AMQP")
|
|
||||||
}
|
|
||||||
|
|
||||||
headers := amqp.Table{}
|
|
||||||
for k, v := range m.Header {
|
|
||||||
headers[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
message := amqp.Publishing{
|
|
||||||
CorrelationId: r.corId,
|
|
||||||
Timestamp: time.Now().UTC(),
|
|
||||||
Body: m.Body,
|
|
||||||
ReplyTo: r.rt.replyTo,
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.rt.conn.Publish("micro", r.addr, message); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportClient) Recv(m *transport.Message) error {
|
|
||||||
select {
|
|
||||||
case d := <-r.reply:
|
|
||||||
mr := &transport.Message{
|
|
||||||
Header: make(map[string]string),
|
|
||||||
Body: d.Body,
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range d.Headers {
|
|
||||||
mr.Header[k] = fmt.Sprintf("%v", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
*m = *mr
|
|
||||||
return nil
|
|
||||||
case <-time.After(time.Second * 10):
|
|
||||||
return errors.New("timed out")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportClient) Close() error {
|
|
||||||
r.rt.popReq(r.corId)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportSocket) Recv(m *transport.Message) error {
|
|
||||||
if m == nil {
|
|
||||||
return errors.New("message passed in is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
mr := &transport.Message{
|
|
||||||
Header: make(map[string]string),
|
|
||||||
Body: r.d.Body,
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range r.d.Headers {
|
|
||||||
mr.Header[k] = fmt.Sprintf("%v", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
*m = *mr
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportSocket) Send(m *transport.Message) error {
|
|
||||||
msg := amqp.Publishing{
|
|
||||||
CorrelationId: r.d.CorrelationId,
|
|
||||||
Timestamp: time.Now().UTC(),
|
|
||||||
Body: m.Body,
|
|
||||||
Headers: amqp.Table{},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range m.Header {
|
|
||||||
msg.Headers[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.conn.Publish("", r.d.ReplyTo, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportSocket) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportListener) Addr() string {
|
|
||||||
return r.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportListener) Close() error {
|
|
||||||
r.conn.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtportListener) Accept(fn func(transport.Socket)) error {
|
|
||||||
deliveries, err := r.conn.Consume(r.addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := func(d amqp.Delivery) {
|
|
||||||
fn(&rmqtportSocket{
|
|
||||||
d: &d,
|
|
||||||
conn: r.conn,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for d := range deliveries {
|
|
||||||
go handler(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) putReq(id string) chan amqp.Delivery {
|
|
||||||
r.Lock()
|
|
||||||
ch := make(chan amqp.Delivery, 1)
|
|
||||||
r.inflight[id] = ch
|
|
||||||
r.Unlock()
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) getReq(id string) chan amqp.Delivery {
|
|
||||||
r.Lock()
|
|
||||||
defer r.Unlock()
|
|
||||||
if ch, ok := r.inflight[id]; ok {
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) popReq(id string) {
|
|
||||||
r.Lock()
|
|
||||||
defer r.Unlock()
|
|
||||||
if _, ok := r.inflight[id]; ok {
|
|
||||||
delete(r.inflight, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) init() {
|
|
||||||
<-r.conn.Init()
|
|
||||||
if err := r.conn.Channel.DeclareReplyQueue(r.replyTo); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
deliveries, err := r.conn.Channel.ConsumeQueue(r.replyTo)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
for delivery := range deliveries {
|
|
||||||
go r.handle(delivery)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) handle(delivery amqp.Delivery) {
|
|
||||||
ch := r.getReq(delivery.CorrelationId)
|
|
||||||
if ch == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ch <- delivery
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
|
|
||||||
id, err := uuid.NewV4()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.once.Do(r.init)
|
|
||||||
|
|
||||||
return &rmqtportClient{
|
|
||||||
rt: r,
|
|
||||||
addr: addr,
|
|
||||||
corId: id.String(),
|
|
||||||
reply: r.putReq(id.String()),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *rmqtport) Listen(addr string) (transport.Listener, error) {
|
|
||||||
id, err := uuid.NewV4()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
conn := newRabbitMQConn("", r.addrs)
|
|
||||||
<-conn.Init()
|
|
||||||
|
|
||||||
return &rmqtportListener{
|
|
||||||
addr: id.String(),
|
|
||||||
conn: conn,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTransport(addrs []string, opt ...transport.Option) transport.Transport {
|
|
||||||
return &rmqtport{
|
|
||||||
conn: newRabbitMQConn("", addrs),
|
|
||||||
addrs: addrs,
|
|
||||||
replyTo: directReplyQueue,
|
|
||||||
inflight: make(map[string]chan amqp.Delivery),
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user