Overhaul of interfaces, begin detailed Activity handling.

このコミットが含まれているのは:
Cory Slep 2018-02-15 23:38:58 +01:00
コミット 683a26f6c1
4個のファイルの変更748行の追加352行の削除

ファイル差分が大きすぎるため省略します 差分を読み込み

ファイルの表示

@ -1,21 +1,97 @@
package pub
import (
"context"
"github.com/go-fed/activity/vocab"
"net/http"
"net/url"
"time"
)
// HandlerFunc returns true if it was able to handle the request as an
// ActivityPub request. If it handled the request then the error should be
// checked. The response will have already been written to when handled. Client
// applications can freely choose how to handle the request if this function
// does not handle it.
// checked. The response will have already been written to when handled and
// there was no error. Client applications can freely choose how to handle the
// request if this function does not handle it.
//
// Note that if the handler attempted to handle the request but returned an
// error, it is up to the client application to determine what headers and
// response to send to the requester.
type HandlerFunc func(http.ResponseWriter, *http.Request) (bool, error)
type HandlerFunc func(context.Context, http.ResponseWriter, *http.Request) (bool, error)
// Clock determines the time.
type Clock interface {
Now() time.Time
}
// Application is provided by users of this library in order to implement a
// social-federative-web application.
//
// The contexts provided in these calls are passed through this library without
// modification, allowing implementations to pass-through request-scoped data in
// order to properly handle the request.
type Application interface {
// Get fetches the ActivityStream representation of the given id.
Get(c context.Context, id url.URL) (PubObject, error)
// Set should write or overwrite the value of the provided object for
// its 'id'.
Set(c context.Context, o PubObject) error
// GetInbox returns the OrderedCollection inbox of the actor with the
// provided ID. It is up to the implementation to provide the correct
// collection for the kind of authorization given in the request.
GetInbox(c context.Context, r *http.Request) (vocab.OrderedCollectionType, error)
// GetOutbox returns the OrderedCollection inbox of the actor with the
// provided ID. It is up to the implementation to provide the correct
// collection for the kind of authorization given in the request.
GetOutbox(c context.Context, r *http.Request) (vocab.OrderedCollectionType, error)
// PostOutboxAuthorized determines whether the request is able to post
// an Activity to the outbox.
PostOutboxAuthorized(c context.Context, r *http.Request) (bool, error)
// NewId takes in a client id token and returns an ActivityStreams IRI
// id for a new Activity posted to the outbox. The object is provided
// as a Typer so clients can use it to decide how to generate the IRI.
NewId(c context.Context, t Typer) url.URL
// AddToOutboxResolver(c context.Context) (*streams.Resolver, error)
// ActorIRI returns the actor's IRI associated with the given request.
ActorIRI(c context.Context, r *http.Request) (url.URL, error)
}
// SocialApp is provided by users of this library and designed to handle
// receiving messages from ActivityPub clients through the Social API.
type SocialApp interface {
// Owns returns true if the provided id is owned by this server.
Owns(c context.Context, id url.URL) bool
// CanAdd returns true if the provided object is allowed to be added to
// the given target collection.
CanAdd(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool
// CanRemove returns true if the provided object is allowed to be
// removed from the given target collection.
CanRemove(c context.Context, o vocab.ObjectType, t vocab.ObjectType) bool
}
// PubObject is an ActivityPub Object.
type PubObject interface {
GetId() url.URL
SetId(url.URL)
HasId() bool
TypeLen() int
GetType(int) interface{}
AddType(interface{})
RemoveType(int)
}
// Typer is an object that has a type.
type Typer interface {
TypeLen() (l int)
GetType(index int) (v interface{})
}
// typeIder is a Typer with additional generic capabilities.
type typeIder interface {
Typer
SetId(v url.URL)
Serialize() (m map[string]interface{}, e error)
}
// actorObject is an object that has "actor" or "attributedTo" properties,
// representing the author or originator of the object.

ファイルの表示

@ -705,6 +705,137 @@ func getURIsInOrderedItemer(i orderedItemer) []url.URL {
return u
}
type activityWithObject interface {
ObjectLen() (l int)
IsObject(index int) (ok bool)
GetObject(index int) (v vocab.ObjectType)
IsObjectIRI(index int) (ok bool)
GetObjectIRI(index int) (v url.URL)
}
func getObjectIds(a activityWithObject) (u []url.URL, e error) {
for i := 0; i < a.ObjectLen(); i++ {
if a.IsObject(i) {
obj := a.GetObject(i)
if !obj.HasId() {
e = fmt.Errorf("object has no id: %v", obj)
return
}
u = append(u, obj.GetId())
} else if a.IsObjectIRI(i) {
u = append(u, a.GetObjectIRI(i))
}
}
return
}
type activityWithTarget interface {
TargetLen() (l int)
IsTargetObject(index int) (ok bool)
GetTargetObject(index int) (v vocab.ObjectType)
IsTargetIRI(index int) (ok bool)
GetTargetIRI(index int) (v url.URL)
}
func getTargetIds(a activityWithTarget) (u []url.URL, e error) {
for i := 0; i < a.TargetLen(); i++ {
if a.IsTargetObject(i) {
obj := a.GetTargetObject(i)
if !obj.HasId() {
e = fmt.Errorf("object has no id: %v", obj)
return
}
u = append(u, obj.GetId())
} else if a.IsTargetIRI(i) {
u = append(u, a.GetTargetIRI(i))
}
}
return
}
func removeCollectionItemWithId(c vocab.CollectionType, iri url.URL) {
for i := 0; i < c.ItemsLen(); i++ {
if c.IsItemsObject(i) {
o := c.GetItemsObject(i)
if !o.HasId() {
continue
}
if o.GetId() == iri {
c.RemoveItemsObject(i)
return
}
} else if c.IsItemsLink(i) {
l := c.GetItemsLink(i)
if !l.HasHref() {
continue
}
if l.GetHref() == iri {
c.RemoveItemsLink(i)
return
}
} else if c.IsItemsIRI(i) {
if c.GetItemsIRI(i) == iri {
c.RemoveItemsIRI(i)
return
}
}
}
}
func removeOrderedCollectionItemWithId(c vocab.OrderedCollectionType, iri url.URL) {
for i := 0; i < c.OrderedItemsLen(); i++ {
if c.IsOrderedItemsObject(i) {
o := c.GetOrderedItemsObject(i)
if !o.HasId() {
continue
}
if o.GetId() == iri {
c.RemoveOrderedItemsObject(i)
return
}
} else if c.IsOrderedItemsLink(i) {
l := c.GetOrderedItemsLink(i)
if !l.HasHref() {
continue
}
if l.GetHref() == iri {
c.RemoveOrderedItemsLink(i)
return
}
} else if c.IsOrderedItemsIRI(i) {
if c.GetOrderedItemsIRI(i) == iri {
c.RemoveOrderedItemsIRI(i)
return
}
}
}
}
// toTombstone creates a Tombstone for the given object.
func toTombstone(obj vocab.ObjectType, id url.URL, now time.Time) vocab.TombstoneType {
tomb := &vocab.Tombstone{}
tomb.SetId(id)
for i := 0; i < obj.TypeLen(); i++ {
if s, ok := obj.GetType(i).(string); ok {
tomb.AddFormerTypeString(s)
} else if fObj, ok := obj.GetType(i).(vocab.ObjectType); ok {
tomb.AddFormerTypeObject(fObj)
}
}
if obj.IsPublished() {
tomb.SetPublished(obj.GetPublished())
} else if obj.IsPublishedIRI() {
tomb.SetPublishedIRI(obj.GetPublishedIRI())
}
if obj.IsUpdated() {
tomb.SetUpdated(obj.GetUpdated())
} else if obj.IsUpdatedIRI() {
tomb.SetUpdatedIRI(obj.GetUpdatedIRI())
}
tomb.SetDeleted(now)
return tomb
}
// TODO: Move this to vocab package.
var activityTypes = []string{"Accept", "Add", "Announce", "Arrive", "Block", "Create", "Delete", "Dislike", "Flag", "Follow", "Ignore", "Invite", "Join", "Leave", "Like", "Listen", "Move", "Offer", "Question", "Reject", "Read", "Remove", "TentativeReject", "TentativeAccept", "Travel", "Undo", "Update", "View"}

ファイルの表示

@ -7,6 +7,34 @@ import (
"net/url"
)
// ToPubObject transforms a json-deserialized ActivityStream object into a
// PubObject for use with the pub library. Note that for an object to be an
// ActivityPub object, it must have an 'id' and at least one 'type'.
func ToPubObject(m map[string]interface{}) (t []PubObject, e error) {
r := &streams.Resolver{
AnyObjectCallback: func(i vocab.ObjectType) error {
if !i.HasId() {
return fmt.Errorf("object type does not have an id: %q", i)
} else if i.TypeLen() == 0 {
return fmt.Errorf("object type does not have a type: %q", i)
}
t = append(t, i)
return nil
},
AnyLinkCallback: func(i vocab.LinkType) error {
if !i.HasId() {
return fmt.Errorf("link type does not have an id: %q", i)
} else if i.TypeLen() == 0 {
return fmt.Errorf("link type does not have a type: %q", i)
}
t = append(t, i)
return nil
},
}
e = r.Deserialize(m)
return t, e
}
func toActorResolver(a *actorObject) *streams.Resolver {
return &streams.Resolver{
AnyObjectCallback: func(i vocab.ObjectType) error {