147 lines
3.8 KiB
Go
147 lines
3.8 KiB
Go
package goap
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/piprate/json-gold/ld"
|
|
)
|
|
|
|
// Internal so that others don't mess with this and potentially accidentally overwrite it, breaking everything
|
|
var allInternalParsersExceptBase []UnmarshalFunc = []UnmarshalFunc{
|
|
ParseUDIdData,
|
|
ParseUDTypeData,
|
|
ParseASActorData,
|
|
ParseASAlsoKnownAsData,
|
|
ParseASAttachmentsData,
|
|
ParseASAttributedToData,
|
|
ParseASCCData,
|
|
ParseASContentData,
|
|
ParseASEndpointsData,
|
|
ParseASFollowersData,
|
|
ParseASFollowingData,
|
|
ParseASHrefData,
|
|
ParseASIconData,
|
|
ParseASImageData,
|
|
ParseASMediaTypeData,
|
|
ParseASNameData,
|
|
ParseASOutboxData,
|
|
ParseASObjectData,
|
|
ParseASPreferredNameData,
|
|
ParseASPublishedData,
|
|
ParseASRestrictedData,
|
|
ParseASRepliesData,
|
|
ParseASSharedInboxData,
|
|
ParseASSummaryData,
|
|
ParseASSensitiveData,
|
|
ParseASTagData,
|
|
ParseASToData,
|
|
ParseASUrlData,
|
|
ParseASUpdatedData,
|
|
|
|
ParseOstatusAtomUriData,
|
|
ParseOstatusConversationData,
|
|
|
|
ParseW3InboxData,
|
|
|
|
ParseW3VcardAddressData,
|
|
ParseW3VcardBirthdayData,
|
|
|
|
ParseW3SecurityOwnerData,
|
|
ParseW3SecurityPublicKeyPemData,
|
|
ParseW3SecurityPublicKeyData,
|
|
|
|
ParseMastoDevicesData,
|
|
ParseMastoDiscoverableData,
|
|
ParseMastoFeaturedData,
|
|
ParseMastoDiscoverableData,
|
|
ParseMastoIndexableData,
|
|
ParseMastoMemorialData,
|
|
|
|
ParseSchemaValueData,
|
|
|
|
ParseMKIsCatData,
|
|
ParseMKSummaryData,
|
|
|
|
ParseFFSpeakAsCatData,
|
|
}
|
|
|
|
func chainParse(
|
|
raw map[string]any,
|
|
start BaseApChain,
|
|
parsers ...UnmarshalFunc,
|
|
) (BaseApChain, []error) {
|
|
var current BaseApChain = start
|
|
errors := []error{}
|
|
|
|
for _, p := range parsers {
|
|
next, err := p(raw, current)
|
|
current = next
|
|
errors = append(errors, err)
|
|
}
|
|
|
|
return current, errors
|
|
}
|
|
|
|
// Unmarshal raw data into an Activitypub object in the form of a recursive BaseApChain
|
|
// Each element corresponds to one attribute the object contained
|
|
// If ldOptions or processor are nil, the following defaults are used:
|
|
// - ldOptions: `ld.NewJsonLdOptions("")`
|
|
// - processor: `ld.NewJsonLdProcessor()`
|
|
// Returns an ActivityPub object and a list of errors produced by the parser functions
|
|
// Not each function has to produce an error. Those will have nil as error value
|
|
// Those errors (or nils) come in the order of the parser functions
|
|
// which can be inspected in the `allInternalParsersExceptBase` internal variable
|
|
func Unmarshal(
|
|
raw []byte,
|
|
ldOptions *ld.JsonLdOptions,
|
|
processor *ld.JsonLdProcessor,
|
|
extraParsers ...UnmarshalFunc,
|
|
) (BaseApChain, []error) {
|
|
if ldOptions == nil {
|
|
ldOptions = ld.NewJsonLdOptions("")
|
|
}
|
|
if processor == nil {
|
|
processor = ld.NewJsonLdProcessor()
|
|
}
|
|
rawData, err := processor.Expand(raw, ldOptions)
|
|
if err != nil {
|
|
return nil, []error{err}
|
|
}
|
|
data, ok := rawData[0].(map[string]any)
|
|
if !ok {
|
|
return nil, []error{fmt.Errorf("failed to cast expand result into map[string]any")}
|
|
}
|
|
return UnmarshalPreprocessed(data, extraParsers...)
|
|
}
|
|
|
|
// Unmarshal a preproccessed object. Preproccessed meaning being first parsed as json and then expanded by json-gold
|
|
// Otherwise the same as Unmarshal
|
|
func UnmarshalPreprocessed(
|
|
raw map[string]any,
|
|
extraParsers ...UnmarshalFunc,
|
|
) (BaseApChain, []error) {
|
|
base := EmptyBaseObject{}
|
|
allParsers := slices.Concat(allInternalParsersExceptBase, extraParsers)
|
|
return chainParse(raw, &base, allParsers...)
|
|
}
|
|
|
|
// Find an attribute in an ActivityPub object of the given type
|
|
// Returns a pointer to the found attribute and whether it found it
|
|
// 2nd parameter is true if the attribute was found, false otherwise
|
|
func FindAttribute[T BaseApChain](object BaseApChain) (*T, bool) {
|
|
var obj T
|
|
var ok bool
|
|
// Try and cast object into wanted type
|
|
// If cast failed, do inner codeblock
|
|
// Try and cast again
|
|
for obj, ok = object.(T); !ok; obj, ok = object.(T) {
|
|
// Get the next attribute in the chain
|
|
object, ok = object.GetSelfOrBase()
|
|
// If this is the final object in the chain, cancel and return false
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
}
|
|
return &obj, true
|
|
}
|