Better abstract programmatic sending of activities.
このコミットが含まれているのは:
コミット
a65388c27b
18
pub/actor.go
18
pub/actor.go
|
@ -1,6 +1,7 @@
|
|||
package pub
|
||||
|
||||
import (
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -96,13 +97,18 @@ type Actor interface {
|
|||
// Activity to a federating peer.
|
||||
type FederatingActor interface {
|
||||
Actor
|
||||
// Deliver sends a federated message.
|
||||
// Send a federated activity.
|
||||
//
|
||||
// The provided url must be the outbox of the sender for identity
|
||||
// purposes only. It is up to the caller to ensure that the provided
|
||||
// activity has been added to the outbox.
|
||||
// The provided url must be the outbox of the sender. All processing of
|
||||
// the activity occurs similarly to the C2S flow:
|
||||
// - If t is not an Activity, it is wrapped in a Create activity.
|
||||
// - A new ID is generated for the activity
|
||||
// - The activity is added to the specified outbox
|
||||
// - The activity is prepared and delivered to recipients
|
||||
//
|
||||
// Note that this function will only behave as expected if the
|
||||
// implementation has been constructed to support federation.
|
||||
Deliver(c context.Context, outbox *url.URL, activity Activity) error
|
||||
// implementation has been constructed to support federation. This
|
||||
// method will guaranteed work for non-custom Actors. For custom actors,
|
||||
// care should be used to not call this method if only C2S is supported.
|
||||
Send(c context.Context, outbox *url.URL, t vocab.Type) (Activity, error)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -329,50 +330,18 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http
|
|||
w.WriteHeader(http.StatusBadRequest)
|
||||
return true, nil
|
||||
}
|
||||
// If the value is not an Activity or type extending from Activity, then
|
||||
// we need to wrap it in a Create Activity.
|
||||
if !streams.IsOrExtendsActivityStreamsActivity(asValue) {
|
||||
asValue, err = b.delegate.WrapInCreate(c, asValue, r.URL)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
// At this point, this should be a safe conversion. If this error is
|
||||
// triggered, then there is either a bug in the delegation of
|
||||
// WrapInCreate, behavior is not lining up in the generated ExtendedBy
|
||||
// code, or something else is incorrect with the type system.
|
||||
activity, ok := asValue.(Activity)
|
||||
if !ok {
|
||||
return true, fmt.Errorf("activity streams value is not an Activity: %T", asValue)
|
||||
}
|
||||
// Delegate generating new IDs for the activity and all new objects.
|
||||
if err = b.delegate.AddNewIds(c, activity); err != nil {
|
||||
return true, err
|
||||
}
|
||||
// Post the activity to the actor's outbox and trigger side effects for
|
||||
// that particular Activity type.
|
||||
deliverable, err := b.delegate.PostOutbox(c, activity, r.URL, m)
|
||||
if err != nil {
|
||||
// Special case: We know it is a bad request if the object or
|
||||
// target properties needed to be populated, but weren't.
|
||||
//
|
||||
// Send the rejection to the peer.
|
||||
if err == ErrObjectRequired || err == ErrTargetRequired {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return true, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
// Request has been processed and all side effects internal to this
|
||||
// application server have finished. Begin side effects affecting other
|
||||
// servers and/or the client who sent this request.
|
||||
// The HTTP request steps are complete, complete the rest of the outbox
|
||||
// and delivery process.
|
||||
activity, err := b.deliver(c, r.URL, asValue, m)
|
||||
// Special case: We know it is a bad request if the object or
|
||||
// target properties needed to be populated, but weren't.
|
||||
//
|
||||
// If we are federating and the type is a deliverable one, then deliver
|
||||
// the activity to federating peers.
|
||||
if b.enableFederatedProtocol && deliverable {
|
||||
if err := b.delegate.Deliver(c, r.URL, activity); err != nil {
|
||||
return true, err
|
||||
}
|
||||
// Send the rejection to the client.
|
||||
if err == ErrObjectRequired || err == ErrTargetRequired {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return true, nil
|
||||
} else if err != nil {
|
||||
return true, err
|
||||
}
|
||||
// Respond to the request with the new Activity's IRI location.
|
||||
w.Header().Set(locationHeader, activity.GetActivityStreamsId().Get().String())
|
||||
|
@ -423,7 +392,67 @@ func (b *baseActor) GetOutbox(c context.Context, w http.ResponseWriter, r *http.
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// Deliver delegates directly to the delegate actor.
|
||||
func (b *baseActorFederating) Deliver(c context.Context, outbox *url.URL, activity Activity) error {
|
||||
return b.delegate.Deliver(c, outbox, activity)
|
||||
// deliver delegates all outbox handling steps and optionally will federate the
|
||||
// activity if the federated protocol is enabled.
|
||||
//
|
||||
// This function is not exported so an Actor that only supports C2S cannot be
|
||||
// type casted to a FederatingActor. It doesn't exactly fit the Send method
|
||||
// signature anyways.
|
||||
//
|
||||
// Note: 'm' is nilable.
|
||||
func (b *baseActor) deliver(c context.Context, outbox *url.URL, asValue vocab.Type, m map[string]interface{}) (activity Activity, err error) {
|
||||
// If the value is not an Activity or type extending from Activity, then
|
||||
// we need to wrap it in a Create Activity.
|
||||
if !streams.IsOrExtendsActivityStreamsActivity(asValue) {
|
||||
asValue, err = b.delegate.WrapInCreate(c, asValue, outbox)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// At this point, this should be a safe conversion. If this error is
|
||||
// triggered, then there is either a bug in the delegation of
|
||||
// WrapInCreate, behavior is not lining up in the generated ExtendedBy
|
||||
// code, or something else is incorrect with the type system.
|
||||
var ok bool
|
||||
activity, ok = asValue.(Activity)
|
||||
if !ok {
|
||||
err = fmt.Errorf("activity streams value is not an Activity: %T", asValue)
|
||||
return
|
||||
}
|
||||
// Delegate generating new IDs for the activity and all new objects.
|
||||
if err = b.delegate.AddNewIds(c, activity); err != nil {
|
||||
return
|
||||
}
|
||||
// Post the activity to the actor's outbox and trigger side effects for
|
||||
// that particular Activity type.
|
||||
//
|
||||
// Since 'm' is nil-able and side effects may need access to literal nil
|
||||
// values, such as for Update activities, ensure 'm' is non-nil.
|
||||
if m == nil {
|
||||
m, err = asValue.Serialize()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
deliverable, err := b.delegate.PostOutbox(c, activity, outbox, m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Request has been processed and all side effects internal to this
|
||||
// application server have finished. Begin side effects affecting other
|
||||
// servers and/or the client who sent this request.
|
||||
//
|
||||
// If we are federating and the type is a deliverable one, then deliver
|
||||
// the activity to federating peers.
|
||||
if b.enableFederatedProtocol && deliverable {
|
||||
if err = b.delegate.Deliver(c, outbox, activity); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Send is programmatically accessible if the federated protocol is enabled.
|
||||
func (b *baseActorFederating) Send(c context.Context, outbox *url.URL, t vocab.Type) (Activity, error) {
|
||||
return b.deliver(c, outbox, t, nil)
|
||||
}
|
||||
|
|
読み込み中…
新しいイシューから参照