This repository has been archived on 2022-11-27. You can view files and clone it, but cannot push or open issues or pull requests.
activitypub/unmarshall.go

367 lines
9.3 KiB
Go
Raw Normal View History

package activitystreams
import (
"encoding"
"encoding/json"
2018-11-21 11:25:29 +00:00
"fmt"
"net/url"
"reflect"
"time"
"github.com/buger/jsonparser"
)
var (
apUnmarshalerType = reflect.TypeOf(new(Item)).Elem()
unmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem()
textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
)
// ItemTyperFunc will return an instance of a struct that implements activitystreams.Item
// The default for this package is JSONGetItemByType but can be overwritten
var ItemTyperFunc TyperFunction
// TyperFunction is the type of the function which returns an activitystreams.Item struct instance
// for a specific ActivityVocabularyType
type TyperFunction func(ActivityVocabularyType) (Item, error)
func JSONGetObjectID(data []byte) ObjectID {
i, err := jsonparser.GetString(data, "id")
if err != nil {
return ObjectID("")
}
return ObjectID(i)
}
func JSONGetType(data []byte) ActivityVocabularyType {
t, err := jsonparser.GetString(data, "type")
typ := ActivityVocabularyType(t)
if err != nil {
return ActivityVocabularyType("")
}
return typ
}
func JSONGetMimeType(data []byte) MimeType {
t, err := jsonparser.GetString(data, "mediaType")
if err != nil {
return MimeType("")
}
return MimeType(t)
}
2018-11-21 11:25:29 +00:00
func JSONGetInt(data []byte, prop string) int64 {
2018-08-05 11:54:01 +00:00
val, err := jsonparser.GetInt(data, prop)
if err != nil {
}
return val
}
func JSONGetString(data []byte, prop string) string {
val, err := jsonparser.GetString(data, prop)
if err != nil {
}
return val
}
func JSONGetNaturalLanguageField(data []byte, prop string) NaturalLanguageValues {
n := NaturalLanguageValues{}
val, typ, _, err := jsonparser.Get(data, prop)
if err != nil {
return nil
}
switch typ {
case jsonparser.Object:
jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
if dataType == jsonparser.String {
l := LangRefValue{}
if err := l.UnmarshalJSON(value); err == nil {
n = append(n, l)
}
}
return err
})
case jsonparser.String:
l := LangRefValue{}
if err := l.UnmarshalJSON(val); err == nil {
n = append(n, l)
}
}
return n
}
2018-08-05 13:25:54 +00:00
func JSONGetTime(data []byte, prop string) time.Time {
t := time.Time{}
str, _ := jsonparser.GetUnsafeString(data, prop)
t.UnmarshalText([]byte(str))
return t
}
func JSONGetDuration(data []byte, prop string) time.Duration {
str, _ := jsonparser.GetUnsafeString(data, prop)
d, _ := time.ParseDuration(str)
return d
}
func JSONUnmarshalToItem(data []byte) Item {
if _, err := url.ParseRequestURI(string(data)); err == nil {
// try to see if it's an IRI
return IRI(data)
}
i, err := ItemTyperFunc(JSONGetType(data))
if err != nil {
return nil
}
p := reflect.PtrTo(reflect.TypeOf(i))
if reflect.TypeOf(i).Implements(unmarshalerType) || p.Implements(unmarshalerType) {
err = i.(json.Unmarshaler).UnmarshalJSON(data)
}
if reflect.TypeOf(i).Implements(textUnmarshalerType) || p.Implements(textUnmarshalerType) {
err = i.(encoding.TextUnmarshaler).UnmarshalText(data)
}
if err != nil {
return nil
}
2018-08-05 13:25:54 +00:00
return i
}
func JSONGetItem(data []byte, prop string) Item {
val, typ, _, err := jsonparser.Get(data, prop)
2018-08-05 13:25:54 +00:00
if err != nil {
return nil
}
switch typ {
case jsonparser.String:
if _, err = url.ParseRequestURI(string(val)); err == nil {
// try to see if it's an IRI
return IRI(val)
}
case jsonparser.Object:
return JSONUnmarshalToItem(val)
case jsonparser.Number:
fallthrough
case jsonparser.Array:
fallthrough
case jsonparser.Boolean:
fallthrough
case jsonparser.Null:
fallthrough
case jsonparser.Unknown:
fallthrough
default:
return nil
}
return nil
2018-08-05 13:25:54 +00:00
}
func JSONGetItems(data []byte, prop string) ItemCollection {
val, typ, _, err := jsonparser.Get(data, prop)
if err != nil {
return nil
}
it := make(ItemCollection, 0)
switch typ {
2018-08-05 11:54:01 +00:00
case jsonparser.Array:
jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
i := JSONUnmarshalToItem(value)
if i != nil {
it.Append(i)
}
2018-08-05 11:54:01 +00:00
}, prop)
case jsonparser.Object:
jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
i := JSONUnmarshalToItem(value)
if i != nil {
it.Append(i)
}
return err
}, prop)
case jsonparser.String:
2018-08-05 13:25:54 +00:00
s, _ := jsonparser.GetString(val)
2018-10-11 18:13:34 +00:00
it.Append(IRI(s))
}
return it
}
2018-11-21 11:25:29 +00:00
func JSONGetURIItem(data []byte, prop string) Item {
val, typ, _, err := jsonparser.Get(data, prop)
if err != nil {
return nil
}
switch typ {
case jsonparser.Object:
return JSONGetItem(data, prop)
case jsonparser.Array:
it := make(ItemCollection, 0)
jsonparser.ArrayEach(val, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
if _, err := url.Parse(string(value)); err == nil {
it.Append(IRI(value))
return
}
i, err := ItemTyperFunc(JSONGetType(value))
if err != nil {
return
}
err = i.(json.Unmarshaler).UnmarshalJSON(value)
if err != nil {
return
}
it.Append(i)
})
return it
case jsonparser.String:
return IRI(val)
}
return nil
}
func JSONGetLangRefField(data []byte, prop string) LangRef {
val, err := jsonparser.GetString(data, prop)
if err != nil {
return LangRef("")
}
return LangRef(val)
}
func JSONGetIRI(data []byte, prop string) IRI {
val, err := jsonparser.GetString(data, prop)
if err != nil {
return IRI("")
}
return IRI(val)
}
// UnmarshalJSON tries to detect the type of the object in the json data and then outputs a matching
// ActivityStreams object, if possible
func UnmarshalJSON(data []byte) (Item, error) {
if ItemTyperFunc == nil {
ItemTyperFunc = JSONGetItemByType
}
return JSONUnmarshalToItem(data), nil
}
func JSONGetItemByType(typ ActivityVocabularyType) (Item, error) {
2018-11-21 11:25:29 +00:00
switch typ {
case ObjectType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case LinkType:
2019-09-09 18:49:19 +00:00
return &Link{Type: typ}, nil
2018-11-21 11:25:29 +00:00
case ActivityType:
2019-09-09 18:49:19 +00:00
return &Activity{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case IntransitiveActivityType:
2019-09-09 18:49:19 +00:00
return &IntransitiveActivity{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ActorType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case CollectionType:
2019-09-09 18:49:19 +00:00
return &Collection{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case OrderedCollectionType:
2019-09-09 18:49:19 +00:00
return &OrderedCollection{Parent: Parent{Type: typ}}, nil
case CollectionPageType:
2019-09-09 18:49:19 +00:00
return &CollectionPage{ParentCollection: ParentCollection{Parent: Parent{Type: typ}}}, nil
case OrderedCollectionPageType:
2019-09-09 18:49:19 +00:00
return &OrderedCollectionPage{OrderedCollection: OrderedCollection{Parent: Parent{Type: typ}}}, nil
2018-11-21 11:25:29 +00:00
case ArticleType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case AudioType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case DocumentType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case EventType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case ImageType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case NoteType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case PageType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case PlaceType:
2019-09-09 18:49:19 +00:00
return &Place{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ProfileType:
2019-09-09 18:49:19 +00:00
return &Profile{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case RelationshipType:
2019-09-09 18:49:19 +00:00
return &Relationship{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case TombstoneType:
2019-09-09 18:49:19 +00:00
return &Tombstone{Parent: Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case VideoType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case MentionType:
2019-09-09 18:49:19 +00:00
return &Mention{Type:typ}, nil
2018-11-21 11:25:29 +00:00
case ApplicationType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case GroupType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case OrganizationType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case PersonType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case ServiceType:
2019-09-09 18:49:19 +00:00
return ObjectNew(typ), nil
2018-11-21 11:25:29 +00:00
case AcceptType:
2019-09-09 18:49:19 +00:00
return &Accept{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case AddType:
2019-09-09 18:49:19 +00:00
return &Add{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case AnnounceType:
2019-09-09 18:49:19 +00:00
return &Announce{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ArriveType:
2019-09-09 18:49:19 +00:00
return &Arrive{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case BlockType:
2019-09-09 18:49:19 +00:00
return &Block{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case CreateType:
2019-09-09 18:49:19 +00:00
return &Create{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case DeleteType:
2019-09-09 18:49:19 +00:00
return &Delete{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case DislikeType:
2019-09-09 18:49:19 +00:00
return &Dislike{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case FlagType:
2019-09-09 18:49:19 +00:00
return &Flag{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case FollowType:
2019-09-09 18:49:19 +00:00
return &Follow{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case IgnoreType:
2019-09-09 18:49:19 +00:00
return &Ignore{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case InviteType:
2019-09-09 18:49:19 +00:00
return &Invite{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case JoinType:
2019-09-09 18:49:19 +00:00
return &Join{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case LeaveType:
2019-09-09 18:49:19 +00:00
return &Leave{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case LikeType:
2019-09-09 18:49:19 +00:00
return &Like{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ListenType:
2019-09-09 18:49:19 +00:00
return &Listen{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case MoveType:
2019-09-09 18:49:19 +00:00
return &Move{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case OfferType:
2019-09-09 18:49:19 +00:00
return &Offer{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case QuestionType:
2019-09-09 18:49:19 +00:00
return &Question{Type: typ}, nil
2018-11-21 11:25:29 +00:00
case RejectType:
2019-09-09 18:49:19 +00:00
return &Reject{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ReadType:
2019-09-09 18:49:19 +00:00
return &Read{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case RemoveType:
2019-09-09 18:49:19 +00:00
return &Remove{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case TentativeRejectType:
2019-09-09 18:49:19 +00:00
return &TentativeReject{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case TentativeAcceptType:
2019-09-09 18:49:19 +00:00
return &TentativeAccept{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case TravelType:
2019-09-09 18:49:19 +00:00
return &Travel{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case UndoType:
2019-09-09 18:49:19 +00:00
return &Undo{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case UpdateType:
2019-09-09 18:49:19 +00:00
return &Update{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case ViewType:
2019-09-09 18:49:19 +00:00
return &View{Parent:Parent{Type: typ}}, nil
2018-11-21 11:25:29 +00:00
case "":
// when no type is available use a plain Object
2019-09-09 18:49:19 +00:00
return &Object{}, nil
2018-11-21 11:25:29 +00:00
}
2019-09-09 18:49:19 +00:00
return nil, fmt.Errorf("unrecognized ActivityStreams type %s", typ)
2018-11-21 11:25:29 +00:00
}