You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

145 lines
3.3 KiB

package clients
import (
log "github.com/Sirupsen/logrus"
"github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/plugin"
"github.com/matrix-org/go-neb/types"
"net/url"
"sync"
)
// A Clients is a collection of clients used for bot services.
type Clients struct {
db *database.ServiceDB
dbMutex sync.Mutex
mapMutex sync.Mutex
clients map[string]clientEntry
}
// New makes a new collection of matrix clients
func New(db *database.ServiceDB) *Clients {
clients := &Clients{
db: db,
clients: make(map[string]clientEntry), // user_id => clientEntry
}
return clients
}
// Client gets a client for the userID
func (c *Clients) Client(userID string) (*matrix.Client, error) {
entry := c.getClient(userID)
if entry.client != nil {
return entry.client, nil
}
entry, err := c.loadClientFromDB(userID)
return entry.client, err
}
// Update updates the config for a matrix client
func (c *Clients) Update(config types.ClientConfig) (types.ClientConfig, error) {
_, old, err := c.updateClientInDB(config)
return old.config, err
}
type clientEntry struct {
config types.ClientConfig
client *matrix.Client
}
func (c *Clients) getClient(userID string) clientEntry {
c.mapMutex.Lock()
defer c.mapMutex.Unlock()
return c.clients[userID]
}
func (c *Clients) setClient(client clientEntry) {
c.mapMutex.Lock()
defer c.mapMutex.Unlock()
c.clients[client.config.UserID] = client
}
func (c *Clients) loadClientFromDB(userID string) (entry clientEntry, err error) {
c.dbMutex.Lock()
defer c.dbMutex.Unlock()
entry = c.getClient(userID)
if entry.client != nil {
return
}
if entry.config, err = c.db.LoadMatrixClientConfig(userID); err != nil {
return
}
if entry.client, err = c.newClient(entry.config); err != nil {
return
}
c.setClient(entry)
return
}
func (c *Clients) updateClientInDB(newConfig types.ClientConfig) (new clientEntry, old clientEntry, err error) {
c.dbMutex.Lock()
defer c.dbMutex.Unlock()
old = c.getClient(newConfig.UserID)
if old.client != nil && old.config == newConfig {
// Already have a client with that config.
new = old
return
}
new.config = newConfig
if new.client, err = c.newClient(new.config); err != nil {
return
}
if old.config, err = c.db.StoreMatrixClientConfig(new.config); err != nil {
new.client.StopSync()
return
}
if old.client != nil {
old.client.StopSync()
return
}
c.setClient(new)
return
}
func (c *Clients) newClient(config types.ClientConfig) (*matrix.Client, error) {
homeserverURL, err := url.Parse(config.HomeserverURL)
if err != nil {
return nil, err
}
client := matrix.NewClient(homeserverURL, config.AccessToken, config.UserID)
// TODO: Check that the access token is valid for the userID by peforming
// a request against the server.
client.Worker.OnEventType("m.room.message", func(event *matrix.Event) {
services, err := c.db.LoadServicesForUser(client.UserID)
if err != nil {
log.WithFields(log.Fields{
log.ErrorKey: err,
"room_id": event.RoomID,
"service_user_id": client.UserID,
}).Warn("Error loading services")
}
var plugins []plugin.Plugin
for _, service := range services {
plugins = append(plugins, service.Plugin(event.RoomID))
}
plugin.OnMessage(plugins, client, event)
})
go client.Sync()
return client, nil
}