mirror of https://github.com/tidwall/tile38.git
Added NATS endpoint
This commit is contained in:
parent
f31cead207
commit
53271ebad6
|
@ -33,6 +33,8 @@ const (
|
||||||
AMQP = Protocol("amqp")
|
AMQP = Protocol("amqp")
|
||||||
// SQS protocol
|
// SQS protocol
|
||||||
SQS = Protocol("sqs")
|
SQS = Protocol("sqs")
|
||||||
|
// NATS protocol
|
||||||
|
NATS = Protocol("nats")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Endpoint represents an endpoint.
|
// Endpoint represents an endpoint.
|
||||||
|
@ -90,6 +92,14 @@ type Endpoint struct {
|
||||||
CredProfile string
|
CredProfile string
|
||||||
QueueName string
|
QueueName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NATS struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
User string
|
||||||
|
Pass string
|
||||||
|
Topic string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conn is an endpoint connection
|
// Conn is an endpoint connection
|
||||||
|
@ -165,6 +175,8 @@ func (epc *Manager) Send(endpoint, msg string) error {
|
||||||
conn = newAMQPConn(ep)
|
conn = newAMQPConn(ep)
|
||||||
case SQS:
|
case SQS:
|
||||||
conn = newSQSConn(ep)
|
conn = newSQSConn(ep)
|
||||||
|
case NATS:
|
||||||
|
conn = newNATSConn(ep)
|
||||||
}
|
}
|
||||||
epc.conns[endpoint] = conn
|
epc.conns[endpoint] = conn
|
||||||
}
|
}
|
||||||
|
@ -209,6 +221,8 @@ func parseEndpoint(s string) (Endpoint, error) {
|
||||||
endpoint.Protocol = MQTT
|
endpoint.Protocol = MQTT
|
||||||
case strings.HasPrefix(s, "sqs:"):
|
case strings.HasPrefix(s, "sqs:"):
|
||||||
endpoint.Protocol = SQS
|
endpoint.Protocol = SQS
|
||||||
|
case strings.HasPrefix(s, "nats:"):
|
||||||
|
endpoint.Protocol = NATS
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s[strings.Index(s, ":")+1:]
|
s = s[strings.Index(s, ":")+1:]
|
||||||
|
@ -549,6 +563,59 @@ func parseEndpoint(s string) (Endpoint, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic NATS connection strings in HOOKS interface
|
||||||
|
// nats://<host>:<port>/<topic_name>/?params=value
|
||||||
|
//
|
||||||
|
// params are:
|
||||||
|
//
|
||||||
|
// user - username
|
||||||
|
// pass - password
|
||||||
|
// when user or pass is not set then login without password is used
|
||||||
|
if endpoint.Protocol == NATS {
|
||||||
|
// Parsing connection from URL string
|
||||||
|
hp := strings.Split(s, ":")
|
||||||
|
switch len(hp) {
|
||||||
|
default:
|
||||||
|
return endpoint, errors.New("invalid SQS url")
|
||||||
|
case 2:
|
||||||
|
endpoint.NATS.Host = hp[0]
|
||||||
|
port, err := strconv.Atoi(hp[1])
|
||||||
|
if err != nil {
|
||||||
|
endpoint.NATS.Port = 4222 // default nats port
|
||||||
|
} else {
|
||||||
|
endpoint.NATS.Port = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing NATS topic name
|
||||||
|
if len(sp) > 1 {
|
||||||
|
var err error
|
||||||
|
endpoint.NATS.Topic, err = url.QueryUnescape(sp[1])
|
||||||
|
if err != nil {
|
||||||
|
return endpoint, errors.New("invalid NATS topic name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing additional params
|
||||||
|
if len(sqp) > 1 {
|
||||||
|
m, err := url.ParseQuery(sqp[1])
|
||||||
|
if err != nil {
|
||||||
|
return endpoint, errors.New("invalid NATS url")
|
||||||
|
}
|
||||||
|
for key, val := range m {
|
||||||
|
if len(val) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch key {
|
||||||
|
case "user":
|
||||||
|
endpoint.NATS.User = val[0]
|
||||||
|
case "pass":
|
||||||
|
endpoint.NATS.Pass = val[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return endpoint, nil
|
return endpoint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package endpoint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nats-io/go-nats"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
natsExpiresAfter = time.Second * 30
|
||||||
|
)
|
||||||
|
|
||||||
|
// NATSConn is an endpoint connection
|
||||||
|
type NATSConn struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
ep Endpoint
|
||||||
|
ex bool
|
||||||
|
t time.Time
|
||||||
|
conn *nats.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNATSConn(ep Endpoint) *NATSConn {
|
||||||
|
return &NATSConn{
|
||||||
|
ep: ep,
|
||||||
|
t: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expired returns true if the connection has expired
|
||||||
|
func (conn *NATSConn) Expired() bool {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
if !conn.ex {
|
||||||
|
if time.Now().Sub(conn.t) > natsExpiresAfter {
|
||||||
|
if conn.conn != nil {
|
||||||
|
conn.close()
|
||||||
|
}
|
||||||
|
conn.ex = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conn.ex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *NATSConn) close() {
|
||||||
|
if conn.conn != nil {
|
||||||
|
conn.conn.Close()
|
||||||
|
conn.conn = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends a message
|
||||||
|
func (conn *NATSConn) Send(msg string) error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
if conn.ex {
|
||||||
|
return errExpired
|
||||||
|
}
|
||||||
|
conn.t = time.Now()
|
||||||
|
if conn.conn == nil {
|
||||||
|
addr := fmt.Sprintf("nats://%s:%d", conn.ep.NATS.Host, conn.ep.NATS.Port)
|
||||||
|
var err error
|
||||||
|
if conn.ep.NATS.User != "" && conn.ep.NATS.Pass != "" {
|
||||||
|
conn.conn, err = nats.Connect(addr, nats.UserInfo(conn.ep.NATS.User, conn.ep.NATS.Pass))
|
||||||
|
}
|
||||||
|
conn.conn, err = nats.Connect(addr)
|
||||||
|
if err != nil {
|
||||||
|
conn.close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := conn.conn.Publish(conn.ep.NATS.Topic, []byte(msg))
|
||||||
|
if err != nil {
|
||||||
|
conn.close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue