Move plugins to go-plugins

This commit is contained in:
Asim 2015-11-25 00:17:15 +00:00
parent 469b12ecea
commit 04e07f4b39
18 changed files with 11 additions and 2007 deletions

View File

@ -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...)
}

View File

@ -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,
}
}

View File

@ -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
)
}

View File

@ -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)
}

View File

@ -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,
}
}

View File

@ -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,
} }
) )

View File

@ -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...)
}

View File

@ -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 := &registry.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 = &registry.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 := &registry.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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -1,13 +0,0 @@
package transport
import (
"io"
)
type buffer struct {
io.ReadWriter
}
func (b *buffer) Close() error {
return nil
}

View File

@ -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...)
}

View File

@ -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)

View File

@ -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,
}
}

View File

@ -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
)
}

View File

@ -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)
}

View File

@ -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),
}
}