7 changed files with 252 additions and 11 deletions
@ -0,0 +1,120 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"log" |
||||||
|
|
||||||
|
"github.com/nats-io/nats" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
BusManagerOffer = "offer" |
||||||
|
BusManagerAnswer = "answer" |
||||||
|
BusManagerBye = "bye" |
||||||
|
BusManagerConnect = "connect" |
||||||
|
BusManagerDisconnect = "disconnect" |
||||||
|
BusManagerAuth = "auth" |
||||||
|
) |
||||||
|
|
||||||
|
// A BusManager provides the API to interact with a bus.
|
||||||
|
type BusManager interface { |
||||||
|
Trigger(name, from, payload string, data interface{}) error |
||||||
|
} |
||||||
|
|
||||||
|
// A BusTrigger is a container to serialize trigger events
|
||||||
|
// for the bus backend.
|
||||||
|
type BusTrigger struct { |
||||||
|
Name string |
||||||
|
From string |
||||||
|
Payload string `json:",omitempty"` |
||||||
|
Data interface{} `json:",omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// BusSubjectTrigger returns the bus subject for trigger payloads.
|
||||||
|
func BusSubjectTrigger(prefix, suffix string) string { |
||||||
|
return fmt.Sprintf("%s.%s", prefix, suffix) |
||||||
|
} |
||||||
|
|
||||||
|
type busManager struct { |
||||||
|
BusManager |
||||||
|
} |
||||||
|
|
||||||
|
// NewBusManager creates and initializes a new BusMager with the
|
||||||
|
// provided flags for NATS support. It is intended to connect the
|
||||||
|
// backend bus with a easy to use API to send and receive bus data.
|
||||||
|
func NewBusManager(useNats bool, subjectPrefix string) BusManager { |
||||||
|
var b BusManager |
||||||
|
if useNats { |
||||||
|
var err error |
||||||
|
b, err = newNatsBus(subjectPrefix) |
||||||
|
if err == nil { |
||||||
|
log.Println("Nats bus connected") |
||||||
|
} else { |
||||||
|
log.Println("Error connecting nats bus", err) |
||||||
|
b = &noopBus{} |
||||||
|
} |
||||||
|
} else { |
||||||
|
b = &noopBus{} |
||||||
|
} |
||||||
|
return &busManager{b} |
||||||
|
} |
||||||
|
|
||||||
|
type noopBus struct { |
||||||
|
} |
||||||
|
|
||||||
|
func (bus *noopBus) Trigger(name, from, payload string, data interface{}) error { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type natsBus struct { |
||||||
|
prefix string |
||||||
|
ec *nats.EncodedConn |
||||||
|
} |
||||||
|
|
||||||
|
func newNatsBus(prefix string) (*natsBus, error) { |
||||||
|
ec, err := EstablishNatsConnection(nil) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
if prefix == "" { |
||||||
|
prefix = "channelling.trigger" |
||||||
|
} |
||||||
|
return &natsBus{prefix, ec}, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (bus *natsBus) Trigger(name, from, payload string, data interface{}) (err error) { |
||||||
|
if bus.ec != nil { |
||||||
|
trigger := &BusTrigger{ |
||||||
|
Name: name, |
||||||
|
From: from, |
||||||
|
Payload: payload, |
||||||
|
Data: data, |
||||||
|
} |
||||||
|
err = bus.ec.Publish(BusSubjectTrigger(bus.prefix, name), trigger) |
||||||
|
if err != nil { |
||||||
|
log.Println("Failed to trigger NATS event", err) |
||||||
|
} |
||||||
|
} |
||||||
|
return err |
||||||
|
} |
@ -0,0 +1,77 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"log" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/nats-io/nats" |
||||||
|
) |
||||||
|
|
||||||
|
// DefaultNatsEstablishTimeout is the default timeout for
|
||||||
|
// calls to EstablishNatsConnection.
|
||||||
|
var DefaultNatsEstablishTimeout = 60 * time.Second |
||||||
|
|
||||||
|
// DefaultNatsURL is the default NATS server URL used for
|
||||||
|
// calls to NewNatsConnection and EstablishNatsConnection.
|
||||||
|
var DefaultNatsURL = nats.DefaultURL |
||||||
|
|
||||||
|
// NewNatsConnection creates a connetion to the default NATS server
|
||||||
|
// and tries to establish the connection. It returns the connection
|
||||||
|
// and any connection error encountered.
|
||||||
|
func NewNatsConnection() (*nats.EncodedConn, error) { |
||||||
|
nc, err := nats.Connect(DefaultNatsURL) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
ec, err := nats.NewEncodedConn(nc, nats.JSON_ENCODER) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return ec, nil |
||||||
|
} |
||||||
|
|
||||||
|
// EstablishNatsConnection is a blocking way to create and establish
|
||||||
|
// connection to the default NATS server. The function will only return
|
||||||
|
// after a timeout has reached or a connection has been established. It
|
||||||
|
// returns the connection and and any timeout error encountered.
|
||||||
|
func EstablishNatsConnection(timeout *time.Duration) (*nats.EncodedConn, error) { |
||||||
|
if timeout == nil { |
||||||
|
timeout = &DefaultNatsEstablishTimeout |
||||||
|
} |
||||||
|
connch := make(chan *nats.EncodedConn, 1) |
||||||
|
errch := make(chan error, 1) |
||||||
|
go func() { |
||||||
|
notify := true |
||||||
|
for { |
||||||
|
ec, err := NewNatsConnection() |
||||||
|
if err == nil { |
||||||
|
connch <- ec |
||||||
|
break |
||||||
|
} |
||||||
|
switch err { |
||||||
|
case nats.ErrTimeout: |
||||||
|
fallthrough |
||||||
|
case nats.ErrNoServers: |
||||||
|
if notify { |
||||||
|
notify = false |
||||||
|
log.Println("Waiting for NATS server to become available") |
||||||
|
} |
||||||
|
time.Sleep(1 * time.Second) |
||||||
|
continue |
||||||
|
default: |
||||||
|
errch <- err |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
select { |
||||||
|
case conn := <-connch: |
||||||
|
return conn, nil |
||||||
|
case err := <-errch: |
||||||
|
return nil, err |
||||||
|
case <-time.After(*timeout): |
||||||
|
return nil, errors.New("NATS connection: timeout") |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue