Browse Source

Add stub RSS Service. Add DefaultService. Add Poller interface.

`DefaultService` serves as a useful no-op service to cut down on bloat when
implementing new Services. This means we can add more methods more freely to
the interface of `Service` without bogging down the Service implementation.

`Poller` is an interface which contains a polling interval and a function to
invoke. This will be used for RSS feeds.

Implemented a stub `RSSService`.
pull/76/head
Kegan Dougal 8 years ago
parent
commit
65963cd93f
  1. 13
      src/github.com/matrix-org/go-neb/database/db.go
  2. 27
      src/github.com/matrix-org/go-neb/database/schema.go
  3. 13
      src/github.com/matrix-org/go-neb/services/echo/echo.go
  4. 5
      src/github.com/matrix-org/go-neb/services/giphy/giphy.go
  5. 7
      src/github.com/matrix-org/go-neb/services/github/github.go
  6. 7
      src/github.com/matrix-org/go-neb/services/github/github_webhook.go
  7. 8
      src/github.com/matrix-org/go-neb/services/jira/jira.go
  8. 35
      src/github.com/matrix-org/go-neb/services/rss/rss.go
  9. 32
      src/github.com/matrix-org/go-neb/types/types.go

13
src/github.com/matrix-org/go-neb/database/db.go

@ -125,6 +125,19 @@ func (d *ServiceDB) LoadServicesForUser(serviceUserID string) (services []types.
return return
} }
// LoadServicesByType loads all the bot services configured for a given type.
// Returns an empty list if there aren't any services configured.
func (d *ServiceDB) LoadServicesByType(serviceType string) (services []types.Service, err error) {
err = runTransaction(d.db, func(txn *sql.Tx) error {
services, err = selectServicesByTypeTxn(txn, serviceType)
if err != nil {
return err
}
return nil
})
return
}
// StoreService stores a service into the database either by inserting a new // StoreService stores a service into the database either by inserting a new
// service or updating an existing service. Returns the old service if there // service or updating an existing service. Returns the old service if there
// was one. // was one.

27
src/github.com/matrix-org/go-neb/database/schema.go

@ -231,6 +231,33 @@ func selectServicesForUserTxn(txn *sql.Tx, userID string) (srvs []types.Service,
return return
} }
const selectServicesByTypeSQL = `
SELECT service_id, service_user_id, service_json FROM services WHERE service_type=$1 ORDER BY service_id
`
func selectServicesByTypeTxn(txn *sql.Tx, serviceType string) (srvs []types.Service, err error) {
rows, err := txn.Query(selectServicesByTypeSQL, serviceType)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
var s types.Service
var serviceID string
var serviceUserID string
var serviceJSON []byte
if err = rows.Scan(&serviceID, &serviceUserID, &serviceJSON); err != nil {
return
}
s, err = types.CreateService(serviceID, serviceType, serviceUserID, serviceJSON)
if err != nil {
return
}
srvs = append(srvs, s)
}
return
}
const deleteServiceSQL = ` const deleteServiceSQL = `
DELETE FROM services WHERE service_id = $1 DELETE FROM services WHERE service_id = $1
` `

13
src/github.com/matrix-org/go-neb/services/echo/echo.go

@ -4,20 +4,18 @@ import (
"github.com/matrix-org/go-neb/matrix" "github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/plugin" "github.com/matrix-org/go-neb/plugin"
"github.com/matrix-org/go-neb/types" "github.com/matrix-org/go-neb/types"
"net/http"
"strings" "strings"
) )
type echoService struct { type echoService struct {
types.DefaultService
id string id string
serviceUserID string serviceUserID string
} }
func (e *echoService) ServiceUserID() string { return e.serviceUserID }
func (e *echoService) ServiceID() string { return e.id }
func (e *echoService) ServiceType() string { return "echo" }
func (e *echoService) Register(oldService types.Service, client *matrix.Client) error { return nil }
func (e *echoService) PostRegister(oldService types.Service) {}
func (e *echoService) ServiceUserID() string { return e.serviceUserID }
func (e *echoService) ServiceID() string { return e.id }
func (e *echoService) ServiceType() string { return "echo" }
func (e *echoService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin { func (e *echoService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin {
return plugin.Plugin{ return plugin.Plugin{
Commands: []plugin.Command{ Commands: []plugin.Command{
@ -30,9 +28,6 @@ func (e *echoService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin {
}, },
} }
} }
func (e *echoService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) {
w.WriteHeader(200) // Do nothing
}
func init() { func init() {
types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service { types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service {

5
src/github.com/matrix-org/go-neb/services/giphy/giphy.go

@ -31,6 +31,7 @@ type giphySearch struct {
} }
type giphyService struct { type giphyService struct {
types.DefaultService
id string id string
serviceUserID string serviceUserID string
APIKey string // beta key is dc6zaTOxFJmzC APIKey string // beta key is dc6zaTOxFJmzC
@ -39,10 +40,6 @@ type giphyService struct {
func (s *giphyService) ServiceUserID() string { return s.serviceUserID } func (s *giphyService) ServiceUserID() string { return s.serviceUserID }
func (s *giphyService) ServiceID() string { return s.id } func (s *giphyService) ServiceID() string { return s.id }
func (s *giphyService) ServiceType() string { return "giphy" } func (s *giphyService) ServiceType() string { return "giphy" }
func (s *giphyService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) {
}
func (s *giphyService) Register(oldService types.Service, client *matrix.Client) error { return nil }
func (s *giphyService) PostRegister(oldService types.Service) {}
func (s *giphyService) Plugin(client *matrix.Client, roomID string) plugin.Plugin { func (s *giphyService) Plugin(client *matrix.Client, roomID string) plugin.Plugin {
return plugin.Plugin{ return plugin.Plugin{

7
src/github.com/matrix-org/go-neb/services/github/github.go

@ -11,7 +11,6 @@ import (
"github.com/matrix-org/go-neb/realms/github" "github.com/matrix-org/go-neb/realms/github"
"github.com/matrix-org/go-neb/services/github/client" "github.com/matrix-org/go-neb/services/github/client"
"github.com/matrix-org/go-neb/types" "github.com/matrix-org/go-neb/types"
"net/http"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -23,6 +22,7 @@ var ownerRepoIssueRegex = regexp.MustCompile(`(([A-z0-9-_]+)/([A-z0-9-_]+))?#([0
var ownerRepoRegex = regexp.MustCompile(`^([A-z0-9-_]+)/([A-z0-9-_]+)$`) var ownerRepoRegex = regexp.MustCompile(`^([A-z0-9-_]+)/([A-z0-9-_]+)$`)
type githubService struct { type githubService struct {
types.DefaultService
id string id string
serviceUserID string serviceUserID string
RealmID string RealmID string
@ -180,9 +180,6 @@ func (s *githubService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin
}, },
} }
} }
func (s *githubService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) {
w.WriteHeader(400)
}
// Register will create webhooks for the repos specified in Rooms // Register will create webhooks for the repos specified in Rooms
// //
@ -212,8 +209,6 @@ func (s *githubService) Register(oldService types.Service, client *matrix.Client
return nil return nil
} }
func (s *githubService) PostRegister(oldService types.Service) {}
// defaultRepo returns the default repo for the given room, or an empty string. // defaultRepo returns the default repo for the given room, or an empty string.
func (s *githubService) defaultRepo(roomID string) string { func (s *githubService) defaultRepo(roomID string) string {
logger := log.WithFields(log.Fields{ logger := log.WithFields(log.Fields{

7
src/github.com/matrix-org/go-neb/services/github/github_webhook.go

@ -6,7 +6,6 @@ import (
"github.com/google/go-github/github" "github.com/google/go-github/github"
"github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/database"
"github.com/matrix-org/go-neb/matrix" "github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/plugin"
"github.com/matrix-org/go-neb/services/github/client" "github.com/matrix-org/go-neb/services/github/client"
"github.com/matrix-org/go-neb/services/github/webhook" "github.com/matrix-org/go-neb/services/github/webhook"
"github.com/matrix-org/go-neb/types" "github.com/matrix-org/go-neb/types"
@ -17,10 +16,11 @@ import (
) )
type githubWebhookService struct { type githubWebhookService struct {
types.DefaultService
id string id string
serviceUserID string serviceUserID string
webhookEndpointURL string webhookEndpointURL string
ClientUserID string // optional; required for webhooks
ClientUserID string
RealmID string RealmID string
SecretToken string SecretToken string
Rooms map[string]struct { // room_id => {} Rooms map[string]struct { // room_id => {}
@ -33,9 +33,6 @@ type githubWebhookService struct {
func (s *githubWebhookService) ServiceUserID() string { return s.serviceUserID } func (s *githubWebhookService) ServiceUserID() string { return s.serviceUserID }
func (s *githubWebhookService) ServiceID() string { return s.id } func (s *githubWebhookService) ServiceID() string { return s.id }
func (s *githubWebhookService) ServiceType() string { return "github-webhook" } func (s *githubWebhookService) ServiceType() string { return "github-webhook" }
func (s *githubWebhookService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin {
return plugin.Plugin{}
}
func (s *githubWebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) { func (s *githubWebhookService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) {
evType, repo, msg, err := webhook.OnReceiveRequest(req, s.SecretToken) evType, repo, msg, err := webhook.OnReceiveRequest(req, s.SecretToken)
if err != nil { if err != nil {

8
src/github.com/matrix-org/go-neb/services/jira/jira.go

@ -24,6 +24,7 @@ var issueKeyRegex = regexp.MustCompile("([A-z]+)-([0-9]+)")
var projectKeyRegex = regexp.MustCompile("^[A-z]+$") var projectKeyRegex = regexp.MustCompile("^[A-z]+$")
type jiraService struct { type jiraService struct {
types.DefaultService
id string id string
serviceUserID string serviceUserID string
webhookEndpointURL string webhookEndpointURL string
@ -38,10 +39,9 @@ type jiraService struct {
} }
} }
func (s *jiraService) ServiceUserID() string { return s.serviceUserID }
func (s *jiraService) ServiceID() string { return s.id }
func (s *jiraService) ServiceType() string { return "jira" }
func (s *jiraService) PostRegister(oldService types.Service) {}
func (s *jiraService) ServiceUserID() string { return s.serviceUserID }
func (s *jiraService) ServiceID() string { return s.id }
func (s *jiraService) ServiceType() string { return "jira" }
func (s *jiraService) Register(oldService types.Service, client *matrix.Client) error { func (s *jiraService) Register(oldService types.Service, client *matrix.Client) error {
// We only ever make 1 JIRA webhook which listens for all projects and then filter // We only ever make 1 JIRA webhook which listens for all projects and then filter
// on receive. So we simply need to know if we need to make a webhook or not. We // on receive. So we simply need to know if we need to make a webhook or not. We

35
src/github.com/matrix-org/go-neb/services/rss/rss.go

@ -0,0 +1,35 @@
package services
import (
"github.com/matrix-org/go-neb/matrix"
"github.com/matrix-org/go-neb/types"
)
type rssService struct {
types.DefaultService
id string
serviceUserID string
ClientUserID string `json:"client_user_id"`
Rooms map[string]struct { // room_id => {}
Feeds map[string]struct { // URL => { }
PollIntervalMs int `json:"poll_interval_ms"`
} `json:"feeds"`
} `json:"rooms"`
}
func (s *rssService) ServiceUserID() string { return s.serviceUserID }
func (s *rssService) ServiceID() string { return s.id }
func (s *rssService) ServiceType() string { return "rss" }
// Register will check the liveness of each RSS feed given. If all feeds check out okay, no error is returned.
func (s *rssService) Register(oldService types.Service, client *matrix.Client) error { return nil }
func init() {
types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service {
r := &rssService{
id: serviceID,
serviceUserID: serviceUserID,
}
return r
})
}

32
src/github.com/matrix-org/go-neb/types/types.go

@ -40,6 +40,12 @@ type BotOptions struct {
Options map[string]interface{} Options map[string]interface{}
} }
// Poller represents a thing that can be polled at a given rate.
type Poller interface {
IntervalSecs() int
OnPoll()
}
// A Service is the configuration for a bot service. // A Service is the configuration for a bot service.
type Service interface { type Service interface {
ServiceUserID() string ServiceUserID() string
@ -57,6 +63,32 @@ type Service interface {
// concurrent modifications to this service whilst this function executes. This lifecycle hook should be used to clean // concurrent modifications to this service whilst this function executes. This lifecycle hook should be used to clean
// up resources which are no longer needed (e.g. removing old webhooks). // up resources which are no longer needed (e.g. removing old webhooks).
PostRegister(oldService Service) PostRegister(oldService Service)
// Return a Poller object if you wish to be invoked every N seconds.
Poller() Poller
}
// DefaultService NO-OPs the implementation of optional Service interface methods. Feel free to override them.
type DefaultService struct {
Service
}
// Plugin returns no plugins.
func (s *DefaultService) Plugin(cli *matrix.Client, roomID string) plugin.Plugin {
return plugin.Plugin{}
}
// Register does nothing and returns no error.
func (s *DefaultService) Register(oldService Service, client *matrix.Client) error { return nil }
// PostRegister does nothing.
func (s *DefaultService) PostRegister(oldService Service) {}
// Poller returns no poller.
func (s *DefaultService) Poller() Poller { return nil }
// OnReceiveWebhook does nothing but 200 OK the request.
func (s *DefaultService) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *matrix.Client) {
w.WriteHeader(200) // Do nothing
} }
var baseURL = "" var baseURL = ""

Loading…
Cancel
Save