76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
"github.com/aws/aws-sdk-go-v2/service/sns"
|
|
)
|
|
|
|
var CatalogueClient Catalogue
|
|
|
|
// CatalogueVideo is what cms announces when a video becomes ready. It is a
|
|
// published contract — every subscriber of the catalogue topic decodes it —
|
|
// so the JSON names here are as much an API as the ones in internal/api, and
|
|
// changing one is a change every subscriber sees.
|
|
//
|
|
// Categories are named rather than numbered on purpose: the ids are cms's
|
|
// own, and a consumer holding a name needs nothing from cms to make sense
|
|
// of it.
|
|
type CatalogueVideo struct {
|
|
VideoID string `json:"videoId"`
|
|
Title string `json:"title"`
|
|
PlaybackURL string `json:"playbackUrl"`
|
|
Categories []string `json:"categories"`
|
|
}
|
|
|
|
type Catalogue interface {
|
|
AnnounceVideo(ctx context.Context, video CatalogueVideo) error
|
|
}
|
|
|
|
type CatalogueConcrete struct {
|
|
SNSClient *sns.Client
|
|
TopicARN string
|
|
}
|
|
|
|
// AnnounceVideo publishes one video to the catalogue topic, which fans it out
|
|
// to whatever has subscribed. Delivery is at-least-once: the caller
|
|
// republishes when a later step fails, so a subscriber has to tolerate seeing
|
|
// the same video twice.
|
|
//
|
|
// A topic delivers only to the subscriptions that exist at the moment it
|
|
// publishes, so a subscriber that wants the backlog needs its queue in place
|
|
// before the announcement, not after.
|
|
func (svc CatalogueConcrete) AnnounceVideo(ctx context.Context, video CatalogueVideo) error {
|
|
// A nil slice marshals to null, which would make "has no categories" and
|
|
// "categories unknown" indistinguishable to a reader. An empty list says
|
|
// the first, which is what an unfiled video means.
|
|
if video.Categories == nil {
|
|
video.Categories = []string{}
|
|
}
|
|
|
|
body, err := json.Marshal(video)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = svc.SNSClient.Publish(ctx, &sns.PublishInput{
|
|
TopicArn: aws.String(svc.TopicARN),
|
|
Message: aws.String(string(body)),
|
|
})
|
|
return err
|
|
}
|
|
|
|
// AssertSuccessfulConnection verifies the topic exists and is readable with
|
|
// the configured credentials. It panics on failure: a service that cannot
|
|
// announce would transcode videos the catalogue never hears about.
|
|
func (svc CatalogueConcrete) AssertSuccessfulConnection(ctx context.Context) {
|
|
if _, err := svc.SNSClient.GetTopicAttributes(ctx, &sns.GetTopicAttributesInput{
|
|
TopicArn: aws.String(svc.TopicARN),
|
|
}); err != nil {
|
|
panic(fmt.Errorf("sns: cannot connect to catalogue topic %q: %w", svc.TopicARN, err))
|
|
}
|
|
}
|