Browse Source

feat: move webhooks under services

backend-refactor
Gabe Kangas 3 years ago
parent
commit
78f942b88e
No known key found for this signature in database
GPG Key ID: 4345B2060657F330
  1. 8
      core/chat/events.go
  2. 5
      core/chat/messages.go
  3. 5
      core/chat/server.go
  4. 4
      core/core.go
  5. 8
      core/streamState.go
  6. 16
      services/webhooks/chat.go
  7. 8
      services/webhooks/chat_test.go
  8. 37
      services/webhooks/manager.go
  9. 10
      services/webhooks/stream.go
  10. 2
      services/webhooks/stream_test.go
  11. 8
      services/webhooks/webhooks.go
  12. 18
      services/webhooks/webhooks_test.go
  13. 27
      services/webhooks/workerpool.go
  14. 6
      webserver/handlers/adminApiConfigHandlers.go

8
core/chat/events.go

@ -9,7 +9,7 @@ import ( @@ -9,7 +9,7 @@ import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/services/webhooks"
"github.com/owncast/owncast/storage"
"github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus"
@ -97,7 +97,8 @@ func (s *Server) userNameChanged(eventData chatClientEvent) { @@ -97,7 +97,8 @@ func (s *Server) userNameChanged(eventData chatClientEvent) {
// Send chat user name changed webhook
receivedEvent.User = savedUser
receivedEvent.ClientID = eventData.client.Id
webhooks.SendChatEventUsernameChanged(receivedEvent)
webhookManager := webhooks.GetWebhooks()
webhookManager.SendChatEventUsernameChanged(receivedEvent)
// Resend the client's user so their username is in sync.
eventData.client.sendConnectedClientInfo()
@ -164,7 +165,8 @@ func (s *Server) userMessageSent(eventData chatClientEvent) { @@ -164,7 +165,8 @@ func (s *Server) userMessageSent(eventData chatClientEvent) {
}
// Send chat message sent webhook
webhooks.SendChatEvent(&event)
webhookManager := webhooks.GetWebhooks()
webhookManager.SendChatEvent(&event)
chatMessagesSentCounter.Inc()
SaveUserMessage(event)

5
core/chat/messages.go

@ -4,7 +4,7 @@ import ( @@ -4,7 +4,7 @@ import (
"errors"
"github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/services/webhooks"
log "github.com/sirupsen/logrus"
)
@ -29,7 +29,8 @@ func SetMessagesVisibility(messageIDs []string, visibility bool) error { @@ -29,7 +29,8 @@ func SetMessagesVisibility(messageIDs []string, visibility bool) error {
return errors.New("error broadcasting message visibility payload " + err.Error())
}
webhooks.SendChatEventSetMessageVisibility(event)
webhookManager := webhooks.GetWebhooks()
webhookManager.SendChatEventSetMessageVisibility(event)
return nil
}

5
core/chat/server.go

@ -14,9 +14,9 @@ import ( @@ -14,9 +14,9 @@ import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/services/geoip"
"github.com/owncast/owncast/services/webhooks"
"github.com/owncast/owncast/storage"
"github.com/owncast/owncast/utils"
)
@ -141,7 +141,8 @@ func (s *Server) sendUserJoinedMessage(c *Client) { @@ -141,7 +141,8 @@ func (s *Server) sendUserJoinedMessage(c *Client) {
}
// Send chat user joined webhook
webhooks.SendChatEventUserJoined(userJoinedEvent)
webhookManager := webhooks.GetWebhooks()
webhookManager.SendChatEventUserJoined(userJoinedEvent)
}
// ClientClosed is fired when a client disconnects or connection is dropped.

4
core/core.go

@ -11,9 +11,9 @@ import ( @@ -11,9 +11,9 @@ import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/services/notifications"
"github.com/owncast/owncast/services/webhooks"
"github.com/owncast/owncast/services/yp"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/video/rtmp"
@ -79,7 +79,7 @@ func Start() error { @@ -79,7 +79,7 @@ func Start() error {
log.Infof("RTMP is accepting inbound streams on port %d.", rtmpPort)
}
webhooks.SetupWebhooks(GetStatus)
webhooks.InitTemporarySingleton(GetStatus)
notifications.Setup(data.GetStore())

8
core/streamState.go

@ -11,9 +11,9 @@ import ( @@ -11,9 +11,9 @@ import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/services/notifications"
"github.com/owncast/owncast/services/webhooks"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/video/rtmp"
"github.com/owncast/owncast/video/transcoder"
@ -68,7 +68,8 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) { @@ -68,7 +68,8 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) {
_transcoder.Start(true)
}()
go webhooks.SendStreamStatusEvent(models.StreamStarted)
webhookManager := webhooks.GetWebhooks()
go webhookManager.SendStreamStatusEvent(models.StreamStarted)
transcoder.StartThumbnailGenerator(segmentPath, data.FindHighestVideoQualityIndex(_currentBroadcast.OutputSettings))
_ = chat.SendSystemAction("Stay tuned, the stream is **starting**!", true)
@ -125,7 +126,8 @@ func SetStreamAsDisconnected() { @@ -125,7 +126,8 @@ func SetStreamAsDisconnected() {
stopOnlineCleanupTimer()
saveStats()
go webhooks.SendStreamStatusEvent(models.StreamStopped)
webhookManager := webhooks.GetWebhooks()
go webhookManager.SendStreamStatusEvent(models.StreamStopped)
}
// StartOfflineCleanupTimer will fire a cleanup after n minutes being disconnected.

16
core/webhooks/chat.go → services/webhooks/chat.go

@ -6,7 +6,7 @@ import ( @@ -6,7 +6,7 @@ import (
)
// SendChatEvent will send a chat event to webhook destinations.
func SendChatEvent(chatEvent *events.UserMessageEvent) {
func (w *LiveWebhookManager) SendChatEvent(chatEvent *events.UserMessageEvent) {
webhookEvent := WebhookEvent{
Type: chatEvent.GetMessageType(),
EventData: &WebhookChatMessage{
@ -20,36 +20,36 @@ func SendChatEvent(chatEvent *events.UserMessageEvent) { @@ -20,36 +20,36 @@ func SendChatEvent(chatEvent *events.UserMessageEvent) {
},
}
SendEventToWebhooks(webhookEvent)
w.SendEventToWebhooks(webhookEvent)
}
// SendChatEventUsernameChanged will send a username changed event to webhook destinations.
func SendChatEventUsernameChanged(event events.NameChangeEvent) {
func (w *LiveWebhookManager) SendChatEventUsernameChanged(event events.NameChangeEvent) {
webhookEvent := WebhookEvent{
Type: models.UserNameChanged,
EventData: event,
}
SendEventToWebhooks(webhookEvent)
w.SendEventToWebhooks(webhookEvent)
}
// SendChatEventUserJoined sends a webhook notifying that a user has joined.
func SendChatEventUserJoined(event events.UserJoinedEvent) {
func (w *LiveWebhookManager) SendChatEventUserJoined(event events.UserJoinedEvent) {
webhookEvent := WebhookEvent{
Type: models.UserJoined,
EventData: event,
}
SendEventToWebhooks(webhookEvent)
w.SendEventToWebhooks(webhookEvent)
}
// SendChatEventSetMessageVisibility sends a webhook notifying that the visibility of one or more
// messages has changed.
func SendChatEventSetMessageVisibility(event events.SetMessageVisibilityEvent) {
func (w *LiveWebhookManager) SendChatEventSetMessageVisibility(event events.SetMessageVisibilityEvent) {
webhookEvent := WebhookEvent{
Type: models.VisibiltyToggled,
EventData: event,
}
SendEventToWebhooks(webhookEvent)
w.SendEventToWebhooks(webhookEvent)
}

8
core/webhooks/chat_test.go → services/webhooks/chat_test.go

@ -26,7 +26,7 @@ func TestSendChatEvent(t *testing.T) { @@ -26,7 +26,7 @@ func TestSendChatEvent(t *testing.T) {
}
checkPayload(t, models.MessageSent, func() {
SendChatEvent(&events.UserMessageEvent{
manager.SendChatEvent(&events.UserMessageEvent{
Event: events.Event{
Type: events.MessageSent,
ID: "id",
@ -79,7 +79,7 @@ func TestSendChatEventUsernameChanged(t *testing.T) { @@ -79,7 +79,7 @@ func TestSendChatEventUsernameChanged(t *testing.T) {
}
checkPayload(t, models.UserNameChanged, func() {
SendChatEventUsernameChanged(events.NameChangeEvent{
manager.SendChatEventUsernameChanged(events.NameChangeEvent{
Event: events.Event{
Type: events.UserNameChanged,
ID: "id",
@ -127,7 +127,7 @@ func TestSendChatEventUserJoined(t *testing.T) { @@ -127,7 +127,7 @@ func TestSendChatEventUserJoined(t *testing.T) {
}
checkPayload(t, models.UserJoined, func() {
SendChatEventUserJoined(events.UserJoinedEvent{
manager.SendChatEventUserJoined(events.UserJoinedEvent{
Event: events.Event{
Type: events.UserJoined,
ID: "id",
@ -160,7 +160,7 @@ func TestSendChatEventSetMessageVisibility(t *testing.T) { @@ -160,7 +160,7 @@ func TestSendChatEventSetMessageVisibility(t *testing.T) {
timestamp := time.Unix(72, 6).UTC()
checkPayload(t, models.VisibiltyToggled, func() {
SendChatEventSetMessageVisibility(events.SetMessageVisibilityEvent{
manager.SendChatEventSetMessageVisibility(events.SetMessageVisibilityEvent{
Event: events.Event{
Type: events.VisibiltyUpdate,
ID: "id",

37
services/webhooks/manager.go

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
package webhooks
import "github.com/owncast/owncast/models"
type Manager interface {
SendEventToWebhooks(payload WebhookEvent)
}
// LiveWebhookManager represents a central place for requesting webhooks
// to be sent out to all registered webhook destinations.
type LiveWebhookManager struct {
queue chan Job
getStatus func() models.Status
}
// NewWebhookManager creates a new webhook manager.
func NewWebhookManager(getStatusFunc func() models.Status) *LiveWebhookManager {
m := &LiveWebhookManager{
getStatus: getStatusFunc,
}
m.initWorkerPool()
return m
}
// InitTemporarySingleton initializes the the temporary global instance of the webhook manager
// to be deleted once dependency injection is implemented.
func InitTemporarySingleton(getStatusFunc func() models.Status) {
temporaryGlobalInstance = NewWebhookManager(getStatusFunc)
}
var temporaryGlobalInstance *LiveWebhookManager
// GetWebhooks returns the temporary global instance of the webhook manager.
// Remove this after dependency injection is implemented.
func GetWebhooks() *LiveWebhookManager {
return temporaryGlobalInstance
}

10
core/webhooks/stream.go → services/webhooks/stream.go

@ -9,19 +9,19 @@ import ( @@ -9,19 +9,19 @@ import (
)
// SendStreamStatusEvent will send all webhook destinations the current stream status.
func SendStreamStatusEvent(eventType models.EventType) {
sendStreamStatusEvent(eventType, shortid.MustGenerate(), time.Now())
func (w *LiveWebhookManager) SendStreamStatusEvent(eventType models.EventType) {
w.sendStreamStatusEvent(eventType, shortid.MustGenerate(), time.Now())
}
func sendStreamStatusEvent(eventType models.EventType, id string, timestamp time.Time) {
SendEventToWebhooks(WebhookEvent{
func (w *LiveWebhookManager) sendStreamStatusEvent(eventType models.EventType, id string, timestamp time.Time) {
w.SendEventToWebhooks(WebhookEvent{
Type: eventType,
EventData: map[string]interface{}{
"id": id,
"name": data.GetServerName(),
"summary": data.GetServerSummary(),
"streamTitle": data.GetStreamTitle(),
"status": getStatus(),
"status": w.getStatus(),
"timestamp": timestamp,
},
})

2
core/webhooks/stream_test.go → services/webhooks/stream_test.go

@ -15,7 +15,7 @@ func TestSendStreamStatusEvent(t *testing.T) { @@ -15,7 +15,7 @@ func TestSendStreamStatusEvent(t *testing.T) {
data.SetStreamTitle("my stream")
checkPayload(t, models.StreamStarted, func() {
sendStreamStatusEvent(events.StreamStarted, "id", time.Unix(72, 6).UTC())
manager.sendStreamStatusEvent(events.StreamStarted, "id", time.Unix(72, 6).UTC())
}, `{
"id": "id",
"name": "my server",

8
core/webhooks/webhooks.go → services/webhooks/webhooks.go

@ -26,11 +26,11 @@ type WebhookChatMessage struct { @@ -26,11 +26,11 @@ type WebhookChatMessage struct {
}
// SendEventToWebhooks will send a single webhook event to all webhook destinations.
func SendEventToWebhooks(payload WebhookEvent) {
sendEventToWebhooks(payload, nil)
func (w *LiveWebhookManager) SendEventToWebhooks(payload WebhookEvent) {
w.sendEventToWebhooks(payload, nil)
}
func sendEventToWebhooks(payload WebhookEvent, wg *sync.WaitGroup) {
func (w *LiveWebhookManager) sendEventToWebhooks(payload WebhookEvent, wg *sync.WaitGroup) {
webhooks := data.GetWebhooksForEvent(payload.Type)
for _, webhook := range webhooks {
@ -38,6 +38,6 @@ func sendEventToWebhooks(payload WebhookEvent, wg *sync.WaitGroup) { @@ -38,6 +38,6 @@ func sendEventToWebhooks(payload WebhookEvent, wg *sync.WaitGroup) {
if wg != nil {
wg.Add(1)
}
addToQueue(webhook, payload, wg)
w.addToQueue(webhook, payload, wg)
}
}

18
core/webhooks/webhooks_test.go → services/webhooks/webhooks_test.go

@ -17,6 +17,8 @@ import ( @@ -17,6 +17,8 @@ import (
jsonpatch "gopkg.in/evanphx/json-patch.v5"
)
var manager *LiveWebhookManager
func fakeGetStatus() models.Status {
return models.Status{
Online: true,
@ -40,9 +42,9 @@ func TestMain(m *testing.M) { @@ -40,9 +42,9 @@ func TestMain(m *testing.M) {
panic(err)
}
SetupWebhooks(fakeGetStatus)
defer close(queue)
InitTemporarySingleton(fakeGetStatus)
manager = GetWebhooks()
defer close(manager.queue)
m.Run()
}
@ -76,7 +78,7 @@ func TestPublicSend(t *testing.T) { @@ -76,7 +78,7 @@ func TestPublicSend(t *testing.T) {
EventData: struct{}{},
Type: models.MessageSent,
}
SendEventToWebhooks(wh)
manager.SendEventToWebhooks(wh)
}
wg.Wait()
@ -125,7 +127,7 @@ func TestRouting(t *testing.T) { @@ -125,7 +127,7 @@ func TestRouting(t *testing.T) {
EventData: struct{}{},
Type: eventType,
}
sendEventToWebhooks(wh, &wg)
manager.sendEventToWebhooks(wh, &wg)
}
wg.Wait()
@ -165,7 +167,7 @@ func TestMultiple(t *testing.T) { @@ -165,7 +167,7 @@ func TestMultiple(t *testing.T) {
EventData: struct{}{},
Type: models.MessageSent,
}
sendEventToWebhooks(wh, &wg)
manager.sendEventToWebhooks(wh, &wg)
wg.Wait()
@ -204,7 +206,7 @@ func TestTimestamps(t *testing.T) { @@ -204,7 +206,7 @@ func TestTimestamps(t *testing.T) {
EventData: struct{}{},
Type: eventTypes[0],
}
sendEventToWebhooks(wh, &wg)
manager.sendEventToWebhooks(wh, &wg)
wg.Wait()
@ -301,7 +303,7 @@ func TestParallel(t *testing.T) { @@ -301,7 +303,7 @@ func TestParallel(t *testing.T) {
EventData: struct{}{},
Type: models.MessageSent,
}
sendEventToWebhooks(wh, &wgMessages)
manager.sendEventToWebhooks(wh, &wgMessages)
}
wgMessages.Wait()

27
core/webhooks/workerpool.go → services/webhooks/workerpool.go

@ -23,39 +23,28 @@ type Job struct { @@ -23,39 +23,28 @@ type Job struct {
wg *sync.WaitGroup
}
var (
queue chan Job
getStatus func() models.Status
)
// SetupWebhooks initializes the webhook worker pool and sets the function to get the current status.
func SetupWebhooks(getStatusFunc func() models.Status) {
getStatus = getStatusFunc
initWorkerPool()
}
// initWorkerPool starts n go routines that await webhook jobs.
func initWorkerPool() {
queue = make(chan Job)
func (w *LiveWebhookManager) initWorkerPool() {
w.queue = make(chan Job)
// start workers
for i := 1; i <= webhookWorkerPoolSize; i++ {
go worker(i, queue)
go w.worker(i, w.queue)
}
}
func addToQueue(webhook models.Webhook, payload WebhookEvent, wg *sync.WaitGroup) {
func (w *LiveWebhookManager) addToQueue(webhook models.Webhook, payload WebhookEvent, wg *sync.WaitGroup) {
log.Tracef("Queued Event %s for Webhook %s", payload.Type, webhook.URL)
queue <- Job{webhook, payload, wg}
w.queue <- Job{webhook, payload, wg}
}
func worker(workerID int, queue <-chan Job) {
func (w *LiveWebhookManager) worker(workerID int, queue <-chan Job) {
log.Debugf("Started Webhook worker %d", workerID)
for job := range queue {
log.Debugf("Event %s sent to Webhook %s using worker %d", job.payload.Type, job.webhook.URL, workerID)
if err := sendWebhook(job); err != nil {
if err := w.sendWebhook(job); err != nil {
log.Errorf("Event: %s failed to send to webhook: %s Error: %s", job.payload.Type, job.webhook.URL, err)
}
log.Tracef("Done with Event %s to Webhook %s using worker %d", job.payload.Type, job.webhook.URL, workerID)
@ -65,7 +54,7 @@ func worker(workerID int, queue <-chan Job) { @@ -65,7 +54,7 @@ func worker(workerID int, queue <-chan Job) {
}
}
func sendWebhook(job Job) error {
func (w *LiveWebhookManager) sendWebhook(job Job) error {
jsonText, err := json.Marshal(job.payload)
if err != nil {
return err

6
webserver/handlers/adminApiConfigHandlers.go

@ -12,9 +12,8 @@ import ( @@ -12,9 +12,8 @@ import (
"github.com/owncast/owncast/activitypub/outbox"
"github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/user"
"github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/services/webhooks"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/requests"
"github.com/owncast/owncast/webserver/responses"
@ -71,7 +70,8 @@ func (h *Handlers) SetStreamTitle(w http.ResponseWriter, r *http.Request) { @@ -71,7 +70,8 @@ func (h *Handlers) SetStreamTitle(w http.ResponseWriter, r *http.Request) {
}
if value != "" {
sendSystemChatAction(fmt.Sprintf("Stream title changed to **%s**", value), true)
go webhooks.SendStreamStatusEvent(models.StreamTitleUpdated)
webhookManager := webhooks.GetWebhooks()
go webhookManager.SendStreamStatusEvent(models.StreamTitleUpdated)
}
responses.WriteSimpleResponse(w, true, "changed")
}

Loading…
Cancel
Save