2017-07-25 18:11:52 +00:00
package gateway
import (
"fmt"
2019-01-18 17:35:31 +00:00
"sync"
2018-11-13 22:30:56 +00:00
"time"
2018-06-09 10:47:40 +00:00
2017-07-25 18:11:52 +00:00
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
2019-02-23 21:51:27 +00:00
"github.com/42wim/matterbridge/gateway/samechannel"
"github.com/sirupsen/logrus"
2017-07-25 18:11:52 +00:00
)
type Router struct {
2018-11-13 22:30:56 +00:00
config . Config
2019-02-23 21:51:27 +00:00
sync . RWMutex
2018-11-13 22:30:56 +00:00
2018-11-30 22:53:00 +00:00
BridgeMap map [ string ] bridge . Factory
2018-11-11 20:56:12 +00:00
Gateways map [ string ] * Gateway
Message chan config . Message
MattermostPlugin chan config . Message
2019-02-23 21:51:27 +00:00
logger * logrus . Entry
2017-07-25 18:11:52 +00:00
}
2019-02-23 21:51:27 +00:00
// NewRouter initializes a new Matterbridge router for the specified configuration and
// sets up all required gateways.
func NewRouter ( rootLogger * logrus . Logger , cfg config . Config , bridgeMap map [ string ] bridge . Factory ) ( * Router , error ) {
logger := rootLogger . WithFields ( logrus . Fields { "prefix" : "router" } )
2018-11-13 22:30:56 +00:00
r := & Router {
Config : cfg ,
2018-11-30 22:53:00 +00:00
BridgeMap : bridgeMap ,
2018-11-13 22:30:56 +00:00
Message : make ( chan config . Message ) ,
MattermostPlugin : make ( chan config . Message ) ,
Gateways : make ( map [ string ] * Gateway ) ,
2019-02-23 21:51:27 +00:00
logger : logger ,
2018-11-13 22:30:56 +00:00
}
2019-02-23 21:51:27 +00:00
sgw := samechannel . New ( cfg )
gwconfigs := append ( sgw . GetConfig ( ) , cfg . BridgeValues ( ) . Gateway ... )
2017-07-25 18:11:52 +00:00
2019-02-23 21:51:27 +00:00
for idx := range gwconfigs {
entry := & gwconfigs [ idx ]
2017-07-25 18:11:52 +00:00
if ! entry . Enable {
continue
}
if entry . Name == "" {
return nil , fmt . Errorf ( "%s" , "Gateway without name found" )
}
if _ , ok := r . Gateways [ entry . Name ] ; ok {
return nil , fmt . Errorf ( "Gateway with name %s already exists" , entry . Name )
}
2019-02-23 21:51:27 +00:00
r . Gateways [ entry . Name ] = New ( rootLogger , entry , r )
2017-07-25 18:11:52 +00:00
}
return r , nil
}
2019-02-23 21:51:27 +00:00
// Start will connect all gateways belonging to this router and subsequently route messages
// between them.
2017-07-25 18:11:52 +00:00
func ( r * Router ) Start ( ) error {
m := make ( map [ string ] * bridge . Bridge )
2019-09-09 21:48:00 +00:00
if len ( r . Gateways ) == 0 {
return fmt . Errorf ( "no [[gateway]] configured. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info" )
}
2017-07-25 18:11:52 +00:00
for _ , gw := range r . Gateways {
2019-02-23 21:51:27 +00:00
r . logger . Infof ( "Parsing gateway %s" , gw . Name )
2019-09-09 21:48:00 +00:00
if len ( gw . Bridges ) == 0 {
return fmt . Errorf ( "no bridges configured for gateway %s. See https://github.com/42wim/matterbridge/wiki/How-to-create-your-config for more info" , gw . Name )
}
2017-07-25 18:11:52 +00:00
for _ , br := range gw . Bridges {
m [ br . Account ] = br
}
}
for _ , br := range m {
2019-02-23 21:51:27 +00:00
r . logger . Infof ( "Starting bridge: %s " , br . Account )
2017-07-25 18:11:52 +00:00
err := br . Connect ( )
if err != nil {
2018-11-25 09:35:35 +00:00
e := fmt . Errorf ( "Bridge %s failed to start: %v" , br . Account , err )
if r . disableBridge ( br , e ) {
continue
}
return e
2017-07-25 18:11:52 +00:00
}
err = br . JoinChannels ( )
if err != nil {
2018-11-25 09:35:35 +00:00
e := fmt . Errorf ( "Bridge %s failed to join channel: %v" , br . Account , err )
if r . disableBridge ( br , e ) {
continue
}
return e
}
}
// remove unused bridges
for _ , gw := range r . Gateways {
for i , br := range gw . Bridges {
if br . Bridger == nil {
2019-02-23 21:51:27 +00:00
r . logger . Errorf ( "removing failed bridge %s" , i )
2018-11-25 09:35:35 +00:00
delete ( gw . Bridges , i )
}
2017-07-25 18:11:52 +00:00
}
}
go r . handleReceive ( )
2019-02-21 20:26:12 +00:00
//go r.updateChannelMembers()
2017-07-25 18:11:52 +00:00
return nil
}
2018-11-25 09:35:35 +00:00
// disableBridge returns true and empties a bridge if we have IgnoreFailureOnStart configured
// otherwise returns false
func ( r * Router ) disableBridge ( br * bridge . Bridge , err error ) bool {
if r . BridgeValues ( ) . General . IgnoreFailureOnStart {
2019-02-23 21:51:27 +00:00
r . logger . Error ( err )
2018-11-25 09:35:35 +00:00
// setting this bridge empty
* br = bridge . Bridge { }
return true
}
return false
}
2017-07-25 18:11:52 +00:00
func ( r * Router ) getBridge ( account string ) * bridge . Bridge {
for _ , gw := range r . Gateways {
if br , ok := gw . Bridges [ account ] ; ok {
return br
}
}
return nil
}
func ( r * Router ) handleReceive ( ) {
for msg := range r . Message {
2018-11-08 21:29:34 +00:00
msg := msg // scopelint
2019-01-18 17:35:31 +00:00
r . handleEventGetChannelMembers ( & msg )
2018-12-12 22:57:17 +00:00
r . handleEventFailure ( & msg )
r . handleEventRejoinChannels ( & msg )
2019-07-08 20:18:37 +00:00
2020-02-09 21:07:26 +00:00
// Set message protocol based on the account it came from
msg . Protocol = r . getBridge ( msg . Account ) . Protocol
2019-07-08 20:18:37 +00:00
filesHandled := false
2017-07-25 18:11:52 +00:00
for _ , gw := range r . Gateways {
2017-08-27 22:33:17 +00:00
// record all the message ID's of the different bridges
var msgIDs [ ] * BrMsgID
2018-12-12 22:57:17 +00:00
if gw . ignoreMessage ( & msg ) {
continue
}
msg . Timestamp = time . Now ( )
gw . modifyMessage ( & msg )
2019-07-08 20:18:37 +00:00
if ! filesHandled {
2019-02-27 19:52:05 +00:00
gw . handleFiles ( & msg )
2019-07-08 20:18:37 +00:00
filesHandled = true
2019-02-27 19:52:05 +00:00
}
2018-12-12 22:57:17 +00:00
for _ , br := range gw . Bridges {
2019-02-23 21:51:27 +00:00
msgIDs = append ( msgIDs , gw . handleMessage ( & msg , br ) ... )
2018-12-12 22:57:17 +00:00
}
2019-07-08 20:18:37 +00:00
if msg . ID != "" {
_ , exists := gw . Messages . Get ( msg . Protocol + " " + msg . ID )
// Only add the message ID if it doesn't already exist
//
// For some bridges we always add/update the message ID.
// This is necessary as msgIDs will change if a bridge returns
// a different ID in response to edits.
2020-12-31 15:59:47 +00:00
if ! exists {
2019-07-08 20:18:37 +00:00
gw . Messages . Add ( msg . Protocol + " " + msg . ID , msgIDs )
}
2017-07-25 18:11:52 +00:00
}
}
}
}
2019-01-18 17:35:31 +00:00
// updateChannelMembers sends every minute an GetChannelMembers event to all bridges.
func ( r * Router ) updateChannelMembers ( ) {
// TODO sleep a minute because slack can take a while
// fix this by having actually connectionDone events send to the router
time . Sleep ( time . Minute )
for {
for _ , gw := range r . Gateways {
for _ , br := range gw . Bridges {
2019-01-24 21:46:05 +00:00
// only for slack now
if br . Protocol != "slack" {
continue
}
2019-02-23 21:51:27 +00:00
r . logger . Debugf ( "sending %s to %s" , config . EventGetChannelMembers , br . Account )
2019-01-18 17:35:31 +00:00
if _ , err := br . Send ( config . Message { Event : config . EventGetChannelMembers } ) ; err != nil {
2019-02-23 21:51:27 +00:00
r . logger . Errorf ( "updateChannelMembers: %s" , err )
2019-01-18 17:35:31 +00:00
}
}
}
time . Sleep ( time . Minute )
}
}