diff options
author | 2021-05-28 19:57:04 +0200 | |
---|---|---|
committer | 2021-05-28 19:57:04 +0200 | |
commit | 87177d840b9703f572392ef4bd0f5013fd5c3a77 (patch) | |
tree | c59388998d5defd5ec3577483f70736238953f72 /internal/federation | |
parent | Notifications (#34) (diff) | |
download | gotosocial-87177d840b9703f572392ef4bd0f5013fd5c3a77.tar.xz |
Announce/boost (#35)
Remote boosts incoming/outgoing now working.
Diffstat (limited to 'internal/federation')
-rw-r--r-- | internal/federation/federatingdb/announce.go | 73 | ||||
-rw-r--r-- | internal/federation/federatingdb/db.go | 1 | ||||
-rw-r--r-- | internal/federation/federatingdb/federating_db_test.go (renamed from internal/federation/federating_db_test.go) | 2 | ||||
-rw-r--r-- | internal/federation/federatingdb/util.go | 13 | ||||
-rw-r--r-- | internal/federation/federatingprotocol.go | 4 | ||||
-rw-r--r-- | internal/federation/federator.go | 3 | ||||
-rw-r--r-- | internal/federation/util.go | 84 |
7 files changed, 177 insertions, 3 deletions
diff --git a/internal/federation/federatingdb/announce.go b/internal/federation/federatingdb/announce.go new file mode 100644 index 000000000..322a4838f --- /dev/null +++ b/internal/federation/federatingdb/announce.go @@ -0,0 +1,73 @@ +package federatingdb + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/go-fed/activity/streams" + "github.com/go-fed/activity/streams/vocab" + "github.com/sirupsen/logrus" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/util" +) + +func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error { + l := f.log.WithFields( + logrus.Fields{ + "func": "Announce", + }, + ) + m, err := streams.Serialize(announce) + if err != nil { + return err + } + b, err := json.Marshal(m) + if err != nil { + return err + } + + l.Debugf("received ANNOUNCE %s", string(b)) + + targetAcctI := ctx.Value(util.APAccount) + if targetAcctI == nil { + l.Error("target account wasn't set on context") + return nil + } + targetAcct, ok := targetAcctI.(*gtsmodel.Account) + if !ok { + l.Error("target account was set on context but couldn't be parsed") + return nil + } + + fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey) + if fromFederatorChanI == nil { + l.Error("from federator channel wasn't set on context") + return nil + } + fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) + if !ok { + l.Error("from federator channel was set on context but couldn't be parsed") + return nil + } + + boost, isNew, err := f.typeConverter.ASAnnounceToStatus(announce) + if err != nil { + return fmt.Errorf("Announce: error converting announce to boost: %s", err) + } + + if !isNew { + // nothing to do here if this isn't a new announce + return nil + } + + // it's a new announce so pass it back to the processor async for dereferencing etc + fromFederatorChan <- gtsmodel.FromFederator{ + APObjectType: gtsmodel.ActivityStreamsAnnounce, + APActivityType: gtsmodel.ActivityStreamsCreate, + GTSModel: boost, + ReceivingAccount: targetAcct, + } + + return nil +} diff --git a/internal/federation/federatingdb/db.go b/internal/federation/federatingdb/db.go index b5207fc34..f6587a1b7 100644 --- a/internal/federation/federatingdb/db.go +++ b/internal/federation/federatingdb/db.go @@ -35,6 +35,7 @@ type DB interface { pub.Database Undo(ctx context.Context, undo vocab.ActivityStreamsUndo) error Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) error + Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error } // FederatingDB uses the underlying DB interface to implement the go-fed pub.Database interface. diff --git a/internal/federation/federating_db_test.go b/internal/federation/federatingdb/federating_db_test.go index b4695b55b..f32314b10 100644 --- a/internal/federation/federating_db_test.go +++ b/internal/federation/federatingdb/federating_db_test.go @@ -16,6 +16,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package federation +package federatingdb_test // TODO: write tests for pgfed diff --git a/internal/federation/federatingdb/util.go b/internal/federation/federatingdb/util.go index be3cff944..53fe194a7 100644 --- a/internal/federation/federatingdb/util.go +++ b/internal/federation/federatingdb/util.go @@ -130,6 +130,19 @@ func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err return idProp.GetIRI(), nil } } + case gtsmodel.ActivityStreamsAnnounce: + // ANNOUNCE aka BOOST + // ID might already be set on an announce we've created, so check it here and return it if it is + announce, ok := t.(vocab.ActivityStreamsAnnounce) + if !ok { + return nil, errors.New("newid: fave couldn't be parsed into vocab.ActivityStreamsAnnounce") + } + idProp := announce.GetJSONLDId() + if idProp != nil { + if idProp.IsIRI() { + return idProp.GetIRI(), nil + } + } } // fallback default behavior: just return a random UUID after our protocol and host diff --git a/internal/federation/federatingprotocol.go b/internal/federation/federatingprotocol.go index 39ed49cfb..e1c1ab184 100644 --- a/internal/federation/federatingprotocol.go +++ b/internal/federation/federatingprotocol.go @@ -257,6 +257,10 @@ func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.Federa func(ctx context.Context, accept vocab.ActivityStreamsAccept) error { return f.FederatingDB().Accept(ctx, accept) }, + // override default announce behavior and trigger our own side effects + func(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error { + return f.FederatingDB().Announce(ctx, announce) + }, } return diff --git a/internal/federation/federator.go b/internal/federation/federator.go index f2f223a65..149f68426 100644 --- a/internal/federation/federator.go +++ b/internal/federation/federator.go @@ -43,6 +43,9 @@ type Federator interface { // DereferenceRemoteAccount can be used to get the representation of a remote account, based on the account ID (which is a URI). // The given username will be used to create a transport for making outgoing requests. See the implementation for more detailed comments. DereferenceRemoteAccount(username string, remoteAccountID *url.URL) (typeutils.Accountable, error) + // DereferenceRemoteStatus can be used to get the representation of a remote status, based on its ID (which is a URI). + // The given username will be used to create a transport for making outgoing requests. See the implementation for more detailed comments. + DereferenceRemoteStatus(username string, remoteStatusID *url.URL) (typeutils.Statusable, error) // GetTransportForUser returns a new transport initialized with the key credentials belonging to the given username. // This can be used for making signed http requests. // diff --git a/internal/federation/util.go b/internal/federation/util.go index 837d92759..7be92e13d 100644 --- a/internal/federation/util.go +++ b/internal/federation/util.go @@ -258,6 +258,88 @@ func (f *federator) DereferenceRemoteAccount(username string, remoteAccountID *u return nil, fmt.Errorf("type name %s not supported", t.GetTypeName()) } +func (f *federator) DereferenceRemoteStatus(username string, remoteStatusID *url.URL) (typeutils.Statusable, error) { + transport, err := f.GetTransportForUser(username) + if err != nil { + return nil, fmt.Errorf("transport err: %s", err) + } + + b, err := transport.Dereference(context.Background(), remoteStatusID) + if err != nil { + return nil, fmt.Errorf("error deferencing %s: %s", remoteStatusID.String(), err) + } + + m := make(map[string]interface{}) + if err := json.Unmarshal(b, &m); err != nil { + return nil, fmt.Errorf("error unmarshalling bytes into json: %s", err) + } + + t, err := streams.ToType(context.Background(), m) + if err != nil { + return nil, fmt.Errorf("error resolving json into ap vocab type: %s", err) + } + + // Article, Document, Image, Video, Note, Page, Event, Place, Mention, Profile + switch t.GetTypeName() { + case gtsmodel.ActivityStreamsArticle: + p, ok := t.(vocab.ActivityStreamsArticle) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsArticle") + } + return p, nil + case gtsmodel.ActivityStreamsDocument: + p, ok := t.(vocab.ActivityStreamsDocument) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsDocument") + } + return p, nil + case gtsmodel.ActivityStreamsImage: + p, ok := t.(vocab.ActivityStreamsImage) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsImage") + } + return p, nil + case gtsmodel.ActivityStreamsVideo: + p, ok := t.(vocab.ActivityStreamsVideo) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsVideo") + } + return p, nil + case gtsmodel.ActivityStreamsNote: + p, ok := t.(vocab.ActivityStreamsNote) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsNote") + } + return p, nil + case gtsmodel.ActivityStreamsPage: + p, ok := t.(vocab.ActivityStreamsPage) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsPage") + } + return p, nil + case gtsmodel.ActivityStreamsEvent: + p, ok := t.(vocab.ActivityStreamsEvent) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsEvent") + } + return p, nil + case gtsmodel.ActivityStreamsPlace: + p, ok := t.(vocab.ActivityStreamsPlace) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsPlace") + } + return p, nil + case gtsmodel.ActivityStreamsProfile: + p, ok := t.(vocab.ActivityStreamsProfile) + if !ok { + return nil, errors.New("error resolving type as ActivityStreamsProfile") + } + return p, nil + } + + return nil, fmt.Errorf("type name %s not supported", t.GetTypeName()) +} + func (f *federator) GetTransportForUser(username string) (transport.Transport, error) { // We need an account to use to create a transport for dereferecing the signature. // If a username has been given, we can fetch the account with that username and use it. @@ -279,5 +361,3 @@ func (f *federator) GetTransportForUser(username string) (transport.Transport, e } return transport, nil } - - |