Better abstract programmatic sending of activities.
このコミットが含まれているのは:
コミット
a65388c27b
18
pub/actor.go
18
pub/actor.go
|
@ -1,6 +1,7 @@
|
||||||
package pub
|
package pub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/go-fed/activity/streams/vocab"
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -96,13 +97,18 @@ type Actor interface {
|
||||||
// Activity to a federating peer.
|
// Activity to a federating peer.
|
||||||
type FederatingActor interface {
|
type FederatingActor interface {
|
||||||
Actor
|
Actor
|
||||||
// Deliver sends a federated message.
|
// Send a federated activity.
|
||||||
//
|
//
|
||||||
// The provided url must be the outbox of the sender for identity
|
// The provided url must be the outbox of the sender. All processing of
|
||||||
// purposes only. It is up to the caller to ensure that the provided
|
// the activity occurs similarly to the C2S flow:
|
||||||
// activity has been added to the outbox.
|
// - 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
|
// Note that this function will only behave as expected if the
|
||||||
// implementation has been constructed to support federation.
|
// implementation has been constructed to support federation. This
|
||||||
Deliver(c context.Context, outbox *url.URL, activity Activity) error
|
// 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"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-fed/activity/streams"
|
"github.com/go-fed/activity/streams"
|
||||||
|
"github.com/go-fed/activity/streams/vocab"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -329,50 +330,18 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
// If the value is not an Activity or type extending from Activity, then
|
// The HTTP request steps are complete, complete the rest of the outbox
|
||||||
// we need to wrap it in a Create Activity.
|
// and delivery process.
|
||||||
if !streams.IsOrExtendsActivityStreamsActivity(asValue) {
|
activity, err := b.deliver(c, r.URL, asValue, m)
|
||||||
asValue, err = b.delegate.WrapInCreate(c, asValue, r.URL)
|
// Special case: We know it is a bad request if the object or
|
||||||
if err != nil {
|
// target properties needed to be populated, but weren't.
|
||||||
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.
|
|
||||||
//
|
//
|
||||||
// If we are federating and the type is a deliverable one, then deliver
|
// Send the rejection to the client.
|
||||||
// the activity to federating peers.
|
if err == ErrObjectRequired || err == ErrTargetRequired {
|
||||||
if b.enableFederatedProtocol && deliverable {
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
if err := b.delegate.Deliver(c, r.URL, activity); err != nil {
|
return true, nil
|
||||||
return true, err
|
} else if err != nil {
|
||||||
}
|
return true, err
|
||||||
}
|
}
|
||||||
// Respond to the request with the new Activity's IRI location.
|
// Respond to the request with the new Activity's IRI location.
|
||||||
w.Header().Set(locationHeader, activity.GetActivityStreamsId().Get().String())
|
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
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deliver delegates directly to the delegate actor.
|
// deliver delegates all outbox handling steps and optionally will federate the
|
||||||
func (b *baseActorFederating) Deliver(c context.Context, outbox *url.URL, activity Activity) error {
|
// activity if the federated protocol is enabled.
|
||||||
return b.delegate.Deliver(c, outbox, activity)
|
//
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
読み込み中…
新しいイシューから参照