123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- package controllers
- import (
- "fmt"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "github.com/pkg/errors"
- log "github.com/sirupsen/logrus"
- "github.com/go-fed/activity/streams"
- "github.com/go-fed/activity/streams/vocab"
- "github.com/owncast/owncast/activitypub/apmodels"
- "github.com/owncast/owncast/activitypub/crypto"
- "github.com/owncast/owncast/activitypub/persistence"
- "github.com/owncast/owncast/activitypub/requests"
- "github.com/owncast/owncast/core/data"
- )
- const (
- followersPageSize = 50
- )
- // FollowersHandler will return the list of remote followers on the Fediverse.
- func FollowersHandler(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodGet {
- w.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
- var response interface{}
- var err error
- if r.URL.Query().Get("page") != "" {
- response, err = getFollowersPage(r.URL.Query().Get("page"), r)
- } else {
- response, err = getInitialFollowersRequest(r)
- }
- if response == nil {
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- if err != nil {
- _, _ = w.Write([]byte(err.Error()))
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- pathComponents := strings.Split(r.URL.Path, "/")
- accountName := pathComponents[3]
- actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
- publicKey := crypto.GetPublicKey(actorIRI)
- if err := requests.WriteStreamResponse(response.(vocab.Type), w, publicKey); err != nil {
- log.Errorln("unable to write stream response for followers handler", err)
- }
- }
- func getInitialFollowersRequest(r *http.Request) (vocab.ActivityStreamsOrderedCollection, error) {
- followerCount, _ := persistence.GetFollowerCount()
- collection := streams.NewActivityStreamsOrderedCollection()
- idProperty := streams.NewJSONLDIdProperty()
- id, err := createPageURL(r, nil)
- if err != nil {
- return nil, errors.Wrap(err, "unable to create followers page property")
- }
- idProperty.SetIRI(id)
- collection.SetJSONLDId(idProperty)
- totalItemsProperty := streams.NewActivityStreamsTotalItemsProperty()
- totalItemsProperty.Set(int(followerCount))
- collection.SetActivityStreamsTotalItems(totalItemsProperty)
- first := streams.NewActivityStreamsFirstProperty()
- page := "1"
- firstIRI, err := createPageURL(r, &page)
- if err != nil {
- return nil, errors.Wrap(err, "unable to create first page property")
- }
- first.SetIRI(firstIRI)
- collection.SetActivityStreamsFirst(first)
- return collection, nil
- }
- func getFollowersPage(page string, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
- pageInt, err := strconv.Atoi(page)
- if err != nil {
- return nil, errors.Wrap(err, "unable to parse page number")
- }
- followerCount, err := persistence.GetFollowerCount()
- if err != nil {
- return nil, errors.Wrap(err, "unable to get follower count")
- }
- followers, _, err := persistence.GetFederationFollowers(followersPageSize, (pageInt-1)*followersPageSize)
- if err != nil {
- return nil, errors.Wrap(err, "unable to get federation followers")
- }
- collectionPage := streams.NewActivityStreamsOrderedCollectionPage()
- idProperty := streams.NewJSONLDIdProperty()
- id, err := createPageURL(r, &page)
- if err != nil {
- return nil, errors.Wrap(err, "unable to create followers page ID")
- }
- idProperty.SetIRI(id)
- collectionPage.SetJSONLDId(idProperty)
- orderedItems := streams.NewActivityStreamsOrderedItemsProperty()
- for _, follower := range followers {
- u, _ := url.Parse(follower.ActorIRI)
- orderedItems.AppendIRI(u)
- }
- collectionPage.SetActivityStreamsOrderedItems(orderedItems)
- partOf := streams.NewActivityStreamsPartOfProperty()
- partOfIRI, err := createPageURL(r, nil)
- if err != nil {
- return nil, errors.Wrap(err, "unable to create partOf property for followers page")
- }
- partOf.SetIRI(partOfIRI)
- collectionPage.SetActivityStreamsPartOf(partOf)
- if pageInt*followersPageSize < int(followerCount) {
- next := streams.NewActivityStreamsNextProperty()
- nextPage := fmt.Sprintf("%d", pageInt+1)
- nextIRI, err := createPageURL(r, &nextPage)
- if err != nil {
- return nil, errors.Wrap(err, "unable to create next page property")
- }
- next.SetIRI(nextIRI)
- collectionPage.SetActivityStreamsNext(next)
- }
- return collectionPage, nil
- }
- func createPageURL(r *http.Request, page *string) (*url.URL, error) {
- domain := data.GetServerURL()
- if domain == "" {
- return nil, errors.New("unable to get server URL")
- }
- pageURL, err := url.Parse(domain)
- if err != nil {
- return nil, errors.Wrap(err, "unable to parse server URL")
- }
- if page != nil {
- query := pageURL.Query()
- query.Add("page", *page)
- pageURL.RawQuery = query.Encode()
- }
- pageURL.Path = r.URL.Path
- return pageURL, nil
- }
|